Comparing images using color difference - java

I'm trying to figure out a good method for comparing two images in terms of their color. One idea I had was to take the average color of both images and subtract that amount to get a "color distance." Whichever two images have the smallest color distance would be a match. Does this seem like a viable option for identifying an image from a database of images?
Ideally I would like to use this to identify playing cards put through an image scanner.
For example if I were to scan a real version of this card onto my computer I would want to be able to compare that with all the images in my database to find the closest one.
Update:
I forgot to mention the challenges involved in my specific problem.
The scanned image of the card and the original image of the card are most likely going to be different sizes (in terms of width and height).
I need to make this as efficient as possible. I plan on using this to scan/identify hundreds of cards at a time. I figured that finding (and storing) a single average color value for each image would be far more efficient than comparing the individual pixels of each image in the database (the database has well over 10,000 images) for each scanned card that needed to be identified. The reason why I was asking about this was to see if anyone had tried to compare average color values before as a means of image recognition. I have a feeling it might not work as I envision due to issues with both color value precision and accuracy.
Update 2:
Here's an example of what I was envisioning.
Image to be identified = A
Images in database = { D1, D2 }
average color of image A = avg(A) = #8ba489
average color of images in database = { #58727a, #8ba489 }
D2 matches with image A because #8ba489 - #8ba489 is less than #8ba489 - #58727a.
Of course the test image would not be an exact match with any of those images because it would be scanned in; however, I'm trying to find the closest match.

Content based image retrieval (CBIR) can do the trick for you. There's LIRE, a java library for that. You can even first try several approaches using different color based image features with the demo. See https://code.google.com/p/lire/ for downloads & source. There's also the "Simple Application" which gets you started with indexing and search really fast.
Based on my experience I'd recommend to use either the ColorLayout feature (if the images are not rotated), the OpponentHistogram, or the AutoColorCorrelogram. The CEDD feature might also yield good results, and it's the smallest with ~ 60 bytes of data per image.

If you want to check color difference like this:
http://en.wikipedia.org/wiki/Color_difference
You can use Catalano Framework,
http://code.google.com/p/catalano-framework/
It works in Java and Android.
Example using Color Difference:
float[] lab = ColorConverter.RGBtoLAB(100, 120, 150, ColorConverter.CIE2_D65);
float[] lab2 = ColorConverter.RGBtoLAB(50, 80, 140, ColorConverter.CIE2_D65);
double diff = ColorDifference.DeltaC(lab, lab2);

I think your idea is not good enough to do the task.
Your method will say all images below are the same (average color of all images are 128).

Your color averaging approach would most likely fail, as #Heejin already explained.
You can do try it in different way. Shrink all images to some arbitrary size, and then subtract uknown image from all know images, the one with smallest difference is the one you are looking for. It's really simple method and it would't be slower than the averaging.
Another option is to use some smarter algorithm:
http://www.hackerfactor.com/blog/index.php?/archives/432-Looks-Like-It.html
I have used this method in past and the results are okay-ish. Ir works great for finding same images, not so well for finding siilar images.

Related

Approximating a fitting image size

The solution I am aiming for does select the best fitting image size from a given number of sizes.
Given a number of rather random resolutions, I would like to find an image sized as close as possible to my preferred size.
Suppose I would like to use an image sized width x height (preferredImageSize).
Example: 320x200
Suppose I have the following image sizes at my disposal (availableImageSize) width1 x height1, width2 x height2, ... (maybe up to 10 different sizes).
Examples: 474x272, 474x310, 264x150, 226x128, 640x365, 474x410, 480x276, 256x144, 160x90, 320x182, 640x365, 192x108, 240x137, 480x276
For developing some generic approach to make the preferredImageSize variable I am trying to find a good solution that computes rather quick but also results into something that does look good on the screen.
I define looks good on the screen as an image that is:
hardly upscaled
as close to the given aspect-ratio (preferredImageSize.width / preferredImageSize.height) as possible
may be heavily downscaled
may be cropped/stretched in very small amounts
My initial (rather trivial) approach:
Run through the available image sizes once and find the smallest width delta (abs(preferredImageSize.width - availableImageSize.width)). The image with that smallest delta is then chosen (bestFitWidth).
That is certainly a way to solve the issue but definitely does not comply with my looks good on the screen hopes.
Any hints, no matter if text, source or links would be awesome. Ow, and if you think that my requirements (aka hopes) are already leading into the wrong direction, go ahead, let me know...
Edit: added cropping and stretching as options - which, I am afraid will make the issue even harder to solve. So if needed leave it out of the equation.
Simple "if/then" approach:
I would do two things:
Since you would rather not upscale, but are OK with downscaling (which I find a good choice), NEVER use a source image that is smaller than your target, unless none is available.
Since "heavy" downscaling is OK, I would try to find an image that matches the aspect ratio as closely as possible, starting with the smallest acceptable image and going to progressively larger images.
To put it together, first throw out all images from the list that are smaller than your target. Then, start with the smallest image left and check its aspect ratio against your target. If the mismatch is acceptable (which you need to quantify), use the image, otherwise go to the next bigger one. If you don't find any acceptable ones, use the one with the best match.
If you've already thrown out all images as smaller than your target, you will likely end up with a bad-looking image either way, but you should then try out whether it is worse the use an image that requires more upscaling, or whether it is worse to use an image that is a worse aspect ratio match.
One other thing you need to think about is whether you want to stretch or crop the images to match your target aspect ratio.
More complex quantitative approach:
The most flexible approach, though, would be to define yourself a "penalty" function that depends on the size mismatch and the aspect ratio mismatch and then find the source image that gives you the lowest "penalty". This is what you have currently done and you've defined your penalty function as abs(preferredImageSize.width - availableImageSize.width). You could go with something a little more complex, like for example:
width_diff = preferredImageSize.width - availableImageSize.width
height_diff = preferredImageSize.height - availableImageSize.height
if (width_diff > 0) width_penalty = upscale_penalty * width_diff
else width_penalty = downscale_penalty * width_diff
if (height_diff > 0) height_penalty = upscale_penalty * height_diff
else height_penalty = downscale_penalty * height_diff
aspect_penalty = ((preferredImageSize.width / preferredImageSize.height) -
(availableImageSize.width / availableImageSize.height)) * stretch_penalty;
total_penalty = width_penalty + height_penalty + aspect_penalty;
Now you can play with the 3 numbers upscale_penalty, downscale_penalty, and stretch_penalty to give these three quality reducing operations different importance. Just try a couple of combinations and see which works best.

How to measure length of line which is drawn on image in java?

I m making app in netbeans platform in java using Swing technology for dentist. i want to measure length of line which is drawn by user on image's of teeth? so, then Doctor can find the length of root canal of teeth.and line can also be not straight, line can be ZigZag.if any one have idea about that then share with me please.
You can use one of the many line detection algorithms to detect the existence of lines and then measure the line in pixels.
You can use an image processing library that already has these algorithms implemented, or you can implement them your self (better use a library though), this question is about image processing libraries and approaches in java.
That is not very easy because the images are taken from different angles or distances as I suppose. You will need some kind of scale in the image which length you know. Think of a tag with a size of 5mm x 5mm which is pasted on the tooth. In you application you can then measure this tag. Lets say its edge size is 200x200 Pixel. Then you know that 200 Pixels are 5mm and you have the formula to calculate the real size from the line length.

How can I compare two images in Java?

I have 5 images by default in the program, and I will allow the user choose an image from the desktop. The program will determine which image between the 5 images is the closest one to the user image.
Can anyone help me and take me to the start of the idea?
You can try to use a feature extraction algorithm like SIFT, SURF etc. Then compare extracted features with your database. You can select the best matching image based on the number of correct matches.
Generally SIFT works fine for 2D objects, like picture of a label or an advertisement board. Rotation on 2D plane or scale wont matter if you are using SIFT. SURF is supposed to be an improvement of SIFT but I do not have much experience on it.
These algorithms are said to be bit heavy. Anyway if you are matching just 5 images it wont be much of a problem.(Or you can simply calculate the descriptors(features) of your images before hand and store them. Then at run time all you have to do is get the descriptor of the user image and compare it) But still if you are trying to match images of basic shapes like squares and circles, using square detection or circle detection might be efficient performance wise.

Java2D & Image creation

I want to dynamically create some image from Java and save it to a file.
As I read in various tutorials, I need to use BufferedImage.
But, the BufferedImage constructor requires that the height and width as parameters. But I don't know the final size of my image. How should I create an image with size unknown in advance?
There are two obvious strategies:
Create a very large image initially, say 10000x10000.
Gradually creating larger image, and copying the original to it. The drawback is that I need to check the bounds before each time I want to add something.
How do you deal with this problem?
You've just run into space vs time issue here. I would be going for the first strategy of creating a very large image 10000x10000, the simple reason being the second approach you say involves mountains of matrix copies which you would want to avoid at any cost.
Moreover, with a good knowledge of the image size, you can further optimize that value of 10000 x 10000 to something like 1000x1000 initially. If the image seems to exceed this, double it like 2000 x 2000 and copy the old one to the new one and keep doing this as your image expands.. This is more of a proven strategy that is used in the famous java.util.ArrayList
By this way, you are indirectly bridging the time vs space trade-off. And yes, you will have to calculate the bounds everytime but that does not look a big task to me, it can be done in O(1) time.
Of course we don't know the specifics of your problem but a simple approach could be like this: You build some kind of model of your image: Which shape goes where and how large is it. From that you should be able to calculate the dimensions of the total image.

What's the best way to analyse the colours in an image (Java)?

I don't have much experience doing image analysis so I thought I'd ask more enlightened individuals :)
Basically what I want to do is analyse an image and work out what the most common colours are (these will be averages obviously).
Does anybody know of an effective way to do this? If at all possible I'd like to avoid using any third party libraries, but everything will be considered at least.
Like I said, I don't have much experience with image analysis so please be patient with me if I don't understand your answers properly!
I've tried Google but there doesn't seem to be anything resembling what I'm after. Maybe my Google-Fu just isn't good enough today.
I'd really appreciate any pointers you guys could give!
Thanks,
Tom
A rough idea of how you might be able to do this:
You could use java.awt.image.PixelGrabber to grab a 2D array of RGB ints from the image, pixel by pixel.
When you have this array populated, you can go through and sort however you want (sounds like it would be memory-intensive), and perform simple functions to order them, count them, etc.
Then you could look at java.awt.Color and, using the Color(int, int, int) constructor, create boxes with those colors (as visual placeholders) with the number of occurrences appearing below it.
To get the hex values for the color, you can use a String like so:
String rgb = Integer.toHexString(color.getRGB());
rgb = rgb.substring(2, rgb.length());
(substring is necessary, otherwise you'd get 8 characters)
Hopefully this gets you on the right track!
Resources: Color Class, Image Class
Consider a "color cube" with RGB instead of XYZ. Split the cube into subcubes, but make them all overlap. Ensure they are all the same size. An easy to remember/calculate cube-pattern would be one that goes from 0-127, 64-191, 128-255 in all directions, making for a total of 27 cubes. For each cube, find what colors in the image fall into them.
As you make the cubes smaller and smaller, the results will change less and less and begin to converge on the most popular color ranges. Once you have that convergence, take the average of the range to get the "actual color".
That's about as much detail as I can go into with my boss hovering around the cubefarm :-)
I know your trying to avoid third party libraries, but do take a look at OpenCV. They have some good stuff w.r.t image manipulation and analysis. Maybe that can work for you.

Categories