Otsu的阈值实现无法正常工作

时间:2014-09-14 03:12:16

标签: matlab image-processing computer-vision

我已经实现了otsu的阈值实现,它将图像分割为前景和背景图像。我的实现的输出似乎与所需的一致。有什么想法吗?提前致谢!非常感谢有人可以告诉我如何解决这个问题。

我的输出: 对于图像1 -

enter image description here

对于图像2 -

enter image description here

我的代码:

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 个答案:

答案 0 :(得分:3)

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

  1. 我只是在挑剔,但您可以使用numel来计算像素总数(N)...它只是更清洁:)
  2. 在原始代码中,您正在检查1到254之间的正确阈值。您应该从0到255进行检查,因为图像中有256种可能的强度。
  3. 您还需要更改sigma声明,以便有256个元素,而不是255个。请记住,图像中有256种可能的强度。
  4. for循环中检查每个强度,当您计算类出现的概率时,您还需要检查强度0。由于MATLAB开始将数组索引为1,因此您需要偏移访问索引,以便从1开始。
  5. 您对对象和背景之间差异的定义略有偏差。您还需要计算对象的类均值的概率。您可以查看代码以获取更多详细信息。
  6. 您的班级平均定义概率略有不准确。您需要除以qbqo,而不是N
  7. 您正在使用m进行计算,然后将其存储在muT中。
  8. 最后,当您找到对象和背景之间的最大差异时,您需要减去 1,因为这将提供0到255之间的强度。
  9. 因此,这就是您的代码的样子。请注意,我省略了阈值图像的代码。我只提供计算图像阈值的代码。

    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
    

    此代码现在应该可以使用了。我使用自己的Otsu实现运行此代码,并获得相同的计算阈值。说实话,由于许多for循环,我觉得这段代码效率很低。我个人会做的是对它进行矢量化,但我会把它作为一个学习练习留给你:)


    修改

    好的,我会放弃。这是我为Otsu写的一些代码,它更加向量化。这基本上执行了您正在执行的操作,但是以更加矢量化的方式执行。非常欢迎您将它用于您自己的目的,但如果您打算使用它,请引用我:)

    %// Function that performs Otsu's adaptive bimodal thresholding
    %// Written by Raymond Phan - Version 1.0
    %// Input - im - Grayscale image
    %// Output - out - Thresholded image via Otsu
    
    function [out] = otsu(im)
    
    %// Compute histogram
    J = imhist(im);
    
    %// Total number of intensities
    L = length(J);
    
    %// Some pre-processing stuff
    %// Determine total number of pixels
    num_pixels = sum(J(:));
    
    %// Determine PDF
    pdf = J / num_pixels;
    
    %// Storing between-class variances for each intensity
    s_b = zeros(1,L);
    
    for idx = 1 : L
        %// Calculate w_0
        w_0 = sum(pdf(1:idx));
    
        %// Calculate w_1
        w_1 = 1 - w_0;
    
        %// Calculate u_0
        u_0 = sum((0:idx-1)'.*pdf(1:idx)) / w_0;
    
        %// Calculate u_1
        u_1 = sum((idx:L-1)'.*pdf(idx+1:L)) / w_1;
    
        % // Calculate \sigma_b^{2}
        s_b(idx) = w_0*w_1*((u_1 - u_0)^2);    
    end
    
    %// Find intensity that provided the biggest variance
    [max_s_b T] = max(s_b);
    T = T - 1; %// Must subtract by 1, since the index starts from 1
    
    %// Now create an output image that thresholds the input image
    out = im >= T;
    
    end
    

    由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);