Generate a value to reflect the average brightness of an image - linux

I need to determine if an image is above a certain brightness.
Using a scale of 0 - 255 I want to generate a value within this range to reflect the image brightness.
i.e. a white image is 255 and a black image is 0.
All this needs to take place via a bash script I am building up at the moment.
I have no idea what image lib could do this for me though.

Generally, it's one of the classic problems of signal processing and there are several approaches, based on how do you define "brightness". It's generally the same for "brightness" of an image, "loudness" of a sound signal, etc.
Some ideas of what you can use as a generic "brightness" is:
Average value of all the pixels (i.e. sum up all the brightnesses of all the pixels, then divide by total amount of pixels, i.e. width * height).
Build up a histogram of brightness distribution, then choose such point x in that histogram that 98% (95%, 90%, 70% - this number can vary) of all the pixels in your image would be less bright than this x. It's called percentile.
Calculate "root mean square" (RMS) for all the pixels (sum up squares of all the pixels, divide by total amount of pixels, extract square root from this one).
There are multiple image libraries that can yield good results. The easiest one to use from a shell script is probably ImageMagick/GraphicsMagick - you can get both simple averages and do some more complex histogramming to check out percentiles if you want to.

Try ImageMagick gray stats or histogram
convert rose: -colorspace gray -format "%[fx:100*mean]%%" info:

Related

how to crop image, using color borders in image with imagemagick

I was wondering how someone will go about cropping an image in 8 parts which are not equal
and dimensions are not known (I could try with some, but def not equal size).
Example: http://i.imgur.com/YG92jJH.jpg
By using the white space between the grey boxes.
Essentially to turn in e.g. (top right corner of original): http://i.imgur.com/swKDTnn.jpg
You should starting by playing with the switches of multicrop's imagemagick script.
$ bash multicrop
multicrop:
Revised by Anthony Thyssen to add -b option ... revised 8/24/2010
Developed by Fred Weinhaus 1/30/2010 .......... revised 7/7/2010
USAGE: multicrop [-c coords] [-b bcolor] [-f fuzzval] [-g grid] [-u unrotate] [-m mask] infile outfile
USAGE: multicrop [-h or -help]
OPTIONS:
-c coords pixel coordinate to extract background color;
may be expressed as gravity value (NorthWest, etc)
or as "x,y" value; default is NorthWest=(0,0)
-b bcolor background color to use instead of option -c;
any valid IM color; default is to use option -c
-f fuzzval fuzz value for separating background color;
expressed as (integer) percent 0 to 100;
default=0 (uniform color)
-g grid grid spacing in both x and y as percent of
image width and height; used to locate images;
integer>0; default=10;
-u unrotate unrotate method; choices are 1 for -deskew,
2 for unrotate script and 3 for no unrotate;
default=1
-m mask mask presentation method; choices are view,
save (to file) or output mask only; default
is none of the above, just output the images
NAME: MULTICROP
PURPOSE: To crop and unrotate multiple images from a scanned image.
DESCRIPTION: MULTICROP crops and unrotates multiple images from a scanned image.
The images must be well separated so that background color shows between them.
The process uses a floofill technique based upon a seed coordinate and a fuzz
value to separate the individual images from the background of the scan.
The correct choice of fuzz factor is very important. If too small, the images
will not be separate. If too larger, parts of the outer area of the image
containing similar colors will be lost and the image may be separated into
multiple parts. There are two unrotate methods. The first uses the IM deskew
function, but is limited to 5 degrees of rotate or less. The second uses my
unrotate script. It allows much larger rotations, but will be slower. If
using the second method, my unrotate script must be downloaded and installed.
IMPORTANT: The images in the scanned file must be well separated in x and y
so that their bounding boxes do not overlap. This is especially important
if the images have a significant rotation.
The output images will be named from the specified outfile and -0, -1,
etc, will be appended before the .suffix.
Arguments:
-c coords ... COORDS is any location within the background (non-image) area
for the algorithm to find the background color. It may be specified in terms
of gravity parameters (NorthWest, North, NorthEast, East, SouthEast, South,
SouthWest or West) or as a pixel coordinate "x,y". The default is the
upper left corner = NorthWest = "0,0".
-b bcolor ... BCOLOR is the background color to use for flood fill instead
of extracting this color from the image. This is useful when an image has
no borders with sub-images hard against the edges. Any valid IM color is
allowed. The default is to use option -c.
-f fuzzval ... FUZZVAL is the fuzz amount specified as an integer percent
value between 0 to 100 (without the % sign). The correct choice of fuzz
factor is very important. If too small, the images will not be separate.
If too larger, parts of the outer area of the image containing similar
colors will be lost and the image may be separated into multiple parts.
Typical values are probably between 5 and 20 percent. The default=10
-g grid ... GRID is the grid spacing for testing points in the input image
to see if they are background or image. The grid value is specified as an
integer percent greater than 0 and less than 100 of the width and height
of the input image. The default=10.
-u unrotate ... UNROTATE is the unrotation method. Choices are: 1, 2 or 3.
The default is unrotate=1, which is fast and uses the IM -deskew function,
but is limited to images that are rotated no more than 5 degrees in the scan.
Option unrotate=2 uses my unrotate script. It can handle larger rotations,
but is slower. If using the latter method, my unrotate script must be
downloaded and also installed so that it is available for this script to use.
Option unrotate=3 makes no attempt to unrotate the images.
-m mask ... MASK provides several options for reviewing the initial mask that
is generated by the fuzz value. The choices are: view (display to X11 window),
save (to disk) along with the images, or output (without processing the images).
The default is to simply process the images without showing or saving the mask.
If using the view mode, then processing will stop until the image is closed.
But this allows you to then kill the script if the mask is not appropriate.
A good approach is to use the output mode repeatedly with various fuzzvals
until a reasonable mask is created. Note that the mask must separate the
images, but the background can "eat" a little into the images so long as no
full edge is lost or the images is split into multiple parts.
NOTE: If using unrotate method 2, then my script, unrotate, is required
as well.
CAVEAT: No guarantee that this script will work on all platforms,
nor that trapping of inconsistent parameters is complete and
foolproof. Use At Your Own Risk.

Alpha Blending to remove seam in an image

I have stitched two images but in the final image there is a visible seam. I am trying to use Alpha blending to remove that seam. I know Alpha blending is applied using the cvAddweight() function, but in this the function parameters are two images,alpha, beta , gamma and desitination . I am taking gamma=0, alpha=0.6, beta=0.4. What will be my two input source images and the destination image as the last part of my code is this->
IplImage* WarpImg = cvCreateImage
(cvSize(T1Img->width*2, T1Img->height*2), T1Img->depth, T1Img- >nChannels);
cvWarpPerspective(T1Img, WarpImg, &mxH);
cvSetImageROI(WarpImg, cvRect(0, 0, T2Img->width, T2Img->height));
cvCopy(T2Img, WarpImg);
cvResetImageROI(WarpImg);
cvNamedWindow("WarpImg Img",1);
cvShowImage("WarpImg Img", WarpImg);
cvSaveImage("save.jpg",WarpImg);
My final Image is
I have to admit, I dont think alpha blending is your answer. The seem is there due to the difference in lighting / exposure. Alpha blending is a way of essentially having one image visible through another by means of weighted averaging the two images colors together. Your right and your left images are backed by black. If you simply alpha blend then you are essentially going to be weighting your images with a black background. The resultant effect will simply be a darkening of both images.
2 potential other methods might be to look at the average color of both images at the seem, and adjust one up or down by 50% of the difference in brightness, and the other opposite by the other 50% (one goes up and the other down and the 50% makes it so that the overall brightness jump by either is only 50% of the difference).
The other might do a more complex image histogram technique where you try to widen or shrink the histogram of one side' image to the other as well as align them, and re-asign your color (in this case grayscale) via the new histograms.
Pyramid/multiband blending should do a good enough job for you scenario. Try enblend: http://enblend.sourceforge.net

Brightness and contrast in color image

Does, anyone know, how I can change brightness and contrast of color image. I know about vtkImageMapToWindowLevel, but after setting level or window of image in this class, the color image becomes grayscale.
Thanks for answers;
By definition, a color image is already color mapped, and you cannot change the brightness/contrast of the image without decomposition and recomposition.
First, define a pair of numbers called brightness and contrast in whatever way you want. Normally, I'd take brightness as the maximum value, and contrast as the ratio between minimum and maximum. Similarly, if you want to use Window/Level semantics, "level" is the minimum scalar value, and window is the difference between maximum and minimum.
Next, you find the scalar range - the minimum and maximum values in your desired output image, using the brightness and contrast. If you're applying brightness/contrast, the scalar range is:
Maximum = brightness
Minimum = Maximum / contrast
Assume a color lookup table (LUT), with a series of colors at different proportional values, say, in the range of 0 to 1. Now, since we know the brightness and contrast, we can setup the LUT with the lower value (range 0) mapping to "minimum" and the upper value (range 1) mapping to "maximum". When this is done, a suitable class, like vtkImageMapToColors can take the single-component input and map it to a 3 or 4 component image.
Now, all this can happen only for a single-component image, as the color LUT classes (vtkScalarsToColors and related classes) are defined only on single-component images.
If you have access to the original one-component image, and you're using vtkImageMapToColors or some similar class, I'd suggest handling it at that stage.
If you don't, there is one way I can think of:
Extract the three channels as three different images using vtkImageExtractComponents (you'll need three instances, each with the original image as input).
Independently scale the 3 channels using vtkImageShiftScale (shift by brightness, scale by contrast)
Combine the channels back using vtkImageAppendComponents
Another possibility is to use vtkImageMagnitude, which will convert the image back to grey-scale (by taking the magnitude of the three channels together), and re-applying the color table using vtkImageMapToColors and any of the vtkScalarsToColors classes as your lookup table.
The first method is better if your image is a real photograph or something similar, where the colors are from some 3-component source, and the second would work better if your input image is already using false colors (say an image from an IR camera, or some procedurally generated fractal that's been image mapped).

A better Greyscale algorithm

I'm trying to create a spectral image with a constant grey-scale value for every row. I've written some fantastically slow code that basically tries 1000 different variation between black and white for a given hue and it finds the one whose grey-scale value most closely approximates the target value, resulting in the following image:
On my laptop screen (HP) there is a very noticeable 'dip' near the blue peak, where blue pixels near the bottom of the image appear much brighter than the neighbouring purple and cyan pixels. On my second screen (Acer, which has far superior colour display) the dip is smaller, but still there.
I use the following function to compute the grey-scale approximation of a colour:
Math.Abs(targetGrey - (0.2989 * R + 0.5870 * G + 0.1140 * B))
when I convert the image to grey-scale using Paint.NET, I get a perfect black to white gradient, so that part of the code at least works.
So, question: Is this purely an artefact of the display qualities of my screens? Or can the above mentioned grey-scale algorithm be improved upon to give a visually more consistent result?
EDIT: The problem seems to be mostly monitor calibration. Not, I repeat not, a problem with the code.
I'm wondering if its more to do with the way our eyes interpret the colors, rather than screen artifacts.
That said... I am using a very-high quality screen (Dell Ultrasharp, IPS) that has incredible color reproduction and I'm not sure what you mean by "dip" in the blue peak. So either I'm just not noticing it, or my screen doesn't show the same picture and it more color-accurate.
The output looks correct given the greyscale conversion you have used (which I believe is the standard one for sRGB colour spaces).
However - there are lots of tradeoffs in colour models and one of these is that you can get results which aren't visually quite what you want. In your case, the fact that there is a very low blue weight means that a greater amount of blue is needed to get any given greyscale value, hence the blue seems to start lower, at least in terms of how the human eye perceives it.
If your objective is to get a visually appealing spectral image, then I'd suggest altering your function to make the R,G,B weights more equal, and see if you like what you get.

Help with the theory behind a pixelate algorithm?

So say I have an image that I want to "pixelate". I want this sharp image represented by a grid of, say, 100 x 100 squares. So if the original photo is 500 px X 500 px, each square is 5 px X 5 px. So each square would have a color corresponding to the 5 px X 5 px group of pixels it swaps in for...
How do I figure out what this one color, which is best representative of the stuff it covers, is? Do I just take the R G and B numbers for each of the 25 pixels and average them? Or is there some obscure other way I should know about? What is conventionally used in "pixelation" functions, say like in photoshop?
If you want to know about the 'theory' of pixelation, read up on resampling (and downsampling in particular). Pixelation algorithms are simply downsampling an image (using some downsampling method) and then upsampling it using nearest-neighbour interpolation. Note that in code these two steps may be fused into one.
For downsampling in general, to downsample by a factor of n the image is first filtered by an appropriate low-pass filter, and then one sample out of every n is taken. An "ideal" filter to use is the sinc filter, but because of issues with implementing it, the Lanczos filter is often used as a close alternative.
However, for almost all purposes when doing pixelization, using a simple box blur should work fine, and is very simple to implement. This is just an average of nearby pixels.
If you don't need to change the output size of the image, then this means you divide the image into blocks (the big resulting pixels) which are k×k pixels, and then replace all the pixels in each block with the average value of the pixels in that block.
when the source and target grids are so evenly divisible and aligned, most algorigthms give similar results. if the grids are fixed, go for simple averages.
in other cases, especially when resizing by a small percentage, the quality difference is quite evident. the simplest enhancement over simple average is weighting each pixel value considering how much of it's contained in the target pixel's area.
for more algorithms, check multivariate interpolation

Resources