9

Most modern mobile cameras has a family of techniques called Image Stabilization to reduce shaky effects in photographs due the motion of the camera lens or associated hardware. But still quite a number of mobile cameras produce shaky photographs. Is there a reliable algorithm or method that can be implemented on mobile devices, specifically on Android for finding whether a given input image is shaky or not? I do not expect the algorithm to stabilize the input image, but the algorithm/method should reliably return a definitive boolean whether the image is shaky or not. It doesn't have to be Java, but can also be C/C++ so that one can build it through the native kit and expose the APIs to the top layer. The following illustration describes the expected result. Also, this question deals with single image problems, thus multiple frames based solutions won't work in this case. It is specifically about images, not videos.

enter image description here

Brad Rippe
  • 3,405
  • 1
  • 18
  • 20
C--
  • 16,393
  • 6
  • 53
  • 60
  • 1
    I have no idea how to help you but maybe this read will put some light on it: http://arxiv.org/pdf/1209.5982v1.pdf Page7: Data reduction and transmission. – Dawid Czerwinski Aug 26 '14 at 01:39
  • Actually that was of some help. I got pointed to this paper and it appears to cover most of the concerns in this question : http://digital.csic.es/bitstream/10261/61694/1/Gabarda.pdf – C-- Aug 26 '14 at 05:39
  • Simply don't shoot when camera is moving. All Android phones have an accelerometer sensor which can tell you if the phone is moving. – Andrey Kamaev Aug 26 '14 at 20:08
  • Andrey, the actual problem is not while shooting. Please read the OP. – C-- Aug 27 '14 at 03:11
  • 1
    How is this not a duplicate of http://stackoverflow.com/questions/7765810/is-there-a-way-to-detect-if-an-image-is-blurry ? – Bull Aug 27 '14 at 14:49
  • 1
    Because of the fact that the other posting focuses on blurry-ness and this is about shaky-ness. Intentional blurryness has to be considered. Secondly, this question was tagged to opencv in a later stage. – C-- Aug 27 '14 at 17:01

3 Answers3

4

Wouldn't out of focus images imply that

a) Edges are blurred, so any gradient based operator will have a low values compared to the luminance in the image

b) edges are blurred, so any curvature based operator will have low values

c) for shaky pictures, the pixels will be correlated with other pixels in the direction of the shake (a translation or a rotation)

I took your picture in gimp, applied Sobel for a) and Laplacian for b) (available in openCV), and got images that are a lot darker in the above portion.

Calibrating thresholds for general images would be quite difficult I guess.

eoinzy
  • 2,152
  • 4
  • 36
  • 67
user3970006
  • 151
  • 1
  • `c) for shaky pictures, the pixels will be correlated with other pixels in the direction of the shake` This isn't going to work since it would not be trivial to find the direction of correlation. Is there any way you suggest? – C-- Aug 25 '14 at 03:49
  • Infact the Laplace works upto an extend (I tried with 32 images and it appears to be reliable). I'm waiting for more answers and offering a bounty as well. – C-- Aug 25 '14 at 06:39
  • 1
    The problem is that some pictures will have natural soft edges, for which the laplacian or gradient will be low. You might have to normalize the measure, by saying for example that this big square in the image has got different colors and luminance, so laplacian and gradient inside it should be high, whereas uniform portions have naturally low derivatives. Note that the laplacian seems to work better, but being a higher derivative it will also highlight noise, so you should definitely check whether blurry and out of focus also blurs camera noise. – user3970006 Aug 25 '14 at 14:50
  • 1
    additionally, you could tag your question 'opencv' to bring some more people on it – user3970006 Aug 25 '14 at 21:44
  • 1
    last comment, if some derivative highlights noisy pixels, you can remove them with a morphological opening – user3970006 Aug 29 '14 at 00:10
3

Are you dealing with video stream or a single image

In case of video stream: The best way is calculate the difference between each 2 adjacent frames. And mark each pixel with difference. When the amount of such pixels is low - you are in a non shaky frame. Note, that this method does not check if image is in focus, but only designed to combat motion blur in the image. Your implementation should include the following

  1. For each frame 'i' - normalize the image (work with gray level, when working with floating points normalize the mean to 0 and standard deviation to 1)
  2. Save the previous video frame.
  3. On each new video frame calculate pixel-wise difference between the images and count the amount of pixels for whom the difference exceed some threshold. If the amount of such pixels is too high (say > 5% of the image) that means that the movement between the previous frame and current frame is big and you expect motion blur. When person holds the phone firmly, you will see a sharp drop in the amount of pixels that changed.
  4. If your images are represented not in floating point but in fixed point (say 0..255) than you can match the histograms of the images prior to subtraction in order to reduce noise.
  5. As long as you are getting images with motion, just drop those frames and display a message to the user "hold your phone firmly". Once you get a good stabilized image, process it but keep remembering the previous one and do the subtraction for each video frame.

The algorithm above should be strong enough (I used it in one of my projects, and it worked like a magic).

In case of Single Image: The algorithm above does not solve unfocused images and is irrelevant for a single image.

  1. To solve the focus I recommend calculating image edges and counting the amount of pixels that have strong edges (higher than a threshold). Once you get high amount of pixels with edges (say > 5% of the image), you say that the image is in focus. This algorithm is far from being perfect and may do many mistakes, depending on the texture of the image. I recommend using X,Y and diagonal edges, but smooth the image before edge detection to reduce noise.
  2. A stronger algorithm would be taking all the edges (derivatives) and calculating their histogram (how many pixels in the image had this specific edge intensity). This is done by first calculating an image of edges and than calculating a histogram of the edge-image. Now you can analyse the shape of the histogram (the distribution of the edges strength). For example take only the top 5% of pixels with strongest edges and calculate the variance of their edge intensity.
  3. Important fact: In unfocused images you expect the majority of the pixels to have very low edge response, few to have medium edge response and almost zero with strong edge response. In images with perfect focus you still have the majority of the pixels with low edge response but the ratio between medium response to strong response changes. You can clearly see it in the histogram shape. That is why I recommend taking only a few % of the pixels with the strongest edge response and work only with them. The rest are just a noise. Even a simple algorithm of taking the ratio between the amount of pixels with strong response divided by the amount of pixels with medium edges will be quite good.

Focus problem in video:

  1. If you have a video stream than you can use the above described algorithms for problematic focus detection, but instead of using constant thresholds, just update them as the video runs. Eventually they will converge to better values than a predefined constants.

Last note: The focus detection problem in a single image is a very tough one. There are a lot of academic papers (using Fourier transform wavelets and other "Big algorithmic cannons"). But the problem remains very difficult because when you are looking at a blurred image you cannot know whether it is the camera that generated the blur with wrong focus, or the original reality is already blurred (for example, white walls are very blurry, pictures taken in a dark tend to be blurry even under perfect focus, pictures of water surface, table surface tend to be blurry). Anyway there are few threads in stack overflow regarding focus in the image. Like this one. Please read them.

Community
  • 1
  • 1
DanielHsH
  • 4,287
  • 3
  • 30
  • 36
  • This is regarding those `single image` situations. I have edited the posting to reflect the same. – C-- Aug 26 '14 at 11:08
  • I have came across this anisotropy based algorithm here : http://digital.csic.es/bitstream/10261/61694/1/Gabarda.pdf It already does have a Matlab implementation. I would definitely take some time to get my hands on it to try out. Page-7 in the paper covers most concerns here. – C-- Aug 26 '14 at 11:10
  • I know it. Though you will need a lot of optimizations to run this code in C/C++ on Android. The matlab version is very slow. Moreover, the thresholds are not calibrated for images with text (if that is what you need to scan) – DanielHsH Aug 31 '14 at 07:47
1

You can also compute the Fourier Transform of the image and then if there is a low accumulation in the high frequencies bins, then the image is probably blurred. JTransform is a reasonable library that provides FFT's if you wish to travel down this route.

There is also a fairly extensive blog post here about different methods that could be used

There is also another stack overflow question asking this but with OpenCV, OpenCV also has Java bindings and can be used in Android projects so this answer could also be helpful.

Community
  • 1
  • 1
pont
  • 549
  • 7
  • 14
  • There will be portions in the images that is intentionally blurred. But in case of a shaky image, everything will be shaky, not a single portion of the image will be in focus. So the methods needs to considered giving appropriate weights to each. – C-- Aug 27 '14 at 10:39