Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding matches between high quality and low quality, pixelated images - is it possible ? How?

I have a problem. My company has given me an awfully boring task. We have two databases of dialog boxes. One of these databases contains images of horrific quality, the other very high quality.

Unfortunately, the dialogs of horrific quality contain important mappings to other info.

I have been tasked with, manually, going through all the bad images and matching them to good images.

Would it be possible to automate this process to any degree? Here is an example of two dialog boxes (randomly pulled from Google images) :

Good quality image

Bad Quality image

So I am currently trying to write a program in C# to pull these photos from the database, cycle through them, find the ones with common shapes, and return theird IDs. What are my best options here ?

like image 987
Simon Kiely Avatar asked Jul 26 '12 14:07

Simon Kiely


People also ask

Why are pictures so low quality?

Your images might be too small if you have downloaded them from the web, come from an older model phone or camera, or if you have the settings on your phone or camera set to save images as a smaller size. If your images are too small, there's no way to edit them to make them bigger and maintain the quality.


2 Answers

I really see no reason to use any external libraries for this, I've done this sort of thing many times and the following algorithm works quite well. I'll assume that if you're comparing two images that they have the same dimensions, but you can just resize one if they don't.

badness := 0.0 For x, y over the entire image:   r, g, b := color at x,y in image 1   R, G, B := color at x,y in image 2   badness += (r-R)*(r-R) + (g-G)*(g-G) + (b-B)*(b-B) badness /= (image width) * (image height) 

Now you've got a normalized badness value between two images, the lower the badness, the more likely that the images match. This is simple and effective, there are a variety of things that make it work better or faster in certain cases but you probably don't need anything like that. You don't even really need to normalize the badness, but this way you can just come up with a single threshold for it if you want to look at several possible matches manually.


Since this question has gotten some more attention I've decided to add a way to speed this up in cases where you are processing many images many times. I used this approach when I had several tens of thousands of images that I needed to compare, and I was sure that a typical pair of images would be wildly different. I also knew that all of my images would be exactly the same dimensions. In a situation in which you are comparing dialog boxes your typical images may be mostly grey-ish, and some of your images may require resizing (although maybe that just indicates a mis-match), in which case this approach may not gain you as much.

The idea is to form a quad-tree where each node represents the average RGB values of the region that node represents. So an 4x4 image would have a root node with RGB values equal to the average RGB value of the image, its children would have RGB values representing the average RGB value of their respective 2x2 regions, and their children would represent individual pixels. (In practice it is a good idea to not go deeper than a region of about 16x16, at that point you should just start comparing individual pixels.)

Before you start comparing images you will also need to decide on a badness threshold. You won't calculate badnesses above this threshold with any reliable accuracy, so this is basically the threshold at which you are willing to label an image as 'not a match'.

Now when you compare image A to image B, first compare the root nodes of their quad-tree representations. Calculate the badness just as you would for a single pixel image, and if the badness exceeds your threshold then return immediately and report the badness at this level. Because you are using normalized badnesses, and since badnesses are calculated using squared differences, the badness at any particular level will be equal to or less than the badness at lower levels, so if it exceeds the threshold at any points you know it will also exceed the threshold at the level of individual pixels.

If the threshold test passes on an nxn image, just drop to the next level down and compare it like it was a 2nx2n image. Once you get low enough just compare the individual pixels. Depending on your corpus of images this may allow you to skip lots of comparisons.

like image 79
Running Wild Avatar answered Oct 04 '22 10:10

Running Wild


I would personally go for an image hashing algorithm.

The goal of image hashing is to transform image content into a feature sequence, in order to obtain a condensed representation. This feature sequence (i.e. a vector of bits) must be short enough for fast matching and preserve distinguishable features for similarity measurement to be feasible.

There are several algorithms that are freely available through open source communities.

A simple example can be found in this article, where Dr. Neal Krawetz shows how the Average Hash algorithm works:

  1. Reduce size. The fastest way to remove high frequencies and detail is to shrink the image. In this case, shrink it to 8x8 so that there are 64 total pixels. Don't bother keeping the aspect ratio, just crush it down to fit an 8x8 square. This way, the hash will match any variation of the image, regardless of scale or aspect ratio.
  2. Reduce color. The tiny 8x8 picture is converted to a grayscale. This changes the hash from 64 pixels (64 red, 64 green, and 64 blue) to 64 total colors.
  3. Average the colors. Compute the mean value of the 64 colors.
  4. Compute the bits. This is the fun part. Each bit is simply set based on whether the color value is above or below the mean.
  5. Construct the hash. Set the 64 bits into a 64-bit integer. The order does not matter, just as long as you are consistent. (I set the bits from left to right, top to bottom using big-endian.)

David Oftedal wrote a C# command-line application which can classify and compare images using the Average Hash algorithm. (I tested his implementation with your sample images and I got a 98.4% similarity).

The main benefit of this solution is that you read each image only once, create the hashes and classify them based upon their similiarity (using, for example, the Hamming distance).

In this way you decouple the feature extraction phase from the classification phase, and you can easily switch to another hashing algorithm if you find it's not enough accurate.


Edit

You can find a simple example here (It includes a test set of 40 images and it gets a 40/40 score).

like image 45
Paolo Moretti Avatar answered Oct 04 '22 10:10

Paolo Moretti