整个程序的流程是:
Main()
{
domain(); //寻找连通区域的总白点数
}
domain()
{
first() //寻找连通区域的第一个白点数
{
round(){} //寻找连通区域的其他白点数
}
}
具体函数:
domain函数:声明两个数组num和flag。num用来存放对应像素点是黑点(0)或白点(1),flag用来标记对应像素点是否被访问过,未访问是false,访问过是true。考虑到检测连通区域时边缘可能会越界,因此将四周的flag设为true。
first函数:用for循环寻找第一个白点,找到后将该白点的num值设为2(这是为后面判断连通区域白点个数作标记,如果连通区域白点个数小于阈值,就要把所有num为2的白点变成黑点)。然后调用round函数判断一片连通区域有多少个白点,如果多余阈值,就将num=2改为num=3(防止和下一个连通区域冲突),否则将所有num为2的白点变成黑点。
round函数:将first函数找到的第一个白点的位置作为实参传过来。之后判断把连通区域的点是否为白点。同时对连通区域的白点又用递归调用round函数判断其连通区域,直到将一片连通区域的白点个数全部统计完。
代码中遇到的问题:
clone函数已经包括将图片所有信息全部复制给另一个图片了,不用再单独将灰度值赋值了。如:
Mat img2=img1.clone();
// img2.data[j*cols+i]=img1.data[j*cols+i]; 这一句不需要
尽量不使用全局变量,使用局部变量时,若其他函数不能用(变红),可以选择用传参的方式传给下一个函数。
对连通区域的第一个白点忘记标记为true,又忘记将第一个白点变黑。因此遇到了好多小白点没变黑的问题。
一个函数内不能定义另一个函数,但是可以调用。
结果效果不好可以调节灰度值的阈值和连通区域白点个数的阈值。
#include<opencv2/opencv.hpp>
#include<math.h>
using namespace cv;
using namespace std;
int rows,cols;
void domain(Mat img1) ;
void round(int xstart ,int ystart,int * num,bool * flag) ;
void first(int * num,bool * flag,Mat img2) ;
int number;
int main()
{
Mat img= imread("1.jpg",CV_LOAD_IMAGE_GRAYSCALE );
rows=img.rows;
cols=img.cols;
uchar *result; //数组和地址的关系
result=new uchar[rows*cols]; //动态分配一个数组result,存每个点的强度值,new分配的数组最后要用delete释放空间
for(int j=0;j<(rows-1);j++)
{
for(int i=0;i<(cols-1);i++)
{
int x=img.data[j*cols+i]-img.data[(j+1)*cols+i+1];
int y=img.data[(j+1)*cols+i]-img.data[j*cols+i+1];
result[j*cols+i]=(uchar)sqrt(x*x+y*y);
}
}
for(int j=0;j<(rows-1);j++)
{
for(int i=0;i<(cols-1);i++)
{
if(result[j*cols+i]<20)
{
img.data[j*cols+i] =0;
}
else
{
img.data[j*cols+i]=255;
}
}
}
delete [] result ;
domain (img );
namedWindow("image0", CV_WINDOW_AUTOSIZE);
imshow("image0",img);
waitKey();
return 0;
}
void domain(Mat img1) //找出一片区域的白点个数
{
//int n; //记录连通域白点个数
Mat img2=img1.clone();
// img2.data[j*cols+i]=img1.data[j*cols+i];
int * num;
num=new int[rows*cols];
bool * flag;
flag=new bool[rows*cols];
for(int j=0;j<rows;j++){
for(int i=0;i<cols;i++){
if(img2.data[j*cols+i]==255)
{
num[j*cols+i]=1;
flag[j*cols+i]=false;
}
else
{
num[j*cols+i]=0;
flag[j*cols+i]=false;
}
}
}
for(int i=0;i<cols;i++) //四个边,第一行
{
flag[i]=true;
}
for(int i=0,j=rows-1;i<cols;i++) //四个边,最后一行
{
flag[j*cols+i]=true;
}
for(int j=0;j<rows;j++) //四个边,左边一列
{
flag[j]=true;
}
for(int i=cols-1,j=0;j<rows;j++) //四个边,右边一列
{
flag[j*cols+i]=true;
}
first(num,flag,img2);
namedWindow("image1", CV_WINDOW_AUTOSIZE);
imshow("image1",img2);
delete [] num ;
delete [] flag ;
}
void first(int * num,bool * flag,Mat img2) //寻找连通域的第一个白点
{
for(int j=0;j<rows;j++){
for(int i=0;i<cols;i++){
if(num[j*cols+i]==1&&!flag[j*cols+i])
{
//round(i,j,num,flag);
num[j*cols+i]=2;
number=0;
flag[j*cols+i]=true;
round(i,j,num,flag);
if(number<80)
{
for(int a=0;a<rows;a++){
for(int b=0;b<cols;b++){
if(num[a*cols+b]==2)
{
img2.data[a*cols+b]=0;
}
}
}
}
else
{
for(int a=0;a<rows;a++){
for(int b=0;b<cols;b++){
if(num[a*cols+b]==2)
{
num[a*cols+b]=3;
}
}
}
}
}
}
}
}
void round(int xstart ,int ystart,int * num,bool * flag) //寻找连通域的白点数
{
if(num[(ystart-1)*cols+xstart-1]==1&&!flag[(ystart-1)*cols+xstart-1]) //左上
{
number++;
flag[(ystart-1)*cols+xstart-1]=true;
num[(ystart-1)*cols+xstart-1]=2;
round(xstart-1,ystart-1,num,flag);
}
if(num[(ystart-1)*cols+xstart]==1&&!flag[(ystart-1)*cols+xstart]) //上
{
number++;
flag[(ystart-1)*cols+xstart]=true;
num[(ystart-1)*cols+xstart]=2;
round(xstart,ystart-1,num,flag);
}
if(num[(ystart-1)*cols+xstart+1]==1&&!flag[(ystart-1)*cols+xstart+1]) //右上
{
number++;
flag[(ystart-1)*cols+xstart+1]=true;
num[(ystart-1)*cols+xstart+1]=2;
round(xstart+1,ystart-1,num,flag);
}
if(num[ystart*cols+xstart-1]==1&&!flag[ystart*cols+xstart-1]) //左
{
number++;
flag[ystart*cols+xstart-1]=true;
num[ystart*cols+xstart-1]=2;
round(xstart-1,ystart,num,flag);
}
if(num[ystart*cols+xstart+1]==1&&!flag[ystart*cols+xstart+1]) //右
{
number++;
flag[ystart*cols+xstart+1]=true;
num[ystart*cols+xstart+1]=2;
round(xstart+1,ystart,num,flag);
}
if(num[(ystart+1)*cols+xstart-1]==1&&!flag[(ystart+1)*cols+xstart-1]) //左下
{
number++;
flag[(ystart+1)*cols+xstart-1]=true;
num[(ystart+1)*cols+xstart-1]=2;
round(xstart-1,ystart+1,num,flag);
}
if(num[(ystart+1)*cols+xstart]==1&&!flag[(ystart+1)*cols+xstart]) //下
{
number++;
flag[(ystart+1)*cols+xstart]=true;
num[(ystart+1)*cols+xstart]=2;
round(xstart,ystart+1,num,flag);
}
if(num[(ystart+1)*cols+xstart+1]==1&&!flag[(ystart+1)*cols+xstart+1]) //右下
{
number++;
flag[(ystart+1)*cols+xstart+1]=true;
num[(ystart+1)*cols+xstart+1]=2;
round(xstart+1,ystart+1,num,flag);
}
}