设计任务
图 28 是一幅正在运行的数字电表图像(ipa28.jpg),试采用图像处理与分析
技术,设计适当的算法和程序,找出电表的数显区域,计算目标区域的长宽比
和像素面积;并提取其中面积最大的 6 个数字字符。请按统一要求写出算法原
理、设计流程,并完成程序测试与分析等内容。
算法设计
解题思路:
运用阈值分割、开运算、取反等方法,使图像只剩下液晶显示屏上的数字和背景作为连通域;运用膨胀,使液晶显示屏上的每个数字都合成独立的一个连通域。之后只需找最小的6个连通域即可提取出数字。
设计方案说明:
先把图片转换为灰度图G,再进行阈值分割,条件为强度>200,得到二值图BW。此时液晶显示屏上数字区域的像素值都是0,使用较大阈值作用于bwareaopen函数(可以去掉小于某个面积的连通域),可以去掉一些比较亮的大区域,得到BW1。之后对BW1取反,使用小阈值作用于bwareaopen函数,去掉一些比较暗的区域,得到BW2。还有一些区域和数字的亮度接近,但是又比最小的数字的一部分(数字1的上部)大,所以进行膨胀操作,使数字连通成一个整体,得到BW3。再进行开运算,可以去掉不关心的区域,得到得到只有6个数字以及数显区域外面构成的7个连通域的BW4。将取反后的BW4作用于regionprops函数,可以得到数显区域的边界框,通过函数返回的结构体里Area、BoundingBox属性,可以得到包围区域的面积以及计算出长宽比。然后将BW4应用于bwlabel,提取出表示数字的连通区域即可。
关键算法的设计原理:
阈值分割:数显屏幕较亮,对于灰度图,取强度>某较大值进行阈值分割,可以在液晶屏中清楚分割数字、字符与屏幕,同时可以去掉一些强度为阈值以下的元素。
开运算:各个连通域组成的像素面积有差异,可以通过取反操作灵活进行以面积为阈值的开运算,去除不关心元素。
膨胀:对于液晶屏上显示的数字字符,其类似于七段数码管,“每段数码管”之间间隙小,可以选取适当大小的方形结构元素,膨胀使得“每段数码管”相连。
计算长宽比(宽高比):使用工具函数返回的长与宽(宽与高)计算。
算法步骤:
图1
算法步骤如图1,与程序流程完全一致。
程序设计
算法名称:阈值分割、开运算、取反、膨胀、边界框包围连通域、连通域分析
工具函数:
阈值分割:I_gray > 200,其中I_gray为原图像经灰度转换得到的灰度图。
开运算:bwareaopen。作用是去掉像素面积为某个阈值以下的连通域。
取反:~。
膨胀:strel函数和imdilate函数。
边界框包围连通域:regionprops。返回stats的BoundingBox字段中有四个属性,依次是矩形框左上角y坐标、矩形框左上角x坐标、矩形框宽(即题目中的长)、矩形框高(即题目中的宽)。
连通域分析:使用bwlabel函数,返回连通域的标签L和连通域总数num。
设计分析:符合题目要求。使用matlabr2020b版本。由于使用算法简单有效步骤少,时间复杂度O(I),空间复杂度O(I)(I为给定图像素数目),系统性能良好。
测试分析:
图2
图2从左到右,为原图→灰度图→阈值分割后图(阈值200)。
图3
图3从左到右,分别为开运算后图(阈值5000)→取反后开运算图(阈值255)→腐蚀后图(结构元素取12*5的矩形)→开运算后图(阈值1000)。
图4
图4为识别到数显区域的框图,准确度高。
图5
图5为各连通区域标注图。可看出图中有7个连通区域,取6个较小的连通区域,保存输出如图6~图11。满足要求。
图6 图7
图8 图9
图10 图11
图12
图12为数显区域长宽比和像素面积的结果,满足要求。
特点和优势:算法简单有效。
存在的问题和不足:边界框识别没有完全框住数显区域,可以使用透视变换优化。
代码
clc,clear
%% step1 -- 预处理
I = imread('ipa28.jpg');
I_gray = rgb2gray(I);
BW = I_gray > 200; % 阈值分割
%% step2 -- 开运算,去除不关心的元素
BW1 = bwareaopen(BW, 5000); % 假设小于5000像素的物体为噪声
BW2 = bwareaopen(~BW1,255);
%% step3 -- 膨胀图像,使数码管显示的数字成为一个整体
SE = strel('rectangle',[12,5]);
BW3 = imdilate(BW2, SE);
%% step4 -- 开运算,再次去除不关心的元素
BW4 = bwareaopen(BW3, 1000);
%% step5 -- 用边界框包围数显区域,得到像素面积计算边界框的宽高比并输出
stats = regionprops(~BW4, 'BoundingBox', 'Area');
bbox = stats.BoundingBox;
area = stats.Area;
aspect_ratio = bbox(3) / bbox(4);
disp("数显区域长宽比:"+num2str(aspect_ratio));
disp("数显区域面积:"+num2str(area));
%% step6 -- 对数显区域应用连通域分析,找到所有的数字字符
[L, num] = bwlabel(BW4); % 找到所有的连通区域,并用不同的标签表示
RGB = label2rgb(L); % 将标签转换为颜色图像
for k = 2:num
BW_k = (L == k); % 提取第k个连通区域的像素
imwrite(BW_k, sprintf('digit%d.png', k-1)); % 保存图像
end
%%
figure(1),subplot(131),imshow(I);title("原图");
subplot(132),imshow(I_gray);title("灰度图");
subplot(133),imshow(BW);title("阈值分割后图");
%%
figure(2),subplot(141),imshow(BW1);title("开运算");
subplot(142),imshow(BW2);title("取反后开运算");
subplot(143),imshow(BW3);title("经过膨胀");
subplot(144),imshow(BW4);title("继续开运算");
%% 画出边界框
figure(3),imshow(I);
hold on;
rectangle('Position', [bbox(1),bbox(2),bbox(3),bbox(4)], ...
'EdgeColor','r','LineWidth',2); % 绘制边界框
hold off;
%% 显示连通区域
figure(4),imshow(RGB); % 显示连通区域