基于区域生长的二值图像标记,去掉区域的细小直线段并选择
2013-02-01 17:21
423 查看
#include <stdlib.h> #include <stdio.h> #include <assert.h> #include <math.h> #include <cv.h> #include <cxcore.h> #include <highgui.h> #include "iostream" #include <fstream> using namespace std; //八邻域 static int NeighborDirection8[8][2] = {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}}; static int NeighborDirection4[4][2] = {{0,1},{1,0},{0,-1},{-1,0}}; typedef unsigned char Byte; //定义队列 typedef struct QNode { int data; struct QNode *next; }QNode; //采用的链式队列的结构 typedef struct Queue { struct QNode* first; struct QNode* last; }Queue; int PopQueue(Queue *queue) { QNode *p = NULL; int data; if(queue->first == NULL) { return -1; } p = queue->first; data = p->data; if(queue->first->next == NULL) { queue->first = NULL; queue->last = NULL; } else { queue->first = p->next; } free(p); return data; } void PushQueue(Queue *queue, int data) { QNode *p = NULL; p = (QNode*)malloc(sizeof(QNode)); p->data = data; if(queue->first == NULL) { queue->first = p; queue->last = p; p->next = NULL; } else { p->next = NULL; queue->last->next = p; queue->last = p; } //free(p); } void SearchNeighbor(int *bitmap, int width, int height, int *labelmap, int labelIndex, int pixelIndex, Queue *queue) { int searchIndex, i, length; labelmap[pixelIndex] = labelIndex; length = width * height; for(i = 0;i < 8;i++) { searchIndex = pixelIndex + NeighborDirection8[i][0] * width + NeighborDirection8[i][1]; if(searchIndex > 0 && searchIndex < length && bitmap[searchIndex] == 255 && labelmap[searchIndex] == 0) { labelmap[searchIndex] = labelIndex; PushQueue(queue, searchIndex); } } } //主调用函数 int ConnectedComponentLabeling(int *bitmap, int width, int height, int *labelmap) { int cx, cy, popIndex , labelIndex = 0; int index; Queue *queue = NULL; queue = (Queue*)malloc(sizeof(Queue)); queue->first = NULL; queue->last = NULL; /*memset(labelmap, 0, width * height);*/ for(cy = 1; cy < height - 1; cy++) { for(cx = 1; cx < width - 1; cx++) { index = cy * width + cx; if(bitmap[index] == 255 && labelmap[index] == 0) { labelIndex++; SearchNeighbor(bitmap, width, height, labelmap, labelIndex, index, queue); popIndex = PopQueue(queue); while(popIndex > -1) { SearchNeighbor(bitmap, width, height, labelmap, labelIndex, popIndex, queue); popIndex = PopQueue(queue); } } } } free(queue); return labelIndex; } void chooselabelarea(RECT *arearect) { char chFileName[]="1.bmp"; IplImage *pImage=NULL; int nRegionNumber=0; int nImageWidth=0, nImageHeight=0, i=0, j=0; //OpenCV输入图像 pImage = cvLoadImage( chFileName, CV_LOAD_IMAGE_GRAYSCALE); assert(pImage!=NULL); nImageWidth=pImage->width, nImageHeight=pImage->height; int *binaryImage = (int *)calloc(nImageWidth*nImageHeight, sizeof(int)); int *labeImage = (int *)calloc(nImageWidth*nImageHeight, sizeof(int)); assert(binaryImage!=NULL && labeImage!=NULL); //提取图像数据,并将像素值转换为1 for ( i=0; i<nImageHeight; i++ ) { for ( j=0; j<nImageWidth; j++ ) { int temp = (uchar)(*(pImage->imageData+i*pImage->widthStep+j)); if(temp > 245) binaryImage[i*nImageWidth+j] = 0; else binaryImage[i*nImageWidth+j] = 255; } } for ( i=0; i<nImageHeight; i++ ) { for ( j=0; j<nImageWidth; j++ ) { int temp = binaryImage[i*nImageWidth+j]; *(pImage->imageData+i*pImage->widthStep+j) = (uchar)temp; } } cvNamedWindow("二值图"); cvShowImage("二值图", pImage); cvWaitKey(0); nRegionNumber = ConnectedComponentLabeling(binaryImage, nImageWidth, nImageHeight, labeImage);//连通域标记 //保存标记数组 ofstream outFile; outFile.open("E:\\label.txt"); int temp = 0; for ( i=0; i<nImageHeight; i++ ) { for ( j=0; j<nImageWidth; j++ ) { temp = labeImage[i*nImageWidth+j]; outFile<<temp<<" "; } outFile<<endl; } outFile.close(); //输出检测到的连通区域数目 printf("检测到连通区域数目为:%d\n",nRegionNumber); //存储各个标记区域的标记的点数、横坐标最大最小值、纵坐标最大最小值 int *areaCharacter = (int *)calloc(nRegionNumber*5, sizeof(int)); for(i = 0; i < nRegionNumber; i++) { areaCharacter[i*5+2] = nImageWidth; areaCharacter[i*5+4] = nImageHeight; } for ( i=0; i<nImageHeight; i++ ) { for ( j=0; j<nImageWidth; j++ ) { int temp = labeImage[i*nImageWidth+j]; if(temp > 0) {//查找连通域的特征点 int k = (temp-1)*5; areaCharacter[k] += 1;//该标记的点数 if(j > areaCharacter[k+1]) areaCharacter[k+1] = j;//横坐标最大 if(j < areaCharacter[k+2]) areaCharacter[k+2] = j;//横坐标最小值 if(i > areaCharacter[k+3]) areaCharacter[k+3] = i;//纵坐标最大 if(i < areaCharacter[k+4]) areaCharacter[k+4] = i;//纵坐标最小值 } } } //选择连通域 int num = 0; for(int n = 0; n < nRegionNumber; n++) { if(areaCharacter[n*5] < 100)//点数大小 areaCharacter[n*5] = 0; else if(areaCharacter[n*5+1]-areaCharacter[n*5+2] <= 5)//列宽太小 areaCharacter[n*5] = 0; else if(areaCharacter[n*5+3]-areaCharacter[n*5+4] <= 5)//行宽太小 areaCharacter[n*5] = 0; else num++; } int num1 = 0;//去掉直线段并重新分连通域后的连通域个数 int flag = 0; //去线段更新连通域的特征值,若连段位于连通域中间则对该连通域重新分区 for(int n = 0; n < nRegionNumber; n++) { flag = 0; if(areaCharacter[n*5] > 0)//剩余的连通域处理 { int premaxrow = 0;//该连通域前面所有列的行最大值 int preminrow = nImageHeight; int startcol = -1;//用于去直线段 int endcol = -1; int linepoints = 0;//直线段点数 int maxrow = 0;//直线段的前面所有列的行最大值 int minrow = nImageHeight; int npoints = 0;//直线段上噪点的统计 flag = 1; num1++; //按列搜索该标记值的高度差 for(i = areaCharacter[n*5+2];i < areaCharacter[n*5+1];i++)//列 { int maxrow1 = 0;//当前列的行最大值 int minrow1 = nImageHeight; for(j = areaCharacter[n*5+4];j < areaCharacter[n*5+3];j++)//行 { if((labeImage[j*nImageWidth+i]) == (n+1)) { if(j > maxrow1) maxrow1 = j; if(j < minrow1) minrow1 = j; if(j > premaxrow) premaxrow = j; if(j < preminrow) preminrow = j; } } if(maxrow1 - minrow1 <= 5)//直线段 { maxrow = MAX(maxrow, maxrow1); minrow = MIN(minrow, minrow1); npoints = 0; } else { npoints++; } if(maxrow-minrow >= 0 && maxrow-minrow <= 5 && npoints <= 3) { linepoints++; endcol = i; if(startcol == -1)//一条直线段只更新一次起始点 startcol = i; } else if(linepoints > 10)//直线段 { //去掉直线段 for(int k = minrow; k < minrow+5; k++) { for(int l = startcol; l < endcol-npoints; l++) { if(labeImage[k*nImageWidth+l] == n+1) { labeImage[k*nImageWidth+l] = 0; areaCharacter[n*5]--; } } } //直线段两边都含有区域时,对其进行拆分,重新标记后部分的区域 if(endcol < areaCharacter[n*5+1]-5 && startcol > areaCharacter[n*5+2]+5)//直线段位于区域中间 { //num1++; flag = 1; nRegionNumber++; areaCharacter = (int *)realloc(areaCharacter, nRegionNumber*5*sizeof(int)); int m = (nRegionNumber-1)*5; areaCharacter[m] = areaCharacter[n*5]; areaCharacter[m+1] = areaCharacter[n*5+1]; areaCharacter[m+2] = endcol-npoints;//areaCharacter[n*5+2]; //areaCharacter[m+3] = areaCharacter[n*5+3]; //areaCharacter[m+4] = areaCharacter[n*5+4]; maxrow1 = 0; minrow1 = nImageHeight; for(int k = endcol-npoints; k < areaCharacter[n*5+1]; k++) { for(int l = areaCharacter[n*5+4]; l < areaCharacter[n*5+3]; l++) { if(labeImage[l*nImageWidth+k] == n+1) { labeImage[l*nImageWidth+k] = nRegionNumber; areaCharacter[n*5]--; if(l > maxrow1) maxrow1 = l; if(l < minrow1) minrow1 = l; } } } areaCharacter[m+3] = maxrow1;//areaCharacter[n*5+3]; areaCharacter[m+4] = minrow1;//areaCharacter[n*5+4]; areaCharacter[m] -= areaCharacter[n*5]; //更新分区后当前标记区域的矩形区域 areaCharacter[n*5+1] = startcol; areaCharacter[n*5+3] = premaxrow; areaCharacter[n*5+4] = preminrow; preminrow = nImageHeight; premaxrow = 0; } else if(startcol < areaCharacter[n*5+2]+5)//直线段位于区域的左侧 { areaCharacter[n*5+1] = endcol-npoints; } else if(startcol > areaCharacter[n*5+2]+15)//直线段位于区域右侧 { areaCharacter[n*5+2] = startcol; } startcol = -1; endcol = -1; linepoints = 0; maxrow = 0; minrow = nImageHeight; } else { startcol = -1; endcol = -1; linepoints = 0; maxrow = 0; minrow = nImageHeight; } //直线段的最后一个列是该连通域的最后一列时 if(j == areaCharacter[n*5+3] && linepoints > 10 && minrow != nImageHeight) { //去掉直线段 for(int k = minrow; k < minrow+5; k++) { for(int l = startcol; l < endcol-npoints; l++) { if(labeImage[k*nImageWidth+l] == n+1) { labeImage[k*nImageWidth+l] = 0; areaCharacter[n*5]--; } } } } } } if(areaCharacter[n*5] < 100) {//连通域更新 areaCharacter[n*5] = 0; if(flag) num1--; } } printf("剩余的连通区域数目为:%d\n",num1); //在水平方向上对连通域进行选择 for(i = 0; i < nRegionNumber; i++) { for(j = 0; j < nRegionNumber; j++) { int k = 5*i; int l = 5*j; if((i == j) || (0 == areaCharacter[k]) || (0 == areaCharacter[l])) continue; if(areaCharacter[k+1] < areaCharacter[l+2])//i连通域在j的左边 { if(areaCharacter[k] > areaCharacter[l]*3 && areaCharacter[l+1] >= nImageWidth-1) {//左区域时右区域的10倍,且右区域与边界相连,此时认为右边的物体只出来一部分 areaCharacter[l] = 0; } else// { areaCharacter[k] = 0; } } else if(areaCharacter[k+1] < areaCharacter[l+1] && areaCharacter[k+2] < areaCharacter[l+2])//i连通域对j只是偏左 { if(areaCharacter[k] > areaCharacter[l]*3 && areaCharacter[l+1] >= nImageWidth-1) {//左区域时右区域的10倍,且右区域与边界相连,此时认为右边的物体只出来一部分 areaCharacter[l] = 0; } else// { areaCharacter[k] = 0; } } else if(areaCharacter[k+1] < areaCharacter[l+1] && areaCharacter[k+2] > areaCharacter[l+2])//区域i在区域j内 { areaCharacter[k] = 0; } } } arearect->right = 0; arearect->left = 0; arearect->bottom = 0; arearect->top = 0; for(i = 0; i < nRegionNumber; i++) { int k = i*5; if(areaCharacter[k] != 0) { if(arearect->right < areaCharacter[k+1]) {//若剩余的连通域个数大于1,则选择右边的 arearect->right = areaCharacter[k+1]; arearect->left = areaCharacter[k+2]; arearect->bottom = areaCharacter[k+3]; arearect->top = areaCharacter[k+4]; } } } cvSetZero(pImage); for ( i=arearect->top; i<arearect->bottom; i++ ) { for ( j=arearect->left; j<arearect->right; j++ ) { *(pImage->imageData+i*pImage->widthStep+j) = (uchar)255; } } cvNamedWindow("标记结果"); cvShowImage("标记结果", pImage); cvWaitKey(0); free(binaryImage); free(labeImage); free(areaCharacter); cvDestroyAllWindows(); cvReleaseImage(&pImage); } void main() { RECT arearect; arearect.right = 0; arearect.left = 0; arearect.bottom = 0; arearect.top = 0; chooselabelarea(&arearect); system("pause"); }
相关文章推荐
- OpenCV 基于轮廓提取的二值图像分析与连通区域标记算法
- 二值图像连通区标记之区域生长法
- 基于区域生长的二值化图像连通域标记
- Matlab函数bwlabel:在二值图像中标记连通区域
- 基于区域的图像分割-----------区域生长
- 实现二值图像连通区标记之区域生长法
- 基于种子区域生长的激光线段特征提取介绍
- 基于ITK和VTK实现三维体数据的区域生长分割和可视化
- 图像处理之基于泛红算法的二值图像内部区域填充
- 二值图像连通区域标记法,两步法
- 使用skimage完成二值图像连通区域标记及属性提取
- matlab练习程序(二值图像连通区域标记法,两步法)
- [置顶] 【Python】使用skimage完成二值图像连通区域标记及属性提取
- 基于OpenCV给二值图像中不同邻域做标记
- 基于区域生长的图像分割
- 基于MITK实现区域生长分割的介绍
- 连通区域标记:c++版的bwlabel实现(基于opencv)
- 基于区域的图像分割-----------区域生长
- 实现二值图像连通区标记之区域生长法
- 基于区域的图像分割-----------区域生长