📄 imganalyse.cpp
字号:
// ImgAnalyse.cpp: implementation of the CImgAnalyse class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "dip.h"
#include "ImgAnalyse.h"
#include "math.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
IMPLEMENT_DYNCREATE(CImgAnalyse, CObject)
//Diagnostics and dump member functions, overridden
#ifdef _DEBUG
void CImgAnalyse::Dump(CDumpContext &dc) const
{
//call base class function first
CObject::Dump(dc);
}
#endif
#ifdef _DEBUG
void CImgAnalyse::AssertValid() const
{
//call inherited AssertValid first
CObject::AssertValid();
//Check CDibObject members...
ASSERT(m_pDibObject != NULL); //Must exist
}
#endif
/***********************************************************************
* *
* 图像特征分析类 *
* *
***********************************************************************/
////////////////////////////////////////////////////////////////////////
//构造函数CImgAnalyse()
//----------------------------------------------------------------------
//基本功能:构造一个CImgAnalyse类的对象,如不传入CDibObject对象。第
// 一次调用某一个处理函数时必须给出一个CDibObject对象指针。
//----------------------------------------------------------------------
//参数说明:无
//----------------------------------------------------------------------
//返 回:无
//----------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////
CImgAnalyse::CImgAnalyse()
{
}
////////////////////////////////////////////////////////////////////////
//构造函数CImgAnalyse()
//----------------------------------------------------------------------
//基本功能:构造一个CImgAnalyse类的对象并传入CDibObject对象。所有的
// 操作都针对该对象,直到另一个对象作为参数被传给图像处理函数。
//----------------------------------------------------------------------
//参数说明:无
//----------------------------------------------------------------------
//返 回:无
//----------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////
CImgAnalyse::CImgAnalyse( CDibObject *pDibObject )
{
m_pDibObject = pDibObject;
}
CImgAnalyse::~CImgAnalyse()
{
}
////////////////////////////////////////////////////////////////////////
//void SetDibObjectClass(CDibObject *pDibObject)
//----------------------------------------------------------------------
//基本功能:本函数为CImgAnalyse类对象指定一个CDibObject对象指针
//----------------------------------------------------------------------
//参数说明:CDibObject *pDibObject, 默认为NULL。
//----------------------------------------------------------------------
//返 回:无。
//----------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////
void CImgAnalyse::SetDibObjectClass( CDibObject *pDibObject )
{
m_pDibObject = pDibObject;
}
////////////////////////////////////////////////////////////////////////
//函数:BOOL EdgeTrace(CDibObject *pDibObject)
//功能:对灰度图像进行轮廓跟踪并生成链码,结果存储在TraceArray中
//说明:只对二值化后的灰度图像跟踪一个连通成分;
// 跟踪之前,应滤除噪声,建议使用灰值 闭运算去噪并平滑边界。
//返回:跟踪成功则返回TRUE
////////////////////////////////////////////////////////////////////////
BOOL CImgAnalyse::EdgeTrace(CDibObject *pDibObject)
{
if(m_pDibObject==NULL) return FALSE;
if(m_pDibObject->GetNumBits()!=8){AfxMessageBox("不是8位灰度图像");return FALSE;}
unsigned char *pOld,*pBits,*pTemp,*pNew,*pNewBits,*pNewTemp;
int nWidthBytes, nNumColors;
DWORD offset,BufSize;
pOld = (BYTE *) m_pDibObject->GetDIBPointer(&nWidthBytes);
if(pOld == NULL) return FALSE;
nNumColors = m_pDibObject->GetNumColors();
offset=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+nNumColors*sizeof(RGBQUAD);
pBits =(unsigned char *)&pOld[offset];
int nHeight=m_pDibObject->GetHeight();
int nWidth=m_pDibObject->GetWidth();
BufSize=nWidthBytes*nHeight ;
HGLOBAL hNewDib;
hNewDib = ::GlobalAlloc(GHND,offset+BufSize );
if( hNewDib == NULL ){
m_pDibObject->m_nLastError = IMAGELIB_MEMORY_ALLOCATION_ERROR;
::GlobalUnlock( m_pDibObject->GetDib() );
return FALSE;}
pNew = (unsigned char *) ::GlobalLock( hNewDib );
if( pNew == NULL )
{
::GlobalFree( hNewDib );
m_pDibObject->m_nLastError = IMAGELIB_MEMORY_LOCK_ERROR;
::GlobalUnlock( m_pDibObject->GetDib());
return FALSE;
}
pNewBits = (unsigned char *)&pNew[offset];
memcpy(pNew,pOld,offset);
//设定初始值为255
memset(pNewBits,(BYTE)255,BufSize);
//是否找到起始点及回到起始点
bool bFindStartPoint;
//是否扫描到一个边界点
bool bFindPoint;
//起始边界点与当前边界点
CPoint StartPoint,CurPoint;
//八个方向和起始扫描方向,依次是左上方、上方、右上方、右方、右下方、下方、左下方和左方。
int Direction[8][2]={{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0}};
int BeginDirect;
//清空样板数组中的数据
TraceArray.RemoveAll();
//定义一个EdgePoint型结构成员变量存放边界点的信息
EdgePoint m_EdgePoint;
//先找到最左下方的边界点
bFindStartPoint=false;
int i,j;
for(j=0;j<nHeight && !bFindStartPoint;j++)
{
for(i=0;i<nWidth && !bFindStartPoint;i++)
{
//指向原图倒数第j行,第i个像素的指针
pTemp=pBits+nWidthBytes*j+i;
//取得当前指针处的像素值
if(*pTemp==0)
{
bFindStartPoint=true;
StartPoint.x=i;
StartPoint.y=j;
//指向目标图像的倒数第j行,第i个像素的指针
pNewTemp=pNewBits+nWidthBytes*j+i;
*pNewTemp=(BYTE)0;
}
}
}
//由于起始点是在左下方,故起始扫描沿左上方向
BeginDirect=0;
//跟踪边界
bFindStartPoint=false;
//从起始点开始扫描
CurPoint.x=StartPoint.x;
CurPoint.y=StartPoint.y;
while(!bFindStartPoint)
{
bFindPoint=false;
while(!bFindPoint)
{
//要注意以下判断的顺序
//判断当前搜索方向上的点是否超出图像左边界
if((CurPoint.x==0) && (CurPoint.x+Direction[BeginDirect][0]<0)) BeginDirect=1;
//判断当前搜索方向上的点是否超出图像上边界
if((CurPoint.y==nHeight-1) && (CurPoint.y+Direction[BeginDirect][1]>nHeight-1)) BeginDirect=3;
//判断当前搜索方向上的点是否超出图像右边界
if((CurPoint.x==nWidth-1) && (CurPoint.x+Direction[BeginDirect][0]>nWidth-1)) BeginDirect=5;
//判断当前搜索方向上的点是否超出图像下边界
if((CurPoint.y==0) && (CurPoint.y+Direction[BeginDirect][1]<0)) BeginDirect=7;
//沿扫描方向查看一个像素
pTemp=pBits+nWidthBytes*(CurPoint.y+Direction[BeginDirect][1])+(CurPoint.x+Direction[BeginDirect][0]);
if(*pTemp==0)
{
bFindPoint=true;
/////////////////////////////////////////////////////
//结构数组中记录的第一个点是最左下边界点,即起始点
//方向为到下一点的矢量方向,2003年2月20日修改
m_EdgePoint.CurPoint.x = CurPoint.x;
m_EdgePoint.CurPoint.y = CurPoint.y;
m_EdgePoint.nCurVerct = (BYTE)BeginDirect;
TraceArray.Add(m_EdgePoint);
////////////////////////////////////////////////////
CurPoint.x=CurPoint.x+Direction[BeginDirect][0];
CurPoint.y=CurPoint.y+Direction[BeginDirect][1];
if(CurPoint.y==StartPoint.y && CurPoint.x==StartPoint.x) bFindStartPoint=true;
pNewTemp = pNewBits + nWidthBytes * CurPoint.y + CurPoint.x;
*pNewTemp= (unsigned char)0;
/*//结构数组中记录的第一个点是最左下边界点的下一个邻点,方向为
//该点的当前矢量;最后一个点为最左下点,2002年5月18日
m_EdgePoint.CurPoint.x = CurPoint.x;
m_EdgePoint.CurPoint.y = CurPoint.y;
m_EdgePoint.nCurVerct = (BYTE)BeginDirect;
TraceArray.Add(m_EdgePoint);*/
//扫描的方向逆时针旋转两格
BeginDirect--;
if(BeginDirect == -1)
BeginDirect = 7;
BeginDirect--;
if(BeginDirect == -1)
BeginDirect = 7;
}
else
{
//扫描方向顺时针旋转一格
BeginDirect++;
if(BeginDirect == 8)
BeginDirect = 0;
}
}
}
::GlobalUnlock(m_pDibObject->GetDib());
::GlobalFree(m_pDibObject->GetDib());
::GlobalUnlock(hNewDib );
//将新图像设置为当前图像
m_pDibObject->SetDib( hNewDib );
return true;
}
////////////////////////////////////////////////////////////////////////
//函数:Calibrate()
//功能:对图像进行尺寸标定
//参数:X_Scale、Y_Scale、XY_Scale分别为水平、垂直和对角方向的标定系数;
// realSize为实际尺寸,单位为mm,标定后的系数单位为mm/pixel。
//返回:无
////////////////////////////////////////////////////////////////////////
void CImgAnalyse::Calibrate(float *X_Scale, float *Y_Scale, float *XY_Scale, float realSize)
{
if(m_pDibObject == NULL) return;
if(m_pDibObject->GetNumBits()!=8)
{
AfxMessageBox("不是8位灰度图像");
return;
}
unsigned char *pOld,*pBits,*pTemp;
int nWidthBytes;
DWORD offset;
pOld = (BYTE *) m_pDibObject->GetDIBPointer(&nWidthBytes);
if(pOld == NULL) return;
offset=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+256*sizeof(RGBQUAD);
pBits =(unsigned char *)&pOld[offset];
int nHeight = m_pDibObject->GetHeight();
int nWidth = m_pDibObject->GetWidth();
int i,j,y1,y2,x1,x2;
//从上向下,逐行搜索像素值为0(黑)的第一个像素点,即为参考物的上切点,记其y坐标为y1。
for(j=0;j<nHeight;j++)
{
pTemp = pBits+(nHeight-j-1)*nWidthBytes;
for(i=0;i<nWidth;i++)
if(pTemp[i] == 0)
{
y1 = j;
//跳出两层循环
j = nHeight;
break;
}
}
//从下向上,逐行搜索像素值为0(黑)的第一个像素点,即为参考物的下切点,记其y坐标为y2。
for(j=0;j<nHeight;j++)
{
pTemp = pBits+j*nWidthBytes;
for(i=0;i<nWidth;i++)
if(pTemp[i] == 0)
{
y2 = nHeight-j-1;
//跳出两层循环
j = nHeight;
break;
}
}
//从左向右逐列找出参考物的最左边一个为0(黑)的像素,记为x1
for(i=0;i<nWidth;i++)
{
for(j=0;j<nHeight;j++)
{
pTemp = pBits+j*nWidthBytes+i;
if(*pTemp == 0)
{
x1 = i;
//跳出两层循环
i = nWidth;
break;
}
}
}
//从右向左逐列找出参考物的最右边一个0(黑)的像素,记为x2
for(i=nWidth-1;i>=0;i--)
{
for(j=0;j<nHeight;j++)
{
pTemp = pBits+j*nWidthBytes+i;
if(*pTemp == 0)
{
x2 = i;
//跳出两层循环
i = -1;
break;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -