簡體   English   中英

使用Matlab實現圖像直方圖

[英]Image histogram implementation with Matlab

我正在試圖實現(我知道有一個實現它的自定義函數)Matlab中的灰度圖像直方圖,到目前為止我已經嘗試過:

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')

我得到一些圖形:

在此輸入圖像描述

這顯然不是我所期望的,x軸應該從0到255,y軸從0到任何最大值都存儲在histogram_values

我需要獲得類似imhist提供的東西:

在此輸入圖像描述

我該如何設置? 我做得不好嗎?

編輯

我已將我的代碼更改為@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)

但直方圖不是預期的:

在此輸入圖像描述

這里很明顯,y軸上存在一些問題或錯誤,因為它肯定會達到2以上。

在計算直方圖方面,雖然存在輕微誤差,但每個強度的頻率計算是正確的......稍后會有更多。 另外,我個人會避免在這里使用循環。 請參閱本文末尾的小記。

然而,您的代碼有三個問題:

問題#1 - 直方圖未正確初始化

histogram_values應包含您的直方圖,但您正在通過0:255的向量初始化直方圖。 每個強度值應以0的計數開始 ,因此您實際需要這樣做:

histogram_values = zeros(256,1);

問題#2 - for循環中的輕微錯誤

您的強度范圍從0到255,但MATLAB開始索引為1.如果您的強度為0,則會出現越界誤差。 因此,正確的做法是獲取p並將其添加為1,以便開始在1開始索引。但是,我需要指出的一個復雜性是,如果你有一個uint8精度圖像,添加1到一個強度為255將簡單地將值飽和到255.它不會達到256 ....所以你也應該謹慎地轉換為double以確保達到256。

因此:

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

您應該覆蓋histogram的行為並包括邊。 基本上,這樣做:

histogram(histogram_values, 0:255);

第二個向量指定我們應該在x軸上放置條形的位置。

小記

您可以自己完全實現直方圖計算,而無需任何for循環。 你可以用組合試試這個bsxfunpermutereshape和兩個sum調用:

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- 圖像直方圖,矢量

但是,它的要點如下。


第一行代碼創建一個1列的3D矢量,范圍從0到255,通過permute ,然后使用帶有eq (等於)函數的bsxfun ,我們使用廣播,這樣我們得到一個3D矩陣,其中每個切片的大小相同作為灰度圖像,給我們的位置等於感興趣的強度。 具體來說,第一個切片告訴你元素在哪里等於0,第二個切片告訴你哪個元素等於1,直到最后一個切片告訴你元素等於255的位置。

對於第二行代碼,一旦我們計算了這個3D矩陣,我們計算兩個總和 - 首先獨立地對每一行求和,然后對該中間結果的每一列求和。 然后我們得到每個切片的總和,它告訴我們每個強度有多少個值。 因此,這是一個3D矢量,因此我們將其reshape為單個1D矢量以完成計算。


為了顯示直方圖,我會使用帶有histc標志的bar 如果我們使用cameraman.tif圖像,這是一個可重現的例子:

%// 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');

我們得到這個:

在此輸入圖像描述

您的代碼看起來正確。 問題在於調用直方圖。 您需要在直方圖調用中提供二進制數,否則將自動計算它們。

嘗試這個簡單的修改,調用詞干來獲得正確的情節,而不是依靠直方圖

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
stem(histogram_values); axis tight;

編輯:經過一些代碼檢查后,你有0/1的錯誤。 如果您的像素值為零,則histogram_value(p)將為您提供索引錯誤

試試這個。 這個簡單的案例不需要矢量化:

function hv = histogram_matlab_vec(I)

  assert(isa(I,'uint8')); % for now we assume uint8 with range [0, 255]

  hv = zeros(1,256);
  for i = 1 : numel(I)
    p = I(i);
    hv(p + 1) = hv(p + 1) + 1;
  end

  stem(hv); axis tight;
end

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM