简体   繁体   English

Matlab图像处理-使用直方图提高对比度

[英]Matlab Image Processing - increasing contrast using histogram

I have to import a greyscale image into matlab, convert the pixels it is composed off from unsigned 8 bit ints into doubles, plot a histogram, and finally improve the image quality using the transformation: 我必须将灰度图像导入到matlab中,将由无符号的8位整数组成的像素转换为双精度,绘制直方图,最后使用以下转换来改善图像质量:

v'(x,y) = a(v(x,y)) + b 

where v(x,y) is the value of the pixel at point x,y and v'(x,y) is the new value of the pixel. 其中v(x,y)是点x,y处像素的值x,yv'(x,y)是像素的新值。

My primary issue is the value of the two constants, a and b that we have to choose for the transformation. 我的主要问题是转换时必须选择的两个常数ab的值。 My understanding is that an equalized histogram is desirable for a good image. 我的理解是,均衡的直方图对于获得良好的图像是理想的。 Other code found on the Internet deals either with using the built-in MATLAB histeq function or calculating probability densities. 互联网上找到的其他代码都使用内置的MATLAB histeq函数或计算概率密度。 I've found no reference anywhere to choosing constants for the transformation given above. 我在任何地方都找不到为上述转换选择常量的参考。

I'm wondering if anyone has any tips or ideas on how to go about choosing these constants. 我想知道是否有人对如何选择这些常量有任何建议或想法。 I think the rest of my code does what it's supposed to: 我认为我的其余代码可以实现预期的功能:

 image = imread('image.png');
 image_of_doubles = double(image);

 for i=1:1024
     for j=1:806
            pixel = image_of_doubles(i,j);
            pixel = 0.95*pixel + 5;
            image_of_doubles(i,j) = pixel;
    end
end

[n_elements,centers] = hist(image_of_doubles(:),20);
bar(centers,n_elements);

xlim([0 255]);

Edit: I also played a bit with different values of constants. 编辑:我也玩了一些不同的常量值。 The a constant when changed seems to be the one that stretches the histogram; 改变时a常数似乎是拉伸直方图a常数。 however this only works for a values that are between 0.8 - 1.2 (and it doesn't stretch it enough - it equalizes the histogram only on the range 150 - 290). 但是,这仅适用于介于0.8-1.2之间的值(并且拉伸范围不足-仅在150-290范围内使直方图相等)。 If you apply an a of let's say 0.5, the histogram is split into two blobs, with a lot of pixels at about 4 or 5 different intensities; 如果将a设为0.5,则直方图将被分为两个斑点,其中许多像素的强度大约为4或5; again, not equalized in the least. 同样,至少没有相等。

The operation that you are interested in is known as linear contrast stretching . 您感兴趣的操作称为线性对比度拉伸 Basically, you want to multiply each of the intensities by some gain and then shift the intensities by some number so you can manipulate the dynamic range of the histogram. 基本上,您希望将每个强度乘以某个增益,然后将强度偏移某个数字,以便可以操纵直方图的动态范围。 This is not the same as histeq or using the probability density function of the image (a precursor to histogram equalization) to enhance the image. 这是一样的histeq或使用图像的概率密度函数(的前体,直方图均衡)以增强图像。 Histogram equalization seeks to flatten the image histogram so that the intensities are more or less equiprobable in being encountered in the image. 直方图均衡化试图使图像直方图平坦化,以使强度在图像中遇到时或多或少是等概率的。 If you'd like a more authoritative explanation on the topic, please see my answer on how histogram equalization works: 如果您希望对此主题进行更权威的解释,请参见我有关直方图均衡化工作原理的回答:

Explanation of the Histogram Equalization function in MATLAB MATLAB中直方图均衡功能的说明


In any case, choosing the values of a and b is highly image dependent. 无论如何,选择ab的值在很大程度上取决于图像。 However, one thing I can suggest if you want this to be adaptive is to use min-max normalization . 但是,我想建议的一件事是使用min-max规范化 Basically, you take your histogram and linearly map the intensities so that the lowest input intensity gets mapped to 0, and the highest input intensity gets mapped to the highest value of the associated data type for the image. 基本上,您可以使用直方图并线性映射强度,以便将最低输入强度映射到0,将最高输入强度映射到图像的关联数据类型的最大值。 For example, if your image was uint8 , this means that the highest value gets mapped to 255. 例如,如果您的图像是uint8 ,则意味着最高值将映射到255。

Performing min/max normalization is very easy. 执行最小/最大归一化非常容易。 It is simply the following transformation: 它只是以下转换:

out(x,y) = max_type*(in(x,y) - min(in)) / (max(in) - min(in));

in and out are the input and output images. inout是输入和输出图像。 min(in) and max(in) are the overall minimum and maximum of the input image. min(in)max(in)是输入图像的整体最小值和最大值。 max_type is the maximum value associated for the input image type. max_type是与输入图像类型关联的最大值。

For each location (x,y) of the input image, you substitute an input image intensity and run through the above equation to get your output. 对于输入图像的每个位置(x,y) ,您都可以替换输入图像的强度,并通过上面的公式进行运算以获得输出。 You can convince yourself that substituting min(in) and max(in) for in(x,y) will give you 0 and max_type respectively, and everything else is linearly scaled in between. 您可以说服自己,用min(in)max(in)代替in(x,y)会分别给您0和max_type ,其他所有参数都在此之间线性缩放。

Now, with some algebraic manipulation, you can get this to be of the form out(x,y) = a*in(x,y) + b as mentioned in your problem statement. 现在,通过一些代数运算,您可以使它的形式为问题陈述中提到的out(x,y) = a*in(x,y) + b Concretely: 具体来说:

out(x,y) = max_type*(in(x,y) - min(in)) / (max(in) - min(in));
out(x,y) = (max_type*in(x,y)/(max(in) - min(in)) - (max_type*min(in)) / (max(in) - min(in)) // Distributing max_type in the summation
out(x,y) = (max_type/(max(in) - min(in)))*in(x,y) - (max_type*min(in))/(max(in) - min(in)) // Re-arranging first term

out(x,y) = a*in(x,y) + b

a is simply (max_type/(max(in) - min(in)) and b is -(max_type*min(in))/(max(in) - min(in)) . a简单地是(max_type/(max(in) - min(in))b-(max_type*min(in))/(max(in) - min(in))

You would make these a and b and run through your code. 您将使它们ab并运行您的代码。 BTW, if I may suggest something, please consider vectorizing your code. 顺便说一句,如果我有什么建议,请考虑向量化您的代码。 You can very easily use the equation and operate on the entire image data at once, rather than looping over each value in the image. 您可以非常容易地使用该方程式并立即对整个图像数据进行运算,而不用遍历图像中的每个值。

Simply put, your code would now look like this: 简而言之,您的代码现在如下所示:

image = imread('image.png');
image_of_doubles = 0.95*double(image) + 5; %// New

[n_elements,centers] = hist(image_of_doubles(:),20);
bar(centers,n_elements);

.... isn't it much simpler? ....不是更简单吗?

Now, modify your code so that the new constants a and b are calculated in the way we discussed: 现在,修改您的代码,以便以我们讨论的方式计算新常数ab

image = imread('image.png');

%// New - get maximum value for image type
max_type = double(intmax(class(image)));

%// Calculate a and b
min_val = double(min(image(:)));
max_val = double(max(image(:)));
a = max_type / (max_val - min_val);
b = -(max_type*min_val) / (max_val - min_val);

%// Compute transformation
image_of_doubles = a*double(image) + b;

%// Plot the histogram - before and after
figure;
subplot(2,1,1);
[n_elements1,centers1] = hist(double(image(:)),20);
bar(centers1,n_elements1);
%// Change
xlim([0 max_type]);

subplot(2,1,2);
[n_elements2,centers2] = hist(image_of_doubles(:),20);
bar(centers2,n_elements2);
%// Change
xlim([0 max_type]);

%// New - show both images
figure; subplot(1,2,1);
imshow(image);
subplot(1,2,2);
imshow(image_of_doubles,[]);

It's very important that you cast the maximum integer to double because what is returned is not only the integer, but the integer cast to that data type. 这是非常重要的,你投的最大整数double ,因为什么被返回的不仅是整数,但整数转换为数据类型。 I've also taken the liberty to change your code so that we can display the histogram before and after the transformation, as well as what the image looks like before and after you transform it. 我还自由更改了代码,以便我们可以在转换之前和之后显示直方图,以及在转换之前和之后图像的外观。


As an example of seeing this work, let's use the pout.tif image that's part of the image processing toolbox. 作为查看这项工作的示例,让我们使用图像处理工具箱中的pout.tif图像。 It looks like this: 看起来像这样:

在此处输入图片说明

You can definitely see that this requires some image contrast enhancement operation because the dynamic range of intensities is quite limited. 可以肯定地看到,这需要一些图像对比度增强操作,因为强度的动态范围非常有限。 This had the appearance of looking washed out. 这看起来像洗掉了。

Using this as the image, this is what the histogram looks like before and after. 使用此图像作为图像,这就是直方图之前和之后的样子。

在此处输入图片说明

We can certainly see the histogram being stretched. 我们当然可以看到直方图被拉伸了。 Now this is what the images look like: 现在这是图像的样子:

在此处输入图片说明

You can definitely see more detail, even though it's more dark. 您肯定可以看到更多细节,即使它更暗。 This tells you that a simple linear scaling isn't enough. 这告诉您,简单的线性缩放是不够的。 You may want to actually use histogram equalization, or use a gamma-law or power law transformation. 您可能需要实际使用直方图均衡,或者使用伽玛定律或幂定律变换。


Hopefully this will be enough to get you started though. 希望这足以使您入门。 Good luck! 祝好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM