【问题标题】:Calculate average of images using pointers使用指针计算图像的平均值
【发布时间】:2020-12-01 01:32:32
【问题描述】:

我的代码计算图像中每个像素的平均颜色并返回一个新图像。

Image calculateAverage(Bitmap image1, Bitmap image2)
{
    // Locking the image into memory.
    BitmapData sourceData = image1.LockBits(new Rectangle(0, 0, image1.Width, image1.Height),
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

    // All of the pixels will be stored in this array(each 4 numbers represent a pixel).
    byte[] sourceBuffer = new byte[sourceData.Stride * sourceData.Height];

    // Copying the image pixels into sourceBuffer.
    Marshal.Copy(sourceData.Scan0, sourceBuffer, 0, sourceBuffer.Length);

    // Don't need the image, unlock memory.
    image1.UnlockBits(sourceData);

    // --- Same thing for the second image ---
    BitmapData blendData = image2.LockBits(new Rectangle(0, 0, image2.Width, image2.Height),
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
    byte[] blendBuffer = new byte[blendData.Stride * blendData.Height];
    Marshal.Copy(blendData.Scan0, blendBuffer, 0, blendBuffer.Length);
    image2.UnlockBits(blendData);
    //---

    // Calculating average of each color in each pixel.
    for (int k = 0; (k + 4 < sourceBuffer.Length) && (k + 4 < blendBuffer.Length); k += 4)
    {
        sourceBuffer[k] = (byte)calcualteAverage(sourceBuffer[k], blendBuffer[k]);
        sourceBuffer[k + 1] = (byte)calcualteAverage(sourceBuffer[k + 1], blendBuffer[k + 1]);
        sourceBuffer[k + 2] = (byte)calcualteAverage(sourceBuffer[k + 2], blendBuffer[k + 2]);
        // Average of Alpha
        sourceBuffer[k + 3] = (byte)calcualteAverage(sourceBuffer[k + 3], sourceBuffer[k + 3]);
    }
    
    // Saving the result.
    Bitmap resultBitmap = new Bitmap(image1.Width, image1.Height);
    BitmapData resultData = resultBitmap.LockBits(new Rectangle(0, 0,
        resultBitmap.Width, resultBitmap.Height),
        ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

    Marshal.Copy(sourceBuffer, 0, resultData.Scan0, sourceBuffer.Length);
    resultBitmap.UnlockBits(resultData);

    return resultBitmap;
}

出于性能原因,我需要使用不安全的代码重写此方法,尽管我是一个带指针的菜鸟;不知道它如何提高性能或算法会发生什么变化?

【问题讨论】:

  • 你为什么不用c++编写并从c#调用c++ dll?代码执行需要多长时间?您希望提高多少性能?
  • 这只是一个小的改进,因为它只是一小部分代码,我不会在一个小应用程序中做太多的改变

标签: c# image-processing unsafe


【解决方案1】:

函数可以用这个代替:

public static Bitmap CalculateAverage(
    Bitmap sourceBitmap, Bitmap blendBitmap)
{
    // Locking the images into the memory.
    BitmapData sourceData = sourceBitmap.LockBits(
        new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

    BitmapData blendData = blendBitmap.LockBits(
        new Rectangle(0, 0, blendBitmap.Width, blendBitmap.Height),
        ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

    // Get required variables. This wont work for images with different sizes.
    int resultWidth = sourceBitmap.Width;
    int resultHeight = sourceBitmap.Height;
    int stride = sourceData.Stride;

    // result will be stored here.
    var resultBitmap = new Bitmap(resultWidth, resultHeight);
    BitmapData resultData = resultBitmap.LockBits(
        new Rectangle(0, 0, resultWidth, resultHeight),
        ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

    unsafe
    {
        // Getting address of locked images.
        byte* sourceAddress = (byte*)sourceData.Scan0.ToPointer();
        byte* blendAddress = (byte*)blendData.Scan0.ToPointer();
        byte* resultAddress = (byte*)resultData.Scan0.ToPointer();

        // Iterating throgh pixels and storing averages inside the result variable.
        for (int y = 0; y < resultHeight; y++)
        {
            for (int x = 0; x < resultWidth; x++)
            {
                for (int color = 0; color < 4; color++)
                {
                    int currentByte = (y * stride) + x * 4 + color;

                    resultAddress[currentByte] = (byte)average(
                        sourceAddress[currentByte],
                        blendAddress[currentByte]);
                }
            }
        }
    }
    
    // Unlocking the Bits; returning the result bitmap.
    sourceBitmap.UnlockBits(sourceData);
    blendBitmap.UnlockBits(blendData);
    resultBitmap.UnlockBits(resultData);
    return resultBitmap;
}

我目前无法对其进行测试,但这可能会给出正确方向的提示。如果有任何问题,请不要犹豫。它基于以下代码:How to calculate the average rgb color values of a bitmap

【讨论】:

  • 谢谢,结果不是数组怎么办?
  • result 是一个字节指针,您向指针添加偏移量的方式与索引数组的方式相同。例如 list[5] 转到列表中的第 6 个值。 ptr[5] 指向内存地址 ptr + 5 处的值。在这种情况下,这将是第 6 个字节,因为所有字节都是按顺序排列的。
  • 在循环中获取'Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
  • 此代码仅适用于图像大小相同的情况,不幸的是我无法调试代码 atm。
  • 我对您的代码进行了一些编辑,现在可以使用了;干杯!
猜你喜欢
  • 1970-01-01
  • 2014-03-01
  • 1970-01-01
  • 1970-01-01
  • 2022-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多