在MIL系列连载的前8篇都是关于图像获取和输出的主题,从这一篇开始,主要的内容就图像处理。
在冈萨雷斯的《数字图像处理》的序言中将图像处理分为如下三类
1.低级处理,主要是用于图像的预处理和增强操作,输入和输出都是图像,在MIL中对应Mim...模块
2.中级处理,主要是对象识别、分析和测量,输入是图像,输出是从图像中提取的属性(如边缘、轮廓、位置、距离等等),在MIL中对应Mblob、Mcode、Medge、Mim、Mmeas、Mmod.、Mocr、Mpat模块
3.高级处理,主要是对提取出属性结合其他属性综合判断得出最优解,这个涉及到很多算法,如采用常见的神经网络算法来提高识别对象的准确率
在这里,我先从中级处理来讲,这样保证第一时间了解如何从图像获取信息以反馈到控制系统实现真正的机器视觉。
所谓匹配就是在图形中查找指定的图像和特征。匹配包括灰度匹配和几何匹配。灰度匹配忽略实际的图像各个物体的构成含义,最简单的灰度匹配就是暴力的像素点和像素点的匹配,实际中通用灰度匹配算法是计算两个图像矩阵的相关(或卷积)。几何匹配则偏向关心图像中物体的构成含义,打个比方在图像中查找三角形就是常见的几何匹配,通用几何匹配的方法是由边缘检测结果得到各个边缘拐点构成的点链(Edge element Chain)进行统计匹配。相比灰度匹配,几何匹配的鲁棒性要好的多(对光照、放大缩小、旋转等偏移的容忍大)。
MIL中提供的几何匹配和灰度匹配是Mmod和Mpat模块,采用的都是通用的匹配算法。在实际应用过程中,对某些要求较高的场合需要自行编写和优化匹配算法。
对于MIL中的中级操作,处理流程遵循如下规则:
分配对象->设置对象->(预处理对象)->用该对象对目标图像进行操作->获取结果
本篇博文要讲的是如何使用MIL的几何匹配模块Mmod,具体算法请参见其他书籍,其操作流程如下
1.使用MmodAlloc分配mod 对象。mod对象好比一个容器,mod对象中可添加多个几何(Model)模型,这样搜索的时候同时搜索,加快了搜索速度。
2.使用MmodDefine或MmodDefineFromFile向mod对象中添加待匹配的几何(Model)模型。
MIL支持的mod模型类型如下:
(1).图像类型(Image-type)
(2).边缘查找结果(Edge Finder-type)
(3).模型查找结果(Model Finder-type)
(4).两个模型合并(Merge-type)
(5).合成模型(Synthetic models),指预先定义的模型如长方形、正方形、三角形等和从CAD文件导入的模型
3.使用MmodMask和MmodContorl对mod对象和其中的几何(Model)模型进行设置。
(1).MmodMask为指定的model模型设置蒙版
(2).MmodControl控制mod对象的预处理时的光滑程度M_SMOOTHNESS和边缘细腻程度M_DETAIL_LEVEL及匹配速度M_SPEED
(3).MmodControl控制mod对象中指定的模型匹配时的位置范围(M_SEARCH_POSITION_RANGE),角度范围(M_SEARCH_ANGLE_RANGE)和缩放比范围(M_SEARCH_SCALE_RANGE)的开启(M_ENABLE或M_DISABLE)
其中,
M_ENABLE时使用M_POSITION_DELTA_NEG_X, M_POSITION_DELTA_NEG_Y, M_POSITION_DELTA_POS_X和M_POSITION_DELTA_POS_Y控制位置范围,每个取值都在0~M_INFINITE之间;
M_DISABLE时使用M_POSITION_X和M_POSITION_Y设置具体的搜索位置;
M_ENABLE时使用M_ANGLE_DELTA_POS和M_ANGLE_DELTA_NEG控制角度范围,每个取值都在0~180之间;
M_DISABLE时使用M_ANGLE设置具体的搜索角度;
M_ENABLE时使用M_SCALE_MAX_FACTOR (1.0~2.0)和M_SCALE_MIN_FACTOR (0.5 ~1.0)控制缩放比范围;
M_DISABLE时使用M_SCALE设置具体的搜索缩放比.
(4).MmodControl控制mod对象中指定的模型匹配时的合格匹配得分(Acceptance levels)M_ACCEPTANCE和M_ACCEPTANCE_TARGET、确认匹配得分(Certainty levels)M_CERTAINTY和M_ACCEPTANCE_TARGET。这里合格匹配得分即可以认为是一个匹配,但是具体的确定还要等到搜索完所有的匹配后排序取排名靠前的匹配再和确定匹配分数线比对;确定匹配得分即在搜索完后,取合格匹配中排名靠前的匹配,如果他们的得分能够超过确定匹配得分线则认为是搜索得到了一个匹配,否则认为没有找到对应匹配。
其中,Acceptance levels和Certainty levels中控制的Score分为M_SCORE和M_TARGET_SCORE
M_SCORE是衡量Model在Target Image中搜索时的匹配程度,匹配度越高,得分越高。
M_TARGET_SCORE是衡量在Target Image中非Model部分占得比例,占得比例越高,得分越低。
几何匹配有很多参数,这里只列举常用的,其它参见手册
4.对mod对象中的模型进行预处理
预处理过程主要是根据设置的参数计算边缘拐点等等
5.使用MmodAllocResult分配查询结果集和使用MmodFind开启查找
6.使用MmodGetResult分析获取指定类型的结果
常用的结果参数如位置、角度、缩放比等
可使用MmodDraw来绘制Model和查找结果
void CModelDlg::OnReadSingle() { // TODO: Add your control notification handler code here if (M_NULL == m_milImageSingle) { MbufFree(m_milImageSingle); m_milImageSingle = M_NULL; } //读入图像 MbufRestore(TEXT(".\\Image\\SingleModel.mim"), m_milSystem, &m_milImageSingle); //显示图像 MdispControl(m_milDisplay, M_OVERLAY_CLEAR, M_DEFAULT); MdispZoom(m_milDisplay, 0.9, 0.9); MdispControl(m_milDisplay, M_CENTER_DISPLAY, M_ENABLE); MdispSelectWindow(m_milDisplay, m_milImageSingle, GetDlgItem(IDP_DISP_IMAGE)->GetSafeHwnd()); }分配、设置及预处理Model
void CModelDlg::OnSetSingle() { // TODO: Add your control notification handler code here if (M_NULL != m_milModelContextSingle) { MmodFree(m_milModelContextSingle); m_milModelContextSingle = M_NULL; } //分配Model Context MmodAlloc(m_milSystem, M_GEOMETRIC, M_DEFAULT, &m_milModelContextSingle); //定义Model MmodDefine(m_milModelContextSingle, M_IMAGE, m_milImageSingle, MODEL_OFFSETX, MODEL_OFFSETY, MODEL_SIZEX, MODEL_SIZEY); //设置Context和Model MmodControl(m_milModelContextSingle, M_CONTEXT, M_SPEED, SINGLE_MODEL_SEARCH_SPEED);//定义搜索速度 //预处理 MmodPreprocess(m_milModelContextSingle, M_DEFAULT); //绘制Model MdispControl(m_milDisplay, M_OVERLAY, M_ENABLE); MdispControl(m_milDisplay, M_OVERLAY_CLEAR, M_DEFAULT); MdispInquire(m_milDisplay, M_OVERLAY_ID, &m_milOverlaySingle); MgraColor(M_DEFAULT, M_COLOR_BLUE); MmodDraw(M_DEFAULT, m_milModelContextSingle, m_milOverlaySingle, M_DRAW_BOX+M_DRAW_POSITION, 0, M_ORIGINAL); }读入单目标搜索的目标图像
void CModelDlg::OnReadtargetSingle() { // TODO: Add your control notification handler code here if (M_NULL == m_milImageSingle) { MbufFree(m_milImageSingle); m_milImageSingle = M_NULL; } //读入图像 MbufRestore(TEXT(".\\Image\\SingleTarget.mim"), m_milSystem, &m_milImageSingle); //显示图像 MdispControl(m_milDisplay, M_OVERLAY_CLEAR, M_DEFAULT); MdispSelectWindow(m_milDisplay, M_NULL, M_NULL); MdispZoom(m_milDisplay, 0.9, 0.9); MdispControl(m_milDisplay, M_CENTER_DISPLAY, M_ENABLE); MdispSelectWindow(m_milDisplay, m_milImageSingle, GetDlgItem(IDP_DISP_IMAGE)->GetSafeHwnd()); }开启查找并 分析获得结果
void CModelDlg::OnFindSingle() { // TODO: Add your control notification handler code here if (M_NULL != m_milResultSingle) { MmodFree(m_milResultSingle); m_milResultSingle = M_NULL; } //分配查找结果集 MmodAllocResult(m_milSystem, M_DEFAULT, &m_milResultSingle); //伪查找,生成Model Cache MmodFind(m_milModelContextSingle, m_milImageSingle, m_milResultSingle); //开启查找 double Time; MappTimer(M_TIMER_RESET+M_SYNCHRONOUS, M_NULL); MmodFind(m_milModelContextSingle, m_milImageSingle, m_milResultSingle); MappTimer(M_TIMER_READ+M_SYNCHRONOUS, &Time); /************************************************************************/ /*获得和分析查找结果*/ /************************************************************************/ long Model[MODEL_MAX_OCCURRENCES]; /* Model index. */ double Score[MODEL_MAX_OCCURRENCES], /* Model correlation score.*/ XPosition[MODEL_MAX_OCCURRENCES], /* Model X position. */ YPosition[MODEL_MAX_OCCURRENCES], /* Model Y position. */ Angle[MODEL_MAX_OCCURRENCES], /* Model occurrence angle. */ Scale[MODEL_MAX_OCCURRENCES]; /* Model occurrence scale. */ MmodGetResult(m_milResultSingle, M_DEFAULT, M_NUMBER+M_TYPE_LONG, &m_nNumResultSingle);//个数 if ( (m_nNumResultSingle >= 1) && (m_nNumResultSingle <= MODEL_MAX_OCCURRENCES) ) { //查找结果中解析数据 MmodGetResult(m_milResultSingle, M_DEFAULT, M_INDEX+M_TYPE_LONG, Model); MmodGetResult(m_milResultSingle, M_DEFAULT, M_POSITION_X, XPosition); MmodGetResult(m_milResultSingle, M_DEFAULT, M_POSITION_Y, YPosition); MmodGetResult(m_milResultSingle, M_DEFAULT, M_ANGLE, Angle); MmodGetResult(m_milResultSingle, M_DEFAULT, M_SCALE, Scale); MmodGetResult(m_milResultSingle, M_DEFAULT, M_SCORE, Score); //绘制查找结果 MdispControl(m_milDisplay, M_OVERLAY, M_ENABLE); MdispControl(m_milDisplay, M_OVERLAY_CLEAR, M_DEFAULT); MdispInquire(m_milDisplay, M_OVERLAY_ID, &m_milOverlaySingle); MgraColor(M_DEFAULT, M_COLOR_RED); int i; for (i=0; i<m_nNumResultSingle; i++) { MmodDraw(M_DEFAULT, m_milResultSingle, m_milOverlaySingle, M_DRAW_EDGES+M_DRAW_BOX+M_DRAW_POSITION, i, M_DEFAULT); } //弹出框显示查找结果 CString csResult; for (i=0; i<m_nNumResultSingle; i++) { csResult.Format(TEXT("Result:%-9dModel:%-8dX:%-13.2fY:%-13.2fAngle:%-8.2fScale:%-8.2fScore:%-5.2f%%"), i, Model[i], XPosition[i], YPosition[i], Angle[i], Scale[i], Score[i]); MessageBox(csResult); } csResult.Format(TEXT("查找总时间:%.1f ms"), Time*1000.0); MessageBox(csResult); } else { MessageBox(TEXT("没有查找到对应模型或者查找到的模型个数比最大允许值还大!")); } }
void CModelDlg::OnReadMulti() { // TODO: Add your control notification handler code here if (M_NULL == m_milImageMulti) { MbufFree(m_milImageMulti); m_milImageMulti = M_NULL; } //读入图像 MbufRestore(TEXT(".\\Image\\MultiModel.mim"), m_milSystem, &m_milImageMulti); //显示图像 MdispControl(m_milDisplay, M_OVERLAY_CLEAR, M_DEFAULT); MdispZoom(m_milDisplay, 0.9, 0.9); MdispControl(m_milDisplay, M_CENTER_DISPLAY, M_ENABLE); MdispSelectWindow(m_milDisplay, m_milImageMulti, GetDlgItem(IDP_DISP_IMAGE)->GetSafeHwnd()); }分配、设置及预处理Model
void CModelDlg::OnSetMulti() { // TODO: Add your control notification handler code here if (M_NULL != m_milModelContextMulti) { MmodFree(m_milModelContextMulti); m_milModelContextMulti = M_NULL; } //分配Model Context MmodAlloc(m_milSystem, M_GEOMETRIC, M_DEFAULT, &m_milModelContextMulti); //定义Model long ModelsOffsetX[MODELS_ARRAY_SIZE] = MODELS_OFFSETX, /* Model X offsets array. */ ModelsOffsetY[MODELS_ARRAY_SIZE] = MODELS_OFFSETY, /* Model Y offsets array. */ ModelsSizeX[MODELS_ARRAY_SIZE] = MODELS_SIZEX, /* Model X sizes array. */ ModelsSizeY[MODELS_ARRAY_SIZE] = MODELS_SIZEY; /* Model Y sizes array. */ int i; for (i=0; i<NUMBER_OF_MODELS; i++) { MmodDefine(m_milModelContextMulti, M_IMAGE, m_milImageMulti, ModelsOffsetX[i], ModelsOffsetY[i], ModelsSizeX[i], ModelsSizeY[i]); } /*设置Context和Model*/ MmodControl(m_milModelContextMulti, M_CONTEXT, M_SPEED, MULTI_MODELS_SEARCH_SPEED);//定义搜索速度 MmodControl(m_milModelContextMulti, M_CONTEXT, M_SMOOTHNESS, 75); MmodControl(m_milModelContextMulti, M_DEFAULT, M_ACCEPTANCE, 40); MmodControl(m_milModelContextMulti, M_DEFAULT, M_CERTAINTY, 60); MmodControl(m_milModelContextMulti, M_DEFAULT, M_NUMBER, 2);//最大查找两个 #if (NUMBER_OF_MODELS>1) /* Change the reference point of the second model. */ MmodControl(m_milModelContextMulti, 1, M_REFERENCE_X, MODEL1_REFERENCEX); MmodControl(m_milModelContextMulti, 1, M_REFERENCE_Y, MODEL1_REFERENCEY); #if (NUMBER_OF_MODELS>2) /* Change the reference point of the third model. */ MmodControl(m_milModelContextMulti, 2, M_REFERENCE_X, MODEL2_REFERENCEX); MmodControl(m_milModelContextMulti, 2, M_REFERENCE_Y, MODEL2_REFERENCEY); #endif #endif //预处理 MmodPreprocess(m_milModelContextMulti, M_DEFAULT); //绘制Model MdispControl(m_milDisplay, M_OVERLAY, M_ENABLE); MdispControl(m_milDisplay, M_OVERLAY_CLEAR, M_DEFAULT); MdispInquire(m_milDisplay, M_OVERLAY_ID, &m_milOverlayMulti); MgraColor(M_DEFAULT, M_COLOR_BLUE); for (i=0; i<NUMBER_OF_MODELS; i++) { MmodDraw( M_DEFAULT, m_milModelContextMulti, m_milOverlayMulti, M_DRAW_BOX+M_DRAW_POSITION, i, M_ORIGINAL); } }读入多目标搜索的目标图像
void CModelDlg::OnReadtargetMulti() { // TODO: Add your control notification handler code here if (M_NULL == m_milImageMulti) { MbufFree(m_milImageMulti); m_milImageMulti = M_NULL; } //读入图像 MbufRestore(TEXT(".\\Image\\MultiTarget.mim"), m_milSystem, &m_milImageMulti); //显示图像 MdispControl(m_milDisplay, M_OVERLAY_CLEAR, M_DEFAULT); MdispSelectWindow(m_milDisplay, M_NULL, M_NULL); MdispZoom(m_milDisplay, 0.9, 0.9); MdispControl(m_milDisplay, M_CENTER_DISPLAY, M_ENABLE); MdispSelectWindow(m_milDisplay, m_milImageMulti, GetDlgItem(IDP_DISP_IMAGE)->GetSafeHwnd()); }开启查找并 分析获得结果
void CModelDlg::OnFindMulti() { // TODO: Add your control notification handler code here if (M_NULL != m_milResultMulti) { MmodFree(m_milResultMulti); m_milResultMulti = M_NULL; } //分配查找结果集 MmodAllocResult(m_milSystem, M_DEFAULT, &m_milResultMulti); //伪查找,生成Model Cache MmodFind(m_milModelContextMulti, m_milImageMulti, m_milResultMulti); //开启查找 double Time; MappTimer(M_TIMER_RESET+M_SYNCHRONOUS, M_NULL); MmodFind(m_milModelContextMulti, m_milImageMulti, m_milResultMulti); MappTimer(M_TIMER_READ+M_SYNCHRONOUS, &Time); /************************************************************************/ /*获得和分析查找结果*/ /************************************************************************/ long Model[MODELS_MAX_OCCURRENCES]; /* Model index. */ double Score[MODELS_MAX_OCCURRENCES], /* Model correlation score.*/ XPosition[MODELS_MAX_OCCURRENCES], /* Model X position. */ YPosition[MODELS_MAX_OCCURRENCES], /* Model Y position. */ Angle[MODELS_MAX_OCCURRENCES], /* Model occurrence angle. */ Scale[MODELS_MAX_OCCURRENCES]; /* Model occurrence scale. */ MmodGetResult(m_milResultMulti, M_DEFAULT, M_NUMBER+M_TYPE_LONG, &m_nNumResultMulti);//个数 if ( (m_nNumResultMulti >= 1) && (m_nNumResultMulti <= MODELS_MAX_OCCURRENCES) ) { //查找结果中解析数据 MmodGetResult(m_milResultMulti, M_DEFAULT, M_INDEX+M_TYPE_LONG, Model); MmodGetResult(m_milResultMulti, M_DEFAULT, M_POSITION_X, XPosition); MmodGetResult(m_milResultMulti, M_DEFAULT, M_POSITION_Y, YPosition); MmodGetResult(m_milResultMulti, M_DEFAULT, M_ANGLE, Angle); MmodGetResult(m_milResultMulti, M_DEFAULT, M_SCALE, Scale); MmodGetResult(m_milResultMulti, M_DEFAULT, M_SCORE, Score); //绘制查找结果 MdispControl(m_milDisplay, M_OVERLAY, M_ENABLE); MdispControl(m_milDisplay, M_OVERLAY_CLEAR, M_DEFAULT); MdispInquire(m_milDisplay, M_OVERLAY_ID, &m_milOverlayMulti); MgraColor(M_DEFAULT, M_COLOR_RED); int i; for (i=0; i<m_nNumResultMulti; i++) { MmodDraw(M_DEFAULT, m_milResultMulti, m_milOverlayMulti, M_DRAW_EDGES+M_DRAW_BOX+M_DRAW_POSITION, i, M_DEFAULT); } //弹出框显示查找结果 CString csResult; for (i=0; i<m_nNumResultMulti; i++) { csResult.Format(TEXT("Result:%-9dModel:%-8dX:%-13.2fY:%-13.2fAngle:%-8.2fScale:%-8.2fScore:%-5.2f%%"), i, Model[i], XPosition[i], YPosition[i], Angle[i], Scale[i], Score[i]); MessageBox(csResult); } csResult.Format(TEXT("查找总时间:%.1f ms"), Time*1000.0); MessageBox(csResult); } else { MessageBox(TEXT("没有查找到对应模型或者查找到的模型个数比最大允许值还大!")); } }