People say that seeing is believing. As humans, we are used to trusting our senses. However, our perception is not perfect; for example, upon exposure to pain, it takes an intensity change of more than 6% before we notice any change. (I have to find a proper source for this; it just stuck in my mind while sleep-listening to RadioLab.) In the ranges of greatest sensitivity, small changes in intensity are noticeable, but when we get far away from that range, large changes go unnoticed. It's like comparing a bite of food when you're famished to a bite in the middle of a long meal.
Most modern electronics have a wider range of sensitivity than we do. They allow us to observe differences that are not registered by our senses. Image enhancement by histogram manipulation simply magnifies the differences so as to be detectable by humans.
What's a histogram again? A histogram is simply a frequency distribution of color intensities in an image. For a grayscale image, the x-axis ranges from black to shades of gray to white (0 to 1 OR 0 to 255), while a truecolor image will have three histograms: intensities of red, green, and blue. On a side note, that's how a digital camera decides the correct exposure: its ideal exposure occurs when the histogram is centrally balanced and not truncated at the sides. I'll add examples here when I have some free time.
Foraging for underexposed images in Flickr, I found a dark picture with only a few discernible details: a tree branch, some shrubs, and a pool ladder.
Nulkku's "The Darkness" (accessible here) |
We open it in Scilab by typing:
Img = gray_imread('image3.jpg');A histogram with 256 bins can be called by typing histplot(256, Img), but we need the values of the histogram if we're going to fix it manually. To get an array of values and frequency of value occurrence,
imsize = size(Img); //gets the dimensions of the image
[freqs, val] = imhist(Img, 256);Displaying the histogram gives us the following picture.
Histogram of original image |
First, we were instructed to see what happens if we try to make the histogram approximate a uniform distribution. We take its cumulative distribution function to be able to remap it.
CDF = cumsum(freqs)/sum(freqs); //normalized CDF of image histogramThe instructions were to get the value of each pixel, (say 0.3 gray) look at where it falls in the corresponding CDF (i.e. 40%), trace the value (40%) to the desired CDF and exchange the original pixel value with the obtained color value in the new CDF. However, that involves a lot of finds and indexing, so I decided to map it instead. I figured out the replacement value for all possible values in the original image and saved the pairs in an array.
CDFline = cumsum(zeros(256,1)+1./256); //linear CDF
trans = [];I'm sure there's a more efficient way, but I'm still feeling my way with Scilab. Any advice would be always welcome. :)
for i = 1:256
new = val(max(find(CDF(i)>=CDFline)))
if new then
trans = [trans,new];
else
trans = [trans,0];
end
end
Replacing the values only needs one line:
newImg = trans(Img*255+1);Getting the new histogram is a bit disappointing.
Remapped to a linear CDF |
It's obvious that the new image will be blocky and pixelized. However, that's to be expected as only colour values with frequency greater than 1 can be remapped. We have not added any code that integrates the surrounding colors to smoothen the remapping.
Looking at the new image,
Enhanced image |
For the second part, we make a Gaussian histogram
gauss = exp(-0.0005*(128-(1:256))^2);and set its CDF, shown in the next figure, as the desired CDF.
CDF of a Gaussian distribution |
Histogram of enhanced image #2 |
Enhanced image using a Gaussian CDF |
I would give myself a grade of 10 for being able to complete the activities detailed in the histogram manipulation manual.
No comments:
Post a Comment