【问题标题】:Travel through pixels in BMP穿越 BMP 中的像素
【发布时间】:2011-08-26 14:21:18
【问题描述】:

嗨,我有一个 bmp 加载到一个 BMP 对象,我需要像上图一样从 (1,1) 像素到 (100,100) px 穿过像素。使用getpixel() 方法。我使用的是 ONE 循环,但没有成功。

如果我使用多维数组的概念,变量值应该是什么?

【问题讨论】:

  • 您总是可以尝试... 两个 循环,看看它们是否成功... :) 您实际上在问什么问题?如何遍历像素的二维数组,或者关于变量值的东西?
  • 该图看起来像所有奇数行从左到右遍历,偶数行从右到左遍历。是这个意图吗?

标签: c# .net image-processing


【解决方案1】:

当你想做图像处理时 在巨大的图像上 GetPixel() 方法需要很长时间 但我认为我的算法需要更少 时间比其他答案,例如 您可以在 800 * 600 上测试此代码 像素图像。


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

【讨论】:

  • 我使用了类似的解决方案,效果很好。您只需要确保您的源 bmp 是相同的像素格式!您还反转了行和列循环(只是名称,因为实现仍然有效)
  • 浏览列不是更快吗?首先 for (int row = 0; row
  • @AmiDATA 不,位图(和大多数 2D 格式)是行优先格式,这意味着像素在内存中逐行排列。
  • Thomas,因为它是行主要的,内部循环应该在列上而不是行上。只是给它一个测试。 wiki.
  • 您可能需要在完成复制后添加bmp.UnlockBits(bmpData);
【解决方案2】:

如果你想在一个循环中向右、向左、向右……遍历它,可以这样做:

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

【讨论】:

  • if (row%2 != 0) c = bmp.Width-col-1;应该是 if (row%2 != 0) col = bmp.Width-col-1;
  • GetPixel 非常昂贵且缓慢。根据答案使用 BitmapData 要好得多。
【解决方案3】:

你需要使用两个循环:

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

【讨论】:

  • 您“不需要”,但它确实有助于提高可读性和良好的编程习惯。双字母循环变量已经是一个好的开始:)
【解决方案4】:

您冷使用 Linq 选择来获取 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);

...然后迭代 IEnumerable(使用隐式类型):

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

【讨论】:

  • 如果 linq 比两个循环快,你能告诉我吗?请我报告
【解决方案5】:

你可以把它变成一个易于访问的多维颜色数组,如下所示:

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
}

你可以这样称呼它:

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

你可以在任何你想要的方向上快速遍历返回的数组。

【讨论】:

  • 多维数组在这个问题上不起作用检查并看到 cz 多维数组不通过line by line
  • @Sudantha:你能说得清楚一点吗?你知道,多维数组确实可以表示一个像素块。
【解决方案6】:

虽然两个嵌套循环方法通常“更好”或更易读,但您可以像这样在 1 个循环中完成:

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

或者稍微好点,把第一行改成:

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

【讨论】:

    【解决方案7】:

    你可以试试这样的

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

    或者您可以将内部循环拆分为:从左到右和从右到左

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多