前言
在Matlab中图像分割是一个很重要的手段,其中迭代选择阈值法的阈值分割算是入门代码。这一次老师给的作业是去补全其中代码的注释,在补全代码的过程中自己了解到了一些新知识,尽管知识很简单,代码也很短,但是自己还是花费了一段时间去了解其中每个代码运行的含义,所以想记录一下这个过程。
一、实现样例
1. 黑白图
2. 彩色图
二、代码注释
代码及注释如下:
%%
clc;
clear;
close all;
%% 导入所需图片并设置为所需格式
% filename = 'fingerprint'; %导入图片
filename = 'wood_dowels'; %导入图片
im = imread([filename, '.tif']);
% 文件类型为.tif,这个文件是一个大小为531x675的矩阵
% 可以用size(im)等命令或者直接点击原资源查看
% im=rgb2gray(im);
% 将RGB通道的三维图(即彩色图)转为二维图(黑白图),在进行阈值分割。在传入的图片为二维图时,此行代码需要注释
%% 更新到合理的阈值,方便之后进行基于阈值的图像分割
thres = 0.5*( double(min(im(:))) + double(max(im(:))) );
%{
初步设定一个阈值,在阈值分割里面,像素点大于这个阈值的,为目标,小于的为背景。
max(im(:))=255,max(im(:))=2
im(:)为先把im文件由矩阵形式转换为一个行向量。
min(im(:))和max(im(:))分别为返回行向量中最小和最大的元素。
元素变量转换为64(8字节)双精度浮点值。
thres为一个double类型的值
参考资料: https://zhidao.baidu.com/question/335941648.html
https://blog.csdn.net/mxr2026588745/article/details/108990666
%}
done = false; % 预设逻辑值
while ~done % ~ 为计算逻辑NOT,即while ture
g = im >=thres;
%{
矩阵im里面的元素依次与thres比较,最后得到一个由0和1组成的矩阵
g的结果为一个维度数与矩阵im维度数一样的矩阵,数据类型是logical(逻辑值)
即g = (im >=thres);
%}
Tnext = 0.5 * ( mean(im(g)) + mean(im(~g)) );
%{
im(g)为大于等于阈值的值,是一维矩阵,假设有im中有a个元素大于等于阈值,im(g)这个一维矩阵便有a行1列
同理im(~g)为小于阈值的值,也是一维矩阵,假设im中有b个元素小于阈值,im(~g)这个一维矩阵便有b行1列
mean为取平均值,经过运算得到新的阈值Tnext
因为im(g)和im(~g)都是一维矩阵,所以通过mean函数求平均值时,可以各自得到唯一一个平均值,而不像二维向量一样,每一列都有一个平均值。
可以在控制台通过输入mean(im),mean(im(g)),mean(im(~g))验证
%}
done = abs(thres - Tnext)<0.5;
%{
done为false时循环一直进行,在这个过程中不断更新阈值,直到取到较为理想的阈值,即新得到的阈值与上一轮的阈值结果相差不大,类似聚类算法里面寻找新的聚类中心。
结束时Tnext与thres的差距的绝对值控制在了0.5之内
%}
thres = Tnext;
% 不断更新,得到新的阈值。
end
Ibw = imbinarize(im,thres/255);
% imbinarize,im2bw函数是基于阈值将图像转换为二值图像,在这里大于阈值的为值1(白色),小于阈值的为值0(黑色)
%% 输出结果
imshow(Ibw)
% 图像分割之后得到的图像
% inshow是显示二维图片的,如果传入的是三维图片会无法显示
% 二维图片是黑白的,三维图片是彩色的(RGB通道)
% 三维图片可通过rgb2gray()函数将三维图片转换为二维图片,再进行阈值分割。
fprintf('The threshold vakue is %8.5f\n', thres);
% 显示阈值
%% 过程中观察变量输出结果
%{
% fprintf('The max(im(:)) is %8.5f\n', max(im(:)));
% fprintf('The min(im(:)) is %8.5f\n', min(im(:)));
% fprintf('The thres is %8.5f\n', thres);
fprintf('The im is %8.5f\n', im);
fprintf('The im(g) is %8.5f\n', im(g));
fprintf('The im((~g) is %8.5f\n', im(~g));
fprintf('The mean(im(g)) is %8.5f\n', mean(im(g)));
fprintf('The mean(im(~g)) is %8.5f\n', mean(im(~g)));
fprintf('The Tnext is %8.5f\n', Tnext);
%}
三、总结
1. 自己所理解的原理
1.基于迭代选择阈值法的阈值分割,是把二维图像输入,通过理想的阈值和二值化明确分割目标与背景。
2.理想的阈值是基于图像本身的像素点,灰度值,通过多次迭代得到的。
3.阈值得到之后,使用im2bw或imbinarize函数进行二值化(新版本的matlab倾向于让用户选择imbinarize),灰度值大于阈值的像素点变为1,成为目标;灰度值小于阈值的像素点变为0,成为背景。
4.最终输出结果。
2. 过程中观察到的有趣现象
1.过程中矩阵维数的变化,函数运用之后变量数值的变化,在控制台单独输出查看,加深了对这个过程的理解。
2.三维图像(即彩色图像),进行基于迭代选择阈值法的阈值分割需要先通过
二维图=rgb2gray(三维图)
函数来转换,之后的步骤一样。之所以需要转换是因为
imshow()
函数输入的参数并不支持三维的。不进行转换的话汇报以下错误:
错误使用 images.internal.imageDisplayValidateParams>validateCData (第 xx 行)
如果输入项为逻辑值(二进制),则必须是二维的。