c# .net image-processing bitmap stride

Mapa de bits inclinado, cálculo de zancada para RGB565 C#



.net image-processing (2)

Esto espera que la zancada se corresponda con el ancho, sin relleno. Puede haber relleno. El relleno "comería" algo de la línea siguiente, lo que, por lo tanto, parecería desplazarse hacia la izquierda.

Como el relleno rompe las líneas, la única manera real de manejarlo (aparte de usar el mismo relleno en todas partes) es copiar línea por línea. Puede calcular la dirección de inicio de una línea con bmpData.Scan0 + y * bmpData.Stride . Copia comenzando allí, por cada y .

// bytes => no usa esto porque da error

Sí, porque su matriz no tiene relleno. Entonces, le pedías que copiara más datos de los que tenía la matriz.

Algunas de mis imágenes resultantes están sesgadas, otras no.

Resultado esperado: (529x22)

Resultado real: (529x22)

No importa los diferentes tamaños de imagen, estas son capturas de pantalla. Ambos son 529x22.

El código que estoy usando, acabo de obtener esto de una respuesta a una pregunta aquí en SO.

// some other method byte[] pixels = new byte[size - 16]; Array.Copy(this.data, offset, pixels, 0, pixels.Length); this.ByteToImage(w, h, pixels); // builds the pixels to a image private Bitmap ByteToImage(int w, int h, byte[] pixels) { var bmp = new Bitmap(w, h, PixelFormat.Format16bppRgb565); var BoundsRect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(BoundsRect, ImageLockMode.WriteOnly, bmp.PixelFormat); // bytes => not using this because it gives error // eg. pixel.Length = 16032, bytes = 16064 int bytes = bmpData.Stride * bmp.Height; Marshal.Copy(pixels, 0, bmpData.Scan0, pixels.Length); bmp.UnlockBits(bmpData); return bmp; }

Estoy confundido porque algunos funcionan bien, no sesgados. Pero otros están sesgados. ¿Qué me perdí?

Actualizar

Como se indica en los comentarios y respuestas, el problema es cómo estoy calculando zancadas. Todavía estoy confundido sobre cómo hacerlo, pero probé esto:

public static void RemovePadding(this Bitmap bitmap) { int bytesPerPixel = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8; BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); var pixels = new byte[bitmapData.Width * bitmapData.Height * bytesPerPixel]; for (int row = 0; row < bitmapData.Height; row++) { var dataBeginPointer = IntPtr.Add(bitmapData.Scan0, row * bitmapData.Stride); Marshal.Copy(dataBeginPointer, pixels, row * bitmapData.Width * bytesPerPixel, bitmapData.Width * bytesPerPixel); } Marshal.Copy(pixels, 0, bitmapData.Scan0, pixels.Length); bitmap.UnlockBits(bitmapData); }

Pero el resultado es (más sesgado):


Esto parece funcionar aquí:

private Bitmap ByteToImage(int w, int h, byte[] pixels) { var bmp = new Bitmap(w, h, PixelFormat.Format16bppRgb565); byte bpp = 2; var BoundsRect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(BoundsRect, ImageLockMode.WriteOnly, bmp.PixelFormat); // copy line by line: for (int y = 0; y < h; y++ ) Marshal.Copy(pixels, y * w * bpp, bmpData.Scan0 + bmpData.Stride * y, w * bpp); bmp.UnlockBits(bmpData); return bmp; }

Uso un bucle para colocar cada fila de datos en el lugar correcto. Los datos no incluyen el relleno, pero la dirección de destino debe hacerlo.

Por lo tanto, necesitamos multiplicar el acceso a los datos por el width * bytePerPixel real width * bytePerPixel pero la dirección de destino por Stride , es decir, la longitud de la línea de exploración, se rellena al siguiente múltiplo de cuatro bytes. Para width=300 es stride=300 , para width=301 es stride=304 ..

Mover todos los datos de píxeles en un solo paso solo puede funcionar cuando no hay relleno, es decir, cuando el ancho es un múltiplo de 4 .