【问题标题】:Using WritePixels when using a writeable bitmap from a intptr to create a bitmap.在使用 intptr 中的可写位图创建位图时使用 WritePixels。
【发布时间】:2011-04-20 13:24:06
【问题描述】:

我目前正在尝试使用 writeablebitmap 对图像扫描进行IntPtr 并将每个图像转换为Bitmap。我想使用 writeablebitmap,因为我遇到了标准 gdi 的问题 GDI+ System.Drawing.Bitmap gives error Parameter is not valid intermittently

WriteableBitmap 上有一个名为 WritePixels 的方法 http://msdn.microsoft.com/en-us/library/aa346817.aspx

我不确定我为缓冲区和步幅设置了什么,我发现它的每个示例都将步幅显示为 0,尽管这会引发错误。当我将步幅设置为 5 时,图像显示为黑色。我知道这可能不是最有效的代码,但我们将不胜感激。

//create bitmap header
bmi = new BITMAPINFOHEADER();

//create initial rectangle
Int32Rect rect = new Int32Rect(0, 0, 0, 0);

//create duplicate intptr to use while in global lock
dibhand = dibhandp;
bmpptr = GlobalLock(dibhand);

//get the pixel sizes
pixptr = GetPixelInfo(bmpptr);

//create writeable bitmap
var wbitm = new WriteableBitmap(bmprect.Width, bmprect.Height, 96.0, 96.0, System.Windows.Media.PixelFormats.Bgr32, null);

//draw the image
wbitm.WritePixels(rect, dibhandp, 10, 0);

//convert the writeable bitmap to bitmap
var stream = new MemoryStream();

var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(wbitm));
encoder.Save(stream);

byte[] buffer = stream.GetBuffer();
var bitmap = new System.Drawing.Bitmap(new MemoryStream(buffer));

GlobalUnlock(dibhand);
GlobalFree(dibhand);
GlobalFree(dibhandp);
GlobalFree(bmpptr);
dibhand = IntPtr.Zero;

return bitmap;

【问题讨论】:

    标签: c# image-processing bitmap scanning


    【解决方案1】:

    在 C# 中处理位图的一种有效方法是暂时以不安全模式传递(我知道我没有准确回答这个问题,但我认为 OP 没有设法使用位图,所以无论如何这可能是一个解决方案) .您只需锁定位即可完成:

    unsafe private void GaussianFilter()
    {
        // Working images
        using (Bitmap newImage = new Bitmap(width, height))
        {
            // Lock bits for performance reason
            BitmapData newImageData = newImage.LockBits(new Rectangle(0, 0, newImage.Width,
                newImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    
            byte* pointer = (byte*)newImageData.Scan0;
            int offset = newImageData.Stride - newImageData.Width * 4;
    
            // Compute gaussian filter on temp image
            for (int j = 0; j < InputData.Height - 1; ++j)
            {
                for (int 0 = 1; i < InputData.Width - 1; ++i)
                {
                    // You browse 4 bytes per 4 bytes
                    // The 4 bytes are: B G R A
                    byte blue = pointer[0];
                    byte green = pointer[1];
                    byte red = pointer[2];
                    byte alpha = pointer[3];
    
                    // Your business here by setting pointer[i] = ...
                    // If you don't use alpha don't forget to set it to 255 else your whole image will be black !!
    
                    // Go to next pixels
                    pointer += 4;
                }
                // Go to next line: do not forget pixel at last and first column
                pointer += offset;
            }
    
    
            // Unlock image
            newImage.UnlockBits(newImageData);
            newImage.Save("D:\temp\OCR_gray_gaussian.tif");
        }
    }
    

    这确实比SetPixel(i, j) 高效得多,您只需要注意指针限制(完成后不要忘记解锁数据)。

    现在回答您关于步幅的问题:步幅是行的字节长度,它是 4 的倍数。在我的示例中,我使用格式Format32bppArgb,每个像素使用 4 个字节(R、G、 B 和 alpha),所以 newImageData.StridenewImageData.Width * 4 总是相同的。我在循环中使用偏移量只是为了显示需要的位置。

    但如果您使用另一种格式,例如Format24bppRgb,每个像素使用 3 个字节(仅限 R、G 和 B),则步幅和宽度之间可能存在偏移。对于这种格式的 10 * 10 像素的图像,您将有 10 * 3 = 30, + 2 的步幅以达到最接近 4 的倍数,即 32。

    【讨论】:

      猜你喜欢
      • 2014-08-16
      • 2012-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多