otsu 双阈值 图像分割

otsu 双阈值算法 图像分割

  • 理论
  • MATLAB代码

理论

网上有很多博客都写了理论,但是很少有代码 就算有也是opencv c++的代码
所以贴一个自己写的matlab版本
otsu理论的话, 看冈萨雷斯的《数字图像处理》 第10.3.6节 多阈值处理
看完书,按照书上的理论来写的

MATLAB代码

otsu 双阈值函数:



function [t1,t2]=DoubleOtsuThresh(img)
%
%  Otsu 双阈值求解
%  输入 图像img,输出 最优阈值t1和t2(归一化,范围在[0,1])
%
%


BinsNum = 256;  
hist = imhist(img,BinsNum);   
p = hist / sum(hist);          % 直方图的概率密度函数
mG= sum(p .* (1:BinsNum)');     % 全局均值

P1 = cumsum(p);                 % 概率分布
m1 = cumsum(p .* (1:BinsNum)')./P1; % 256*1  每个阈值的前景平均灰度

% 根据算法理论,从k2+1累加到L-1,可以先倒着累加再翻转回来
P3= cumsum(flip(p));          
m3 = cumsum(flip(p) .* flip(1:BinsNum)')./P3;
P3=flip(P3);
P3=[P3(2:end) ;0];             %P3的索引用k2,则P3(1)实际上是从p(2)加到p(256),所以要移动一个
                               %移动后也用不到P3(1)这个值,因为k2>k1>1
m3=flip(m3);
m3=[m3(2:end) ;0];

% m2 P2为 k1*k2的索引矩阵,为 256*256 的上三角矩阵 因为k1<k2
m2=zeros(BinsNum,BinsNum);    
P2=zeros(BinsNum,BinsNum);


for k1=1:BinsNum-2
    for k2=k1+1:BinsNum-1
        P2(k1,k2)=1-P1(k1)-P3(k2);
        m2(k1,k2) = sum( (k1+1:k2)' .* p(k1+1:k2) )./ P2(k1,k2) ;        
    end
end


% 遍历k1,k2各种组合  求方差
variance=zeros(BinsNum,BinsNum);
for k1=1:BinsNum-2
    for k2=k1+1:BinsNum-1
        
    % variance 为256*256 的上三角矩阵 因为l1<k2
    variance(k1,k2) = P1(k1)*(m1(k1)-mG)^2 + ...
                      P2(k1,k2)*(m2(k1,k2)-mG)^2 + ...
                      P3(k2)*(m3(k2)-mG)^2;
   
    end
end

% 最大方差点即为最优阈值
[~,index] = max(variance(:));
[index_row,index_col] = ind2sub(size(variance),index);

%灰度值为[0,255] 因此需要-1
t1= (index_row-1)./(BinsNum-1);
t2= (index_col-1)./(BinsNum-1);

end

根据上面求得的两个阈值,把图分成0 127 255三个灰度值显示的函数:


function out=img2gray(img,t1,t2)
 [M,N]=size(img);
 out=zeros(M,N);
  
 for m=1:M
     for n=1:N
         if img(m,n)<t1
             out(m,n)=0;
         else
             if( img(m,n)>t1 && img(m,n)<t2)
                 out(m,n)=127;  %灰度级可调
             else
                out(m,n)=255;	%灰度级可调
             end
         end
     end
 end
end

测试函数

%%B 彩色图
 imgB =imread('window.jpg');  
 imgB=rgb2gray(imgB);
 imgB=im2double(imgB);


%% 先高斯滤波平滑图B,去高频,再用阈值处理 
 gaussH=fspecial('gaussian',[5 5],10);
 smoothB=imfilter(imgB,gaussH);

 [t1B,t2B] =DoubleOtsuThresh(smoothB);    

% 如果imgB是unit8类型,则灰度范围在[0,255] 要把算法得到的两个阈值乘255
% 如果imgB是[0,1]范围的double类型则不用乘
%  T1B=t1B*255;   
%  T2B=t2B*255;

 T1B=t1B;  
 T2B=t2B;

J9=img2gray(smoothB,T1B,T2B); %转为灰度图

 figure 
 imshow(J9,[]);title('平滑+双阈值分割'); % imshow里面J9后面的[]相当于直方图均衡效果,让灰度值均匀分布,可以去掉对比一下

图B平滑滤波后,右边是灰度直方图:
otsu 双阈值 图像分割_第1张图片
双阈值处理:
otsu 双阈值 图像分割_第2张图片


%%
% —— 图D —— %


  imgD=imread('ladder.jpg');
%   imgD=rgb2gray(imgD);
 [t1D,t2D] =DoubleOtsuThresh(imgD);    

 T1D=t1D*255;
 T2D=t2D*255;
  % 分为 0 127 255 显示
  
J8=img2gray(imgD,T1D,T2D);

 
 figure 
 subplot 121
 imshow(imgD);title('原图D');

subplot 122
 imshow(J8,[]);title('双阈值分割');
 

处理结果:
otsu 双阈值 图像分割_第3张图片


%% 用书上的图测试算法,输出的两个阈值和书上结果一样 80177

imgC=imread('iceberg.tif');  % 用书上例子的图片测试,验证算法正确与否
 

 [t1,t2] =DoubleOtsuThresh(imgC); 
 T1=t1*255;
 T2=t2*255;
J7=img2gray(imgC,T1,T2);
 figure
 subplot 121
 imshow(imgC);title('原图C');
 subplot 122
 imshow(J7,[]);title('双阈值');
 disp(['     otsu双阈值为:   ' ,'t1=',num2str(T1),'     t2=',num2str(T2)])

书上的例子: otsu 双阈值 图像分割_第4张图片

你可能感兴趣的:(图像处理,otsu,图像分割,阈值处理)