kirsch原理:
Kirsch算子是R.Kirsch提出来一种边缘检测新算法,它采用8个模板对图像上的每一个像素点进行卷积求导数,这8个模板代表8个方向,对图像上的8个特定边缘方向作出最大响应,运算中取最大值作为图像的边缘输出(上述算法中用到的8个模板在下面的实现代码中给出)。为了便于读者理解该算法的实现,这里我们给出实现该算法的函数代码,读者可以稍加改动应用到自己的项目中去。
[1]
int ntemplate[8][9]={{5,5,5,-3,0,-3,-3,-3,-3},
{-3,5,5,-3,0,5,-3,-3,-3},
{-3,-3,5,-3,0,5,-3,-3,5},
{-3,-3,-3,-3,0,5,-3,5,5},
{-3,-3,-3,-3,0,-3,5,5,5},
{-3,-3,-3,5,0,-3,5,5,-3},
{5,-3,-3,5,0,-3,5,-3,-3},
{5,5,-3,5,0,-3,-3,-3,-3}};//3×3
用这个8个模版来计算每个边缘方向的最大响应值作为边缘特征值-边缘强度。
c++代码实现:
BOOL CWMSpatialDomain::Kirsch(HANDLE hImage)
{
int Nn=9;
int ntemplate[8][9]={{5,5,5,-3,0,-3,-3,-3,-3},
{-3,5,5,-3,0,5,-3,-3,-3},
{-3,-3,5,-3,0,5,-3,-3,5},
{-3,-3,-3,-3,0,5,-3,5,5},
{-3,-3,-3,-3,0,-3,5,5,5},
{-3,-3,-3,5,0,-3,5,5,-3},
{5,-3,-3,5,0,-3,5,-3,-3},
{5,5,-3,5,0,-3,-3,-3,-3}};//3×3
int nSum[8];
if(hImage==NULL)
{
WriteLog(TRA_LEVEL_WARN,_T("CImageWaterMarkTest::Kirsch, Image is null"));
return FALSE;
}
int i, j, k, l;
int bThre = 5;
BITMAPINFOHEADER ds;
memcpy(&ds,hImage, sizeof(ds));
int effwdt = ((((ds.biBitCount * ds.biWidth ) + 31) / 32) * 4);
BYTE* pbBits = (BYTE*)hImage + *(DWORD*)hImage + ds.biClrUsed * sizeof(RGBQUAD);
WriteLog(TRA_LEVEL_DEBUG,_T("CImageWaterMarkTest::Kirsch, Pic's width=%d, height=%d"),ds.biWidth,ds.biHeight);
switch (ds.biBitCount)
{
case 1: // 1-bit DIB
case 4: // 4-bit DIB
break;
case 8: // 8-bit DIB
{
int biWidth=ds.biWidth+2;
int biHeight=ds.biHeight+2;
long dwEffWidth = ((((ds.biBitCount * biWidth) + 31) / 32) * 4);
BYTE* pImage = new BYTE[dwEffWidth * biHeight];// copy the hImage to new pImage
memset(pImage,0,dwEffWidth * biHeight);
for (i=0; i {
for (j=0; j {
pImage[(i+1)*dwEffWidth+j+1] = pbBits[i*effwdt + j];
}
}
pImage[0]=pbBits[effwdt+1];
pImage[biWidth-1]=pbBits[effwdt+ds.biWidth-2];
pImage[dwEffWidth*(biHeight-1)]=pbBits[(ds.biHeight-2)*effwdt+1];
pImage[(dwEffWidth)*(biHeight)-1]=pbBits[(ds.biHeight-2)*effwdt+ds.biWidth-2];
for (j=0; j {
pImage[j+1] = pbBits[effwdt + j];
pImage[(biHeight-1)*dwEffWidth+j+1] = pbBits[(ds.biHeight-2)*effwdt + j];
}
for (i=0; i {
pImage[(i+1)*dwEffWidth] = pbBits[i*effwdt + 1];
pImage[(i+1)*dwEffWidth+biWidth-1] = pbBits[i*effwdt + ds.biWidth-2];
}
//SaveAsBmpFileEx(_T("Testfort.bmp"),8,dwEffWidth,biHeight,pImage);
m_ipFramework->ShowProgressCtrl();
for (i=0; i {
for (j=0; j {
int nIndex=0;
nSum[0]=nSum[1]=nSum[2]=nSum[3]=nSum[4]=nSum[5]=nSum[6]=nSum[7]=0;
for (k=i;k<=i+2;k++)
{
for (l=j;l<=j+2;l++)
{
nSum[0] += pImage[k*dwEffWidth+l] * ntemplate[0][nIndex];
nSum[1] += pImage[k*dwEffWidth+l] * ntemplate[1][nIndex];
nSum[2] += pImage[k*dwEffWidth+l] * ntemplate[2][nIndex];
nSum[3] += pImage[k*dwEffWidth+l] * ntemplate[3][nIndex];
nSum[4] += pImage[k*dwEffWidth+l] * ntemplate[4][nIndex];
nSum[5] += pImage[k*dwEffWidth+l] * ntemplate[5][nIndex];
nSum[6] += pImage[k*dwEffWidth+l] * ntemplate[6][nIndex];
nSum[7] += pImage[k*dwEffWidth+l] * ntemplate[7][nIndex];
nIndex++;
}
}
int nMax=0;
//取最大方向的导数;
for(k=0;k<8;k++)
{
if(nMax nMax=nSum[k];
}
if(nMax<0)
nMax=0;
if(nMax>255)
nMax=255;
if(nMax<255)
{
if(nMax>=bThre)
{
pbBits[i*effwdt + j]=nMax;
}
else
{
pbBits[i*effwdt + j]=0;
}
}
else
{
pbBits[i*effwdt + j]=255;
}
}
m_ipFramework->SetPosProgressCtrl(int((i+1)*100/ds.biHeight));
}
m_ipFramework->SetPosProgressCtrl(100);
m_ipFramework->HideProgressCtrl();
delete[] pImage;
}
break;
case 24: // 24-bit DIB
{
int biWidth=ds.biWidth+2;
int biHeight=ds.biHeight+2;
long dwEffWidth = ((((ds.biBitCount * biWidth) + 31) / 32) * 4);
BYTE* pImage = new BYTE[dwEffWidth * biHeight];// copy the hImage to new pImage
memset(pImage,0,dwEffWidth * biHeight);
int cb = 0;
int cg = 0;
int cr = 0;
for (i=0; i {
for (j=0; j {
BYTE *p1 = &pbBits[i*effwdt + j*3];
cb = *p1;cg = *(p1+1);cr = *(p1+2);
pImage[(i+1)*dwEffWidth+j+1] = RGB2GRAY(cr,cg,cb);
}
}
pImage[0]=RGB2GRAY(pbBits[effwdt+5],pbBits[effwdt+4],pbBits[effwdt+3]);
pImage[biWidth-1]=RGB2GRAY(pbBits[effwdt+(ds.biWidth-2)*3+2],pbBits[effwdt+(ds.biWidth-2)*3+1],pbBits[effwdt+(ds.biWidth-2)*3]);
pImage[dwEffWidth*(biHeight-1)]=RGB2GRAY(pbBits[(ds.biHeight-2)*effwdt+5],pbBits[(ds.biHeight-2)*effwdt+4],pbBits[(ds.biHeight-2)*effwdt+3]);
pImage[(dwEffWidth)*(biHeight)-1]=RGB2GRAY(pbBits[(ds.biHeight-2)*effwdt+(ds.biWidth-2)*3+2],pbBits[(ds.biHeight-2)*effwdt+(ds.biWidth-2)*3+1],pbBits[(ds.biHeight-2)*effwdt+(ds.biWidth-2)*3]);
for (j=0; j {
pImage[j+1] = RGB2GRAY(pbBits[effwdt + j*3+2],pbBits[effwdt + j*3+1],pbBits[effwdt + j*3]);
pImage[(biHeight-1)*dwEffWidth+j+1] = RGB2GRAY(pbBits[(ds.biHeight-2)*effwdt + j*3+2],pbBits[(ds.biHeight-2)*effwdt + j*3+1],pbBits[(ds.biHeight-2)*effwdt + j*3]);
}
for (i=0; i {
pImage[(i+1)*dwEffWidth] = RGB2GRAY(pbBits[i*effwdt + 5],pbBits[i*effwdt + 4],pbBits[i*effwdt + 3]);
pImage[(i+1)*dwEffWidth+biWidth-1] = RGB2GRAY(pbBits[i*effwdt + (ds.biWidth-2)*3+2],pbBits[i*effwdt + (ds.biWidth-2)*3+1],pbBits[i*effwdt + (ds.biWidth-2)*3]);
}
//SaveAsBmpFileEx(_T("Testfort.bmp"),8,dwEffWidth,biHeight,pImage);
m_ipFramework->ShowProgressCtrl();
for (i=0; i {
for (j=0; j {
int nIndex=0;
nSum[0]=nSum[1]=nSum[2]=nSum[3]=nSum[4]=nSum[5]=nSum[6]=nSum[7]=0;
for (k=i;k<=i+2;k++)
{
for (l=j;l<=j+2;l++)
{
nSum[0] += pImage[k*dwEffWidth+l] * ntemplate[0][nIndex];
nSum[1] += pImage[k*dwEffWidth+l] * ntemplate[1][nIndex];
nSum[2] += pImage[k*dwEffWidth+l] * ntemplate[2][nIndex];
nSum[3] += pImage[k*dwEffWidth+l] * ntemplate[3][nIndex];
nSum[4] += pImage[k*dwEffWidth+l] * ntemplate[4][nIndex];
nSum[5] += pImage[k*dwEffWidth+l] * ntemplate[5][nIndex];
nSum[6] += pImage[k*dwEffWidth+l] * ntemplate[6][nIndex];
nSum[7] += pImage[k*dwEffWidth+l] * ntemplate[7][nIndex];
nIndex++;
}
}
int nMax=0;
//取最大方向的导数;
for(k=0;k<8;k++)
{
nSum[k] = fabs(nSum[k]);
if(nMax nMax=nSum[k];
}
if(nMax<0)
nMax=0;
if(nMax>255)
nMax=255;
if(nMax<255)
{
if(nMax>=bThre)
{
pbBits[i*effwdt + j*3]=nMax;
pbBits[i*effwdt + j*3+1]=nMax;
pbBits[i*effwdt + j*3+2]=nMax;
}
else
{
pbBits[i*effwdt + j*3]=0;
pbBits[i*effwdt + j*3+1]=0;
pbBits[i*effwdt + j*3+2]=0;
}
}
else
{
pbBits[i*effwdt + j*3]=255;
pbBits[i*effwdt + j*3+1]=255;
pbBits[i*effwdt + j*3+2]=255;
}
}
m_ipFramework->SetPosProgressCtrl(int((i+1)*100/ds.biHeight));
}
m_ipFramework->SetPosProgressCtrl(100);
m_ipFramework->HideProgressCtrl();
delete[] pImage;
}
break;
default: // Unrecognized color format
WriteLog(TRA_LEVEL_WARN,_T("CImageWaterMarkTest::Kirsch, Unrecognized color format"));
return FALSE;
}
return TRUE;
}