MATLAB--數字圖像處理 圖像直方圖規定化

直方圖規定化

原理
所謂直方圖規定化,就是通過一個灰度映像函數,將原灰度直方圖改造成所希望的直方圖。說的通俗一點就是,原圖像的灰度是從0~255的,其分佈是隨機的,在一些情況下,我們可能需要一些特定的灰度值,比如我們只需要灰度值爲0 3 40 240 255 這些值,除此之外的灰度值我們不需要,那麼從原圖像到我們需要的圖像就可以理解成圖像的規定化。

具體事例
左圖是原圖像的灰度直方圖,右圖是我們需要的圖(這裏的需要是指需要灰度由原來的0~7變成規定的1 3 6,規定化後圖像的縱座標是會變的,這裏只需要橫座標吻合就行!)
在這裏插入圖片描述
規定化後的圖像(橫座標和規定一樣,縱座標是會變化的):
在這裏插入圖片描述
實現步驟:

  1. 分別計算出原圖像和規定圖像的累加直方圖
  2. 利用SML或者GML映射灰度值
  3. 利用更新後的映射錶轉換原圖像的灰度值

看完之後,應該還是不懂?那麼直接實戰一題!題目見下圖:
在這裏插入圖片描述
解題步驟:

  1. 這裏是直接給出的原圖像各灰度的像素個數,爲了得到我們需要的直方累加圖(其實是概率累加值,當然也可以不用概率,直接用像素點數也行,就是看起來數字比較大),需要先算出原圖像各灰度的概率(佔總像素個數的比例),然後在計算累加值在這裏插入圖片描述
  2. 根據給出的規定直方圖,同樣的方法計算累加直方圖,見下圖在這裏插入圖片描述
  3. 利用SML映射規則得出結果在這裏插入圖片描述
  4. 利用映射變化表,更新原圖像

提示

這裏可能不懂SML映射規則,我說說自己簡單的理解(自己也可以自行百度):
SML就是單映射,這裏我們關注原圖累加直方圖和規定累加直方圖,所謂SML,就是從原圖累加直方圖開始,在規定累加直方圖尋找和自己最接近的值,然後把它的灰度值變成自己的。具體來說,原圖第一個累加概率是0.19,在規定累加直方圖中,最接近它的就是0.15,那麼原圖的灰度0變成規定的3,第二個累加概率是0.44,最接近規定累加直方圖的0.35,所以由1變成4,同理,依次遍歷完原圖累加直方圖的概率就行,在規定累加直方圖找到最靠近自己的值,最後進行灰度變化。

SML規則懂了,GML規則也就好理解了(GML規則其實編程更難):

SML中,我們是依次遍歷原圖累加直方圖,在規定累加直方圖尋找最靠近自己的。在GML(組映射)中,就變成了依次從規定累加直方圖中,對比原圖累加直方圖,也是找到最靠近的值,進行灰度變換,只是這裏的變換規則變了。
在這裏插入圖片描述
具體舉例來說,從上圖看,這裏我們這裏從規定累加直方圖的0.15看,前面的0其實不用看,再從原始累加直方圖找到最接近0.15的值,是0.19,那麼0.19對應和它對應灰度值前面的灰度變成規定累加直方圖中0.15所對應的灰度值:3;第二個看規定累加直方圖的0.35,靠近原圖的0.44,那麼原圖的1變成4(假設這裏0.44對應的原圖灰度值爲4,那麼在前一個不爲0和4之間變成4)
這裏有的不好理解,舉個例子:
原數組:1 0 0 2 0 3 0 0 0 4 0 0 6
GML映射變化規則的目標數組就是:1 2 2 2 3 3 4 4 4 4 6 6 6
解釋:1前面的數變爲1,1和2之間變成2,2和3之間變成3,3和4之間變成4,4和6之間變成6,簡單的說就是變0變成後面最靠近的一個不爲0的數。(這裏算法自己需要掌握,即如何從原數組變成目標數組,這裏先給個C++的驗證算法)

#include<iostream>
using namespace std;
int main()
{
	int t[8]={2,0,1,0,3,0,0,6};
	int i,j;
	int tem;
	int flag=0;
	for (i=0;i<8;i++)
	{
	if(t[i]==0)
	{
	
	for(j=i;j<8;j++)
	{
	if(t[j]!=0)
	{
	tem=t[j];
	break;}
	}
     t[i]=tem;
	
	}
	}
for(i=0;i<8;i++)
cout<<t[i]<<" ";
return 0;
}

如果還是不懂SML和GML規則的話?那自己根據下面兩種圖片再理解理解吧。在這裏插入圖片描述
在這裏插入圖片描述

MATLAB實戰
原理懂了,肯定就是要開始實戰了啊!
這裏我先上全部代碼:

 t=imread('a1.jpg')
%獲取圖片的長和寬,用於計算總像素,即m*n
[m,n]=size(t);

%n_1 這裏是先統計各灰度的像素數,後面會變換爲概率
n_1=zeros(1,256);

%統計各灰度的像素數
for i=1:m
for j=1:n
n_1(t(i,j)+1)=n_1(t(i,j)+1)+1;
end
end

%轉換爲概率
n_1=n_1/m/n; %計算各個灰度級的概率

%p_1  記錄原圖的累積直方圖概率
p_1=zeros(1,256);

%p_1 計算原始累積直方圖的概率
for i=1:256
for j=1:i
p_1(i)=p_1(i)+n_1(j);
end
end

%n_2  規定直方圖的灰度概率分佈
n_2=[zeros(1,50),0.1,zeros(1,50),0.2,zeros(1,50),0.3,zeros(1,50),0.2,zeros(1,20),0.1,zeros(1,30),0.1];

%p_2 記錄規定直方圖的累積概率
p_2=zeros(1,256);

% 計算規定直方圖累積概率
for i=1:256
for j=1:i
p_2(i)=p_2(i)+n_2(j);
end
end

%SML映射算法
data_1=zeros(1,256);%data_1 SML映射表

for i=1:256
min=abs(p_1(i)-p_2(1));
for j=2:256
if  abs(p_1(i)-p_2(j))<min
min=abs(p_1(i)-p_2(j));
data_1(i)=j-1;
end
end
end

%GML
 data_2=zeros(1,256); %data_2記錄GML映射表

for i=1:256
if n_2(i)~=0
tem=1;
min=abs(p_2(i)-p_1(1));
for j=2:256
if abs(p_2(i)-p_1(j))<min
min=abs(p_2(i)-p_1(j));
tem=j;
end
end
data_2(tem)=i-1;
end
end

%將上面得到的data_2 轉換爲目標數組(原理解釋有c++算法)
for i=1:256
if data_2(i)==0
for j=i:256
if data_2(j)~=0
tem=data_2(j);
break;
end
end
data_2(i)=tem;
end
end


%利用SML、GML映射表,轉換原圖像
t2=t;
t3=t;

%轉換算法
for i=1:m
for j=1:n
t2(i,j)=data_1(t(i,j)+1);
end
end
for i=1:m
for j=1:n
t3(i,j)=data_2(t(i,j)+1);
end
end

%顯示
subplot(3,2,1),imshow(t),title('原圖')
subplot(3,2,2),imhist(t),title('原圖')
subplot(3,2,3),imshow(t2),title('SML')
subplot(3,2,4),imhist(t2),title('SML')
subplot(3,2,5),imshow(t3),title('GML')
subplot(3,2,6),imhist(t3),title('GML')

效果圖:
在這裏插入圖片描述

總結

SML、GML兩個算法用來一天才搞清楚原理,書上的公式開始看真的是好難啊,看不進去,網上的方法,真的是,沒有自己想要的。算法其實一天就搞定了,當時由於MATLAB語法還不是很熟,走了很多彎路。下面總結下自己的踩坑吧:

  • MATLAB裏面的循環寫法 for i=1:256 c++:for(i=1;i<=256;i++)
  • for、if等用end結束,end個數必須和if、for配對,比如,3個for,2個if,就必須有5個end結束,不然程序會一直執行下去
  • 程序語句最後有無 ; 的區別:寫了 ; 本地代碼區不會顯示具體數據,反之不寫,則會顯示,建議還是寫吧,和c++語法類似。
  • 多打印數據,一步一步調試,便於尋找bug
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章