2010-03-14 18 views
5

En mi aplicación, estoy almacenando Bitmap datos en una matriz de enteros bidimensional (int[,]). Para acceder a los valores de R, G y B que utilizo algo como esto:matriz de enteros o matriz de estructuras: ¿cuál es mejor?

// read: 
int i = _data[x, y]; 
byte B = (byte)(i >> 0); 
byte G = (byte)(i >> 8); 
byte R = (byte)(i >> 16); 
// write: 
_data[x, y] = BitConverter.ToInt32(new byte[] { B, G, R, 0 }, 0); 

estoy usando matrices de enteros en lugar de un verdadero System.Drawing.Bitmap porque mi aplicación se ejecuta en dispositivos Windows Mobile, donde la memoria disponible para la creación de mapas de bits está severamente limitado.

Me pregunto, sin embargo, si tendría más sentido para declarar una estructura como esta:

public struct RGB 
{ 
    public byte R; 
    public byte G; 
    public byte B; 
} 

... y luego usar una gran variedad de RGB lugar de una matriz de int. De esta forma, podría leer y escribir fácilmente los valores separados R, G y B sin tener que hacer cambios de bit y BitConverter. Recuerdo vagamente algo de días anteriores que las variables byte estaban alineadas en bloques en sistemas de 32 bits, por lo que un byte realmente ocupa 4 bytes de memoria en lugar de solo 1 (pero tal vez esto era solo algo de Visual Basic).

¿Usaría una matriz de estructuras (como el ejemplo anterior RGB) sería más rápido que usar una matriz de entradas, y usaría 3/4 de la memoria o 3 veces la memoria de las entradas?

Respuesta

2

Si se encuentra en aproximadamente velocidad, entonces técnicamente Yo esperaría que la versión int[] para ser más rápido, ya que hay una instrucción de IL específico para conseguir una int de una matriz (ver OpCodes.Ldelem_I4). Para hacer una estructura personalizada, debe obtener la dirección (OpCodes.Ldelema) y luego copiar la estructura (OpCodes.Ldobj) - procesando los metadatos de tipo para ambos pasos. En resumen, el enfoque int debería tener mejores optimizaciones. Pero esto es micro-optimización - en general prefiera la versión que hace que su código sea más legible.Lo que podría considerar es escribir la estructura con un operador de conversión implícita a medida estática de int a su estructura - entonces usted puede tener la int[] y todavía lo hacen:

MyColor col = intArr[12]; 

(que va a hacer una llamada estática en el medio, por supuesto)

también puede considerar el uso de un sindicato por lo que no tiene que hacer un montón de cambio:

IMPORTANTE I no he sanidad verificado el endianness en esto; simplemente cambie los desplazamientos de R/G/B para cambiarlo.

class Program 
{ 
    static void Main() 
    { 
     int[] i = { -1 }; 
     RGB rgb = i[0]; 
    } 
} 
[StructLayout(LayoutKind.Explicit)] 
public struct RGB 
{ 
    public RGB(int value) { 
     this.R = this.G = this.B = 0; this.Value = value; 
    } 
    [FieldOffset(0)] 
    public int Value; 
    [FieldOffset(2)] 
    public byte R; 
    [FieldOffset(1)] 
    public byte G; 
    [FieldOffset(0)] 
    public byte B; 

    public static implicit operator RGB(int value) { 
     return new RGB(value); 
    } 
    public static implicit operator int(RGB value) { 
     return value.Value; 
    } 
} 
+0

OK, el regreso de la unión. No sabía .NET permitió la superposición de campos. –

+0

Gracias por la información: no me di cuenta de que hay una diferencia IL en obtener un int de una matriz en lugar de una estructura, lo que explica por qué la lectura puede ser más rápida desde una matriz int. ¿Conoces alguna forma de escribir en la matriz int sin usar BitConverter.ToInt32? – MusiGenesis

+0

Además, definitivamente voy con el rendimiento sobre la legibilidad aquí. Mi aplicación tiene que procesar y combinar grandes cantidades de estos mapas de bits, por lo que cualquier mejora en la velocidad de lectura/escritura reduce significativamente el tiempo total empleado. – MusiGenesis

2

¿Por qué no usar la estructura Color en System.Drawing? Es más fácil de manejar y hacer referencia. De acuerdo, tiene 4 bytes (otro valor representa Alpha), pero también lo hace tu primera implementación, y si recuerdo correctamente, cualquier 3 bytes se alineará de todos modos con un bloque de 4 bytes. Eche un vistazo a la muestra here.

+0

He intentado usar 'matrices Color', pero para acceder a los valores de R, G y de un' Color' es más lento que el desplazamiento de bits un int (creo que era * mucho * más lento, pero no puedo recordar). – MusiGenesis

+0

'Color' tiene más de cuatro bytes, ya que no solo contiene los valores de R, G, B y A, sino que también hace un seguimiento de dónde provienen. – supercat

2

Un solo byte en sí mismo probablemente se alinee en bloque, pero se pueden empaquetar varios bytes en una estructura. Y de acuerdo con Marshal.SizeOf, su estructura RGB ocupa solo tres bytes de memoria. (Técnicamente, este es el tamaño cuando se coordina con la memoria no administrada, y el CLR podría elegir establecerlo de forma diferente, pero en la práctica creo que esto será correcto.)

Sin embargo, el CLR aún podría insertar relleno entre RGB y otras estructuras, y este comportamiento puede depender del procesador, la versión CLR, etc. En un sistema x86, asignar una matriz de 300 millones de RGB dio como resultado que el Administrador de tareas informara aproximadamente 900 MB comprometidos, mientras que asignar una matriz de 300 millones resultó en 1200 MB comprometido. Por lo tanto, parece que el 2.0 CLR en x86 le ofrece un ahorro del 25%. (Tengo que admitir que esto me sorprendió, como Traveling Tech Guy, esperaba que las estructuras de 3 bytes se alinearan con un límite de 4 bytes. Así que me puede estar perdiendo algo.) Pero el CF puede ser diferente: realmente solo lo sé probándolo en su plataforma objetivo.

+0

Gracias por la evaluación comparativa. – MusiGenesis

1

Creo que id depende de lo que desea lograr. Es ciertamente más Readabl utilizar a struct, y se puede utilizar con seguridad con

unsafe { } 

que realmente acelerar el acceso de mapa de bits. (SI sabe qué hacer, sin verificación de condiciones de contorno y cosas por el estilo) Y definitivamente, si desea hacer operadores para la multiplicación de mapas de bits, enmascaramiento, greyscaling, filtrando las gráficas habituales, INT es su amigo en términos de velocidad , pero lamentablemente no en caso de legibilidad. El filtro de matriz solo multiplica las entradas (se puede escribir de esa manera) no los valores RGB de forma independiente, pero con la estructura de Marks que de todos modos no debería ser el problema. creo que sirve

Cuestiones relacionadas