Notification

Icon
Error

Comparing Photo's for Differences
shapingstuff
#1 Posted : Monday, March 05, 2012 4:19:15 PM(UTC)
Rank: Tinkerer

Joined: 2/3/2012(UTC)
Posts: 2

Hi,


I was trying to put together some code to determine wither two photographs are different i.e. someone is standing in one and not the other.  Write now this is what I have - it returns a percentage of colour difference and generally if it's above 50% there is something else in it.


This code is ridiculously slow to run and takes about a minute or so... I need it in seconds!  It's even slow with the thumbnail sized images.


I'm not looking for anything hugely accurate - the big problem doing this is clearly that a pixel is going to be different depending on light levels.


I'd be really grateful for any suggestions, feedback or an existing solution that I can easily use.


I'm not a coder - so I'm trying to keep it simple - feel free to tell me what im doing wrong!  It's good to share.


     void compareImages ()
{
Debug.Print("Comparing Images");

int height = camera.CurrentPictureResolution.Height;
int width = camera.CurrentPictureResolution.Width;
int DiferentPixels = 0;

Bitmap container = new Bitmap(width, height);

for (int i = 0; i < width; i++) // increment by ten in width
{
for (int j = 0; j < height; j++) // increment in ten by height
{
Debug.Print("doing...");
Color currentPixel1 = picture1.GetPixel(i, j);
int r1 = ColorUtility.GetRValue(currentPixel1);
int g1 = ColorUtility.GetGValue(currentPixel1);
int b1 = ColorUtility.GetRValue(currentPixel1);

Color currentPixel2 = picture2.GetPixel(i, j);
int r2 = ColorUtility.GetRValue(currentPixel2);
int g2 = ColorUtility.GetGValue(currentPixel2);
int b2 = ColorUtility.GetRValue(currentPixel2);

if (r1 != r2 && g1 != g2 && b1 != b2)
{
DiferentPixels++;
container.SetPixel(i, j, GT.Color.Red);
}
else
container.SetPixel(i, j, picture1.GetPixel(i, j));
}
}
int TotalPixels = width * height;
float difference = (float)((float)DiferentPixels / (float)TotalPixels);
float percentage = difference * 100;

oledDisplay.SimpleGraphics.DisplayImage(container, 0, 0);

Debug.Print("Difference: " + difference + "Percentage Difference: " + percentage);

}

 
Jedibowler
#2 Posted : Tuesday, March 06, 2012 5:45:47 PM(UTC)
Rank: Tinkerer

Joined: 12/13/2011(UTC)
Posts: 5

Bitmap.Equals() could be worth trying, not sure if that will actually compare two images and check if they are different though or just check to see if they are the same type.  Ie, both bitmaps.


One thing to remember though is that comparing two images is quite intensive and with the relatively limited resources (compared to a desktop machine) onboard it may never be possible to get this process down to seconds.  There may be an option to get the behaviour another way though, what is the end goal of the device you are building?

shapingstuff
#3 Posted : Wednesday, March 07, 2012 5:05:44 AM(UTC)
Rank: Tinkerer

Joined: 2/3/2012(UTC)
Posts: 2

I think your right.

I was looking to detect movement in an image in order to know were people are around 360 degrees.

I've been told the best way is to upload the image and have a web server do the processing - here I could use existing API's.

My attempt was for a quick and easy solution!
darrellp
#4 Posted : Friday, March 09, 2012 4:14:35 AM(UTC)
Rank: Tinkerer

Joined: 3/9/2012(UTC)
Posts: 1

If it's taking a minute and you want it in seconds then you might want to consider only looking at every 8th pixel in both horizontal and vertical directions.  This should mean you're only checking about 1/64th the pixels which would hopefully whittle your time down to seconds.  You'd of course lose some resolution, but assuming that the objects you're looking for (presumably humans) would end up being larger than 8 pixels on the screen, you'd still pretty much work.


Another thing - I'd keep the old picture in an array - should work faster than referencing off the picture object.  That might cut your time pretty substantially also.  I see in your comments you say something along the lines of "go through picture by ten on width" so maybe you're already thought of doing every tenth pixel, but the code as written doesn't go by ten but iterates through every pixel in the image.


Finally, do you really want to do exact equality on pixel values?  Any tiny lighting difference or noise will register as a "changed pixel".  I would only count them when the difference exceeds some limit.  I don't trust the gadgeteer to be such a precision instrument that taking identical pictures one after the other would get precisely the same value for each pixel every time.

MoonDragon
#5 Posted : Friday, March 16, 2012 11:28:40 AM(UTC)
MoonDragon

Rank: Tinkerer

Joined: 3/16/2012(UTC)
Posts: 5

Thanks: 1 times
For starters, take out Debug.Print statements from your code. Those are INSANELY slow. Useful when trying to figure out what your code is doing, but super slow. Next thing, make sure not to run your code in the debugger. Thirdly, you're constructing a new image with "changed" pixels for display--that is another huge drain on your processing (the display part primarily).

As far as the algorithm itself... If you truly want to compare colour information between the two pixels, then just compare the colour values. Don't spend 6 function calls decomposing the individual colour channels, and then 3 operations comparing them for equality. The whole thing can be done in a single operation: colour1 == colour2. Done.

Finally, there is no simple way to do image processing. It has been the bane of computer scientists for a long time. With the new-found popularity of the GPGPUs massively parallel computations are making the pain a bit easier, but in a small CPU as you have, there is very little you can do, but wait for your code to process pixels one at the time.
ransomhall
#6 Posted : Friday, March 16, 2012 1:25:42 PM(UTC)
ransomhall

Rank: Gadgeteer

Joined: 5/21/2011(UTC)
Posts: 26

Thanks: 1 times

MoonDragon - very nice avatar! Is that your own creation?

Make NETMF Sense
www.ransomhall.com
Kerry H
#8 Posted : Monday, March 19, 2012 9:11:43 PM(UTC)
Kerry H

Rank: Admin

Joined: 11/22/2011(UTC)
Posts: 80

Thanks: 8 times
Was thanked: 5 time(s) in 5 post(s)

If connecting to the Internet is an option for your project, you could offload the image processing to a Web service.  It's higher-latency, but it saves a lot of local compute power.  Also, a Web service can store more images and look for differences over time. 


There are some good tutorials on connecting Gadgeteer devices to Web service at in the Featured Projects area.  The Text-to-Speech Translator is a great model (though it uses a pre-existing Web service and you'd probably need to build something custom).

-- K

Kerry Hammil
Microsoft Research
SolderMonkey
#9 Posted : Tuesday, March 20, 2012 8:39:43 PM(UTC)
Rank: Tinkerer

Joined: 3/20/2012(UTC)
Posts: 1

Was thanked: 1 time(s) in 1 post(s)
You could also speed things up a bit by puting all of your variable declarations outside the processing loop. In the above code for a 100x100 image you would be creating and destroying 80000 variables. (not including the indexes...) This should save you tons of GC time.
1 user thanked SolderMonkey for this useful post.
Kerry H on 3/21/2012(UTC)
MoonDragon
#7 Posted : Wednesday, March 21, 2012 12:09:04 PM(UTC)
MoonDragon

Rank: Tinkerer

Joined: 3/16/2012(UTC)
Posts: 5

Thanks: 1 times

ransomhall;8619 wrote:


MoonDragon - very nice avatar! Is that your own creation?



Thanks! Yeah, made it a while ago.


 


P.S. any idea why I can't set my avatar on tinyCLR forums?

David
#10 Posted : Friday, May 25, 2012 3:56:11 AM(UTC)
Rank: Tinkerer

Joined: 5/25/2012(UTC)
Posts: 1


I've been looking at this myself and there are a number of problems.  Comparing pixel by pixel is not very successful, even if you can guarantee that the camera is absolutely stationary (otherwise the slightest movement means that all your pixels are different), because of the presence of image noise.  If you try sampling, there is a significant chance of hitting noise and getting a false positive.


The best way would be to use edge detection algorithms to calculate a rough outline of large objects in the picture, but I doubt the processing power available will allow for that.


I've been looking at calculating the average colour or tone of the image as a way of quickly assessing whether an image has changed, which shows some promise.  One advantage is that it can halve processing overhead because you only need to calculate the new image - you can store the calculation for the old image and reuse it.


Anyway it's still a work in progress - good luck!


RorschachUK
#11 Posted : Friday, May 25, 2012 7:54:04 AM(UTC)
Rank: Tinkerer

Joined: 4/19/2012(UTC)
Posts: 7

I did something similar myself but concluded Gadgeteer wasn't up to the job (I was porting code that worked fine in native C on somewhat similar-ish hardware). My method was to calculate average colour values for 10x10 pixel blocks (in order to filter out the noise and jitter), and store reference arrays of those averaged block colours. To compare one photo against a reference, perform the calculations on the pixels to obtain a new set of averaged colours, then work out abs(old.R-new.R)+abs(old.G-new.G)+abs(old.B-new.B) for each block position, if it's above some threshold you can count that block as 'different', and tot up how many blocks were 'different' to decide if you're detecting movement. Replace your reference image every so often in order to cope with changes in brightness as the time of day changes and the sun moves around. Unfortunately though, code that runs fast enough in C to process a 320x240 camera frame buffer many times a second, takes minutes per frame in C# in Gadgeteer. If the hardware is Fez Spider, maybe it's possible to do natively in RLP?
PaulMineau
#12 Posted : Friday, May 25, 2012 10:08:43 AM(UTC)
Rank: Tinkerer

Joined: 3/31/2012(UTC)
Posts: 7

Was thanked: 1 time(s) in 1 post(s)

Just use a kernel method, this is pretty fast, this is a method taught in the Stanford AI class. If interested, we can put some cookbook code together on codeplex. the kernel method will give you features, and then you can compare the features using a similarity algorithm.

Rss Feed  Atom Feed
Users browsing this topic
Guest
Forum Jump  
You cannot post new topics in this forum.
You cannot reply to topics in this forum.
You cannot delete your posts in this forum.
You cannot edit your posts in this forum.
You cannot create polls in this forum.
You cannot vote in polls in this forum.

Powered by YAF | YAF © 2003-2011, Yet Another Forum.NET
This page was generated in 0.168 seconds.