As part of a project I am working on, I need to simply analyze a picture using a CLI Linux application and determining if its dark image (high contrast, low brightness).
So far, I figured out I can use ImageMagick to get verbose information of the image, but not sure how to use that data...or is there a simpler solution?
You could scale the image to a very small one -- one that has a dimension of 1x1 pixels and represents the "average color" of your original image:
convert original.jpeg -resize 1x1 1pixel-original.jpeg
Then investigate that single pixel's color, first
convert 1pixel-original.jpeg 1pixel-jpeg.txt
then
cat 1pixel-jpeg.txt
# ImageMagick pixel enumeration: 1,1,255,srgb
0,0: (130,113,108) #82716C srgb(130,113,108)
You can also get the same result in one go:
convert original.jpeg -resize 1x1 txt:-
# ImageMagick pixel enumeration: 1,1,255,srgb
0,0: (130,113,108) #82716C srgb(130,113,108)
This way you get the values for your "avarage pixel" in the original color space of your input image, which you can evaluate for its 'brightness' (however you define that).
You could convert your image to grayscale and then resize. This way you'll get the gray value as a measure of 'brightness':
convert original.jpeg -colorspace gray -resize 1x1 txt:-
# ImageMagick pixel enumeration: 1,1,255,gray
0,0: (117,117,117) #757575 gray(117,117,117)
You can also convert your image to HSB space (hue, saturation, brightness) and do the same thing:
convert original.jpeg -colorspace hsb -resize 1x1 txt:-
# ImageMagick pixel enumeration: 1,1,255,hsb
0,0: ( 61, 62,134) #3D3E86 hsb(24.1138%,24.1764%,52.4941%)
The 'brightness' values you see here (either of 134, #86 or 52.4941%) is probably what you want to know.
Related
I am in a situation where I have a set of images with variable width and height and I need to ensure that those images comply with an aspect ratio of 2:1.
The only assumption I can make is that those images have an aspect ratio greater than 2 so I need to expand the canvas.
With ImageMagick I can do this:
magick input.jpg -background black -gravity north -extent 2:1 output.jpg
But this crops instead of adding canvas as desired. Is there an option to avoid cropping, i.e. force image padding? Remember I do not know the image resolution beforehand.
Of course with a more complex script I can extract the image dimensions and compute the desired resolution but I am trying to keep things simple if possible.
P.S.: The images comes from a laser scanner and are going to be used in a 360 panorama viewer hence the need to meet an aspect ration without cropping.
With ImageMagick v7 you can do some inline calculations that will adjust the results of the -extent operation to pad any size input to a 2:1 ratio. See this command as an example...
magick input.png -gravity center -extent "%[fx:max(w,h*2)]x%[fx:max(w/2,h)]" result.png
That will pad any extra space with black. Add -background <somecolor> before the extent operation to change the padding color.
I have an image with nearly smooth background with some extra lines on it. I want to convert the image from RGB color space to LAB color space and then average the "L" part of pixels.
But before converting I want to delete extra lines or somehow ignore lines pixels in averaging the "L" part. Is there any algorithm to do this?
Below is an example of the images I have.
An option is to compute the gradient (Sobel for instance) and avoid doing the accumulation where the gradient magnitude is significant.
Following the comment by #Paul, it will be interesting to see the influence of the threshold level on the computed average.
I am using ImageMagick like your other question.
This will give you a mask of all the pixels that differ by more than 5% from their surrounding area (it's the 0.05 in the -fx part). It works by loading the stone image, copying it and blurring the copy to remove local details. It then calculates the absolute difference between the original and the blurred copy and sets the pixel to 1 if the difference exceeds 5% else sets it to 0:
convert stone.jpg -colorspace gray \( +clone -blur x10 \) -fx "abs(u-v)>0.05?1:0" mask.png
Experiment with changing the 0.05 and see what you think.
This will tell you how many pixels in the mask are white. It relies on the mean being sum of pixel brightnesses divided by number of pixels and knowing all pixels are either 0 or 1:
convert mask.png -format "%[fx:int(mean*w*h)]" info:
6155
This will blacken all the masked pixels. It works by loading both the stone and the mask, inverting the mask and then, at each pixel position, choosing the darker of the two images - so it will choose black everywhere the mask is white and it will choose the stone everywhere else:
convert stone.jpg \( mask.png -negate \) -compose darken -composite nolines.png
In ImageMagick, if you make the pixels to be ignored transparent, you can get the average of all non-transparent pixels using -scale 1x1!. For example, from the two images above:
So first put the mask into the alpha channel, then scale the result to one pixel, turn alpha off and get the pixel color:
convert image.jpg mask.png -alpha off -compose copy_opacity -composite -scale 1x1! -alpha off -format "%[pixel:u.p{0,0}]" info:
srgb(231,214,198)
To check, lets make a swatch:
convert -size 100x100 xc:"srgb(231,214,198)" swatch.png
Or we can recolor the original image:
convert image.jpg -fill "srgb(231,214,198)" -colorize 100 newimage.png
I'm trying to make a capcha solver, but I have ran into some trouble. The captcha that I am trying to solve has different coloured backgrounds.
I need to convert it to black text on white background so that it could easily be recognised by tesseract-ocr
I have tried
convert *.png -threshold 50% *.png which only shows some of the digits.
The problem with simple 50% thresholding is that both colours may be lighter than 50% grey and will therefore come out as white. Or, conversely, both colours may be darker than mid-grey and therefore bith come out as black.
You need to do a 2-colour quantisation to get just 2 colours, then go to greyscale and normalize so the lighter colour goes white and the darker one goes black. I am not near a computer, to test, but that should be:
convert input.png -colors 2 -colorspace gray -normalize result.png
Now, you will find some images are inverted (black on white instead of white on black), so you can either test the top left corner pixel and if it is white, then invert the image. Or, you could get the mean of the image and if it is more than 0.5 that would indicate that the image is largely white and therefore needs inverting.
Invert with:
convert input.png -negate output.png
Get top-left pixel with:
convert image.png -format '%[pixel:p{0,0}]' info:-
Get mean value with:
convert image.png -format "%[mean]" info:-
I want draw boundery box around the text like this image Image 2
from this Image 1. Can anyone suggest me a good way to do this or some algorithm or turorial anything?.
As you haven't suggested a tool, I will use ImageMagick straight at the command line as it is installed on most Linux distros and is available for OSX and Windows. It also has PHP, Perl, Python and .Net bindings.
So, as your background is uniform (ish) you can just use trim to trim it off:
convert image.jpg -fuzz 20% -trim result.jpg
Now you can add a border like this:
convert result.jpg -bordercolor black -border 5 result.jpg
Except you want the other grey background to be retained so that doesn't work for you. So, instead of actually trimming, we can ask ImageMagick where it "would" trim but to not actually do it like this:
convert image.jpg -fuzz 20% -format %# info:
81x22+1+14
So, we know it would make a 81x22px box starting 1 pixel in from the left and 14 pixels down from the top, so we'll just draw a rectangle there instead of trimming it:
convert image.jpg -fill none -stroke black -draw "rectangle 1,14 82,36" result.jpg
Or, if you want the outline fatter:
convert image.jpg -fill none -stroke black -strokewidth 5 -draw "rectangle 1,14 82,36" result.jpg
For a uniform background, a simple solution would be to identify all of the pixels that do not match the background color and then find the minimum and maximum indices in each axis of those pixels to define a rectangle.
For instance, if you were using Matlab, this might resemble:
Use 'find' to identify non-background pixels (e.g. linearIndices = find(~(image1 == background)) where background is either a hard coded set of RGB values corresponding to the background pixels or a set of RGB values identified by the mode of the image.
'Find' will return linear indices rather than subscripts (i.e. bottom right corner of a 3x3 matrix is 9, not [3,3]) so use 'ind2sub' to convert to subscripts (e.g. [I,J] = ind2sub(imageSize, linearIndices)
Use 'max' and 'min' to find range in x and y (e.g. rangeX = [min(I) max(I); rangeY = [min(J) max(J)])
Change pixels along min and max indices to border color. For instance, image1 ( rangeX(1), rangeY(1):rangeY(2) ) = boxColour (where boxColour is the RGB values of the colour you want the box to be) would draw the left border of the box. Repeat this process for the three other borders and you're done.
Of course this approach only works if the background is completely uniform. It also assumes you only want to draw a border that is one pixel thick.
While the function recommendations correspond specifically to Matlab functions, the thought process behind those functions could likely be ported elsewhere.
I'm using graphicsmagick to resize an image to a thumbnail, but it's adding a white surrounding border padding.
The command I'm using is:
gm convert matrix.jpg -resize "80x80>" -gravity center -extent 80x80 thumbnail.jpeg
As you can see, there is some white padding around the image, but I don't want this. Ideally I'd like (the entire image not just a crop of it) to fill the desired 80x80 output size.
How can this be achieved in either imagemagick or graphicsmagick?
I used ImageMagick with this image. This solution requires to know the size of the input image.
Input
The image has 145 pixels horizontally and 200 pixels vertically.
Crop
Crop from the top of the image:
convert -crop 145x145+0+0 -resize 80x80 matrix.jpg thumbnail.jpeg
I used 145x145 in order to extract a square from the original image. +0+0 is the offset of the extracted square, hereby the top left.
Crop with the center of the image:
convert -crop 145x145+0+27 -resize 80x80 matrix.jpg thumbnail.jpeg
The vertical offset is set to 27 because we have to remove 55 (200 - 145) pixels on top or bottom, so we need to remove 27 (55 รท 2) pixels on the top and 28 pixels on the bottom.
Crop with the bottom of the image:
convert -crop 145x145+0+55 -resize 80x80 matrix.jpg thumbnail.jpeg
Resizing without crop
convert -resize 80x80\! matrix.jpg thumbnail.jpeg
The ! flag (escaped with \! as suggested in the documentation) after the resize parameters forces ImageMagick to ignore the aspect ratio.
If you want to keep the original aspect ratio, without image distortion, you can use the ImageMagick -trim option to get rid of the white padding:
convert "matrix.jpg" -resize "80x80" -gravity center -extent 80x80
-trim "thumbnail.jpg"
This will produce a 58x80 uncropped image with the same aspect ratio as the original. It is 58x80 because ImageMagick uses the larger dimension of the original to compute the scale factor (in this case 80/200) and scales the smaller dimension by that same factor to preserve aspect ratio.
If you want an uncropped image of exactly 80x80 pixels, this is a different aspect ratio than the original. The output image will have distortion, and #AL's resizing without crop option will work.
convert "matrix.jpg" -resize "80x80!" -gravity center -extent 80x80
"thumbnail.jpg"
Tested in Windows 7 with ImageMagick 6.8.9. #AL syntax is probably Linux.