I have thousands of images shot for 3D reconstruction using photogrammetry and I want to evaluate which images are too blurry using Imagemagick or any other command line able software. What means too blury: based on the average blurriness/sharpness of all images, the worst images can be picked out easily. But how to evaluate the bluriness. I have gone into FFT, Fast Fournier Transform and think here can be found the solution. The frequencies can be calculated by the IM -fft command, which produces the magnitude and phases images. How can one use these images to calculate an overall bluriness/sharpness factor?
Update: Here are some of the images I have to treat. The real challenge is, all images are alongside many others of these kinds in a single folder and need to be checked for motion blur issues. I have to detect too high motion blur and avoid these images in further production.
Next 3 images have from all images the lowest deviation, but are very sharp in the original full-reso version.
These 2 images have a lower deviation because of the white areas, but also don't lack of enough sharpness.
Here the edge detection brings various edges, because of the mosaic. From all images the first image is blurry.
This image has low blurriness.
I have an idea using ImageMagick. I take an original image as follows:
then I put it into Photoshop and blur it with Motion blur of 5 pixesl and 10 pixels, saving the results as blur5.txt and blur10.txt.
Now, I use ImageMagick to compare the statistics:
identify -verbose original.jpg > orig.txt
identify -verbose blur5.jpg > blur5.txt
identify -verbose blur10.jpg > blur10.txt
Then use opendiff (on Mac) to compare the statistics,
opendiff orig.txt blur5.txt
I note that the blurrier the image, the lower the standard deviation - so that seems to measure relative bluriness.
I then used a Canny Edge Detector, and you can see that the sharpest image gets the most edges, not unexpectedly. So, you could count the white pixels in the Canny Edge detected image as a measure of your sharpness.
Like this:
convert original.jpg -canny 0x1+10%+30% -format %c histogram:info:-
875184: ( 0, 0, 0) #000000 gray(0)
72576: (255,255,255) #FFFFFF gray(255) <--- sharp image has high white pixel count
convert blur5.jpg -canny 0x1+10%+30% -format %c histogram:info:-
912322: ( 0, 0, 0) #000000 gray(0)
35438: (255,255,255) #FFFFFF gray(255) <--- slightly blurry has lower white pixel count
convert blur10.jpg -canny 0x1+10%+30% -format %c histogram:info:-
925759: ( 0, 0, 0) #000000 gray(0)
22001: (255,255,255) #FFFFFF gray(255) <--- blurriest has lowest white pixel count
If you want a single line that calculates the number of white pixels and echoes the filename, you can do this:
convert original.jpg -canny 0x1+10%+30% -format "%[fx:mean*h*w] %f\n" info:
72576 original.jpg
That will allow you to analyse all your images and sort them into order of sharpness like this:
find . -name "*.jpg" -exec convert "{}" -canny 0x1+10%+30% -format "%[fx:mean*h*w] %f\n" info: \; | sort
22001 blur10.jpg
35438 blur5.jpg
72576 original.jpg
Related
I don't understand :
if we considerate the value 00001111 (15) is a byte and a RGB pixel (220,180,155) it's 3 bytes whatever the values of the pixel.
so why when i reduce the values of my pixels (with bitshift operation or whatever) the size of
my image is not = pixel numbers x 3. when i say "pixel numbers" i mean "pixel numbers bigger than fully black".
how the mechanism works ? is it counted in bits and then divided by eight as an average ?
if i have a 3MB picture and i do a bitshift (factor 2 on each 3 RGB channel) i found a 300 KB picture.
Don't tell me 90% of my pixels turned fully black.
Thanks.
If you shift all the pixel values right by 2 places, you will have around 1/4 as many shades of red as before, and around 1/4 as many greens and likewise for blues. That means overall you will have vastly fewer colours. That means your image may well have fewer than 256 colours which means it can be palettised. It also means it is likely to compress better because there will be more repetition of fewer unique sequences.
You can check if your image is palettised in several ways:
open it with PIL and check if image.mode contains a P
run exiftool on it and check if Colour Type is Palette
run ImageMagick on it with magick identify -verbose YOURIMAGE
You can count the number of unique colours in your image with ImageMagick using:
magick identify -format %k YOURIMAGE
Or you can do it in Python with the last part (entitled "Update") of this answer.
I am searching for a faster way to blur an image than to use the GaussianBlur.
The solution I am looking for can be a command line solution, but I prefer code in perl notation.
Actually, we use the Perl image magick API to blur images:
# $image is our Perl object holding a imagemagick perl image
# level is a natural number between 1 and 10
$image->GaussianBlur('x' . $level);
This works fine, but with the level height the amount of time it consumes seems to grow exponentially.
Question: How can I improve the time used for the bluring operation?
Is there another faster approach to blur images?
I found that the suggested method of resizing image for blur imitation makes output look very pixelated for very large values of sigma like 25 or more. So I finally came to an idea of downscale-blur-enlarge, which makes very nice result (almost indistinguishable from simple blur with large sigma):
# plain slow blur
convert -blur 0x25 sample.jpg blurred_slow.jpg
# much faster
convert -scale 10% -blur 0x2.5 -resize 1000% sample.jpg blurred_fast.jpg
On my i5 2.7Ghz it shows up to 10x speed up.
The documentation speaks of the difference between Blur and GaussianBlur.
There has been some confusion as to which operator, "-blur" or the
"-gaussian-blur" is better for blurring images. First of all "-blur"
is faster, but it does this using two stage technique. First in one
axis, then in the other. The "-gaussian-blur" operator on the other
hand is more mathematically correct as it blurs in all directions
simultaneously. The speed cost between the two can be enormous, by a
factor of 10 or more, depending on the amount of bluring involved.
[...]
In summary, the two operators are slightly different, but only
minimally. As "-blur" is much faster, use it. I do in just about all
the examples involving blurring. Large
That would simply be:
$image->Blur( 'x' . $level );
But the Perl ImageMagick documentation has the same text on both Blur and GaussianBlur (emphasis mine). I can't try now, you would have to benchmark it yourself.
Blur: reduce image noise and reduce detail levels with a Gaussian operator of the given radius and standard deviation (sigma).
GaussianBlur: reduce image noise and reduce detail levels with a Gaussian operator of the given radius and standard deviation (sigma).
An alternative that the documentation also lists is resizing the image to be very tiny, and then enlarging again.
Using large sigma values for image bluring is very slow. But onw
technique can be used to speed up this process. This however is only a
rough method and could use some mathematicaly rigor to improve
results. Essentually the reason large blurs are slow is because you
need a large window or 'kernel' to merge lots of pixels together, for
each and every pixel in the image. However resize (making image
smaller) does the same thing but generates fewer pixels in the
process. The technique is basically shrink the image, then enlarge it
again to generate the heavilly blured result. The Gaussian Filter is
especially useful for this as you can directly specify a Gaussian
Sigma define.
The example command line code is this:
convert rose: -blur 0x5 rose_blur_5.png
convert rose: -filter Gaussian -resize 50% \
-define filter:sigma=2.5 -resize 200% rose_resize_5.png
Not sure if I could still help OP with this, but I recently tried the same for a blurred screenlock picture.
I found that omitting the -blur part saves even more calculation time and is still delivering great results for a 4K picture:
convert in.png -scale 2.5% -resize 4000% out.png
# real: 0.174s user: 0.144s size: 1.2MiB
convert in.png -scale 10% -blur 0x2.5 -resize 1000% out.png
# real: 0.136s user: 2.117s size: 1.2MiB
convert in.png -blur 0x25 out.png
# real: 2.425s user: 21.408s size: 1KiB
However, you couldn't go lower than 2.5% with 3840x2160. It will resize the image. I guess the eps value differs for pictures of other sizes.
It should be noted, that the resulting image sizes differ noticably!
Please look at the attached image. It is a GPR profile and using image processing techniques, I am trying to divide this image into 3 zones by labeling with colors the whole image on the top:
when parabolas in the image are very clear and distinct with high pixel values - green zone/ line at the top
when parabolas in the image are blurred but visible - yellow zone
when parabolas are distorted or when not parabolas are present - red zone
What techniques should I use? What's the best approach to solve it?
I have tried various techniques but not with success in every case, because, as you can in the following image, sometimes the parabolas are too close to one another and identifying them is becoming an issue.
A sample of how I want to zone it: https://www.dropbox.com/s/9zm9epgf0gt7591/sample.png?dl=0
One of the tried code: simplest one.
clear all
clc
%read png image
H=imread ('origpng.png');
%convert to gray scale
I = rgb2gray(H);
I(I>150)=0;I(I<100)=0;
figure,imshow(I)
J=I;
J=255-J;
figure, imshow (J)
J(J<255)=0;
figure,imshow (J)
Your question is not very clearly posed, but I spent some time on it and felt like sharing my thoughts. I am not preteding for an instant that this is anywhere near a complete, or rigorous answer - just some musings that might give you some ideas. Also, I use ImageMagick, but if you have and know Matlab, you should use that - I am not suggesting you switch tools.
First, I did a Canny Edge detection like this:
convert http://i.stack.imgur.com/XITAE.png -canny 0x1+15%+50% canny.jpg
that gives me this:
I then "squash" that down till it is just 1 pixel high, which effectively totals up and averages all the columns - I make it 10 pixels high here so you can see it. Where it is white, there are lots of parabolas, elsewhere there are fewer.
Then I stretch that back up to the full height of the original image and blur it a bit - note that everything up to the following image is just one line of "code":
convert http://i.stack.imgur.com/XITAE.png -canny 0x1+15%+50% -resize x1! -normalize -resize 827x310! -blur 0x11 -colorspace gray mask.png
I then use the above as an opacity mask for a red image the same size as your original like this:
convert -size 827x310! xc:red mask.png -compose copy-opacity -composite colouredmask.png
Then I took your original image and coloured it with yellow like this by first creating a yellow image and then blending it onto your image and then I blended the red image from above on top of that:
convert -size 827x310! xc:yellow yellow.png
convert http://i.stack.imgur.com/XITAE.png yellow.png -compose colorize -composite colouredmask.png -compose overlay -composite result.png
giving
Obviously you can set different parameters and use different thresholds and things, but it kind of heads towards the sort of thing you are aiming it.
So the entire process is:
# Make mask of peaky areas - line 1
convert http://i.stack.imgur.com/XITAE.png -canny 0x1+15%+50% -resize x1! -normalize -resize 827x310! -blur 0x11 -colorspace gray mask.png
# Colour mask with red - line 2
convert -size 827x310! xc:red mask.png -compose copy-opacity -composite colouredmask.png
# Tint original image with yellow and then overlay semi-transparent red area
convert -size 827x310! xc:yellow yellow.png
convert http://i.stack.imgur.com/XITAE.png yellow.png -compose colorize -composite colouredmask.png -compose overlay -composite result.png
Notes
Squashing pixels... sorry for confusing you with my terminology! Basically, when I squash the pixels down to a single row, you need to imagine dropping a brick on the top of the image and flattening it down to just one pixel tall. So, essentially, you draw an imaginary line underneath the image and then you work across the image totalling up the number of WHITE (i.e. edge) pixels in each vertical column. Columns that have more white pixels will add up to larger numbers. Columns that have no white pixels will add up to zero. Once you have got the totals for each column, you find the highest total - let's say it is 32 and then you multiply all totals by 255/32 so that everything is normalized to 255, or white. Now the squashed strip represents the edge energy in each column. And I then use that as the opacity for the red when I overlay - so columns with more white edges in the Canny image will show up with more red in the result.
Let's demo what happens if I squash down to 10 pixels wide and 1 pixel high before scaling back up to the original size - basically it means that my resulting mask will have only 10 possible values (or columns) columns and that each column will be a single constant brightness. I'll put the Canny image underneath so you can see that the brightness of the squashed strip represents the edge energy:
convert http://i.stack.imgur.com/XITAE.png -canny 0x1+15%+50% -resize 10x1! -normalize -scale 827x310! mask.png
If you want to introduce another colour, you need to work out what your algorithm is for controlling where that colour should appear. You then do exactly the same thing again - you make a mask that is light where you want that colour in your output image and dark where you don't want that colour. Then you use that mask as the opacity for your new colour (as I did at the line labelled line 2 above) and then you overlay it like I did in the last line of my code above.
I have an image with grayscale background and 2 thin lines (1 pixel wide) drawn in color. I'm trying to use various JPEG compression table (luminance and chrominance) to get the best possible result while staying under a certain file size.
The grayscale background compresses well and looks decent. The thin vertical and horizontal color lines get mutilated / smeared. The current JPEG algorithm uses 2x2 sub-sampling on the Cb and Cr channels and the chrominance compression table is fairly aggressive (high compression).
Is there any way to embed a "BMP" type data into JPEG image. Basically specify a color for specific pixels to be applied after the JPEG is de-compressed?
Any other ways clean up how thin color lines get encoded / decoded in JPEG without increasing the overall file size by a lot.
P.S. I'm testing all this stuff in Matlab.
Using ImageMagick's convert to barrel-distort a photo to correct a strongly visible pincushion distortion, I provide positive a, b or c values (from a database for my lens + focal length). This results in an image that is corrected, has the original width and height, but includes a non-rectangular, bent/distorted border, as the image is corrected towards its center. Simplified example:
convert rose: -virtual-pixel black -distort Barrel '+0.0 +0.1 +0.0' out.png
How can I automatically crop the black, bent border to the largest possible rectangle in the original aspect ratio within the rose?
The ImageMagick website says, that a parameter "d" is automatically calculated, that could do this (resulting in linear distortion effectively zooming into the image and pushing the bent border right outside the image bounds), but the imagemagick-calculated value seems to aim for something different (v6.6.9 on ubuntu 12.04). If I guess and manually specify a "d", I can get the intended result:
convert rose: -virtual-pixel black -distort Barrel '+0.0 +0.1 +0.0 +0.6' out.png
The given formular a+b+c+d=1 does not seem to be a proper d for my cropping case. Also, d seems to depend on the aspect ratio of the image and not only on a/b/c. How do I make ImageMagick crop the image, or, how to I calculate a proper d?
Update
I found Fred's ImageMagick script innercrop (http://www.fmwconcepts.com/imagemagick/innercrop/index.php) that does a bit what I need, but has drawbacks and is no solution for me. It asumes arbitrary outer areas, so it takes long to find the cropping rectangle. It does not work within Unix pipes, and it does not keep the original aspect ratio.
Update 2
Contemplating on the problem makes me think that calculating a "d" is not the solution, as changing d introduces more or less bending and seems to do more than just zoom. The d=1-(a+b+c) that is calculated by imagemagick results in the bent image touching the upper/lower bounds (for landscape images) or the left/right bounds (for portrait images). So I think the proper solution would be to calculate where one of the new 4 corners will be given a/b/c/d, and then crop to those new corners.
The way I understand the docs, you do not use commas to separate the parameters for the barrel-distort operator.
Here is an example image, alongside the output of the two commands you gave:
convert o.png -virtual-pixel black -distort Barrel '+0.0 +0.1 +0.0' out0.png
convert o.png -virtual-pixel black -distort Barrel '+0.0 +0.1 +0.0 +0.6' out1.png
I created the example image in order to better visualize what you possibly want to achieve.
However, I do not see the point you stated about the automatically calculated parameter 'd', and I do not see the effect you stated about using 'd=+0.6'...
I'm not sure I understand your wanted result correctly, so I'm assuming you want the area marked by the yellow rectangle cropped.
The image on the left is out0.png as created by the first command above.
In order to guess the required coordinates, we have to determine the image dimensions first:
identify out0.png
out0.png PNG 700x700 700x700+0+0 8-bit sRGB 36KB 0.000u 0:00.000
The image in the center is marked up with the white rectangle. The rectangle is there so you can look at it and tell me if that is the region you want cropped. The image on the right is the cropped image (without scaling it back to the original size).
Is this what you want? If yes, I can possibly update the answer in order to automatically determine the required coordinates of the cropping. (For now I've done it based on guessing.)
Update
I think you may have mis-understood the purpose of the barrel-distortion operation. It is meant for correcting a barrel (slight) distortion, as is produced by camera lenses. The 3 parameters a, b and c to be used for any specific combination of camera, lens and current zoom could possibly be stated in your photo's EXIF data. The formula were a+b+c+d = 1 is meant to be used when the new, distortion-corrected image should have the same dimensions as the original (distorted) image.
So to imitate the barrel-correction, we should probably use the second image from the last row above as our input:
convert out3.png -virtual-pixel gray -distort barrel '0 -0.2 0' corrected.png
Result: