📄 segment.cpp
字号:
* 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&¤tP.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;
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -