use*_*118 1 matlab image-processing histogram
我必须将一个灰度图像导入到matlab中,将它由无符号8位整数组成的像素转换为双精度,绘制直方图,最后使用变换提高图像质量:
v'(x,y) = a(v(x,y)) + b
Run Code Online (Sandbox Code Playgroud)
其中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]);
Run Code Online (Sandbox Code Playgroud)
编辑:我也玩了一些不同的常量值.a改变时的常数似乎是延伸直方图的常数; 但是这仅适用于介于0.8 - 1.2之间的值(并且它不会足够拉伸 - 它仅在150-290的范围内均衡直方图).如果你应用一个a假设0.5,直方图被分成两个blob,有很多像素在4或5个不同的强度; 再次,至少没有平等.
您感兴趣的操作称为线性对比度拉伸.基本上,您希望将每个强度乘以某个增益,然后将强度移动一些数字,以便您可以操纵直方图的动态范围.这是不一样histeq或使用图像的概率密度函数(的前体,直方图均衡)以增强图像.直方图均衡试图使图像直方图变平,使得在图像中遇到的强度或多或少具有等概率.如果您想对该主题进行更权威的解释,请参阅我关于直方图均衡如何工作的答案:
在任何情况下,选择值a和b高度依赖于图像.但是,如果您希望自适应,我可以建议的一件事是使用min-max规范化.基本上,您可以采用直方图并线性映射强度,以便将最低输入强度映射到0,并将最高输入强度映射到图像的关联数据类型的最高值.例如,如果您的图像是uint8,则表示最高值被映射到255.
执行最小/最大标准化非常容易.这只是以下转变:
out(x,y) = max_type*(in(x,y) - min(in)) / (max(in) - min(in));
Run Code Online (Sandbox Code Playgroud)
in并且out是输入和输出图像. min(in)并且max(in)是输入图像的总体最小值和最大值. max_type是输入图像类型的最大值.
对于(x,y)输入图像的每个位置,您可以替换输入图像强度并运行上面的等式来获得输出.你可以说服自己代替min(in)和max(in)for in(x,y)将max_type分别给你0和其他一切在两者之间线性缩放.
现在,通过一些代数操作,您可以将其设置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
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
....这不简单吗?
现在,修改你的代码,以便新的常量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,[]);
Run Code Online (Sandbox Code Playgroud)
这是非常重要的,你投来的最大整数double因为什么被返回的不仅是整数,但整数投来的数据类型.我也冒昧地改变你的代码,这样我们就可以在转换前后显示直方图,以及转换前后图像的样子.
作为看到这项工作的一个例子,让我们使用pout.tif图像处理工具箱的图像.它看起来像这样:
你可以肯定地看到,这需要一些图像对比度增强操作,因为强度的动态范围非常有限.这看起来有些褪色.
使用它作为图像,这是直方图之前和之后的样子.
我们当然可以看到直方图被拉伸.现在这就是图像的样子:
你可以肯定看到更多的细节,即使它更黑暗.这告诉您简单的线性缩放是不够的.您可能希望实际使用直方图均衡,或使用伽马定律或幂律变换.
希望这足以让你开始.祝好运!