Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculate image differences in C#

Tags:

c#

.net

image

How could I generate a System.Drawing.Image that contains the differences between the pixels of two other images?

Something similar to GitHub does, but written in C#

The algorithm that GiHub uses is implemented in javascript. There is a context-blender project that replicates Photoshop blend modes.

Do you know if is translated to C# or a similar algorithm that has the same quality level? I need to manage also transparent images (with alpha channel).

like image 486
Daniel Peñalba Avatar asked Feb 20 '12 19:02

Daniel Peñalba


2 Answers

Here's a quick and dirty implementation:

void Main()
{
    var a = (Bitmap)Image.FromFile("image1.png");
    var b = (Bitmap)Image.FromFile("image2.png");
    var diff = PixelDiff(a, b);
}

unsafe Bitmap PixelDiff(Bitmap a, Bitmap b)
{
    Bitmap output = new Bitmap(a.Width, a.Height, PixelFormat.Format32bppArgb);
    Rectangle rect = new Rectangle(Point.Empty, a.Size);
    using (var aData = a.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
    using (var bData = b.LockBitsDisposable(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb))
    using (var outputData = output.LockBitsDisposable(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb))
    {
        byte* aPtr = (byte*)aData.Scan0;
        byte* bPtr = (byte*)bData.Scan0;
        byte* outputPtr = (byte*)outputData.Scan0;
        int len = aData.Stride * aData.Height;
        for (int i = 0; i < len; i++)
        {
            // For alpha use the average of both images (otherwise pixels with the same alpha won't be visible)
            if ((i + 1) % 4 == 0)
                *outputPtr = (byte)((*aPtr  + *bPtr) / 2);
            else
                *outputPtr = (byte)~(*aPtr ^ *bPtr);

            outputPtr++;
            aPtr++;
            bPtr++;
        }
    }
    return output;
}

static class Extensions
{
    public static DisposableImageData LockBitsDisposable(this Bitmap bitmap, Rectangle rect, ImageLockMode flags, PixelFormat format)
    {
        return new DisposableImageData(bitmap, rect, flags, format);
    }

    public class DisposableImageData : IDisposable
    {
        private readonly Bitmap _bitmap;
        private readonly BitmapData _data;

        internal DisposableImageData(Bitmap bitmap, Rectangle rect, ImageLockMode flags, PixelFormat format)
        {
            bitmap.CheckArgumentNull("bitmap");
            _bitmap = bitmap;
            _data = bitmap.LockBits(rect, flags, format);
        }

        public void Dispose()
        {
            _bitmap.UnlockBits(_data);
        }

        public IntPtr Scan0
        {
            get { return _data.Scan0; }
        }

        public int Stride
        {
            get { return _data.Stride;}
        }

        public int Width
        {
            get { return _data.Width;}
        }

        public int Height
        {
            get { return _data.Height;}
        }

        public PixelFormat PixelFormat
        {
            get { return _data.PixelFormat;}
        }

        public int Reserved
        {
            get { return _data.Reserved;}
        }
    }   
}

Notes:

  • this implementation assumes that both images have the same size, which might not be the case... taking different sizes into account is possible of course, just a little harder.
  • the LockBitsDisposable method is just a convenience, if you prefer you can use the standard LockBits method (but don't forget to unlock the bits when you're done)
like image 123
Thomas Levesque Avatar answered Nov 20 '22 15:11

Thomas Levesque


A quick google search yielded this:

http://www.bryancook.net/2009/10/find-differences-between-images-c.html

If your're going to be using ARGB rather then RGB, it'll probably need a bit of editing. If you wanted to get that 'inverted difference' effect, like in the Github link posted, you could find the differance between RGB colors and use that for each pixel in the difference image, etc.

like image 2
K893824 Avatar answered Nov 20 '22 17:11

K893824