开发者

Travel through pixels in BMP

Travel through pixels in BMP

Hi i have a bmp loaded to a BMP object and im required to travel though the pixels as the above image from (1,1) pixel to (100,100) px . 开发者_StackOverflow中文版using getpixel() method. I was using was ONE loop but it was not successful .

If im using the concept of multidimensional array what should be variable values ?


When you want to doing image processing on huge images GetPixel() method takes long time but I think my algorithm takes less time than other answers , for example you can test this code on 800 * 600 pixels image.


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]);
    }
}


if you want to traverse it right, left, right, ... in one loop, this would do it:

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);
}


You need to use two loops:

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


You cold use a Linq selection to obtain a IEnumerable object:

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);

...then iterate on the IEnumerable (using implicit typing):

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


You can turn it into an easy-to-access multidimensional array of colors like so:

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(bd.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
}

You would call it like so:

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
    }
}

And you could traverse the returned array quite quickly in any direction you want at all.


Though the two nested loop approach is typically "better" or more readable, you can do it in 1 loop like this:

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);
}

Or slightly better, change the first line to:

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


You can try something like this

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);
   }
}

or you can split internal cycle to: left to right and right to left

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);
         }
       }
    }
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜