Matlab 大津';s的阈值化实现工作不正常

Matlab 大津';s的阈值化实现工作不正常,matlab,image-processing,computer-vision,Matlab,Image Processing,Computer Vision,我已经实现了otsu的阈值实现,它将图像分为前景图像和背景图像。我的实现的输出似乎与期望的不一致。有什么想法吗?提前谢谢!如果有人能告诉我如何解决这个问题,我将不胜感激 我的输出: 对于图1- 对于图2- 我的代码: im1=imread('D:\root-image.pgm'); % im1=rgb2gray(im1); [n,m]=size(im1); hst=imhist(im1); mu=zeros(255,1); N=0; for i=1:255 N=N+hst(i);

我已经实现了otsu的阈值实现,它将图像分为前景图像和背景图像。我的实现的输出似乎与期望的不一致。有什么想法吗?提前谢谢!如果有人能告诉我如何解决这个问题,我将不胜感激

我的输出: 对于图1-

对于图2-

我的代码:

im1=imread('D:\root-image.pgm');
% im1=rgb2gray(im1);
[n,m]=size(im1);
 hst=imhist(im1);
mu=zeros(255,1);
N=0;
for i=1:255
    N=N+hst(i);
end
% The total mean level of the original image
for i=1:255
    mu(i)=mu(i)+((i.*hst(i))./N);
end


for T=1:254
    qb=0;
    muT=0;
    qo=0;
    for i=1:T
        qb=qb+(hst(i)./N); % probability of class occurence (background)
        m=m+((i.*hst(i))./N);% probability of class mean (background)
    end
    for i=T+1:255
        qo=qo+(hst(i)./N);% probability of class occurence (object)
    end
    sigma(T)=((mu(T)-(qb*muT))^2)/(qb*qo);
end
[Y,T] = max(sigma);

[n,m]=size(im1);
for i=1:n
    for j=1:m
        if im1(i,j)>T
            im(i,j)=1;
        else
            im(i,j)=0;
        end
    end
end
figure(1);
subplot(1,2,1);
imshow(im1);
% subplot(1,3,2);
% imhist(im1);
subplot(1,2,2);
imshow(im);

您的代码存在一些问题,我将概述错误之处:

  • 我只是吹毛求疵,但您可以使用。。。它只是更干净:)
  • 在原始代码中,您正在检查介于1和254之间的正确阈值。你真的应该检查从0到255,因为在你的图像中有256个可能的强度
  • 您还需要更改
    sigma
    声明,以便有256个元素,而不是255个。请记住,图像中有256种可能的强度
  • 在检查每个强度的
    for
    循环中,当计算类出现的概率时,还需要检查强度0。因为MATLAB从1开始索引数组,所以需要偏移访问索引,以便从1开始
  • 您对对象和背景之间差异的定义有点偏离。您还需要计算对象的类平均值的概率。您可以查看代码以了解更多详细信息
  • 你的类平均值定义的概率有点不准确。您需要除以
    qb
    qo
    ,而不是
    N
  • 您正在使用
    m
    计算平均值,然后将其存储在
    muT
  • 最后,当您找到对象和背景之间的最大方差时,您需要用1减去,因为这将提供介于0和255之间的强度 因此,这就是您的代码的外观。请注意,我省略了设置图像阈值的代码。我只提供计算图像阈值的代码

    hst=imhist(im1);
    sigma = zeros(256,1); %// Change
    N = numel(im1); %// Change
    
    for T=0:255 %// Change
        qb=0;
        muT=0;
        qo=0;
        muQ=0; %// Change
        for i=0:T %// Change
            qb=qb+(hst(i+1)./N); % probability of class occurence (background)
        end    
        for i=T+1:255 
            qo=qo+(hst(i+1)./N);% probability of class occurence (object)
        end
        for i=0:T%// Change        
            muT=muT+((i.*hst(i+1))./qb);% probability of class mean (background)    
        end
        for i=T+1:255 %// Change
            muQ=muQ+((i.*hst(i+1))./qo);% probability of class mean (object)        
        end   
        sigma(T+1) = qb*qo*((muT-muQ)^2); %// Change
    end
    [Y,T] = max(sigma);
    T = T-1; %// Change - For 0 to 255
    

    这段代码现在应该可以工作了。我用自己的大津实现运行了这段代码,得到了相同的计算阈值。老实说,我发现这段代码效率很低,因为有许多
    for
    循环。我个人会做的是将其矢量化,但我将把它留给您作为一个学习练习:)


    编辑 好吧,我会让步的。下面是我为大津编写的一些代码,这些代码更加矢量化。这基本上执行了上面所做的操作,但以更矢量化的方式执行。您完全可以出于自己的目的使用它,但如果您打算使用它,请务必引用我的话:)


    Divakar编辑 Divakar(谢谢!)创建了矢量化代码来替换上述函数代码的循环部分,这基本上消除了
    s_b
    的预分配:

    w_0 = cumsum(pdf);
    w_1 = 1 - w_0;
    u_0 = cumsum((0:L-1)'.*pdf)./w_0;
    u_1 = flipud([0 ; cumsum((L-1:-1:1)'.*pdf((L:-1:2)))])./w_1;
    s_b = w_0.*w_1.*((u_1 - u_0).^2); 
    

    @James你为什么想要递归实现?我想它会比上面的代码运行得快,而我的实际需求是写一个大津的递归代码。当然!这将是一个真正的挑战help@James-完成!去看看吧。请注意,您正在执行的许多操作都可以通过一两行代码来简化。无论我在哪里使用它,我都会引用您。
    w_0 = cumsum(pdf);
    w_1 = 1 - w_0;
    u_0 = cumsum((0:L-1)'.*pdf)./w_0;
    u_1 = flipud([0 ; cumsum((L-1:-1:1)'.*pdf((L:-1:2)))])./w_1;
    s_b = w_0.*w_1.*((u_1 - u_0).^2);