Image XOR algorithm (Code contribution)

Jun 2, 2010 at 8:33 AM
Edited Jun 2, 2010 at 8:36 AM

Hello... im working on some Webcam stuff and have implemented an XOR algorithm for WriteableBitmap... i'd like to contribute to the project, if you don't already have it in there.. ?

        /// <summary>
        /// XOR two images, 
        /// NOTe: the diff image will be changed
        /// </summary>
        /// <param name="reference">The refernce image</param>
        /// <param name="diff">The image to be compared to</param>
        public static WriteableBitmap XOR(this WriteableBitmap reference, WriteableBitmap diff)
        {
            if (reference.Pixels.Length != diff.Pixels.Length)
                throw new Exception("images is not the same length !");

            int idx = reference.Pixels.Length - 1;

            WriteableBitmap output = new WriteableBitmap(diff.PixelWidth, diff.PixelHeight);

            do //loop unrolling ftw :)
            {
                unchecked
                {
                    output.Pixels[idx] = diff.Pixels[idx] ^ reference.Pixels[idx--] ^ (int)(uint)0xFF000000;
                    output.Pixels[idx] = diff.Pixels[idx] ^ reference.Pixels[idx--] ^ (int)(uint)0xFF000000;
                    output.Pixels[idx] = diff.Pixels[idx] ^ reference.Pixels[idx--] ^ (int)(uint)0xFF000000;
                    output.Pixels[idx] = diff.Pixels[idx] ^ reference.Pixels[idx--] ^ (int)(uint)0xFF000000;

                    output.Pixels[idx] = diff.Pixels[idx] ^ reference.Pixels[idx--] ^ (int)(uint)0xFF000000;
                    output.Pixels[idx] = diff.Pixels[idx] ^ reference.Pixels[idx--] ^ (int)(uint)0xFF000000;
                    output.Pixels[idx] = diff.Pixels[idx] ^ reference.Pixels[idx--] ^ (int)(uint)0xFF000000;
                    output.Pixels[idx] = diff.Pixels[idx] ^ reference.Pixels[idx--] ^ (int)(uint)0xFF000000;

                }

            } while (idx > 0);

            return output;
        }
Coordinator
Jun 2, 2010 at 9:47 AM

Hi Montago,

Good idea. XOR is really useful for difference images and other nice things. We should actually implement some more operators as well. But I'd rather see them as Blend operators that are used in the Blend method. We already have the following BlendMode s:

      public enum BlendMode
      {
         Alpha,
         Additive,
         Subtractive,
         Mask,
         Multiply,
         None
      }

A special implementation as you propose might be a bit faster for some special cases, but it blows the API up. Try to convince me why we should not implement it as BlendMode? :)

Jun 2, 2010 at 1:24 PM

I'm reading the code just now... i must say, its a mess !!

when you want to blend 2 images, you'll use a method called 'Blit' which is non-explanatory. Many of the overloads are also non-explanatory (one might blit'ing without the enum = what ?) - and all of them require a rectangle to define the size of effect (but lacks an offset if the starting point isn't 0,0 )

is easier to read the code and use the methods if they are named by their use - although one might get used to the enum...

:-)

What i like about my method is that:

- it returns a new WBMP

- it expects that both images are equal size (one might need overloads for crops and offsets)

- it's self explanatory and easy to find

- the syntax/design pattern allows dot-notation : "bmp1.XOR(bmp2).XOR(bmp3)"

anyways - i dont care how you insert the code above - im keeping my version in any case.

Coordinator
Jun 2, 2010 at 2:39 PM

I must admit that the code structure is not very well. I always wanted to change these contributed Blit pieces and make it more consistent, but the code works and I postponed it. It also takes a good amount of time to unknot it. I created an Issue [workitem:13420] to refactor it before 1.0.0.0 and people can also vote on it. I also created an Issue for your XOR contribution [workitem:13421].

Thanks for your direct feedback. (I hope you only mean the Blit extensions.)

 

BTW, I a see performance hit in your code. Try to use local variables instead of the Pixels property directly. Trust me, it increases the performance noticeable:

var outputPixels = output.Pixels;
var diffPixels = diff.Pixels;
var referencePixels = reference.Pixels;
do //loop unrolling ftw :)
{
	unchecked
	{
		outputPixels[idx] = diffPixels[idx] ^ referencePixels[idx--] ^ (int)0xFF000000;
        // ...

	}

} while (idx > 0);

 

Jun 2, 2010 at 2:44 PM
Edited Jun 2, 2010 at 3:03 PM

im only talking about the Blit thing.. :-)

performancehit... lol... I gotta benchmark that to see if you have a point - the compiler shouldn't differ between local vs ref variables !!!

brb.


WOW... after benchmarking, im getting a 2x performance !!

holy crap ! - can't believe the compiler is that bad !

Coordinator
Jun 2, 2010 at 2:49 PM
Montago wrote:

performancehit... lol... I gotta benchmark that to see if you have a point - the compiler shouldn't differ between local vs ref variables !!!

The Pixels property is not a ref variable. The Getter (/Setter) of a property is actually a method you are calling vs. a object reference access. Here: Pixels_get()[i] vs. pixels[i]

Sep 24, 2010 at 11:31 AM
Montago wrote:

im only talking about the Blit thing.. :-)

performancehit... lol... I gotta benchmark that to see if you have a point - the compiler shouldn't differ between local vs ref variables !!!

brb.

 


 

WOW... after benchmarking, im getting a 2x performance !!

holy crap ! - can't believe the compiler is that bad !

Did you really perform your tests on a release build and without Visual Studio? Running an application in debug configuration, as well as running an application in release configuration from within VS will prevent JIT optimization to occur. Normally, JIT compiler in release mode will inline property accessors, resulting in equal speed compared to direct reference access. Only if complex logic lies within the property getter, then the getter will not be inlined and caching it will improve performance.