net manipulation imagesharp asp c# .net image-processing

c# - manipulation - imagesharp



Viaje a través de píxeles en BMP (7)

Hola, tengo un bmp cargado en un objeto BMP y debo viajar a través de los píxeles como la imagen anterior desde (1,1) píxeles a (100,100) px. utilizando el método getpixel() . Estaba usando ONE loop pero no fue exitoso.

Si estoy usando el concepto de matriz multidimensional, ¿cuáles deberían ser los valores variables?


Cuando desee realizar el procesamiento de imágenes en imágenes grandes, el método GetPixel () lleva mucho tiempo, pero creo que mi algoritmo toma menos tiempo que otras respuestas, por ejemplo, puede probar este código en una imagen de 800 * 600 píxeles.

Bitmap bmp = new Bitmap("SomeImage"); // Lock the bitmap''s bits. Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb); // Get the address of the first line. IntPtr ptr = bmpData.Scan0; // Declare an array to hold the bytes of the bitmap. int bytes = bmpData.Stride * bmp.Height; byte[] rgbValues = new byte[bytes]; byte[] r = new byte[bytes / 3]; byte[] g = new byte[bytes / 3]; byte[] b = new byte[bytes / 3]; // Copy the RGB values into the array. Marshal.Copy(ptr, rgbValues, 0, bytes); int count = 0; int stride = bmpData.Stride; for (int column = 0; column < bmpData.Height; column++) { for (int row = 0; row < bmpData.Width; row++) { b[count] = (byte)(rgbValues[(column * stride) + (row * 3)]); g[count] = (byte)(rgbValues[(column * stride) + (row * 3) + 1]); r[count++] = (byte)(rgbValues[(column * stride) + (row * 3) + 2]); } }


Aunque el enfoque de dos bucles anidados suele ser "mejor" o más legible, puede hacerlo en 1 bucle como este:

for(int i = 0; i < bmp.Height * bmp.Width; i++) { int row = i / bmp.Width; int col = i % bmp.Width; var pixel = bmp.GetPixel(col, row); }

O un poco mejor, cambie la primera línea a:

var numberOfPixels = bmp.Height * bmp.Width; for(int i = 0; i < numberOfPixels; i++)


Necesitas usar dos bucles:

for (int ii = 0; ii < 100; ii++) { for (int jj = 0; jj < 100; jj++) { Color pixelColor = bitmap.GetPixel(ii, jj); // do stuff with pixelColor } }


Puede convertirlo en una gama de colores multidimensionales de fácil acceso como:

using System.Drawing.Imaging; using System.Runtime.InteropServices; // ... Color[,] GetSection(Image img, Rectangle r) { Color[,] r = new Color[r.Width, r.Height]; // Create an array of colors to return using (Bitmap b = new Bitmap(img)) { // Turn the Image into a Bitmap BitmapData bd = b.LockBits(r, ImageLockMode.ReadOnly, PixelFormat.Format32BppArgb); // Lock the bitmap data int[] arr = new int[b.Width * b.Height - 1]; // Create an array to hold the bitmap''s data Marshal.Copy(b.Scan0, arr, 0, arr.Length); // Copy over the data b.UnlockBits(bd); // Unlock the bitmap for (int i = 0; i < arr.Length; i++) { r[i % r.Width, i / r.Width] = Color.FromArgb(arr[i]); // Copy over into a Color structure } } return r; // Return the result }

Usted lo llamaría así:

Color[,] c = GetSection(myImage, new Rectangle(0, 0, 100, 100)); // Get the upper-left 100x100 pixel block in the image myImage for (int x = 0; x < c.GetUpperBound(0); x++) { for (int y = 0; y < c.GetUpperBound(1); y++) { Color thePixel = c[x, y]; // do something with the color } }

Y podría atravesar la matriz devuelta bastante rápidamente en la dirección que desee.


Puedes probar algo como esto

for(int y = 0; y < bmp.Height; y++) { var even = y % 2 == 0; var startX = even ? 0 : bmp.Width - 1; var endX = even ? bmp.Width : -1; var delta = even ? 1 : -1; for(int x = startX; x != endX; x += delta) { var pixel = bmp.GetPixel(x,y); } }

o puede dividir el ciclo interno para: de izquierda a derecha y de derecha a izquierda

for(int y = 0; y < bmp.Height; y += 2) { for(int x = 0; x < bmp.Width; x++) { var pixel = bmp.GetPixel(x,y); } var line = y + 1; if(line < bmp.Height) { for(int x = bmp.Width; x >= 0; --x) { var pixel = bmp.GetPixel(x,line); } } }


Usted usa una selección Linq para obtener un objeto IEnumerable:

var pixelColors = from x in Enumerable.Range(0, bmp.Width - 1) from y in Enumerable.Range(0, bmp.Height - 1) select bmp.GetPixel(x, y);

... luego itere en el IEnumerable (usando la escritura implícita):

foreach(var color in pixelColors) { //do stuff on RGB values, etc... }


si quieres atravesarlo a la derecha, izquierda, derecha, ... en un bucle, esto lo haría:

for (int i = 0 ; i < bmp.Height * bmp.Width; ++i) { int row = i / bmp.Height; int col = i % bmp.Width; if (row%2 != 0) col = bmp.Width - col-1; var pixel = bmp.GetPixel(col, row); }