www.gusucode.com > VC++图像处理典型算法完整演示源代码源码程序 > VC++图像处理典型算法完整演示源代码源码程序/code/Segment.cpp

    #include "stdafx.h"
#include "Segment.h"
#include "math.h"
// Download by http://www.NewXing.com
/***********************************************************************
* 函数名称:
* ImgSegment()
*
*说明:无参数的构造函数,对成员变量进行初始化
***********************************************************************/
ImgSegment::ImgSegment()
{
	m_pImgDataOut=NULL;//输出图像位图数据指针为空

	m_lpColorTableOut=NULL;//输出图像颜色表指针为空
	
	m_nColorTableLengthOut=0;//输出图像颜色表长度为0

    m_nBitCountOut=0;//输出图像每像素位数为0	

	m_imgWidthOut=0;//输出图像的宽为0

	m_imgHeightOut=0;//输出图像的高为0
}

/***********************************************************************
* 函数名称:
* ImgSegment()
*
*函数参数:
*  CSize size -图像大小(宽、高)
*  int nBitCount  -每像素所占位数
*  LPRGBQUAD lpColorTable  -颜色表指针
*  unsigned char *pImgData  -位图数据指针
*
*返回值:
*   无
*
*说明:本函数为带参数的构造函数,给定位图的大小、每像素位数、颜色表
*      及位图数据,调用ImgCenterDib()对基类成员初始化,并初始化派生类的
*      数据成员
***********************************************************************/
ImgSegment::ImgSegment(CSize size, int nBitCount, LPRGBQUAD lpColorTable, unsigned char *pImgData):
ImgCenterDib(size, nBitCount, lpColorTable, pImgData)
{
	m_pImgDataOut=NULL;//输出图像位图数据指针为空

	m_lpColorTableOut=NULL;//输出图像颜色表指针为空
	
	m_nColorTableLengthOut=0;//输出图像颜色表长度为0

    m_nBitCountOut=0;//输出图像每像素位数为0

	m_imgWidthOut=0;//输出图像的宽为0

	m_imgHeightOut=0;//输出图像的高为0
}

/***********************************************************************
* 函数名称:
*   ~ImgSegment()
*
*说明:析构函数,释放资源
***********************************************************************/
ImgSegment::~ImgSegment()
{
	//释放输出图像位图数据缓冲区
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}

	//释放输出图像颜色表
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}
}

/***********************************************************************
* 函数名称:
* GetDimensions()
*
*函数参数:
*  无
*
*返回值:
*   图像的尺寸,用CSize类型表达
*
*说明:返回输出图像的宽和高
***********************************************************************/
CSize ImgSegment::GetDimensions()
{	
	if(m_pImgDataOut == NULL) return CSize(0, 0);
	return CSize(m_imgWidthOut, m_imgHeightOut);
}

/***********************************************************************
* 函数名称:
* threshOtus()
*
*函数参数:
*  int histArray[256]  -图像的统计直方图
*
*  返回值:
*     最佳阈值
*
*说明:大津阈值选择函数,给定直方图数组,根据方差最大原理自动选择阈值,
*      对于彩色图像,该函数根据亮度直方图计算阈值
***********************************************************************/
int ImgSegment::threshOtus(int histArray[256])
{
	//c0和c1组的均值
	float u0,u1;

	//c0和c1组产生的概率
	float w0,w1;

	//c0组的像素数
	int count0;

	//阈值t及记录方差最大时的最佳阈值maxT
	int t, maxT;

	//方差及最大方差
	float devi, maxDevi=0;

	//循环变量
	int i;

	//统计直方图中像素的个数,存放在sum中
	int sum=0;
	for(i=0;i<256;i++)
		sum = sum+histArray[i];

	for(t=0;t<255;t++){
		//计算阈值为t时,c0组的均值和产生的概率
		u0=0;
		count0=0;
		for(i=0; i<=t;i++){
			u0 += i*histArray[i];
			count0 += histArray[i];
		}
		u0=u0/count0;
		w0=(float)count0/sum;

		//计算阈值为t时,c1组的均值和产生的概率
		u1=0;
		for(i=t+1; i<256;i++)
			u1+=i*histArray[i];
		//C0组像素数与C1组像素数之和为图像总像素数。
		u1=u1/(sum-count0);
		w1=1-w0;

		//两组间的方差
		devi=w0*w1*(u1-u0)*(u1-u0);

		//记录最大的方差及最佳阈值位置
		if(devi>maxDevi){
			maxDevi=devi;
			maxT=t;
		}

	}

	//返回最佳阈值
	return maxT;

}


/***********************************************************************
* 函数名称:
* Roberts()
*
*函数参数:
*  无
*
*返回值:
*   无
*
*说明:Roberts边缘检测,函数将图像看作若干通道数据的合成,在不同通道上
*      完成了边缘检测,因此可同时适用于灰度和彩色图像
***********************************************************************/
void ImgSegment::Roberts()
{
	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];


	//循环变量,图像的坐标
	int i,j;

	//每像素占字节数,输出图像与输入图像相同
	int pixelByte=m_nBitCount/8;

	//循环变量,遍历像素的每个通道,比如彩色图像三个分量
	int k;

	//中间变量
	int x, y, t;

	//Roberts算子
	for(i=1;i<m_imgHeight-1;i++){
		for(j=1;j<m_imgWidth-1;j++){
			for(k=0;k<pixelByte;k++){
				//x方向梯度
				x=*(m_pImgData+i*lineByte+j*pixelByte+k)
					-*(m_pImgData+(i+1)*lineByte+j*pixelByte+k);

				//y方向梯度
				y=*(m_pImgData+i*lineByte+j*pixelByte+k)
					-*(m_pImgData+i*lineByte+(j+1)*pixelByte+k);

				t=sqrt(x*x+y*y)+0.5;
				if(t>255)
					t=255;
				*(m_pImgDataOut+i*lineByte+j*pixelByte+k)=t;
			}
		}
	}
}

/***********************************************************************
* 函数名称:
* Sobel()
*
*函数参数:
*  无
*
*返回值:
*   无
*
*说明:Sobel边缘检测,函数将图像看作若干通道数据的合成,在不同通道上
*      完成了边缘检测,因此可同时适用于灰度和彩色图像
***********************************************************************/
void ImgSegment::Sobel()
{
	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];


	//循环变量,图像的坐标
	int i,j;

	//每像素占字节数,输出图像与输入图像相同
	int pixelByte=m_nBitCount/8;

	//循环变量,遍历像素的每个通道,比如彩色图像三个分量
	int k;

	//中间变量
	int x, y, t;

	//Sobel算子
	for(i=1;i<m_imgHeight-1;i++){
		for(j=1;j<m_imgWidth-1;j++){
			for(k=0;k<pixelByte;k++){
				//x方向梯度
				x= *(m_pImgData+(i-1)*lineByte+(j+1)*pixelByte+k)
				 + 2 * *(m_pImgData+i*lineByte+(j+1)*pixelByte+k)
				 + *(m_pImgData+(i+1)*lineByte+(j+1)*pixelByte+k)
				 - *(m_pImgData+(i-1)*lineByte+(j-1)*pixelByte+k)
				 - 2 * *(m_pImgData+i*lineByte+(j-1)*pixelByte+k)
				 - *(m_pImgData+(i+1)*lineByte+(j-1)*pixelByte+k);

				//y方向梯度
				y= *(m_pImgData+(i-1)*lineByte+(j-1)*pixelByte+k)
				 + 2 * *(m_pImgData+(i-1)*lineByte+j*pixelByte+k)
				 + *(m_pImgData+(i-1)*lineByte+(j+1)*pixelByte+k)
				 - *(m_pImgData+(i+1)*lineByte+(j-1)*pixelByte+k)
				 - 2 * *(m_pImgData+(i+1)*lineByte+j*pixelByte+k)
				 - *(m_pImgData+(i+1)*lineByte+(j+1)*pixelByte+k);

				t=sqrt(x*x+y*y)+0.5;
				if(t>255)
					t=255;
				*(m_pImgDataOut+i*lineByte+j*pixelByte+k)=t;
			}
		}
	}

}

/***********************************************************************
* 函数名称:
* Prewitt()
*
*函数参数:
*  无
*
*返回值:
*   无
*
*说明:Prewitt边缘检测,函数将图像看作若干通道数据的合成,在不同通道上
*      完成了边缘检测,因此可同时适用于灰度和彩色图像
***********************************************************************/
void ImgSegment::Prewitt()
{
	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];


	//循环变量,图像的坐标
	int i,j;

	//每像素占字节数,输出图像与输入图像相同
	int pixelByte=m_nBitCount/8;

	//循环变量,遍历像素的每个通道,比如彩色图像三个分量
	int k;

	//中间变量
	int x, y, t;

	//Prewitt算子
	for(i=1;i<m_imgHeight-1;i++){
		for(j=1;j<m_imgWidth-1;j++){
			for(k=0;k<pixelByte;k++){
				//x方向梯度
				x= *(m_pImgData+(i-1)*lineByte+(j+1)*pixelByte+k)
				 + *(m_pImgData+i*lineByte+(j+1)*pixelByte+k)
				 + *(m_pImgData+(i+1)*lineByte+(j+1)*pixelByte+k)
				 - *(m_pImgData+(i-1)*lineByte+(j-1)*pixelByte+k)
				 - *(m_pImgData+i*lineByte+(j-1)*pixelByte+k)
				 - *(m_pImgData+(i+1)*lineByte+(j-1)*pixelByte+k);

				//y方向梯度
				y= *(m_pImgData+(i-1)*lineByte+(j-1)*pixelByte+k)
				 + *(m_pImgData+(i-1)*lineByte+j*pixelByte+k)
				 + *(m_pImgData+(i-1)*lineByte+(j+1)*pixelByte+k)
				 - *(m_pImgData+(i+1)*lineByte+(j-1)*pixelByte+k)
				 - *(m_pImgData+(i+1)*lineByte+j*pixelByte+k)
				 - *(m_pImgData+(i+1)*lineByte+(j+1)*pixelByte+k);

				t=sqrt(x*x+y*y)+0.5;
				if(t>255)
					t=255;
				*(m_pImgDataOut+i*lineByte+j*pixelByte+k)=t;
			}
		}
	}

}


/***********************************************************************
* 函数名称:
* Laplacian()
*
*函数参数:
*  无
*
*返回值:
*   无
*
*说明:Laplacian边缘检测,函数将图像看作若干通道数据的合成,在不同通道上
*      完成了边缘检测,因此可同时适用于灰度和彩色图像
***********************************************************************/
void ImgSegment::Laplacian()
{
	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];


	//循环变量,图像的坐标
	int i,j;

	//每像素占字节数,输出图像与输入图像相同
	int pixelByte=m_nBitCount/8;

	//循环变量,遍历像素的每个通道,比如彩色图像三个分量
	int k;

	//中间变量
	int t;

	//Laplacian算子
	for(i=1;i<m_imgHeight-1;i++){
		for(j=1;j<m_imgWidth-1;j++){
			for(k=0;k<pixelByte;k++){
				t= 4 * *(m_pImgData+i*lineByte+j*pixelByte+k)
				 - *(m_pImgData+(i-1)*lineByte+j*pixelByte+k)
				 - *(m_pImgData+(i+1)*lineByte+j*pixelByte+k)
				 - *(m_pImgData+i*lineByte+(j-1)*pixelByte+k)
				 - *(m_pImgData+i*lineByte+(j+1)*pixelByte+k);

				t=abs(t)+0.5;
				if(t>255)
					t=255;
				*(m_pImgDataOut+i*lineByte+j*pixelByte+k)=t;
			}
		}
	}
}

/*************************************************************************
 *
 * 函数名称:
 *   TemplateEdge()
 *
 * 参数:
 *   unsigned char *imgIn	- 输入图像数据指针
 *   int width, int height  - 图像的宽和高(像素为单位)
 *   int nBitCount  -图像每像素位数
 *   int *mask -  模板指针
 *   int maskW, int maskH  - 模板的宽和高
 *   unsigned char *imgOut - 图像与模板卷积后(边缘检测)的输出
 *
 * 返回值:
 *   无
 *
 * 说明:
 *   模板卷积函数该函数用给定的mask模板与输入图像进行卷积,函数将灰度和彩色
 *   看作不同通道数据的合成,分别对不同通道数据进行模板卷积,从而完成灰度
 *   和彩色图像的边缘检测
 ************************************************************************/
void ImgSegment::TemplateEdge(unsigned char *imgIn, int width, int height, int nBitCount,
							int *mask, int maskW, int maskH, unsigned char *imgOut)
{
	//每行像素字节数
	int lineByte=(width*nBitCount/8+3)/4*4;

	//循环变量,图像的坐标
	int i,j;

	//每像素占字节数
	int pixelByte=nBitCount/8;

	//循环变量,遍历像素的每个通道,比如彩色图像三个分量
	int k;

	//循环变量,用于模板卷积运算
	int  c, r;
	
	//中间变量
	int sum;

	//模板卷积运算,边缘像素不处理
	for(i=maskH/2;i<height-maskH/2; i++){
		for(j=maskW/2; j<width-maskH/2; j++){
			//对每个通道数据进行卷积
			for(k=0; k<pixelByte; k++){
				//卷积求和
				sum=0;
				for(r=-maskH/2;r<=maskH/2;r++){
					for(c=-maskW/2;c<=maskW/2;c++){
						sum += *(mask+(r+maskH/2)*maskW+c+maskW/2) 
							* *(imgIn+(i+r)*lineByte+(j+c)*pixelByte+k);
					}
				}
				
				//取绝对值
				sum=abs(sum);
				if(sum>255)
					sum=255;
				else if(sum<0)
					sum=0;
				
				*(imgOut+i*lineByte+j*pixelByte+k)=sum;
			}
		}
	}
}


/***********************************************************************
* 函数名称:
* EdgeByAnyMask()
*
*函数参数:
*  int *mask   -二维的模板
*  int maskW   -模板宽
*  int maskH   -模板高
*
*返回值:
*   无
*
*说明:根据自定义模板检测边缘,同时适合于灰度和彩色图像
***********************************************************************/
void ImgSegment::EdgeByAnyMask(int *mask ,int maskW, int maskH)
{
	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount,
		       mask, maskW, maskH, m_pImgDataOut);	
}

/***********************************************************************
* 函数名称:
* Krisch()
*
*函数参数:
*  无
*
*返回值:
*   无
*
*说明:Krisch边缘检测,同时适合于灰度和彩色图像
***********************************************************************/
void ImgSegment::Krisch()
{
	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,
			sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

	//输出图像缓冲区初始化为0
	memset(m_pImgDataOut, 0, lineByte*m_imgHeight);

	//循环变量,图像的坐标
	int i,j;

	//每像素占字节数,输出图像与输入图像相同
	int pixelByte=m_nBitCount/8;

	//循环变量,遍历像素的每个通道,比如彩色图像三个分量
	int k;	

	//两个指针变量
	unsigned  char *p1, *p2;
	//申请临时缓冲区,存放中间结果
	unsigned char *buf=new unsigned char[lineByte* m_imgHeight];

	//模板数组
	int mask[9];

	// 设置Kirsch模板1参数
	mask[0] = 5;
	mask[1] = 5;
	mask[2] = 5;
	mask[3] = -3;
	mask[4] = 0;
	mask[5] = -3;
	mask[6] = -3;
	mask[7] = -3;
	mask[8] = -3;

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount,
		         mask, 3, 3, buf);

	//求两幅缓存图像的最大值,并将大的值存入m_pImgDataOut中
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			for(k=0;k<pixelByte;k++){
				p1=m_pImgDataOut+i*lineByte+j*pixelByte+k;
				p2=buf+i*lineByte+j*pixelByte+k;
				if(*p1<*p2)
					*p1=*p2;
			}
		}
	}

	// 设置Kirsch模板2参数
	mask[0] = -3;
	mask[1] = 5;
	mask[2] = 5;
	mask[3] = -3;
	mask[4] = 0;
	mask[5] = 5;
	mask[6] = -3;
	mask[7] = -3;
	mask[8] = -3;

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount, 
		         mask, 3, 3, buf);

	//求两幅缓存图像的最大值,并将大的值存入m_pImgDataOut中
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			for(k=0;k<pixelByte;k++){
				p1=m_pImgDataOut+i*lineByte+j*pixelByte+k;
				p2=buf+i*lineByte+j*pixelByte+k;
				if(*p1<*p2)
					*p1=*p2;
			}
		}
	}

	// 设置Kirsch模板3参数
	mask[0] = -3;
	mask[1] = -3;
	mask[2] = 5;
	mask[3] = -3;
	mask[4] = 0;
	mask[5] = 5;
	mask[6] = -3;
	mask[7] = -3;
	mask[8] = 5;

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount, 
		         mask, 3, 3, buf);

	//求两幅缓存图像的最大值,并将大的值存入m_pImgDataOut中
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			for(k=0;k<pixelByte;k++){
				p1=m_pImgDataOut+i*lineByte+j*pixelByte+k;
				p2=buf+i*lineByte+j*pixelByte+k;
				if(*p1<*p2)
					*p1=*p2;
			}
		}
	}


	// 设置Kirsch模板4参数
	mask[0] = -3;
	mask[1] = -3;
	mask[2] = -3;
	mask[3] = -3;
	mask[4] = 0;
	mask[5] = 5;
	mask[6] = -3;
	mask[7] = 5;
	mask[8] = 5;

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount, 
		         mask, 3, 3, buf);

	//求两幅缓存图像的最大值,并将大的值存入m_pImgDataOut中
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			for(k=0;k<pixelByte;k++){
				p1=m_pImgDataOut+i*lineByte+j*pixelByte+k;
				p2=buf+i*lineByte+j*pixelByte+k;
				if(*p1<*p2)
					*p1=*p2;
			}
		}
	}

	// 设置Kirsch模板5参数
	mask[0] = -3;
	mask[1] = -3;
	mask[2] = -3;
	mask[3] = -3;
	mask[4] = 0;
	mask[5] = -3;
	mask[6] = 5;
	mask[7] = 5;
	mask[8] = 5;

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount, mask, 3, 3, buf);

	//求两幅缓存图像的最大值,并将大的值存入m_pImgDataOut中
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			for(k=0;k<pixelByte;k++){
				p1=m_pImgDataOut+i*lineByte+j*pixelByte+k;
				p2=buf+i*lineByte+j*pixelByte+k;
				if(*p1<*p2)
					*p1=*p2;
			}
		}
	}

	// 设置Kirsch模板6参数
	mask[0] = -3;
	mask[1] = -3;
	mask[2] = -3;
	mask[3] = 5;
	mask[4] = 0;
	mask[5] = -3;
	mask[6] = 5;
	mask[7] = 5;
	mask[8] = -3;

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount, 
		         mask, 3, 3, buf);

	//求两幅缓存图像的最大值,并将大的值存入m_pImgDataOut中
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			for(k=0;k<pixelByte;k++){
				p1=m_pImgDataOut+i*lineByte+j*pixelByte+k;
				p2=buf+i*lineByte+j*pixelByte+k;
				if(*p1<*p2)
					*p1=*p2;
			}
		}
	}

	// 设置Kirsch模板7参数
	mask[0] = 5;
	mask[1] = -3;
	mask[2] = -3;
	mask[3] = 5;
	mask[4] = 0;
	mask[5] = -3;
	mask[6] = 5;
	mask[7] = -3;
	mask[8] = -3;

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount, 
		         mask, 3, 3, buf);

	//求两幅缓存图像的最大值,并将大的值存入m_pImgDataOut中
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			for(k=0;k<pixelByte;k++){
				p1=m_pImgDataOut+i*lineByte+j*pixelByte+k;
				p2=buf+i*lineByte+j*pixelByte+k;
				if(*p1<*p2)
					*p1=*p2;
			}
		}
	}

	// 设置Kirsch模板8参数
	mask[0] = 5;
	mask[1] = 5;
	mask[2] = -3;
	mask[3] = 5;
	mask[4] = 0;
	mask[5] = -3;
	mask[6] = -3;
	mask[7] = -3;
	mask[8] = -3;
	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount, 
		         mask, 3, 3, buf);

	//求两幅缓存图像的最大值,并将大的值存入m_pImgDataOut中
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			for(k=0;k<pixelByte;k++){
				if(*(m_pImgDataOut+i*lineByte+j*pixelByte+k)<*(buf+i*lineByte+j*pixelByte+k))
					*(m_pImgDataOut+i*lineByte+j*pixelByte+k)=*(buf+i*lineByte+j*pixelByte+k);
			}
		}
	}
}

/***********************************************************************
* 函数名称:
* GaussLaplacian()
*
*函数参数:
*  无
*
*返回值:
*   无
*
*说明:Gauss-Laplacian边缘检测,同时适合于灰度和彩色图像
***********************************************************************/
void ImgSegment::GaussLaplacian()
{
	//定义Gauss-Laplacian模板
	int mask[25];
	mask[0] = -2;
	mask[1] = -4;
	mask[2] = -4;
	mask[3] = -4;
	mask[4] = -2;
	mask[5] = -4;
	mask[6] = 0;
	mask[7] = 8;
	mask[8] = 0;
	mask[9] = -4;
	mask[10] = -4;
	mask[11] = 8;
	mask[12] = 24;
	mask[13] = 8;
	mask[14] = -4;
	mask[15] = -4;
	mask[16] = 0;
	mask[17] = 8;
	mask[18] = 0;
	mask[19] = -4;
	mask[20] = -2;
	mask[21] = -4;
	mask[22] = -4;
	mask[23] = -4;
	mask[24] = -2;

	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

	//模板卷积函数调用
	TemplateEdge(m_pImgData, m_imgWidth, m_imgHeight, m_nBitCount, mask, 5, 5, m_pImgDataOut);

}


/***********************************************************************
* 函数名称:
* HoughTransform()
*
*函数参数:
*  unsigned char *imgBinaryIn  -二值图像输入数据指针
*  int width  -图像的 宽
*  int height -图像的高
*  int *houghBuf  -Hough变换所需要的缓冲区指针
*  int  houghWidth  -Hough变换缓冲区的宽
*  int houghHeight  -Hough变换缓冲区的高
*  float radiusResolution  -Hough变换的极坐标半径的检测分辨率
*  float angleResolution  -Hough变换的角度检测分辨率 
*  float *radius  -用来返回Hough变换检测出来的最长直线的极半径
*  float *angle   -用来返回Hough变换检测出来的最长直线的角度

*返回值:
*   无
*
*说明:给定图像数据,通过线检测hough变换检测直线
***********************************************************************/
void ImgSegment::HoughTransform(unsigned char *imgBinaryIn, int width, 
			int height, int *houghBuf, int  houghWidth, int houghHeight,
		    float radiusResolution, float angleResolution, 
		    float *radius, float *angle)
{
	//申请循环变量
	int i, j;

	//清理变换空间累加数组
	for(i=0;i<houghHeight;i++){
		for(j=0;j<houghWidth;j++){
			*(houghBuf+i*houghWidth+j)=0;
		}
	}

	//循环变量
	int r, a;

	//中间变量
	float tempR, tempA; 

	//遍历图像数据
	for(i=0;i<height;i++){
		for(j=0;j<width;j++){
			//出现一个目标点
			if(*(imgBinaryIn+i*width+j)==0){

				//a代表角度的循环变量,在变换空间累加数组的垂直方向上
				for(a=0;a<houghHeight;a++){

					//按照给定变换角度的分辨率,求取角度
					tempA=(a-houghHeight/2)*angleResolution;

					//根据当前遍历的角度及x,y值求取对应极半径
					tempR=(j-width/2)*cos(tempA*2*3.1415926/360)+(i-height/2)*sin(tempA*2*3.1415926/360);
					r=tempR/radiusResolution;

					//累加数组累加
					*(houghBuf+a*houghWidth+ r+houghWidth/2)+=1;
				}
			}
		}
	}

	//求累加数组的极大值,并记录此时的数组坐标
	int max, maxR, maxA;
	max=*(houghBuf+0*houghWidth+0);
	maxR=0;
	maxA=0;
	for(a=0;a<houghHeight;a++){
		for(r=0;r<houghWidth;r++){
			if(max<=*(houghBuf+a*houghWidth+r)){
				max=*(houghBuf+a*houghWidth+r);
				maxR=r;
				maxA=a;
			}
		}
	}

	//将极大值位置转换成极坐标半径和角度,并通过参数返回
	*radius=(maxR-houghWidth/2)*radiusResolution;
	*angle=(maxA-houghHeight/2)*angleResolution;
}


/***********************************************************************
* 函数名称:
* Hough()
*
*函数参数:
*  float radiusResolution  -Hough变换的极坐标半径的检测分辨率
*  float angleResolution  -Hough变换的角度检测分辨率 
*  float *radius  -用来返回Hough变换检测出来的最长直线的极半径
*  float *angle   -用来返回Hough变换检测出来的最长直线的角度

*返回值:
*   无
*
*说明:给定Hough变换的极半径分辨率和角度分辨率,通过调用HoughTransform()
*      对输入图像m_pImgData做线检测,Hough变换的结果输出到m_pImgDataOut中
***********************************************************************/
void ImgSegment::Hough(float radiusResolution, float angleResolution,
					   float *radius, float *angle)
{
	//只处理灰度图像
	if(m_nBitCount!=8)
		return;

	//释放缓冲区
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像的每像素位数及颜色表长度
	m_nBitCountOut=m_nBitCount;
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,
			sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}
	

	//图像的中心为坐标原点,线与原点的距离最大
	//为sqrt(m_imgWidth*m_imgWidth+m_imgHeight*m_imgHeight)/2,所以Hough变换
	//的高度为:
	int houghWidth=sqrt(m_imgWidth*m_imgWidth+m_imgHeight*m_imgHeight);
	 houghWidth /= radiusResolution;

	//线的角度在[-90,90]之间,所以申请的累加数组高度为181/angleResolution
	int houghHeight=181/angleResolution;

	//申请累加数组缓冲区
	int *houghBuf=new int[houghWidth*houghHeight];

	//Hough变换,结果存入houghBuf中
	HoughTransform(m_pImgData, m_imgWidth, m_imgHeight, houghBuf,  houghWidth,
	        	houghHeight,radiusResolution, angleResolution, radius, angle);
	
	//输出图像的大小是Hough变换累加数组的大小			
	m_imgWidthOut=houghWidth;
	m_imgHeightOut=houghHeight;
	int lineByteOut=(m_imgWidthOut*m_nBitCountOut/8+3)/4*4;
	m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];

	//求出累加数组的最大值
	int i, j, max=0; 
	for(i=0;i<m_imgHeightOut;i++){
		for(j=0;j<m_imgWidthOut;j++){
			if(max<=*(houghBuf+i*houghWidth+j))
				max=*(houghBuf+i*houghWidth+j);
		}
	}
	//根据最大值将累加数组映射到输出图像
	for(i=0;i<m_imgHeightOut;i++){
		for(j=0;j<m_imgWidthOut;j++){
			*(m_pImgDataOut+i*lineByteOut+j)=
				*(houghBuf+i*houghWidth+j)*255.0/max;
		}
	}
	
	//释放缓冲区
	delete []houghBuf;
}

/***********************************************************************
* 函数名称:
* longestLineDetectByHough()
*
*函数参数:
*  float radiusResolution  -Hough变换的极坐标半径的检测分辨率
*  float angleResolution  -Hough变换的角度检测分辨率 
*  float *radius  -用来返回Hough变换检测出来的最长直线的极半径
*  float *angle   -用来返回Hough变换检测出来的最长直线的角度

*返回值:
*   无
*
*说明:给定Hough变换的极半径分辨率和角度分辨率,通过调用HoughTransform()
*      对输入图像m_pImgData做线检测,根据最长线的角度和极坐标半径,将最
*     长线输出到m_pImgDataOut中
***********************************************************************/
void ImgSegment::longestLineDetectByHough(float radiusResolution, float angleResolution)
{
	//只处理灰度图像
	if(m_nBitCount!=8)
		return;

	//释放缓冲区
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像的每像素位数及颜色表长度
	m_nBitCountOut=m_nBitCount;
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,
			sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}
	

	//图像的中心为坐标原点,线与原点的距离最大
	//为sqrt(m_imgWidth*m_imgWidth+m_imgHeight*m_imgHeight)/2,所以Hough变换
	//的高度为:
	int houghWidth=sqrt(m_imgWidth*m_imgWidth+m_imgHeight*m_imgHeight);
	 houghWidth /= radiusResolution;

	//线的角度在[-90,90]之间,所以申请的累加数组高度为181/angleResolution
	int houghHeight=181/angleResolution;

	//申请累加数组缓冲区
	int *houghBuf=new int[houghWidth*houghHeight];

	//Hough变换,结果存入houghBuf中
	float radius, angle;
	HoughTransform(m_pImgData, m_imgWidth, m_imgHeight, houghBuf,  houghWidth,
	        	houghHeight,radiusResolution, angleResolution, &radius, &angle);

	//输出图像的大小与输入图像相同
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;
	int lineByteOut=(m_imgWidthOut*m_nBitCountOut/8+3)/4*4;
	m_pImgDataOut=new unsigned char[lineByteOut*m_imgHeightOut];

	//根据求得的角度和极坐标半径,在白色背景下画出最长直线并作为输出图像显示
	memset(m_pImgDataOut,255,lineByteOut*m_imgHeightOut);

	//angle的单位是度,此处转换为弧度进行计算
	float alfa=angle*2*3.1415926/360;

	
	int x, y, i, j;
	for( x=-m_imgWidthOut/2;x<m_imgWidthOut/2;x++){
		//图像的中心位置为坐标原点,(x,y)为直角坐标系中的点,
		//将其转换至坐标原点在图像左下角的坐标系(i,j)
		y=radius/sin(alfa)-x/tan(alfa);
		j=x-m_imgWidthOut/2;
		i=y+m_imgHeightOut/2;
		if(i>0&&i<m_imgHeightOut)
	    	*(m_pImgDataOut+i*m_imgWidthOut+j)=0;
	}

	//空间释放
	delete []houghBuf;
}



/***********************************************************************
* 函数名称:
* RegionGrow()
*
*函数参数:
*  CPoint seed  -种子点
*  int thresh   -阈值
*
*返回值:
*   无
*
*说明:区域生长算法,给定一个种子点seed和阈值thresh,从种子点处开始生长,
*      将与种子点像素灰度值之差thresh的像素合并在一起形成一个区域,该函
*      数只处理灰度图像
***********************************************************************/
void ImgSegment::RegionGrow(CPoint seed, int thresh)
{
	//只处理灰度图像
	if(m_nBitCount!=8)
		return;

	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,
			     sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

	//以下是区域生长代码

	//循环变量
	int i, j;

	//将输出图像初始化置255,用0代表像素的生长标记
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			*(m_pImgDataOut+i*lineByte+j)=255;
		}
	}

	//二维数组direction代表中心像素点8邻域坐标与该点在x和y方向上的偏移,
	//其中第一列为x方向的偏移,第二列为y方向的偏移
	int direction[8][2]={{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};

	//栈申请,此处假定进栈的像素最多为图像总像素数
	CPoint *stack=new CPoint[m_imgWidth*m_imgHeight];

	//栈顶指针
	int top;

	//当前正处理的点和弹出的点
	CPoint currentPoint, popPoint;

	//循环变量,遍历array数组的第一维下标
	int k;

	//标记变量
	int label;

	//临时变量
	int temp1, temp2;

	//记录种子像素的灰度值
	temp1=*(m_pImgData+seed.y*lineByte+seed.x);

	//将给定种子点置标记0,入栈
	*(m_pImgDataOut+seed.y*lineByte+seed.x)=0;
	top=0;
	stack[top].x=seed.x;
	stack[top].y=seed.y;

	//堆栈
	while(top>-1){
		//弹出栈顶元素,该元素已经生长过
		popPoint.x=stack[top].x;
		popPoint.y=stack[top].y;
		top--;

		//考察弹出像素周围是否有没有生长的像素
		for(k=0;k<8;k++){

			//待考察的邻域点
			currentPoint.x=popPoint.x+direction[k][0];
			currentPoint.y=popPoint.y+direction[k][1];

			//如果待考察的点不在图像内,则跳过
			if(currentPoint.x<0||currentPoint.x>m_imgWidth-1||
				currentPoint.y<0||currentPoint.y>m_imgHeight-1)
				continue;
			
			//该点标号
			label=*(m_pImgDataOut+currentPoint.y*lineByte+currentPoint.x);

			//弹出的点周围有尚没生长的点
			if(label==255){
				temp2=*(m_pImgData+currentPoint.y*lineByte+currentPoint.x);
				//如果当前被考察的像素灰度值与种子点灰度值之差小于给定的阈值,
				//则认为相似,将其进栈处理
				if(abs(temp1-temp2)<thresh){
					//给该点置生长标记0
					*(m_pImgDataOut+currentPoint.y*lineByte+currentPoint.x)=0;
					top++;
					stack[top].x=currentPoint.x;
					stack[top].y=currentPoint.y;
				}
			}
		}
		
	}
	
	//清除缓冲区
	delete []stack;
}



/***********************************************************************
* 函数名称:
* ContourExtract()
*
*函数参数:
*  无
*
*返回值:
*   无
*
*说明:给定一个二值图像,把黑色区域看作目标,白色看作背景,提取目标的轮廓
***********************************************************************/
void ImgSegment::ContourExtract()
{
	//只处理灰度图像
	if(m_nBitCount!=8)
		return;

	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

	//以下是轮廓提取代码

	//将输入图像数据拷贝置输出图像缓冲区
	memcpy(m_pImgDataOut,m_pImgData,lineByte*m_imgHeight);

	//存放黑点像素8邻域的像素灰度值
	int array[8];

	//数组求和
	int sum;

	//循环变量
	int i, j, k;

	//搜索图像中的黑点,不考虑边界上的点
	for(i=1;i<m_imgHeight-1;i++){
		for(j=1;j<m_imgWidth-1;j++){
			//找到一个黑点
			if(*(m_pImgData+i*lineByte+j)==0){
				//拷贝周围8邻域像素进array数组
		    	array[0]=*(m_pImgData+i*lineByte+j+1);
				array[1]=*(m_pImgData+(i+1)*lineByte+j+1);
				array[2]=*(m_pImgData+(i+1)*lineByte+j);
				array[3]=*(m_pImgData+(i+1)*lineByte+j-1);
				array[4]=*(m_pImgData+i*lineByte+j-1);
				array[5]=*(m_pImgData+(i-1)*lineByte+j-1);
				array[6]=*(m_pImgData+(i-1)*lineByte+j);
				array[7]=*(m_pImgData+(i-1)*lineByte+j+1);
				
				//对数组求和
				sum=0;
				for(k=0;k<8;k++)
					sum += array[k];

				//周围8邻域均为黑点,则输出图像对应像素置白色
				if(sum==0)
				   *(m_pImgDataOut+i*lineByte+j)=255;
				
			}
		}
	}

}

/***********************************************************************
* 函数名称:
* ContourTrace()
*
*函数参数:
*  无
*
*返回值:
*   无
*
*说明:给定一个二值图像,把黑色区域看作目标,白色看作背景,跟踪目标的边界
***********************************************************************/
void ImgSegment::ContourTrace()
{
	//只处理灰度图像
	if(m_nBitCount!=8)
		return;

	//释放m_pImgDataOut指向的图像数据空间
	if(m_pImgDataOut!=NULL){
		delete []m_pImgDataOut;
    	m_pImgDataOut=NULL;
	}
	//释放颜色表空间
	if(m_lpColorTableOut!=NULL){
		delete []m_lpColorTableOut;
		m_lpColorTableOut=NULL;
	}

	//输出图像与输入图像为同一类型
	m_nBitCountOut=m_nBitCount;

	//输出图像颜色表长度
	m_nColorTableLengthOut=ComputeColorTabalLength(m_nBitCountOut);

	//输出图像颜色表,与输入图像相同
	if(m_nColorTableLengthOut!=0){
    	m_lpColorTableOut=new RGBQUAD[m_nColorTableLengthOut];
		memcpy(m_lpColorTableOut,m_lpColorTable,
			           sizeof(RGBQUAD)*m_nColorTableLengthOut);
	}

	//输出图像的宽高,与输入图像相等
	m_imgWidthOut=m_imgWidth;
	m_imgHeightOut=m_imgHeight;

	//每行像素所占字节数,输出图像与输入图像相同
	int lineByte=(m_imgWidth*m_nBitCount/8+3)/4*4;

	//申请输出图像缓冲区
	m_pImgDataOut=new unsigned char[lineByte*m_imgHeight];

	//将输出图像初始化置255,用0代表轮廓像素标记
	memset(m_pImgDataOut,255,lineByte*m_imgHeight);

	//顺时针定义中心像素点的8邻域坐标,第一列为x方向的偏移,第二列为y方向的偏移
	int direction[8][2]={{-1,1},{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0}};

	//边界起始点,待处理的当前点,当前点的邻域点
	CPoint startP, currentP, neighborP;

	//是否当前点与起始边界点重合的标志变量
	int findStartPoint;

	//搜索边界起始点
	findStartPoint=0;

	//循环变量,图像坐标
	int i,j;
	for(i=0;i<m_imgHeight;i++){
		for(j=0;j<m_imgWidth;j++){
			//找到起始边界点
			if(*(m_pImgData+i*lineByte+j)==0){
				startP.x=j;
				startP.y=i;
				*(m_pImgDataOut+i*lineByte+j)=0;
				findStartPoint=1;
				break;
			}
		}

		//已经找到起始边界点
		if(findStartPoint)
			break;
	}

	//边界跟踪
	//从初始点开始跟踪
	currentP.x=startP.x;
	currentP.y=startP.y;

	//邻域点是否边界点标志变量
	int isContourP;

	//开始方向
	int startDirect=0;

	//0表示还没有返回最初的边界起始点
	findStartPoint=0;
	while(findStartPoint==0){
		isContourP=false;
		while(isContourP==false){
			neighborP.x=currentP.x+direction[startDirect][0];
			neighborP.y=currentP.y+direction[startDirect][1];

			//搜索到邻域点
			if(*(m_pImgData+neighborP.y*lineByte+neighborP.x)==0){
				isContourP=true;
				currentP.x=neighborP.x;
				currentP.y=neighborP.y;

				if(currentP.x==startP.x&&currentP.y==startP.y)
					findStartPoint=true;//回到边界起始点了

				*(m_pImgDataOut+currentP.y*lineByte+currentP.x)=0;

				//扫描方向逆时针旋转90度
				startDirect-=2;
				if(startDirect<0)
					startDirect+=8;
			}
			else{
				//扫描方向顺时针旋转45度
				startDirect++;
				if(startDirect==8)
					startDirect=0;
			}

		}
	}
	
}