测试对象:骨头的DR照片
测试目标:找出骨头的轮廓,并且测出轮廓内部的面积大小。
采用方法:具体过程由下面的流程图详细说明。
以及每步操作的效果图如下所示:
图1 流程图 图2 原始图像
图3 选择ROI区域 图4 大津阈值分割
图5 canny边缘检测 图6 边缘+原图
其中ROI区域提取、大津阈值、轮廓提取均使用的是opencv提供的库函数进行操作。
这里主要介绍区域生长的使用。
1、种子点的设置:
(1)需要设置种子点,进行生长,适用于灰度图和二值图,并且计算速度快。
(2)不设置种子点,对全图进行遍历,仅适用于二值图。
这里使用的方法(1)
2、种子邻域的选择:
(1)8邻域,适用于二值图。
(2)4邻域,适用于灰度图和二值图。
这里使用的方法(2)
结果显示如下:
具体代码如下所示:
//以下是区域生长代码
int RegionGrow(Point seed)
{
//循环变量
int i, j;
//二维数组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}};
int direction[4][2]={{0,-1},{1,0},{0,1},{-1,0}};
//栈申请,此处假定进栈的像素最多为图像总像素数
Point *stack=new Point[imageROI.rows*imageROI.cols];
//栈顶指针
int top;
//当前正处理的点和弹出的点
Point currentPoint, popPoint;
//循环变量,遍历array数组的第一维下标
int k;
//标记变量
int label;
//临时变量
int temp1;
//统计数量
int count=0;
//记录种子像素的灰度值
g_srcImage.at<unsigned char>(seed.y,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<4;k++){
//待考察的邻域点
currentPoint.x=popPoint.x+direction[k][0];
currentPoint.y=popPoint.y+direction[k][1];
//如果待考察的点不在图像内,则跳过
if(currentPoint.x<476||currentPoint.x>1470||currentPoint.y<398||currentPoint.y>1400)
continue;
/*g_srcImage.at<unsigned char>(currentPoint.y,currentPoint.x)=0;
count++;*/
//该点标号
label=g_srcImage.at<unsigned char>(currentPoint.y,currentPoint.x);
//弹出的点周围有尚没生长的点
if(label!=255&&label!=0){
//没碰到边界,将其进栈处理,给该点置生长标记0
g_srcImage.at<unsigned char>(currentPoint.y,currentPoint.x)=0;
count++;
top++;
stack[top].x=currentPoint.x;
stack[top].y=currentPoint.y;
}
}
}
//清除缓冲区
delete []stack;
return count;
}