6

I think it will take a bit of explaining, so please bear with me...

I captured 2000+ images in sub-second bursts of 4-6 at a time. They all got dumped in the same place, so I need to sort them. I need to sort them by bursts, but the EXIF data only offers one minute resolution. The bursts should be of almost exactly the same thing, and different bursts are designed to be significantly different.

I need to look at each image, compare it to the following one and see if it's similar. If it's too different, it must be from another burst, it needs to go into a new folder, along with any of the following images that are similar to it, and so on.

My thought is to add up the absolute value of the difference between each pixel of the current image, and the next one. Once that sum reaches a threshold, then that must mean they are from different bursts (I can do some testing to find out what a good threshold is).

Biggest problem is how? Does PIL/Pillow support something like this? Is there a better way to see if one image is "mostly" the same as another one?

I'm more interested in sorting them quickly than using any particular technique, so other approaches are welcome.

...and it pretty much has to be Python.

EDIT: Here's a pair of sample images that should both go in the same folder: 001 002

These are two of the images from the following burst, and should go in another folder: 003 004

Matt
  • 775
  • 7
  • 24
  • What's the resolution on the timestamps in the EXIF data? A much simpler way could be to identify pictures taken as a burst based on the small difference in timestamps. A visual similarity method should achieve a similar result, shouldn't it? Time resolution will depend on your camera. – John Lyon Jun 17 '15 at 01:21
  • Comparing the time stamps is not enough? It would probably be easiest to see if the pictures were taken within a small time frame of one another than the actually compare the photos themselves. – erdekhayser Jun 17 '15 at 01:21
  • Yeah, this particular camera offers one MINUTE resolution :-( You're right, that would be a much better option... if I had the data. – Matt Jun 17 '15 at 01:23
  • @mHurley what's your camera make and model? Sometimes there are additional EXIF fields that hold the extra precision information. – John Lyon Jun 17 '15 at 01:25
  • Oh! That'd be cool! It's a Nikon CoolPix L100 – Matt Jun 17 '15 at 01:26
  • 1
    Could you link a photo? – dting Jun 17 '15 at 01:33
  • 2
    Looks like it should at least record seconds (timestamp should be ISO format that includes this). I'd experiment with [PyExifTool](http://smarnach.github.io/pyexiftool/) to see what you can get out before going down the visual similarity route. – John Lyon Jun 17 '15 at 01:33
  • @DTing, I'll try, but IDK if the upload will preserve all that. We'll see. – Matt Jun 17 '15 at 01:43
  • @mHurley-- the images that you have linked to above, do they go into the same folder or different folders? – Sandman Jun 17 '15 at 01:49
  • @mHurley uploading to imgur has stripped all of the metadata by the looks – John Lyon Jun 17 '15 at 01:50
  • Seems like that camera is capable of second timestamp resolution. Try throwing a photo into http://regex.info/exif.cgi – dting Jun 17 '15 at 01:51
  • :-/ I figured. @Sandman, these two should go in the same folder. I'll put up examples from the very next folder, too. – Matt Jun 17 '15 at 01:55
  • @DTing, 1 second might be enough. I can't really remember how quickly I was able to pull off those bursts. I'll do some mining... – Matt Jun 17 '15 at 01:55
  • @mHurley- Would it be possible for you zip these pictures up and share them. I'd like to play around with them both in terms of similarity matching using image processing and timestamp based method. I am doing something similar at the moment where I am analyzing each frame of a video to see how much it changes from the next frame. – Sandman Jun 17 '15 at 01:57
  • Sure thing! I'll pack up a whole slew of them for you ;-) Do you want them organized into folders the way I have them, or all in one folder? I've done the legwork already, so... – Matt Jun 17 '15 at 01:59
  • Are the folders sequentially labelled and are the images in them sequentially labelled too? – Sandman Jun 17 '15 at 02:00
  • Both. The images have the default Nikon naming, and the folders are 001, 002, 003, etc. – Matt Jun 17 '15 at 02:02
  • Here's a dropbox link. I'll leave it up for a few days. Anyone is welcome to it. https://www.dropbox.com/s/3a7ho17ad349e7h/ImageBurstsDataset.zip?dl=0 – Matt Jun 17 '15 at 02:09

4 Answers4

3

The OpenCV library is a good bet here if you want to do content based matching as opposed to timestamp based sorting suggested by the good folks above. Check this post on how to use the OpenCV library for different techniques on image similarity matching: Checking images for similarity with OpenCV

There are a ton of SO questions on the same topic, so reading through them will give you a better idea.

Based on the time idea above, when I plot just the times that your pictures were taken, this is a plot I get:

Clusters

The different colors represent different folders(should have used a different color map for better visibility, but oh well...).

Just based on these times, it does seem like your inter-cluster time, is visibly more pronounced than your intra-cluster time.

I also calculated some intra- and inter-cluster metrics in the output below:

folder: ImageBurstsDataset/001
Total image files in folder: 6
Total intra-cluster time: 1.0
Average intra-cluster time: 0.166666666667
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/002
Total image files in folder: 7
Total intra-cluster time: 1.0
Average intra-cluster time: 0.142857142857
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/003
Total image files in folder: 6
Total intra-cluster time: 1.0
Average intra-cluster time: 0.166666666667
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/004
Total image files in folder: 6
Total intra-cluster time: 2.0
Average intra-cluster time: 0.333333333333
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/005
Total image files in folder: 6
Total intra-cluster time: 2.0
Average intra-cluster time: 0.333333333333
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/006
Total image files in folder: 6
Total intra-cluster time: 1.0
Average intra-cluster time: 0.166666666667
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/007
Total image files in folder: 6
Total intra-cluster time: 2.0
Average intra-cluster time: 0.333333333333
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/008
Total image files in folder: 5
Total intra-cluster time: 2.0
Average intra-cluster time: 0.4
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/009
Total image files in folder: 6
Total intra-cluster time: 1.0
Average intra-cluster time: 0.166666666667
Max: 1.0, Min: 0.0

folder: ImageBurstsDataset/010
Total image files in folder: 6
Total intra-cluster time: 2.0
Average intra-cluster time: 0.333333333333
Max: 1.0, Min: 0.0


Inter-cluster times: [10.0, 8.0, 7.0, 5.0, 6.0, 6.0, 5.0, 10.0, 6.0]

Disclaimer: Wrote this script in a haste, just need to go back and make sure that all the edge-cases are correct. But otherwise... the conclusion that I draw from the dataset you uploaded is this:

  1. within a cluster, one picture is never more than 1 second apart from the previous one.

  2. The first picture in the next cluster is at least 5 seconds apart from the last picture in the previous cluster.

Community
  • 1
  • 1
Sandman
  • 5,432
  • 5
  • 20
  • 23
  • 1
    @mHurley- Here you go: [code](https://github.com/sandeepklr/so-imageburst/blob/master/main.py) – Sandman Jun 17 '15 at 13:34
2

Sorry, turns out the EXIF data was the way to go. Looks like there are a good 10-15 seconds between bursts, so it should be really easy to tell when one ends and another begins.

PIL/Pillow has sufficient tools for looking at that creation date using:

from PIL.ExifTags import TAGS

def get_exif(fn):
    ret = {}
    i = Image.open(fn)
    info = i._getexif()
    for tag, value in info.items():
        decoded = TAGS.get(tag, tag)
        ret[decoded] = value
    return ret

...or something along those lines.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
Matt
  • 775
  • 7
  • 24
  • 1
    Actually, according to my analysis in my answer, the minimum time between bursts is 5 seconds and maximum time is 10 seconds. Using a 10 second threshold will pretty much put everything in the same folder. – Sandman Jun 17 '15 at 04:07
1

How similar two images are is an open research question. However, given that your images have been taken in a quick burst, using absolute differences is reasonable. Another possibility is to use correlation, e.g., multiply pixel values and accept results that are above a threshold.

The problem is going to be speed. Depending upon your requirements for accuracy, you might be able to subsample the images quite significantly. It might be that comparing the values of 100 or 1000 evenly distributed pixels --- the same pixels in each image --- would give you a statistic sufficiently accurate for your purposes.

Darrell
  • 33
  • 6
  • Multiplication is an option I hadn't considered before. The main question would be how to get at that data? I'm not any good with numpy arrays... – Matt Jun 17 '15 at 01:48
  • Hmmm. It looks like your images from different bursts are still pretty similar. You might want to think about something like the maximum difference. However, to make the method less sensitive to noise, you could histogram the differences and declare a difference when a certain percentage (say, 10-20%) of the pixels in your sample differ by more than a threshold. – Darrell Jun 17 '15 at 02:41
1

PIL can give RGB data of an image, which in theory can be used for comparison of images. To measure how close two images are, you probably have to calculate the difference of the two images or even more error calculating statistical methods. You can get RGB data using

import Image
pic  = Image.open('/path/to/file')
rgbdata = pic.load()
width, height = pic.size

You can view the data purely in terms of RGB values of ijth pixel in rgbdata[i,j].

Hope this helps.

[edit] This method works only assuming that all the pictures are taken in the same frame... If the camera moves a little this won't work.

If they are from say a camera on tripod (stationary) and the objects are moving then we can even trace the movement of the object (where the pixel value difference is higher).

Or else one has to define tracker points as done in face recognition sort of applications. (I am not an expert in image processing but have seen few applications that work this way)

Another way to compare two images is in Fourier domain. But not sure how well it would work for you.

Rohin Kumar
  • 730
  • 2
  • 10
  • 24
  • I tried loading your first two images and printing the pixel data. There is literally thousands of data points. There must be some better methods to solve this problem than to do a brute force difference analysis. – Rohin Kumar Jun 17 '15 at 02:41
  • LOL!!!! Yeah, they're huge images. My hope was that for images that bear little resemblance, I'd hit the threshold quickly and abort, but for images that are very similar, the abs diff would be much smaller. Maybe not... – Matt Jun 17 '15 at 04:55
  • But defining that 'threshold' is the key... we can't just choose some random number! – Rohin Kumar Jun 17 '15 at 05:05
  • Oh that's certainly true, but if a good threshold exists, it should be easy to find. Guess-and-check is a valid investigative tool ;-) In other words, if it takes a high degree of precision and lots of analysis to figure out what the threshold is, then it's not a good approach for the dataset. – Matt Jun 17 '15 at 12:52