【问题标题】:Create Image Mask创建图像蒙版
【发布时间】:2013-07-20 07:51:02
【问题描述】:

用户向我的应用提供了一张图片,应用需要从中制作蒙版:

掩码包含原始图像中每个透明像素的红色像素。

我尝试了以下方法:

Bitmap OrgImg = Image.FromFile(FilePath);
Bitmap NewImg = new Bitmap(OrgImg.Width, OrgImg.Height);
for (int y = 0; y <= OrgImg.Height - 1; y++) {
    for (int x = 0; x <= OrgImg.Width - 1; x++) {
        if (OrgImg.GetPixel(x, y).A != 255) {
            NewImg.SetPixel(x, y, Color.FromArgb(255 - OrgImg.GetPixel(x, y).A, 255, 0, 0));
        }
    }
}
OrgImg.Dispose();
PictureBox1.Image = NewImg;

我担心慢速 PC 的性能。有没有更好的方法来做到这一点?

【问题讨论】:

  • 我会使用完全相同的方法。它很慢,但请记住,您正在处理像素,并且它的数量可能非常大。在任何计算机中,只分析一张图像应该是一个非常快速的过程。
  • 对于非常大的图像,您可以考虑使用 Taskworker thread 而不是冻结 UI 直到完成处理的主线程。
  • 我已经为此使用了BackgroundWorker

标签: c# .net vb.net image bitmap


【解决方案1】:

如果只是偶尔使用 GetPixel() 是完全可以接受的,例如在加载一张图片时。但是,如果你想做更严肃的图像处理,最好直接使用BitmapData。一个小例子:

//Load the bitmap
Bitmap image = (Bitmap)Image.FromFile("image.png"); 

//Get the bitmap data
var bitmapData = image.LockBits (
    new Rectangle (0, 0, image.Width, image.Height),
    ImageLockMode.ReadWrite, 
    image.PixelFormat
);

//Initialize an array for all the image data
byte[] imageBytes = new byte[bitmapData.Stride * image.Height];

//Copy the bitmap data to the local array
Marshal.Copy(bitmapData.Scan0,imageBytes,0,imageBytes.Length);

//Unlock the bitmap
image.UnlockBits(bitmapData);

//Find pixelsize
int pixelSize = Image.GetPixelFormatSize(image.PixelFormat);

// An example on how to use the pixels, lets make a copy
int x = 0;
int y = 0;
var bitmap = new Bitmap (image.Width, image.Height);

//Loop pixels
for(int i=0;i<imageBytes.Length;i+=pixelSize/8)
{
    //Copy the bits into a local array
    var pixelData = new byte[3];
    Array.Copy(imageBytes,i,pixelData,0,3);

    //Get the color of a pixel
    var color = Color.FromArgb (pixelData [0], pixelData [1], pixelData [2]);

    //Set the color of a pixel
    bitmap.SetPixel (x,y,color);

    //Map the 1D array to (x,y)
    x++;
    if( x >= bitmap.Width)
    {
        x=0;
        y++;
    }

}

//Save the duplicate
bitmap.Save ("image_copy.png");

【讨论】:

  • 我知道这是旧的,但以后有人可能会发现这很有用。
  • 我知道这是旧的,但以后有人可能会发现这很有用。如果您要在 C# 中谈论位图速度,那么您需要了解在 for 循环中,您不应该使用 bitmap.Width,因为 C# 访问速度非常慢。相反,将局部变量设置为 Bitmap.Width 并在循环比较中使用它。快多了。 Vadim 也是正确的,因为锁定内存要快得多。
【解决方案2】:

这种方法确实很慢。更好的方法是使用 Lockbits 并直接访问底层矩阵。查看 https://web.archive.org/web/20141229164101/http://bobpowell.net/lockingbits.aspxhttp://www.mfranc.com/programming/operacje-na-bitmapkach-net-1/ 或 https://docs.microsoft.com/en-us/dotnet/api/system.drawing.bitmap.lockbits 或其他有关 StackOverflow 中锁定位的文章。

这有点复杂,因为您必须直接使用字节(如果使用 RGBA,则每像素 4 个字节),但性能提升非常显着,非常值得。

另一个注意事项 - OrgImg.GetPixel(x, y) 很慢,如果你坚持使用它(而不是 lockbits),请确保你只使用它一次(它可能已经优化,只需检查是否有区别) .

【讨论】:

    猜你喜欢
    • 2013-10-23
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 2011-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多