Matlab 图像处理 - 使用直方图增加对比度
Matlab Image Processing - increasing contrast using histogram
我必须将灰度图像导入 matlab,将它由无符号 8 位整数组成的像素转换为双精度数,绘制直方图,最后使用变换提高图像质量:
v'(x,y) = a(v(x,y)) + b
其中v(x,y)
是点x,y
处的像素值,v'(x,y)
是像素的新值。
我的主要问题是我们必须为转换选择的两个常量 a
和 b
的值。我的理解是均衡的直方图对于良好的图像是可取的。在 Internet 上找到的其他代码涉及使用内置 MATLAB histeq
函数或计算概率密度。我在任何地方都找不到为上面给出的转换选择常量的参考。
我想知道是否有人对如何选择这些常量有任何提示或想法。我认为我的其余代码都在做它应该做的事情:
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]);
编辑:我还尝试了一些不同的常量值。更改后的 a
常量似乎是拉伸直方图的常量;然而,这仅适用于 0.8 - 1.2 之间的值(并且它没有足够拉伸 - 它仅在 150 - 290 范围内均衡直方图)。如果你应用一个 a
比方说 0.5,直方图被分成两个斑点,有很多像素大约有 4 或 5 个不同的强度;再次,至少没有均衡。
您感兴趣的操作称为线性对比度拉伸。基本上,您希望将每个强度乘以某个增益,然后将强度移动某个数字,以便您可以操纵直方图的动态范围。这和不一样histeq
还是利用图像的概率密度函数(直方图均衡化的前身)来增强图像。直方图均衡化旨在使图像直方图变平,以便在图像中遇到的强度或多或少是等概率的。如果您想对该主题进行更权威的解释,请参阅我关于直方图均衡化工作原理的回答:
Explanation of the Histogram Equalization function in MATLAB
在任何情况下,选择 a
和 b
的值都高度依赖于图像。但是,如果您希望它具有自适应性,我可以建议的一件事是使用 min-max 规范化 。基本上,您获取直方图并线性映射强度,以便将最低输入强度映射到 0,并将最高输入强度映射到图像相关数据类型的最大值。例如,如果您的图像是 uint8
,这意味着最高值映射到 255。
执行min/max 规范化非常容易。简单来说就是下面的变换:
out(x,y) = max_type*(in(x,y) - min(in)) / (max(in) - min(in));
in
和 out
是输入和输出图像。 min(in)
和 max(in)
是输入图像的 整体 最小值和最大值。 max_type
是与输入图像类型关联的最大值。
对于输入图像的每个位置 (x,y)
,您可以通过上述等式替换输入图像强度和 运行 以获得输出。您可以说服自己用 min(in)
和 max(in)
代替 in(x,y)
将分别得到 0 和 max_type
,其他所有内容都在两者之间线性缩放。
现在,通过一些代数运算,您可以将其变为问题陈述中提到的 out(x,y) = a*in(x,y) + b
形式。具体来说:
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
就是 (max_type/(max(in) - min(in))
而 b
就是 -(max_type*min(in))/(max(in) - min(in))
.
您可以通过您的代码生成这些 a
和 b
以及 运行。顺便说一句,如果我可以提出建议,请考虑对您的代码进行矢量化。您可以非常轻松地使用方程式并一次对整个图像数据进行运算,而不是循环遍历图像中的每个值。
简而言之,您的代码现在将如下所示:
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);
.....是不是简单多了?
现在,修改您的代码,以便按照我们讨论的方式计算新常量 a
和 b
:
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,[]);
将最大整数转换为 double
非常 很重要,因为返回的不仅是整数,而且是整数 cast 到该数据类型。我还冒昧地更改了您的代码,以便我们可以显示转换前后的直方图,以及转换前后图像的外观。
作为查看此作品的示例,让我们使用图像处理工具箱中的 pout.tif
图像。它看起来像这样:
你可以肯定地看到这需要一些图像对比度增强操作,因为强度的动态范围非常有限。
这看起来像是褪色了。
以此为图像,前后直方图是这样的。
我们当然可以看到直方图被拉伸了。现在这就是图像的样子:
你绝对可以看到更多细节,即使它更暗。这告诉您简单的线性缩放是不够的。您可能想实际使用直方图均衡化,或使用 gamma-law 或幂律变换。
希望这足以让您入门。祝你好运!
我必须将灰度图像导入 matlab,将它由无符号 8 位整数组成的像素转换为双精度数,绘制直方图,最后使用变换提高图像质量:
v'(x,y) = a(v(x,y)) + b
其中v(x,y)
是点x,y
处的像素值,v'(x,y)
是像素的新值。
我的主要问题是我们必须为转换选择的两个常量 a
和 b
的值。我的理解是均衡的直方图对于良好的图像是可取的。在 Internet 上找到的其他代码涉及使用内置 MATLAB histeq
函数或计算概率密度。我在任何地方都找不到为上面给出的转换选择常量的参考。
我想知道是否有人对如何选择这些常量有任何提示或想法。我认为我的其余代码都在做它应该做的事情:
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]);
编辑:我还尝试了一些不同的常量值。更改后的 a
常量似乎是拉伸直方图的常量;然而,这仅适用于 0.8 - 1.2 之间的值(并且它没有足够拉伸 - 它仅在 150 - 290 范围内均衡直方图)。如果你应用一个 a
比方说 0.5,直方图被分成两个斑点,有很多像素大约有 4 或 5 个不同的强度;再次,至少没有均衡。
您感兴趣的操作称为线性对比度拉伸。基本上,您希望将每个强度乘以某个增益,然后将强度移动某个数字,以便您可以操纵直方图的动态范围。这和不一样histeq
还是利用图像的概率密度函数(直方图均衡化的前身)来增强图像。直方图均衡化旨在使图像直方图变平,以便在图像中遇到的强度或多或少是等概率的。如果您想对该主题进行更权威的解释,请参阅我关于直方图均衡化工作原理的回答:
Explanation of the Histogram Equalization function in MATLAB
在任何情况下,选择 a
和 b
的值都高度依赖于图像。但是,如果您希望它具有自适应性,我可以建议的一件事是使用 min-max 规范化 。基本上,您获取直方图并线性映射强度,以便将最低输入强度映射到 0,并将最高输入强度映射到图像相关数据类型的最大值。例如,如果您的图像是 uint8
,这意味着最高值映射到 255。
执行min/max 规范化非常容易。简单来说就是下面的变换:
out(x,y) = max_type*(in(x,y) - min(in)) / (max(in) - min(in));
in
和 out
是输入和输出图像。 min(in)
和 max(in)
是输入图像的 整体 最小值和最大值。 max_type
是与输入图像类型关联的最大值。
对于输入图像的每个位置 (x,y)
,您可以通过上述等式替换输入图像强度和 运行 以获得输出。您可以说服自己用 min(in)
和 max(in)
代替 in(x,y)
将分别得到 0 和 max_type
,其他所有内容都在两者之间线性缩放。
现在,通过一些代数运算,您可以将其变为问题陈述中提到的 out(x,y) = a*in(x,y) + b
形式。具体来说:
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
就是 (max_type/(max(in) - min(in))
而 b
就是 -(max_type*min(in))/(max(in) - min(in))
.
您可以通过您的代码生成这些 a
和 b
以及 运行。顺便说一句,如果我可以提出建议,请考虑对您的代码进行矢量化。您可以非常轻松地使用方程式并一次对整个图像数据进行运算,而不是循环遍历图像中的每个值。
简而言之,您的代码现在将如下所示:
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);
.....是不是简单多了?
现在,修改您的代码,以便按照我们讨论的方式计算新常量 a
和 b
:
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,[]);
将最大整数转换为 double
非常 很重要,因为返回的不仅是整数,而且是整数 cast 到该数据类型。我还冒昧地更改了您的代码,以便我们可以显示转换前后的直方图,以及转换前后图像的外观。
作为查看此作品的示例,让我们使用图像处理工具箱中的 pout.tif
图像。它看起来像这样:
你可以肯定地看到这需要一些图像对比度增强操作,因为强度的动态范围非常有限。 这看起来像是褪色了。
以此为图像,前后直方图是这样的。
我们当然可以看到直方图被拉伸了。现在这就是图像的样子:
你绝对可以看到更多细节,即使它更暗。这告诉您简单的线性缩放是不够的。您可能想实际使用直方图均衡化,或使用 gamma-law 或幂律变换。
希望这足以让您入门。祝你好运!