基于OTSU最大类间方差法的ROI分割、提取图像中的形状特征--面积、周长、离心率、zernike矩

分享一下最近学习的图像分类方面知识,整体的思路如下(之前的汇报ppt里截的)
在这里插入图片描述

把这个过程拆分几个部分共同学习一下吧

1.Otsu法原理

最大类间方差法OTSU是一种自适应的全局阈值确定的方法,根据灰度阈值T将图像分成背景和目标两部分,像素点数占比为ω_0和ω_1,平均灰度值为μ_0和μ_1

由已知,
在这里插入图片描述
图像平均灰度
在这里插入图片描述
类间方差
在这里插入图片描述
代入式(2-1)、(2-2)可得目标函数为
在这里插入图片描述
背景和目标之间的类间方差最大时,目标和背景的错分概率最小

2.原始Otsu算法与改进算法的实现

改进算法思想是在原始Otsu算法基础上求取最大类间、类内方差比值最小的情况。
在分割之前利用了一些灰度变换的方法做图像的预处理,详细内容可以看链接

% 原始的与改进的OTSU算法
clc,clear,close all

f = imread('C:\Users\HS\Desktop\duck.jpg');
f = rgb2gray(f);f1 = f;

figure,imshow(f);title('原图的灰度化');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

figure,histogram(f);title('原图的灰度直方图');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

g = imadjust(f,[0.1,0.85],[],0.5);%mamma<1时,变换凸显高灰度区域

ng = imnoise(g,'gaussian',0,0.1);

[frest,psnr] = get_winer(g,ng);  % 维纳滤波
figure();imshow(frest); title(['维纳滤波去噪,PSNR=',num2str(psnr)]);
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

figure,histogram(frest);title('0.1高斯噪声滤波后的灰度直方图');
axis([0,255,0,7000]);
set(gca,'xtick',0:50:255); 
set(gca,'ytick',0:1000:7000); 
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

%% 正式开始:传统的OTSU算法
[thresh,SM] = graythresh(frest); % OTSU算法,自适应选取二值化阈值
BWimg = im2bw(frest,thresh);%im2bw的结果是白底黑目标

figure;
imshow(BWimg);title('OTSU算法二值化结果');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

figure,histogram(BWimg);title('OTSU算法二值化结果的灰度直方图');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);
%% 最大类间、类内比值法
[m,n] = size(f);
th = zeros(1,254); % 准备存放比值
f = double(f); % 必须转换成double格式!!!!否则不能计算像素!!!
% fi = 0;
% for i=1:m
%     for j=1:n
%         fprintf('fi=%d,',fi);
%         fprintf('f(%d,%d)=%d\n',i,j,f(i,j));
%         fi = fi+f(i,j);
%         
%     end
% end

for T = 1:254
    s1 = 0;
    s2 = 0;
    c1 = 0;
    c2 = 0;
    q1 = 0;
    q2 = 0;
    u1 = 0;
    u2 = 0;
    p1 = 0;
    p2 = 0; % 初始化
    
    for i = 1:m
        for j = 1:n
            if f(i,j)>=T
                s1 = f(i,j)+s1; % 这一类的像素点灰度值求和
                c1 = c1+1;      % 这一类的像素点数量
            else
                s2 = f(i,j)+s2;
                c2 = c2+1;
            end
        end
    end
    u1 = s1/c1;          % 这一类的的灰度均值u1
    u2 = s2/c2; 
    p1 = c1/(c1+c2);     % 这一类的分布概率
    p2 = c2/(c1+c2); 
    u = (s1+s2)/(c1+c2); % 总体均值
    x = p1*(u-u1)*(u-u1)-p2*(u-u2)*(u-u2); % 类间方差
    
    for i = 1:m
        for j = 1:n
            if f(i,j)>=T
                q1 = q1+(f(i,j)-u1)*(f(i,j)-u1); % 这一类的灰度方差
            else
                q2 = q2+(f(i,j)-u2)*(f(i,j)-u2);
            end
        end
    end
    y = p1*q1+p2*q2; % 类内方差
    c = x/y;         % 类间、类内方差的比值
    th(T) = c;
end
d = find(th==max(th(:))); % 寻找最大比值对应的位置,即T的值
Th = d;                   % 最优阈值
b = zeros(m,n);
for i = 1:m
    for j = 1:n
        if f(i,j)>=Th
            b(i,j) = 0;
        else
            b(i,j) = 255;
        end
    end
end
figure,imshow(b);title('最大类间、类内方差比值法所得二值化图像');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

figure,histogram(b);title('新Otsu法的灰度直方图');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);
    

figure,subplot(231); imshow(f1);title('原图灰度化结果');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

subplot(232); imshow(BWimg);title('OTSU算法二值化结果');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

subplot(233); imshow(b);title('改进的OTSU算法二值化结果');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

subplot(234);histogram(f1);title('原图的灰度直方图');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

subplot(235);histogram(BWimg);title('OTSU算法二值化结果的灰度直方图');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

subplot(236);histogram(b);title('改进的OTSU算法二值化结果的灰度直方图');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);


结果是这样的
在这里插入图片描述
似乎原始Otsu算法已经可以实现把目标及其影子分割出来了呢,改进的算法可以把影子也剔除掉

3.基于OTSU方法的灰度图像二值化,提取ROI及其形状特征

对文件夹下图像统一操作——Otsu分割、形态学操作、提取roi,最后计算形状特征

说明几点:
1.势必会提取到多个ROI,对单亮点模型,我设置了只保留外接矩形面积最大的那一个
2.二值化的结果必须是前景为白色,背景为黑色,否则下一步瘪瘪出错
3.形状特征是用以分类的主要特征,包括但不限于我这里计算的四维–面积、周长、离心率、zernike矩

clc,clear,close all

file_path = 'C:\Users\HS\Desktop\图片素材\滤波后';% 获取指定文件夹下所有子文件的路径

SCALE = [];% 存放形状特征
ALL_EM = [];% 存放分割率
ALL_num = [];% 存放ROI数量

p=genpath(file_path);
%这些路径存在于字符串p中,以';'分割
length_p=size(p,2);  % 字符串p的长度
path={}; % 建立一个元胞数组,数组的每个单元中包含一个目录
temp=[];
for i=1:length_p % 寻找分隔符';',一旦找到,则将路径temp写入path数组中
    if p(i)~=';'
        temp=[temp p(i)];
        else
        temp=[temp '\'];%在路径的后面加上\
        path=[path;temp];
        temp=[];
    end
end
clear p length_p temp
%获得了指定文件夹及其所有子文件夹,接下来就是逐一文件夹读取图像,利用上面的path数组,将路径取出来
file_num=size(path,1);%获取子文件夹的个数


for i=1:file_num
    file_path = path{i};
    img_path_list=dir(strcat(file_path,'*.jpg')); %获取每个文件夹下的图像列表
    img_num=length(img_path_list);%获取文件夹下图像的数量
    if img_num > 0
        for j=1:img_num
            image_name=img_path_list(j).name;%获取图像名
            %new_image_name = image_name(1:end-4);%去掉原图名中的.jpg
            SIFT_imageFile = strcat(file_path,image_name);
            image=imread(SIFT_imageFile);
            %image=imread(strcat(file_path,image_name));%读取文件夹下的每一帧图像
            fprintf('第%d个文件夹中第%d个图片 %s\n',i,j,strcat(file_path,image_name));%显示正在读取的文件夹和其中图像数量

           %% 正式操作
            
            % 根据滤波后图像二值化提取尺度特征scale
            [EM,num,scale] = getScaleFeatures(image);
            SCALE = [SCALE;scale];
            
            ALL_EM = [ALL_EM,EM]; % 窥探图片分割率如何
            ALL_num = [ALL_num,num];% 分别划分了几个ROI

        end
    end
end

fprintf('完成!记得保存好每一类目标的特征矩阵!!\n');

其中调用了几个小函数

%% 基于OTSU方法的灰度图像二值化,提取尺度特征
function [EM,num,scale] = getScaleFeatures(frest)
% 对调整好的灰度图片frest,返回尺度特征矩阵scale、分割率EM、ROI数量num

[thresh,EM] = graythresh(frest); % OTSU算法,自适应选取二值化阈值

% if EM>0.7
%     fprintf('EM=%f, 适合分割\n',EM);
% else 
%     fprintf('EM=%f, 恐怕不适合分割\n',EM);
% end
% fprintf('\n');

% 依次替换灰度值,自定义目标为黑色、背景为白色

[width,height]=size(frest);
BWimg = ones(width,height);
T = 255*thresh; 

for i=1:width
    for j=1:height
        if(frest(i,j)>T)
            BWimg(i,j)= 0;
        else 
            BWimg(i,j)= 255;
        end
    end
end                           

% BWimg = getNewOtsu(f);         % 改用一种新的Otsu算法得到BWimg

%% 分割、提取ROI,统计标注连通域

% 1.创建平面结构化元素,闭运算,开运算
se = strel('disk',5,4); %创建一个指定半径5的平面圆盘形的结构元素,
% N缺省值为4,圆盘形结构元素由一组N(或N+2)个周期线结构元素来近似

% 创建一个指定领域的平面结构化元素
% 用于膨胀腐蚀及开闭运算等操作的结构元素对象
BWimg = imclose(BWimg,se);%消弭狭窄的间断,消除小的孔洞
BWimg = imopen(BWimg,se);%平滑物体轮廓,断开狭窄的间断和消除细小的突出物
% 
% figure;
% imshow(BWimg);title('形态学操作后的图像');
% set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);

% 2.统计标注连通域
%使用外接矩形框选连通域,并使用形心确定连通域位置
[mark_image,num] = bwlabel(BWimg,4); % 找二值图像中的连通区域

status = regionprops(mark_image,'BoundingBox'); % 最小外接矩形

centroid = regionprops(mark_image,'Centroid');% 每个区域的质心(重心)

figure;
imshow(mark_image);title('Otsu方法标记后的图像');
set(gcf,'color','w');set(gca,'linewidth',1,'fontsize',16);


for i=1:num
    rectangle('position',status(i).BoundingBox,'edgecolor','r','LineWidth',2);
    %参数说明:position绘制的为二维图像(他是通过对角的两点确定矩形框)
    %edgecolor 指边缘图像,r表示变换为红色。
    %facecolor 指内部填充颜色。
    text(centroid(i,1).Centroid(1,1)-15,centroid(i,1).Centroid(1,2)-15, num2str(i),'Color', 'r','FontSize',15) 
    %这个是为绘制出来的矩形框图标记数字
    %S(i) = status(i).BoundingBox(2,1)*status(i).BoundingBox(2,1);
    
end

AREA = zeros(1,num);% 选择外接矩形最大的一个
for ii = 1:num
AREA(ii) = status(ii).BoundingBox(3)*status(ii).BoundingBox(4);
end

[maxAREA,bestNum] = max(AREA);

% 选择观察目标 
% 注意:regionprops计算周长和面积,计算的是白色区域的周长和面积!!!
% 黑白颜色颠倒后会出错!!!
copy_mark_image = mark_image;
number1 = bestNum;   % 必要适合选择保留最大的区域!!!!!!!!!!
image_part1 = (copy_mark_image == number1); %进行区域的选择,例如只保留3


% 求面积,对二值图像而言就是求目标像素点数
round_area = regionprops(image_part1,'Area');
% fprintf('round_area面积/目标像素点 = %f\n', round_area.Area);



% 求周长
girth = regionprops(image_part1,'Perimeter');
% fprintf('s.Perimeter周长 = %f\n', girth.Perimeter);
 

%求离心率 oval.Eccentricity
oval = regionprops(image_part1,'Eccentricity');%离心率 0 < e < 1之间,e越小,越像圆。
% fprintf('oval.Eccentricity离心率 = %f\n', oval.Eccentricity);

% 求不变矩
image_part1 = imresize(image_part1,[256 256]); % 拉伸为正方形!!!!
image_part1 = logical(not(image_part1));
[Z, A, Phi] = Zernikmoment(image_part1,4,2);
% fprintf('不变矩 = %f\n', A);


scale = []; % 形状特征!!!
scale = [scale,round_area.Area,girth.Perimeter,oval.Eccentricity,A];
end

以及用来计算正方形图像ROI(需要提前用imresize修改ROI的尺寸)的不变矩的

function [Z, A, Phi] = Zernikmoment(p,n,m)
% Function to find the Zernike moments for an N x N binary ROI,
% 计算泽尔尼克矩(必须是正方形的ROI)

%   p = input image N x N matrix (N should be an even number)
      % 输入图像N x N矩阵(N应为偶数)
%   n = The order of Zernike moment (scalar) 
      % Zernike矩(标量)的阶数
%   m = The repetition number of Zernike moment (scalar)
      % Zernike矩重复次数(标量)
% and
%   Z = Complex Zernike moment                      Zernike矩
%   A = Amplitude of the moment                     振幅(我需要的)
%   Phi = phase (angle) of the mement (in degrees)  相位(°)
%
% Example: 
%   1- calculate the Zernike moment (n,m) for an oval shape,
%   2- rotate the oval shape around its centeroid,
%   3- calculate the Zernike moment (n,m) again,
%   4- the amplitude of the moment (A) should be the same for both images
%   5- the phase (Phi) should be equal to the angle of rotation
N = size(p,1);
x = 1:N; y = x;
[X,Y] = meshgrid(x,y);
R = sqrt((2.*X-N-1).^2+(2.*Y-N-1).^2)/N;
Theta = atan2((N-1-2.*Y+2),(2.*X-N+1-2));
R = (R<=1).*R;
Rad = radialpoly(R,n,m);    % get the radial polynomial
Product = p(x,y).*Rad.*exp(-1i*m*Theta);
Z = sum(Product(:));        % calculate the moments
cnt = nnz(R)+1;             % count the number of pixels inside the unit circle
Z = (n+1)*Z/cnt;            % normalize the amplitude of moments
A = abs(Z);                 % calculate the amplitude of the moment
Phi = angle(Z)*180/pi;      % calculate the phase of the mement (in degrees)


我的结果如下,有效提取出鸭子的影子呵呵,其实我想要的是鸭子本鸭~我的算法对这样的图只能这样了呵呵
在这里插入图片描述
我的方法是用来探测其他东西的,只是拿着鸭子的图片来说明一下哦,如果是想要去除背景实现抠图功能,建议试一下这个免费网站

结果很不错的哦
在这里插入图片描述

4.参考文章

借鉴了很多前人经验,列出如下

详解-OTUS(大津法-最大类间方差)原理
基于最大类间、类内方差比法图像分割(有两个小错误,我在程序里面已经修改过了)
zernike矩
基于Matlab的形状识别与计算图形周长,面积,圆周率
这类方法对图像分类很有用但已经很老了,大家可以多思考提出一些新的方法

  • 2
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值