find average of all the pixels using cli - image

Is there a cli way of getting the average value of all the pixels in an image
for example - if i have an all black image, I would want to type:
*cmd* black-img.jpg
and the output will be 0 in the shell

Oh, this is simple:
convert image.jpg -scale 1x1\! txt:-
The command uses ImageMagick's convert to enforce scaling of the input image to a size 1x1 pixels. Output will be something like this for an 8-bit RGBA image:
# ImageMagick pixel enumeration: 1,1,255,srgba
0,0: (151,161,212, 92) #97A1D45C srgba(151,161,212,0.361928)
or this for an 8-bit sRGB image:
# ImageMagick pixel enumeration: 1,1,255,srgb
0,0: (229,226,229) #E5E2E5 srgb(229,226,229)
It represents the color value of the single-pixel image that was produced:
0,0: are the coordinates of this pixel: 1st row in 1st column.
(151,161,212, 92) represent the R ed, G reen, B lue and A lpha values of the RGBA pixel.
(229,226,229) represent the R ed, G reen and B lue values of the sRGB pixel.
#97A1D45C and #E5E2E5 are the respective hex values.
Now it's your own job to compute this output into 'a '0' in the shell' if it is a black pixel. :-)

Ok, so the original poster seems to want not the 3 or 4 color channel values when he asks about 'getting the average value of all the pixels in an image'... he wants one single value that can be derived by converting the image to grayscale first:
convert image.jpg -colorspace gray -scale 1x1\! txt:-
Sample output for the same 8-bit RGBA (with Alpha channel) image as in the other answer:
# ImageMagick pixel enumeration: 1,1,255,graya
0,0: (119,119,119, 92) #7777775C graya(119,119,119,0.361928)
Output for the 8-bit sRGB image (without Alpha channel) from before:
# ImageMagick pixel enumeration: 1,1,255,gray
0,0: (221,221,221) #DDDDDD gray(221,221,221)

Related

8-bit color image matrix representation

I have just started learning image processing by myself, and I am using MATLAB. I have been getting myself familiarized with basic image operations. When I read the below image(res: 225x300), which is supposed to be an 8-bit color image, I expected the resultant matrix to have 3 dimensions with one each for RGB. A simple web search about 8-bit color image led me to Wikipedia with the following information:
The simplest form of quantization frequently called 8-bit truecolor is to simply assign 3 bits to red, 3 to green and 2 to blue (the human eye is less sensitive to blue light) to create a 3-3-2.
Therefore, I expected the image matrix to have 225x300x3 dimensions with the above distribution of bits b/w RGB. But after I checked the dimensions of the matrix of the image, I found it to be 225x300 unit8, which is what one expects from an 8-bit grayscale image. But the image is a color image, as seen by any image viewer. So what is that I lack in knowledge or doing wrong? Is the problem with how I read the image?
Also, it occurred to me that uint8 is the smallest unsigned integer class. So how can we have colored images of 4,8,10, etc., bits represented and created?
My code:
>> I_8bit = imread('input_images\8_bit.png');
>> size(I_8bit)
ans =
225 300
>> class(I_8bit)
ans =
'uint8'
>> I_24bit = imread('input_images\24_bit.png');
>> size(I_24bit)
ans =
225 300 3
>> class(I_24bit)
ans =
'uint8'
(source: https://en.wikipedia.org/wiki/Color_depth#/media/File:8_bit.png)
Matlab supports several types of images, including
RGB images, which allow arbitrary colors, stored in terms of R,G,B components. The image is defined by a 3D m×n×3 array
Indexed images, in which each pixel is defined by an index to a colormap. The image is defined by a 2D m×n array and a c×3 colormap, where c si the number of colors.
It looks like the image you are loading is indexed. So you need the two-output version of imread to get the 2D array and the colormap:
[I_8bit, cmap] = imread('input_images\8_bit.png');
To display the image you need to specify the 2D array and the colormap:
imshow(I_8bit, cmap)
You can see the effect of changing the colormap, for example
cmap_wrong = copper(size(cmap, 1)); % different colormap with the same size
imshow(I_8bit, cmap_wrong)
To convert to an RGB image, use ind2rgb:
I_8bit_RGB = ind2rgb(I_8bit, cmap);
which then you can display as
imshow(I_8bit_RGB)

Histogram equalization help in MATLAB

My code is shown below:
G= histeq(imread('F:\Thesis\images\image1.tif'));
figure,imshow(G);
The error message I got was the following and I'm not sure why it is appearing:
Error using histeq
Expected input number 1, I, to be two-dimensional.
Error in histeq (line 68)
validateattributes(a,{'uint8','uint16','double','int16','single'}, ...
Error in testFile1 (line 8)
G= histeq(imread('F:\Thesis\images\image1.tif'));
Your image is most likely colour. histeq only works on grayscale images. There are three options available to you depending on what you want to do. You can either convert the image to grayscale, you can histogram equalize each channel individually or what is perceptually better is to convert the image into the HSV colour space, histogram equalize the V or Value component, then convert back into RGB. I tend to prefer the last option for colour images. Therefore, one method will be an enhanced grayscale image, and the other two will be an enhanced colour image.
Option #1 - Convert to grayscale then equalize
G = imread('F:\Thesis\images\image1.tif');
G = histeq(rgb2gray(G));
figure; imshow(G);
Use rgb2gray to convert the image to grayscale, then equalize the image.
Option #2 - Equalize each channel individually
G = imread('F:\Thesis\images\image1.tif');
for i = 1 : size(G, 3)
G(:,:,i) = histeq(G(:,:,i));
end
figure; imshow(G);
Loop through each channel and equalize.
Option #3 - Convert to HSV, histogram equalize the V channel then convert back
G = imread('F:\Thesis\images\images1.tif');
Gh = rgb2hsv(G);
Gh(:,:,3) = histeq(Gh(:,:,3));
G = im2uint8(hsv2rgb(Gh));
figure; imshow(G);
Use the rgb2hsv function to convert a colour image into HSV. We then use histogram equalization on the V or Value channel, then convert back from HSV to RGB with hsv2rgb. Note that the output of hsv2rgb will be a double type image and so assuming that the original input image was uint8, use the im2uint8 function to convert from double back to uint8.

Precise adjusting of two colours simultaneously via manipulation with brightness, contrast and gamma

I have a black and white image which has to be rendered on screen as grayscale image of precise colours. Black should be displayed as rgb(40,40,40) and white as rgb(128,128,128).
The problem is the software to render this image does not allow colours to be specified directly; the only parameters I can vary are brightness, contrast and gamma (converting image to the desired colours is not an option).
Is there any formulae to calculate specific values for those parameters to adjust colours as desribed?
Without knowing how they compute brightness and contrast, it is hard to tell you how to do your computation.
Perhaps I still misunderstand. But you can find the min and max values in your image using Imagemagick
convert image -format %[fx:255*minima] info:
convert image -format %[fx:255*maxima] info:
Those will be in the range of 0 to 255.
As Mark showed above the transformation is linear. So it obeys the equation
Y = a*X + b
where a is a measure of contrast and b is a measure of brightness; X is your input value and Y is your desired output value.
Thus
Ymax = a*Xmax + b
and
Ymin = a*Xmin + b
Subtracting and solving for a, we get
a = (Ymax-Ymin)/(Xmax-Xmin)
and substituting that into the equation for Ymax and saving for b, we get
b = Ymax - a*Xmax = Ymax - ( (Ymax-Ymin)/(Xmax-Xmin) )*Xmax
Then you can use the Imagemagick function -function polynomial to process your image.
In unix, I would do it as follows
Xmin=$(convert image -format %[fx:255*minima] info:)
Xmax=$(convert image -format %[fx:255*maxima] info:)
If your image is pure black and pure white, then you can skip the above and just use
Xmin=0
Xmax=255
And your desired values are
Ymin=40
Ymax=128
These are now variables and I can use -fx to do the calculations for a and b
a = $(convert xc: -format "%[fx:($Ymax-$Ymin)/($Xmax-$Xmin)]" info:)
b = $(convert xc: -format "%[fx:$Ymax - $a*$Xmax]" info:)
And to convert your image,
convert image -function polynomial "$a,$b" result image
In general, there are several ways to alter an image's contrast, gamma and brightness and it is difficult to know which method your chosen tool uses, and therefore provide the correct answer.
What you are trying to do is move the blue line (no contrast or brightness changes) in the image below to where the red line (decreased contrast) is:
In general, decreasing the contrast will rotate the blue line clockwise whereas increasing it will rotate it anti-clockwise. In general, increasing the brightness will shift the blue line to the right whereas decreasing the brightness will shift it left. Changing the gamma will likely make the line into a curve.
Can you use ImageMagick at the commandline instead?
convert input.png +level 15.69%,50.2% -depth 8 result.png
If you have v7+, use magick in place of convert.
I made a little gradient for you with:
convert -size 60x255 gradient: -rotate 90 gradient.png
And if you apply the suggested command:
convert gradient.png +level 15.69%,50.2% -depth 8 result.png
You will get this:
And you can check the statistics (min and max) with:
identify -verbose result.png | more
Image: result.png
Format: PNG (Portable Network Graphics)
Mime type: image/png
Class: PseudoClass
Geometry: 255x60+0+0
Units: Undefined
Type: Grayscale
Base type: Palette
Endianess: Undefined
Colorspace: Gray
Depth: 8-bit
Channel depth:
Gray: 8-bit
Channel statistics:
Pixels: 15300
Gray:
min: 40 (0.156863) <--- MIN looks good
max: 128 (0.501961) <--- MAX looks good
mean: 84.0078 (0.329443)
standard deviation: 25.5119 (0.100047)
kurtosis: -1.19879
skewness: 0.000197702

Calculate source RGBA given two samples composited over black and white backgrounds

Explanation
I have a semi-transparent color of unknown value.
I have a sample of this unknown color composited over a black background and another sample over a white background.
How do I find the RGBA value of the unknown color?
Example
Note: RGB values of composites are calculated using formulas from the Wikipedia article on alpha compositing
Composite over black:
rgb(103.5, 32.5, 169.5)
Composite over white:
rgb(167.25, 96, 233.25)
Calculated value of unknown color will be:
rgba(138, 43, 226, 0.75)
What I've Read
Manually alpha blending an RGBA pixel with an RGB pixel
Calculate source RGBA value from overlay
It took some experimentation, but I think I figured it out.
Subtracting any of the color component values between the black and white composite should give you the inverse of the original color's alpha value, eg:
A_original = 1 - ((R_white_composite - R_black_composite) / 255) // in %, 0.0 to 1.0
It should yield the same value whether you use the R, G, or B component. Now that you have the original alpha, finding the new components is as easy as:
R_original = R_black_composite / A_original
G_original = G_black_composite / A_original
B_original = B_black_composite / A_original

Pixelate a portion of an image to hide information

I my application users are able to upload photos. Sometime, I want them to hide some information of the picture, for instance the registration plate of a vehicle, or the personal address of an invoice.
To meet that need I plan to pixelate a portion of the image. How can I pixelate an image in such a way given the coordinates of the area to hide and the size of the area.
I found out how to pixelate (by scaling the image down and up) but how can I only target an area of the image?
The area is specified by two pairs of coordinates (x1, y1, x2, y2), or a pair of coordinates and dimensions (x, y, width, height).
I am at work at the moment so can not test any code. I would see if you could work with -region or else use a mask.
Copy the image and pixelate the whole image create a mask of the area required, cut a hole in the original image with the mask and overlay it over the pixelated image.
You could modify this code ( quite old and could probably be improved on ):
// Get the image size to creat the mask
// This can be done within Imagemagick but as we are using php this is simple.
$size = getimagesize("$input14");
// Create a mask with a round hole
$cmd = " -size {$size[0]}x{$size[1]} xc:none -fill black ".
" -draw \"circle 120,220 120,140\" ";
exec("convert $cmd mask.png");
// Cut out the hole in the top image
$cmd = " -compose Dst_Out mask.png -gravity south $input14 -matte ";
exec("composite $cmd result_dst_out1.png");
// Composite the top image over the bottom image
$cmd = " $input20 result_dst_out1.png -geometry +60-20 -composite ";
exec("convert $cmd output_temp.jpg");
// Crop excess from the image where the bottom image is larger than the top
$cmd = " output_temp.jpg -crop 400x280+60+0 ";
exec("convert $cmd composite_sunflower_hard.jpg ");
// Delete tempory images
unlink("mask.png");
unlink("result_dst_out1.png");
unlink("output_temp.jpg");
Thanks for your answer, Bonzo.
I found a way to achieve what I want with ImageMagick convert command. It's a 3-steps process:
I create a pixelated version of the whole source image.
I then build a mask using the original image (to keep the same size) filled with black (with gamma 0) then I draw blank rectangle where I want unreadable areas.
Then I merge the three images (original, pixelated and mask) in a composite operation.
Here is an example with 2 areas (a et b) pixelated.
convert original.png -scale 10% -scale 1000% pixelated.png
convert original.png -gamma 0 -fill white -draw "rectangle X1a, Y1a, X2a, Y2a" -draw "rectangle X1b, Y1b, X2b, Y2b" mask.png
convert original.png pixelated.png mask.png -composite result.png
It works like a charm. Now I will do it with RMagick.

Resources