使用Matlab实现图像直方图 [英] Image histogram implementation with Matlab
问题描述
我正在实施(我知道有一个实现它的自定义功能)Matlab中的灰度图像直方图,到目前为止我已经尝试过:
I'm tyring to implement (I know there's a custom function for achieving it) the grayscale image histogram in Matlab, so far I've tried:
function h = histogram_matlab(imageSource)
openImage = rgb2gray(imread(imageSource));
[rows,cols] = size(openImage);
histogram_values = [0:255];
for i = 1:rows
for j = 1:cols
p = openImage(i,j);
histogram_values(p) = histogram_values(p) + 1;
end
end
histogram(histogram_values)
但是当我调用该函数时,例如: histogram_matlab('Harris.png')
However when I call the function, for example: histogram_matlab('Harris.png')
我获得了一些图如:
这显然不是我的预期,x轴应该从0到255,y轴从0到任何最大值都存储在 histogram_values
。
which is obviously not what I expect, x axis should go from 0 to 255 and y axis from 0 to whatever max value is stored in histogram_values
.
我需要获得类似什么 imhist
优惠:
I need to obtain something like what imhist
offers:
我该如何设置?我执行得不好吗?
How should I set it up? Am I doing a bad implementation?
我已将代码更改为改进和更正建议@rayryeng:
I've changed my code to improvements and corrections suggested by @rayryeng:
function h = histogram_matlab(imageSource)
openImage = rgb2gray(imread(imageSource));
[rows,cols] = size(openImage);
histogram_values = zeros(256,1)
for i = 1:rows
for j = 1:cols
p = double(openImage(i,j)) +1;
histogram_values(p) = histogram_values(p) + 1;
end
end
histogram(histogram_values, 0:255)
然而直方图不是预期的:
However the histogram plot is not that expected:
这里很明显,y轴上存在一些问题或错误,因为它肯定会超过2个。
Here it's noticeable that there's some issue or error on y axis as it definitely would reach MORE than 2.
推荐答案
在计算直方图方面,虽然存在轻微误差,但每个强度的频率计算是正确的......稍后会详细说明。另外,我个人会避免在这里使用循环。请参阅本文末尾的小注释。
In terms of calculating the histogram, the computation of the frequency per intensity is correct though there is a slight error... more on that later. Also, I would personally avoid using loops here. See my small note at the end of this post.
然而,您的代码存在三个问题:
Nevertheless, there are three problems with your code:
histogram_values
应该包含你的直方图,但你正在初始化直方图通过 0:255
的向量。每个强度值应以0 开始,因此您实际需要这样做:
histogram_values
should contain your histogram, yet you are initializing the histogram by a vector of 0:255
. Each intensity value should start with a count of 0, and so you actually need to do this:
histogram_values = zeros(256,1);
问题#2 - 中的轻微错误
循环
您的强度范围从0到255,但MATLAB开始索引为1.如果您的强度为0,则会出现超出范围的错误。因此,正确的做法是采用 p
并将其添加为1,以便开始索引为1.但是,我需要指出的一个复杂性是,如果你有一个 uint8
精度图像,加上1强度为255只会将值饱和到255.它不会达到256 ....所以它也是谨慎的您投射到 double
之类的东西,以确保达到256。
Problem #2 - Slight error in for
loop
Your intensities range from 0 to 255, yet MATLAB starts indexing at 1. If you ever get intensities that are 0, you will get an out-of-bounds error. As such, the proper thing to do is to take p
and add it with 1 so that you start indexing at 1. However, one intricacy I need to point out is that if you have a uint8
precision image, adding 1 to an intensity of 255 will simply saturate the value to 255. It won't go to 256.... so it's also prudent that you cast to something like double
to ensure that 256 will be reached.
因此:
histogram_values = zeros(256,1);
for i = 1:rows
for j = 1:cols
p = double(openImage(i,j)) + 1;
histogram_values(p) = histogram_values(p) + 1;
end
end
问题#3 - 不致电 histogram
right
你应该覆盖 histogram
的行为,包括边缘。基本上,这样做:
Problem #3 - Not calling histogram
right
You should override the behaviour of histogram
and include the edges. Basically, do this:
histogram(histogram_values, 0:255);
第二个向量指定我们应该在 x $上放置小节的位置c $ c> -axis。
The second vector specifies where we should place bars on the x
-axis.
你可以自己完全实现直方图计算而不需要任何 for
循环。您可以结合使用 bsxfun
, permute
, reshape
和两个 总和
来电:
You can totally implement the histogram computation yourself without any for
loops. You can try this with a combination of bsxfun
, permute
, reshape
and two sum
calls:
mat = bsxfun(@eq, permute(0:255, [1 3 2]), im);
h = reshape(sum(sum(mat, 2), 1), 256, 1);
如果你想要更多有关此代码如何工作的详细解释,请参阅kkuilla和我之间的对话: http://chat.stackoverflow.com/rooms/81987/conversation/explanation-of-computing-an-images-histogram-vectorized
然而,它的要点如下。
第一行代码创建一个3D向量的1列,范围从0到255 置换
,然后使用 bsxfun
与 eq
(等于)函数,我们使用广播,以便我们得到一个3D矩阵,其中每个切片与灰度图像的大小相同,并为我们提供等于感兴趣强度的位置。具体来说,第一个切片告诉你元素在哪里等于0,第二个切片告诉你哪个元素等于1直到最后一个切片,它告诉你元素等于255的位置。
The first line of code creates a 3D vector of 1 column that ranges from 0 to 255 by permute
, and then using bsxfun
with the eq
(equals) function, we use broadcasting so that we get a 3D matrix where each slice is the same size as the grayscale image and gives us locations that are equal to an intensity of interest. Specifically, the first slice tells you where elements are equal to 0, the second slice tells you where elements are equal to 1 up until the last slice where it tells you where elements are equal to 255.
对于第二行代码,一旦我们计算出这个3D矩阵,我们计算两个总和 - 首先独立地对每一行求和,然后对该中间结果的每一列求和。然后我们得到每个切片的总和,它告诉我们每个强度有多少个值。因此这是一个3D矢量,所以我们重塑
这会重新变成一个1D矢量来完成计算。
For the second line of code, once we compute this 3D matrix, we compute two sums - first summing each row independently, then summing each column of this intermediate result. We then get the total sum per slice which tells us how many values there were for each intensity. This is consequently a 3D vector, and so we reshape
this back into a single 1D vector to finish the computation.
为了显示直方图,我会使用 bar
和 histc
旗帜。如果我们使用 cameraman.tif
图像,这是一个可重现的例子:
In order to display a histogram, I would use bar
with the histc
flag. Here's a reproducible example if we use the cameraman.tif
image:
%// Read in grayscale image
openImage = imread('cameraman.tif');
[rows,cols] = size(openImage);
%// Your code corrected
histogram_values = zeros(256,1);
for i = 1:rows
for j = 1:cols
p = double(openImage(i,j)) + 1;
histogram_values(p) = histogram_values(p) + 1;
end
end
%// Show histogram
bar(0:255, histogram_values, 'histc');
我们得到这个:
这篇关于使用Matlab实现图像直方图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!