matlab:圆形的图像识别(一)
图像的预处理与图像分割都是图像识别的基础。图像识别技术在不同领域的应用,对图像的预处理和图像分割有着不同的技术要求。在现有的实际应用中,数字图像处理技术往往所需处理的图像信息量巨大,同时图像采集装置在采集图像时,受到多种因素的影响,如环境条件、视觉性能、光照强度、温度等。所以图像识别技术更好的应用依然是多学科领域研究的重点。本节将以图像识别技术在工业包装领域对药丸进行计数的应用实例,介绍如何通过图
图像的预处理与图像分割都是图像识别的基础。图像识别技术在不同领域的应用,对图像的预处理和图像分割有着不同的技术要求。在现有的实际应用中,数字图像处理技术往往所需处理的图像信息量巨大,同时图像采集装置在采集图像时,受到多种因素的影响,如环境条件、视觉性能、光照强度、温度等。所以图像识别技术更好的应用依然是多学科领域研究的重点。
本节将以图像识别技术在工业包装领域对药丸进行计数的应用实例,介绍如何通过图像识别技术识别给定图像中药品的个数,从而实现药品包装计数的功能。
1.使用MATLAB工具箱函数进行图像处理
(1)读入图像。在MATLAB命令窗口输入如下代码:
clear;
close all
I=imread('pill.png');
figure,imshow(I);
运行程序结果,读取的原始图像如图12.7所示。
(2)由于该图像为彩色RGB格式图像,而将图像转换为灰度图像进行处理,才能充分发挥MATLAB语言进行图像分析的特长。可以通过以下程序代码将图像进行格式转换,原始灰度图像如图12.8所示,转换后图像显示效果如图12.9所示。在MATLAB命令窗口中输入如下程序代码:
i=rgb2gray(I);
figure, imshow(i);
figure,imhist(i);title('直方图');
程序运行结果如图12.8和图12.9所示。

(3)从灰度图像以及直方图可以判断,图像的灰度值在范围[30 140]之间,灰度值所属区域不到整个范围的一半。为调整图像清晰度,提高图像质量,对图像进行中值滤波处理。在MATLAB命令窗口输入如下指令代码:
F0=imadjust(i,stretchlim(i),[0 1]);
Ft=medfilt2(F0,[5 5]);
figure,imshow(Ft);
figure, imhist(Ft);title('直方图');
程序运行,处理后的图像如图12.10和图12.11所示。

(4)图像经过滤波处理后,图像的预处理过程结束,已经获得了比较清晰的原始图像的灰度图。下面将对图像进行图像分割处理,提取所需目标的特征。由于目标图像与背景有较大区别,可以利用灰度的梯度信息来实现图像分割。通过图像分割,将原始图像中目标药丸显示为黑色,背景区域显示为白色。在MATLAB命令窗口中输入如下代码:
level=graythresh(Ft);
BW=im2bw(Ft,level);
imshow(BW);
程序运行,处理后的图像如图12.12所示。
(5)执行程序后,从图12.12可以看出,目标图像间存在连接状态,这不利于实现正确计数,故在图像分割时所取阈值并不合适。可以从MATLAB的Workspace中读取阈值level的值为0.4353,通过给定这个阈值来获得更好的图像分割效果。需要采取实验的方法评估level的值增加或者减小对图像的影响,通过实验取值分析,最后获得合适的阈值为level=0.3,图像效果如图12.13所示。

(6)边缘检测,通过阈值分割后,下面将对图像进行边缘检测,将采用sobel算子进行边缘检测。在MATLAB命令窗口输入如下代码:
BW1=edge(BW,'sobel',0.3);
imshow(BW1);
程序运行后,检测后的图像如图12.14所示。

(7)从图像边缘检测图像可以看出,药丸的形状不是标准的圆形,且在图像边缘处存在不完整的图形,需要将图像中药丸的形状进行调整,并且删去图像边缘不完整的图形。具体要通过膨胀和填充操作实现,即对图像边缘进行膨胀处理,补全药丸的缺口,然后利用填充命令进行闭合区域的填充。在MATLAB命令窗口中输入如下代码:
se90=strel('line',7,90);
se0=strel('line',7,0);
BW2=imdilate(BW1,[se90,se0]);
figure,imshow(BW2);
BW3=imfill(BW2,'holes');
figure,imshow(BW3);
运行程序,实现后的效果如图12.15和图12.16所示。

(8)经过膨胀和填充处理后图像中依然存在不完整的图像元素,需要删去图像边缘不完整的图形。通过移除与边界相连通的目标,在MATLAB命令窗口中输入如下代码:
BW4=imclearborder(BW3,4);
figure,imshow(BW4);
运行程序,得到如图12.17所示结果。
(9)最后通过统计计算函数,计算图像中药丸数目。在MATLAB命令窗口输入如下代码:
[labeled numpills]=bwlabel(BW4,4);

numpills
numpills =
10
可见计算结果与实际图像中的结果相符,从而实现了通过图像识别进行药丸计数的功能。
2.使用Visual C++设计界面并调用MATLAB引擎
使用Visual C++设计的界面如图12.18所示,包括图像预处理、图像处理和识别、计数结果查看等功能。其中,图像预处理包括打开原始图像、处理成灰度图像、中值滤波处理等功能,图像处理和识别包括图像分割处理、图像边缘检测、图像膨胀填充处理和删除不清晰边缘等功能。按照功能设定相应的按钮,添加一个编辑框控件显示计数结果值,用显示图像的Picture控件来显示要识别的原始图像。

为了在界面的Picture控件上显示原始图像,需要在对话框类的OnPaint()函数中添加以下代码:
void CTestMatlabEngineDlg::OnPaint()
{
CBitmap bmp;
HBITMAP hbmp;
CString strpicname;
//将pStatic指向要显示图片的地方
CStatic *pPicture;
pPicture=(CStatic*)GetDlgItem(IDC_PICTURE);//IDC_PHOTO为picture控件ID
strpicname="D:\\VCMatlabTest\\PillCaculation\\pill.bmp";
//加载资源 hbmp=(HBITMAP)::LoadImage(NULL,strpicname,IMAGE_BITMAP, 0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);//strpicname为图片的名字
bmp.Attach(hbmp);//获得加载图片的句柄
//获取图片格式
BITMAP bmInfo;
bmp.GetBitmap(&bmInfo);
//创建设备内存
CDC dcMem;
dcMem.CreateCompatibleDC(GetDC());
CBitmap *pOldmap=(CBitmap*)dcMem.SelectObject(bmp);
//获得矩形区域
CRect lRect;
pPicture->GetClientRect(&lRect);
// ScreenToClient(&lRect);
//显示位图
pPicture->GetDC()->StretchBlt(lRect.left,lRect.top,lRect.Width(),lRect. Height(),&dcMem,0,0,bmInfo.bmWidth,bmInfo.bmHeight,SRCCOPY);
dcMem.SelectObject(&pOldmap);
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
实现图像处理、识别和药丸计数的程序代码如下:
Engine *ep;
mxArray *count=NULL; //定义mxArray类型变量指针
double *Result; //定义double变量指针
if(!(ep=engOpen(NULL)))
::MessageBox(NULL,"不能启动MATLAB engine"," Visual C++调用matlab engine示例程序",MB_OK);
engEvalString(ep,"[FileName,PathName] = uigetfile('*.*','选择二值图像文件');");
engEvalString(ep,"imfile = strcat(PathName,FileName);");
engEvalString(ep,"I=imread(imfile);");
engEvalString(ep,"i=rgb2gray(I);");
engEvalString(ep,"F0=imadjust(i,stretchlim(i),[0 1]);");
engEvalString(ep,"Ft=medfilt2(F0,[5 5]);");
engEvalString(ep,"level=graythresh(Ft);");
engEvalString(ep,"BW=im2bw(Ft,level);");
engEvalString(ep,"BW1=edge(BW,'sobel',0.3);");
engEvalString(ep,"se90=strel('line',7,90);");
engEvalString(ep,"se0=strel('line',7,0);");
engEvalString(ep,"BW2=imdilate(BW1,[se90,se0]);");
engEvalString(ep,"BW3=imfill(BW2,'holes');");
engEvalString(ep,"BW4=imclearborder(BW3,4);");
engEvalString(ep,"[labeled numpills]=bwlabel(BW4,4);");
count = engGetVariable(ep,"numpills");
Result = mxGetPr(count);
CString Result_str;
int m_intResult;
m_intResult = (int)(Result[0]+0.5); //double转换为整型
Result_str.Format( "%d ",m_intResult); //整型转换为CString型
SetDlgItemText(IDC_EDIT1,Result_str); //计数结果写到Edit控件上面
::MessageBox(NULL,"按下任意键继续"," Visual C++调用matlab引擎",MB_OK);
engClose(ep);
程序编译运行后的主界面如图12.19所示。单击“计数结果”按钮,将在Edit控件上显示计数结果为10,和直接使用MATLAB进行统计的数据结果相符合。

更多推荐


所有评论(0)