击中击不中变换

首先给大家推荐一下我老师大神的人工智能教学网站。教学不仅零基础,通俗易懂,而且非常风趣幽默,还时不时有内涵黄段子!点这里可以跳转到网站

  击中击不中变换:形态学中用来检测形状的一个基本工具;检测不应该只限于形状,还有大小;我这里只写了二值图像的,对于灰度图还没试过;

  它的原理就是使用腐蚀;如果要在一幅图像A上找到B形状的目标,我们要做的是:

首先,建立一个比B大的模板W;使用此模板对图像A进行腐蚀,得到图像假设为Process1;

其次,用B减去W,从而得到V模板(W-B);使用V模板对图像A的补集进行腐蚀,得到图像假设为Process2;

然后,Process1与Process2取交集;得到的结果就是B的位置。这里的位置可能不是B的中心位置,要视W-B时对齐的位置而异;

  其实很简单,两次腐蚀,然后交集,结果就出来了;下面把我的处理的图像贴出来,见下。为了方便起见,本次处理我没有使用模板图像,代之以模板数据,当然了代码很乱;可能的话直接使用一幅模板图像会更好,更通用。关于代码,一会也贴下面,没有新建类,直接在一个函数中给处理了;

处理图像

处理后,形状检测的结果是一个点,但是太小了,我这里给加粗了!

形状检测

本次测试没有使用三角形,椭圆等,其实本质上都一样。。。。。。

关于代码,因为没有加新类,所以把那个函数放出来:

void CMyDIPView::OnMophoHit() { // TODO: Add your command handler code here CMyDIPDoc* pDoc = GetDocument(); unsigned char *lpSrc=NULL,*lpDest=NULL,*lpDest1=NULL,*lpDest2=NULL; int i,j; int nWidth=21,nHeight=21; int nWidthExtend=5,nHeightExtend=5; //搜索窗口扩展象素 int *pTemplet=NULL,*pTemplet1=NULL; ASSERT_VALID(pDoc); if(pDoc->m_hDIB == NULL) return ; LPSTR lpDIB = (LPSTR) ::GlobalLock((HGLOBAL) pDoc->m_hDIB); LPSTR lpDIBBits=::FindDIBBits (lpDIB); int cxDIB = (int) ::DIBWidth(lpDIB); // Size of DIB – x int cyDIB = (int) ::DIBHeight(lpDIB); // Size of DIB – y long lLineBytes = WIDTHBYTES(cxDIB * 8); // 计算图像每行的字节数 CExpend ce; ce.SetSrcImage(lpDIBBits); ce.SetWidthHeight(cxDIB,cyDIB); pTemplet=new int[nWidth*nHeight]; for(i=0;i<nWidth*nHeight;i++) { pTemplet[i]=1; } ce.SetTemplet(pTemplet,nWidth,nHeight); ce.Process(false); lpDest=(unsigned char*)ce.GetDestImage(); //第一次腐蚀的结果,保存起来 lpDest1=new unsigned char [cxDIB*cyDIB]; memcpy(lpDest1,lpDest,cxDIB*cyDIB); for(i = 0; i < cyDIB; i++) { // 每列 for(j = 0; j < cxDIB; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (cyDIB – 1 – i) + j; *lpSrc=lpDest[i*lLineBytes+j]; } } //第二次腐蚀 //先对图像进行反转,也就是求补 for(i = 0; i < cyDIB; i++) { // 每列 for(j = 0; j < cxDIB; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (cyDIB – 1 – i) + j; *lpSrc=255-*lpSrc; } } int nW,nH; pTemplet1=new int[(nWidth+nWidthExtend*2)*(nHeight+nHeightExtend*2)]; for(i=0;i<(nWidth+nWidthExtend*2)*(nHeight+nHeightExtend*2);i++) { nH=i/(nWidth+nWidthExtend*2); //求得矩阵坐标 nW=i%(nWidth+nWidthExtend*2); if(abs(nW-(nWidth+nWidthExtend*2)/2)>nWidthExtend|| abs(nH-(nHeight+nHeightExtend*2)/2)>nHeightExtend) {//扩展象素部分 pTemplet1[i]=1; } else pTemplet1[i]=0; } pTemplet1[(nWidth+nWidthExtend*2)*(nHeight+nHeightExtend*2)/2]=1; ce.SetTemplet(pTemplet1,(nWidth+nWidthExtend*2),(nHeight+nHeightExtend*2)); ce.Process(false); lpDest=(unsigned char*)ce.GetDestImage(); /* // 每行 for(i = 0; i < cyDIB; i++) { // 每列 for(j = 0; j < cxDIB; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (cyDIB – 1 – i) + j; *lpSrc=lpDest[i*lLineBytes+j]; } }*/ //第二次腐蚀的结果,保存起来 lpDest2=new unsigned char [cxDIB*cyDIB]; memcpy(lpDest2,lpDest,cxDIB*cyDIB); //把二次结果取交集 //显示击中的结果 // 每行 for(i = 0; i < cyDIB; i++) { // 每列 for(j = 0; j < cxDIB; j++) { // 指向DIB第i行,第j个象素的指针 lpSrc = (unsigned char*)lpDIBBits + lLineBytes * (cyDIB – 1 – i) + j; if(lpDest1[i*lLineBytes+j]==0&&lpDest2[i*lLineBytes+j]==0) *lpSrc=0; else *lpSrc=255; } } ::GlobalUnlock((HGLOBAL) pDoc->m_hDIB); Invalidate(TRUE); if(lpDest1) { delete []lpDest1; lpDest1=NULL; } if(lpDest2) { delete []lpDest2; lpDest2=NULL; } if(pTemplet) { delete []pTemplet; pTemplet=NULL; } if(pTemplet1) { delete []pTemplet1; pTemplet1=NULL; } }

好了,就到这里了,大家新年快乐!

点这里可以跳转到人工智能网站

发表评论