静态图像分割

Posted by 周宝航 on May 15, 2018

静态图像分割

  • 这次图像处理的老师布置了静态图像分割的实验。具体要求如下:
  • 1 将药板从黑色背景中分离(药板部分显示为白色,背景显示为黑色);
  • 2 根据分割结果将药板旋转至水平;
  • 3 提取药板中的药丸的位置信息;
  • 4 对不同颜色药丸的药板进行检测,分析结果上差异,并改进算法使其适应不同颜色的药丸;
  • 5 获取标签位置信息,用框在原图中框出来;
  • 6 对有缺陷的药板进行缺陷定位检测。

实验步骤

  • 首先以如下图片为例,进行图像水平矫正、分割等操作步骤的说明。 Alt text

二值化

  • 在该部分中,我使用Otsu方法获取图像的阈值。然后使用im2bw函数将原始图像变为二值图像。
    % 图像二值化
    I=rgb2gray(origin_img);
    T=graythresh(I);
    bw = im2bw(I,T);
    figure, imshow(bw);title('二值化');
    

    Alt text

孔洞填充

  • 由于进行图像水平矫正的过程中,我只需要图像的边缘部分。因此,使用孔洞填充将图像的中心药丸部分去除掉,获得只有药板部分的二值图像。
    % 孔洞填充, 分离药板
    fh_bw = imfill(bw, 'holes');
    figure;imshow(fh_bw);title('分离出药板');
    

    Alt text

边缘检测

  • 这里使用Canny算子对药板二值图像进行边缘检测。如此一来,我们得到了药板的边缘信息。接下来,根据边缘找出图像的倾斜角度。
    % 边缘检测
    edg_bw = edge(fh_bw,Canny);
    figure, imshow(edg_bw);title('检测边缘后图像');
    

    Alt text

Radon变换

  • Radon 变换:将原来的函数做一个空间转换,即,将原来的XY平面内的点映射到AB平面上,那么原来在XY平面上的一条直线的所有的点在AB平面上都位于同一点。记录AB平面上的点的积累厚度,便可知XY平面上的线的存在性。

Alt text

  • 我们对上一步得到的边缘检测后的图像进行Radon变换,得到了上图的结果。横坐标为Radon变换的角度参数,而图中点的明亮程度表示在垂直于该角度上图像每列灰度值的叠加。因此,图中最明亮的四个点的横坐标即为边缘图像的四条边对于水平线的旋转角度。
  • 然后,使用两次max函数对Radon变换返回的角度结果寻找其中的最大值,即为图像的倾斜角度。由于图像需要矫正,所以旋转角度就为90-J(J为边缘线的最大倾角)。
    % 利用radon变换找出倾斜角
    theta = 1:180;
    [R,xp] = radon(edg_bw, theta);
    [I, J] = max(max(R));
    theta = 90 - J;
    lv_bw = imrotate(origin_img, theta, 'bilinear', 'crop');
    figure, imshow(lv_bw);title('校正后图像');
    

    Alt text

阈值分割

  • 对于药丸部分的分割,我打算采用阈值分割的方法。首先我比较了RGB空间与YCbCr空间的每个通道的二值化图像。

Alt text

  • 通过观察发现,由于药丸与药板的颜色接近,在RGB空间,原图像的二值化图像只有药丸的一半。而在YCbCr空间中,结合Y空间与Cb空间,我们可以得到完整的药丸部分。因此,采用YCbCr空间的Y通道与Cb通道进行阈值分割。
% 基于YcBcr空间的阈值分割
ycbcr=rgb2ycbcr(lv_bw);
y=ycbcr(:,:,1);
cb=ycbcr(:,:,2);
cr=ycbcr(:,:,3);
bw_y=im2bw(y,graythresh(y));
bw_cb=im2bw(cb, graythresh(cb));
B=~(~bw_y+~bw_cb);

Alt text

形态学处理

% 形态学处理
se=strel('disk',5);
B=imclose(B,se);
B=imopen(B,se);
figure, imshow(B);

Alt text

连通域标记

  • 为了得到药丸的位置信息,我们对上一步得到的图像进行取反,使得药丸部分为白色。然后使用regionprops函数,得到了所有连通域的位置信息。最后,对所有的连通域使用rectangle函数进行标记。至此,完成了药丸部分的分割工作。

Alt text

测试其他图像

  • 基于上面的方法,我测试了对其他图像的效果。
  • 由下图可以看出,通过上面的一系列操作,我们成功地将图像水平校准,同时将药丸部分分割出来。不过,对于有残缺的药丸,分割效果不是很好。为此,接下来进行药丸残缺部分的检测。

Alt text

药丸残缺检测

二值化

  • 下图左侧为完好药丸与残缺药丸图像,而右侧为对应图像基于RGB空间中的B通道的二值化图像。我们可以看出,在B通道下残缺药丸与完好药丸有着明显的对比。基于此,我们可以将两幅二值图像相减,得到残缺药丸的位置。

Alt text

bw_source = im2bw(source_img(:,:,3), graythresh(source_img(:,:,3)));
bw_cmp = im2bw(cmp_img(:,:,3), graythresh(cmp_img(:,:,3)));
Figure;
subplot(2,2,1),imshow(source_img),subplot(2,2,2),imshow(bw_source);
subplot(2,2,3),imshow(cmp_img),subplot(2,2,4),imshow(bw_cmp);

图像差分法

  • 其实就是和完整的图片做差。

Alt text

figure,imshow(bw_source - bw_cmp);

形态学处理

  • 基于上一步骤,我们得到了只有残缺药丸部分的图像。然后,使用二值形态学的处理方法,对其进行开运算与闭运算,去除由于不重合产生的噪声部分。

Alt text

B=imopen(bw_source - bw_cmp,strel('disk',9));
B=imclose(B,strel('disk',20));
figure, imshow(B);

连通域标记

  • 基于上一步得到的只有残缺药丸部分的二值图像,我们使用连通域标记的方法,得到所有残缺部分的位置信息。然后,使用rectangle将这些位置标记出来。至此,完成了药丸残缺检测的工作。

Alt text

figure, imshow(source_img);
hold on;
for i=1:size(position,1)
	if position(i).BoundingBox(1) > 5
	rectangle('Position', position(i).BoundingBox, 'edgecolor','g', 'LineWidth', 2);
	end
end

总结一哈

  • 在图像水平矫正部分,我们主要使用的方法为:先对只有药板部分的二值图像进行边缘检测。然后,分析边缘图像在0-180°上的Radon变换,找出最大值点减去90°即为原图像旋转至水平的角度。由于分析时只将药板部分作为关注点,因此该方法适用于其它所有情况的药片图像矫正。

  • 在图像分割部分,我比较了原图像在RGB与YCbCr两空间的各通道的二值图像,发现在Y通道与Cb通道下的二值化图像可以拼凑出完整的药丸信息。经过调查,Cb通道下的图像受到的亮度影响小,而且描述的是RGB输入信号蓝色部分与RGB信号亮度值之同的差异。基于此,再使用Otsu法即可将药丸色度差异大的两部分区分开。如此一来,解决了无法获取完整药丸信息的问题。