使用指针计算图像的平均值

Calculate average of images using pointers

我的代码计算图像和 returns 新图像中每个像素的平均颜色。

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

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

函数可以这样替换:

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.