您的位置:首页 > 运维架构

OpenCV—漫水填充floodFill之区域信息统计

2017-10-28 23:25 501 查看
本文的主要参考为

1、官方文档OpenCV249-floodFill

2、《Learning OpenCV 3》page361-364

OpenCV中提供的直线拟合API如下:

int floodFill(InputOutputArray image, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )
int floodFill(InputOutputArray image, InputOutputArray mask, Point seedPoint, Scalar newVal, Rect* rect=0, Scalar loDiff=Scalar(), Scalar upDiff=Scalar(), int flags=4 )
详细参数含义参见官方文档,这里提出几点注意:

(1)由于mask的尺寸大于原图,所以原图的坐标(x,y)对应于模板为(x+1,y+1)

(2)flag的设置包括四部分,设置方式见下面源码

实例介绍:

使用函数floodFill对原图像中的感兴趣区域进行信息统计,处理的结果如下图所示。

注意事项已经在源码中做了详细的注释,参看源码。



源码:

#include "opencv2/opencv.hpp"
#include <iostream>
#include <numeric>  //std::accumulate
#include <vector>  // std::vector
using namespace cv;
using namespace std;

Mat g_srcImage, g_floodFillImage, g_maskImage, g_edgeImage, g_showImage;//定义原始图、目标图、灰度图、掩模图
int g_nLowDifference = 20, g_nUpDifference = 20;//负差最大值、正差最大值
int g_nConnectivity = 8;//表示floodFill函数标识符低八位的连通值
int g_nNewMaskVal = 255;//新的重新绘制的像素值

static void onMouse( int event, int x, int y, int, void* )
{
// 若鼠标左键没有按下,便返回
if( event != CV_EVENT_LBUTTONDOWN )
return;

//若seed为已统计过的区域则返回
//at(i,j)等价于point(y,x),一定注意对应关系:i->y,j->x
int nn = g_maskImage.at<uchar>(y+1,x+1);
if (nn == 128 || nn == 255)
return;

Point seed = Point(x,y);
//标识符的0-7位为g_nConnectivity,8-15位为g_nNewMaskVal左移8位的值
//16-23位为CV_FLOODFILL_FIXED_RANGE或者0,24-31位为CV_FLOODFILL_MASK_ONLY或者0;
//下面两种写法都可以
int flags = g_nConnectivity | (g_nNewMaskVal << 8) | CV_FLOODFILL_FIXED_RANGE | CV_FLOODFILL_MASK_ONLY;
//int flags = g_nConnectivity + (g_nNewMaskVal << 8) + CV_FLOODFILL_FIXED_RANGE + CV_FLOODFILL_MASK_ONLY;

//定义重绘区域的最小边界矩形区域
Rect roi_rect;
//掩膜灰度值为三种:0/128/256,256表示刚生成的区域,128表示之前生成的区域
threshold(g_maskImage, g_maskImage, 1, 128, CV_THRESH_BINARY);
//漫水填充
int area = floodFill(g_floodFillImage, g_maskImage, seed, Scalar::all(255), &roi_rect,
Scalar::all(g_nLowDifference),Scalar::all(g_nUpDifference), flags);
//threshold(g_maskImage, g_edgeImage, 200, 255, CV_THRESH_BINARY);
//imshow( "mask", g_maskImage );

//填充区域的统计信息
vector<uchar> roi_info;
for( int i = roi_rect.y; i < roi_rect.y+roi_rect.height; ++i)
{
for( int j = roi_rect.x; j < roi_rect.x+roi_rect.width; ++j )
{
//由于mask的尺寸大于原图,所以原图的坐标(x,y)对应于模板为(x+1,y+1)
if(g_maskImage.at<uchar>(i+1,j+1)==255)
{
roi_info.push_back(g_floodFillImage.at<uchar>(i,j));
}
}
}

//均值
double sum = std::accumulate(std::begin(roi_info), std::end(roi_info), 0.0);
double mean =  sum / roi_info.size();

//方差
double accum  = 0.0;
std::for_each (std::begin(roi_info), std::end(roi_info), [&](const double d) {
accum  += (d-mean)*(d-mean);  });
double stdev = sqrt(accum/(roi_info.size()-1));

//最大值最小值
double min = *std::min_element(std::begin(roi_info), std::end(roi_info));
double max = *std::max_element(std::begin(roi_info),std::end(roi_info));

//显示统计信息
int text_x = roi_rect.x+roi_rect.width;//写字的位置
int text_y = roi_rect.y+roi_rect.height/4;
int line_gap = 20;//字体行间距
char text_area[1024];
sprintf(text_area,"area:%d",area);
putText(g_showImage,text_area,Point(text_x,text_y),CV_FONT_HERSHEY_COMPLEX,0.5,Scalar(0,0,255),1,8);
char text_mean[1024];
sprintf(text_mean,"mean:%.2f",mean);
putText(g_showImage,text_mean,Point(text_x,text_y+line_gap),CV_FONT_HERSHEY_COMPLEX,0.5,Scalar(0,0,255),1,8);
char text_max[1024];
sprintf(text_max,"max:%.2f",max);
putText(g_showImage,text_max,Point(text_x,text_y+line_gap*2),CV_FONT_HERSHEY_COMPLEX,0.5,Scalar(0,0,255),1,8);
char text_min[1024];
sprintf(text_min,"min:%.2f",min);
putText(g_showImage,text_min,Point(text_x,text_y+line_gap*3),CV_FONT_HERSHEY_COMPLEX,0.5,Scalar(0,0,255),1,8);
char text_std[1024];
sprintf(text_std,"stdev:%.2f",stdev);
putText(g_showImage,text_std,Point(text_x,text_y+line_gap*4),CV_FONT_HERSHEY_COMPLEX,0.5,Scalar(0,0,255),1,8);

//将统计区域的边缘绘制在原图上
Canny(g_maskImage,g_edgeImage,20,60);
for( int i = roi_rect.y; i < roi_rect.y+roi_rect.height; ++i)
{
for( int j = roi_rect.x; j < roi_rect.x+roi_rect.width; ++j )
{
//由于mask的尺寸大于原图,所以原图的坐标(x,y)对应于模板为(x+1,y+1)
if(g_edgeImage.at<uchar>(i+1,j+1)==255)
{
g_showImage.at<Vec3b>(i,j)[0]= 0;
g_showImage.at<Vec3b>(i,j)[1]= 0;
g_showImage.at<Vec3b>(i,j)[2]= 255;
}
}
}

//imshow("edge",g_edgeImage);
imshow("效果图", g_showImage);
}

int main( int argc, char** argv )
{
//载入原图
g_srcImage = imread("1.bmp", 0);
if( !g_srcImage.data ) { printf("Oh,no,读取图片image0错误~! \n"); return false; }

//拷贝源图到目标图--用于计算的图
g_srcImage.copyTo(g_floodFillImage);

//构造显示的图像(仅用来显示和获取鼠标坐标,不参与计算)
g_srcImage.copyTo(g_showImage);
//显示的图为彩色格式,用来显示彩色的边缘和文字
cvtColor(g_showImage,g_showImage,CV_GRAY2RGB);

//初始化掩膜mask
g_maskImage.create(g_floodFillImage.rows+2, g_floodFillImage.cols+2, CV_8UC1);
g_maskImage = Scalar::all(0);

namedWindow( "效果图",CV_WINDOW_AUTOSIZE );
imshow("效果图",g_floodFillImage);

//创建Trackbar
createTrackbar( "负差最大值", "效果图", &g_nLowDifference, 255, 0 );
createTrackbar( "正差最大值" ,"效果图", &g_nUpDifference, 255, 0 );

//鼠标回调函数
setMouseCallback( "效果图", onMouse, 0 );
waitKey();
return 0;
}


4000
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐