寻找轮廓:findContours()函数-------用于在二值图像中寻找轮廓
void findContours(
InputOutputArray image, //输入图像
OutputArrayOfArrays contours, //检测到的轮廓、函数调用后的运算结果存在这里
OutputArray hierarchy, //可选的输出向量,包含图像的拓普信息
int mode, //轮廓检索模式
int method, //为轮廓的近似办法
Point offset=Point() //每个轮廓点的可选偏移量
);
参数四:可选的轮廓检索模式
①RETR_EXTERNAL----表示只检测最外面的轮廓。对所有轮廓,设置hierarchy[i][2]=hierarchy[i][3]=-1
②RETR_LIST------提取所有轮廓,并且放置在list中。检测的轮廓不建立等级关系
③RETR_CCOMP-----提取所有轮廓,并且将其组织为双层结构(顶层为连通域的外围边界;次层为孔的内层边界)
④RETR_TREE------提取所有轮廓,并重新建立网状的轮廓结构
参数五:可选的轮廓的近似办法
①CHAIN_APPROX_NONE------获取每个轮廓的每个像素,相邻的两点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
②CHAIN_APPROX_SIMPLE-----压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标(eg:矩形轮廓只需4个点来保存轮廓)
③CHAIN_APPROX_TC89_L1,CHAIN_APPROX_TC89_KCOS-----使用Teh-Chinl链逼近算法中的一个
绘制找轮廓:drawdContours()函数--------用于在图像中绘制外部或内部轮廓
void drawdContours(
InputOutputArray image, //输入图像
InputArrayOfArrays contours, //所有的输入轮廓
int contourIdx, //轮廓绘制的指示变量
const Scalar& color, //轮廓的颜色
int thickness=1, //轮廓线条的粗细度
int lineType=8, //线条的类型(默认8---8连通线性;4;LINE_AA----抗锯齿线型)
InputArray hierarchy=noArray(), //可选的层次结构信息(默认noArray())
int maxLevel=INT_MAX, //表示用于轮廓绘制的最大等级(默认INT_MAX)
Point offset=Point() //每个轮廓点的可选偏移量
);
查找并绘制轮廓综合示例代码:
//-----------------------【查找并绘制轮廓】-----------------------
#include
#include
#include
#include
using namespace cv;
using namespace std;
//--------------------【宏定义部分】-----------------
// 描述:定义一些辅助宏
//---------------------------------------------------
#define WINDOW_NAME1 "【原始图窗口】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【轮廓图】" //为窗口标题定义的宏
//--------------------【全局变量声明部分】----------------
// 描述:全局变量声明
//--------------------------------------------------------
Mat g_srcImage, g_grayImage;
int g_nThresh = 80, g_nThresh_max = 255;
RNG g_rng(12345);
Mat g_cannyMat_output;
vector> g_vContours;
vector g_vHierarchy;
//--------------------【全局函数声明部分】----------------
// 描述:全局函数声明
//--------------------------------------------------------
static void ShowHelpText();
void on_ThreshChange(int,void*);
//--------------------【main()函数】-----------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//---------------------------------------------------------
int main(int argc,char** argv) {
//改变console的颜色
system("color 1F");
//显示欢迎和帮助文档
ShowHelpText();
//载入原图
g_srcImage = imread("juan.jpg");
if (!g_srcImage.data) { printf("读取图片错误 \n"); return false; }
//转换灰度并模糊化降噪
cvtColor(g_srcImage,g_grayImage,COLOR_BGR2GRAY);
blur(g_grayImage,g_grayImage,Size(3,3));
//创建窗口
namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME1, g_srcImage);
//创建滚动条并初始化
createTrackbar("canny阈值",WINDOW_NAME1,&g_nThresh,g_nThresh_max,on_ThreshChange);
on_ThreshChange(0,0);
waitKey (0);
return 0;
}
//--------------------------【on_ThreshChange()函数】----------------------
// 描述:回调函数
//-----------------------------------------------------------------------
void on_ThreshChange(int,void*) {
//用Canny算子检测边缘
Canny(g_grayImage,g_cannyMat_output,g_nThresh,g_nThresh*2,3);
//寻找轮廓
findContours(g_cannyMat_output,g_vContours,g_vHierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point(0,0));
//绘出轮廓
Mat drawing = Mat::zeros(g_cannyMat_output.size(),CV_8UC3);
for (int i = 0; i < g_vContours.size();i++) {
Scalar color=Scalar(g_rng.uniform(0,255),g_rng.uniform(0,255),g_rng.uniform(0,255));//任意值
drawContours(drawing,g_vContours,i,color,2,8,g_vHierarchy,0,Point());
}
//显示图像
imshow(WINDOW_NAME2,drawing);
}
//--------------------------【ShowHelpText()函数】----------------------
// 描述:输出一些帮助信息
//-----------------------------------------------------------------------
static void ShowHelpText() {
//输出一些帮助信息
printf("\n\n\n\t欢迎来到【在图形中寻找轮廓】示例程序~\n\n");
printf("\t当前使用的opencv版本为opencv3.4.1");
printf("\n\n\t按键操作说明:\n\n"
"\n\n\t按键盘任意键-退出程序\n\n"
"\t\t滑动滚动条改变阈值\n\n");
}
给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它是包含点集中所有点的。
寻找凸包:convexHull()函数---用于寻找图像点集中的凸包
void convexHull(
InputArray points, //输入的二维点集
OutputArray hull, //输出参数,函数调用后找到的凸包
bool clockwise=false, //操作方向标识符(为真时,凸包为顺时针方像。否则逆时针)
bool returnPoints=true//操作标识符(默认true--返回各凸包的各个点,否则返回凸包个点的指数)
);
寻找和绘制物体的凸包示例代码:
//-------------------------【寻找和绘制物体的凸包】------------------
#include
#include
#include
#include
using namespace cv;
using namespace std;
//--------------------【宏定义部分】-----------------
// 描述:定义一些辅助宏
//---------------------------------------------------
#define WINDOW_NAME1 "【原始图窗口】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【效果图窗口】" //为窗口标题定义的宏
//--------------------【全局变量声明部分】----------------
// 描述:全局变量声明
//--------------------------------------------------------
Mat g_srcImage, g_grayImage;
int g_nThresh =50, g_maxThresh = 255;
RNG g_rng(12345);
Mat srcImage_copy=g_srcImage.clone();
Mat g_thresholdImage_output;
vector> g_vContours;
vector g_vHierarchy;
//--------------------【全局函数声明部分】----------------
// 描述:全局函数声明
//--------------------------------------------------------
void on_ThreshChange(int, void*);
//--------------------【main()函数】-----------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//---------------------------------------------------------
int main(int argc, char** argv) {
//载入原图
g_srcImage = imread("juan.jpg");
if (!g_srcImage.data) { printf("读取图片错误 \n"); return false; }
//转换灰度并模糊化降噪
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
blur(g_grayImage, g_grayImage, Size(3, 3));
//创建窗口
namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME1, g_srcImage);
//创建滚动条并初始化
createTrackbar("阈值", WINDOW_NAME1, &g_nThresh, g_maxThresh, on_ThreshChange);
on_ThreshChange(0, 0);//调用一次进行初始化
waitKey(0);
return 0;
}
//--------------------------【on_ThreshChange()函数】----------------------
// 描述:回调函数
//-----------------------------------------------------------------------
void on_ThreshChange(int, void*) {
//对图像进行二值化,控制阈值
threshold(g_grayImage,g_thresholdImage_output,g_nThresh,255,THRESH_BINARY);
//寻找轮廓
findContours(g_thresholdImage_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//遍历每个轮廓寻找其凸包
vector>hull(g_vContours.size());
for (unsigned int i = 0; i < g_vContours.size();i++) {
convexHull(Mat(g_vContours[i]),hull[i],false);
}
//绘出轮廓及其凸包
Mat drawing = Mat::zeros(g_thresholdImage_output.size(), CV_8UC3);
for (unsigned int i = 0; i < g_vContours.size(); i++) {
Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));//任意值
drawContours(drawing, g_vContours, i, color, 1, 8, vector(), 0, Point());
drawContours(drawing, hull, i, color, 1, 8, vector(), 0, Point());
}
//显示图像
imshow(WINDOW_NAME2, drawing);
}
返回外部矩形边界:boundingRect()函数----计算并返回指定点集最外面的矩形边界
Rect boundingRect(InputArray points);//参数:输入的二维点集
寻找最小包围矩形:minAreaRect()函数----用于对给定的2D点集,寻找可旋转的最小面积的包围矩形
RotatedRect minAreaRect(InputArray points);//参数:输入的二维点集
寻找最小包围圆形:minEnclosingCircle()函数----利用一种迭代算法对给定的2D点集,去寻找面积最小的可包围他们的圆形
void minEnclosingCircle(InputArray points,Point2f& center,float& radius);//参数:输入的二维点集、圆心、圆半径
用椭圆拟合二维点集:fitEllipse()函数
RotatedRect fitEllipse(InputArray points);
逼近多边形曲线:approxPolyDP()函数
void approxPolyDP(
InputArray curve, //输入的二维点集
OutputArray approxCurve,//多边形逼近的结果
double epsilon, //逼近的精度
bool closed //为真则近似的曲线为封闭曲线,否则不封闭
);
使用多边形包围轮廓示例代码:
//----------------【使用多边形包围轮廓】-----------------
#include
#include
#include
#include
using namespace cv;
using namespace std;
//--------------------【宏定义部分】-----------------
// 描述:定义一些辅助宏
//---------------------------------------------------
#define WINDOW_NAME1 "【原始图窗口】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【效果图窗口】" //为窗口标题定义的宏
//--------------------【全局变量声明部分】----------------
// 描述:全局变量声明
//--------------------------------------------------------
Mat g_srcImage, g_grayImage;
int g_nThresh = 50, g_maxThresh = 255;
RNG g_rng(12345);//随机数生成器
//--------------------【全局函数声明部分】----------------
// 描述:全局函数声明
//--------------------------------------------------------
void on_ContoursChange(int, void*);
static void ShowHelpText();
//--------------------【main()函数】-----------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//---------------------------------------------------------
int main(int argc, char** argv) {
//改变console字体颜色
system("color 1A");
//载入原图
g_srcImage = imread("juan.jpg",1);
if (!g_srcImage.data) { printf("读取图片错误 \n"); return false; }
//转换灰度并模糊化(平滑)降噪
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
blur(g_grayImage, g_grayImage, Size(3, 3));
//创建窗口
namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME1, g_srcImage);
//创建滚动条并初始化
createTrackbar("阈值", WINDOW_NAME1, &g_nThresh, g_maxThresh, on_ContoursChange);
on_ContoursChange(0, 0);//调用一次进行初始化
waitKey(0);
return 0;
}
//--------------------------【on_ContoursChange()函数】----------------------
// 描述:回调函数
//-----------------------------------------------------------------------
void on_ContoursChange(int, void*) {
//定义一些参数
Mat threshold_output;
vector> contours;
vector hierarchy;
//对图像进行二值化,控制阈值(边缘检测)
threshold(g_grayImage, threshold_output, g_nThresh, 255, THRESH_BINARY);
//寻找轮廓
findContours(threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//多边形逼近轮廓+获取矩形和圆形边界框
vector> contours_poly(contours.size());
vector boundRect(contours.size());
vector center(contours.size());
vectorradius(contours.size());
//遍历所有部分,进行本程序最核心的操作
for (unsigned int i = 0; i (), 0, Point());
rectangle(drawing,boundRect[i].tl(),boundRect[i].br(),color,2,8,0 );//绘制矩形
circle(drawing,center[i],(int)radius[i],color,2,8,0 );//绘制圆
}
//显示图像
namedWindow(WINDOW_NAME2,WINDOW_AUTOSIZE);
imshow(WINDOW_NAME2, drawing);
}
一个从一幅数字图像中计算出来的矩集,通常描述了该图像形状的全局特征,并提供了大量的关于该图像不同类型的几何特性信息(大小、位置、方向及形状)。
一阶矩与形状有关;
二阶矩显示曲线围绕直线平均值的扩展程度;
三阶矩是关于平均值的对称性的测量。
由二阶矩和三阶矩可以导出一组共7个不变矩阵
不变矩是图像的统计特征,满足平移、伸缩、旋转均不变的不变性。
矩的计算:moments()函数------用于计算多边形和光栅形状的最高达三阶的所有矩。
矩用来计算形状的重心、面积,主轴和其它形状特征。
Moments moments(InputArray array,bool binaryImage=false);
参数一:输入参数,可以是光栅图像(单通道,8位或浮点的二维数组)或二维数组。
参数二:默认值false。若此参数取true,则所有非零像素为1.此参数仅对于图像使用。
计算轮廓面积:contourArea()函数------用于计算整个轮廓或部分轮廓的面积
double contourArea(InputArray contour,bool oriented=false);
参数一:输入的向量,二维点
参数二:面向区域标识符。为true时返回一个带符号的面积值,其正负取决于轮廓的方向。根据这个特性
我们可以根据面积的符号来确定轮廓的位置。为false时,以绝对值返回,不带符号。
计算轮廓长度:arcLength()函数-----用于计算封闭轮廓的周长或曲线的长度。
double srcLength(InputArray curve,bool closed);
参数一:输入的二维点集
参数二:一个用于指定曲线是否封闭的标识符(默认closed---表示曲线封闭)
查找和绘制图像轮廓矩综合示例代码:
//--------------------【查找和绘制图像轮廓矩】----------------------
#include
#include
#include
#include
using namespace cv;
using namespace std;
//--------------------【宏定义部分】-----------------
// 描述:定义一些辅助宏
//---------------------------------------------------
#define WINDOW_NAME1 "【原始图窗口】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【效果图窗口】" //为窗口标题定义的宏
//--------------------【全局变量声明部分】----------------
// 描述:全局变量声明
//--------------------------------------------------------
Mat g_srcImage, g_grayImage;
int g_nThresh = 100, g_nMaxThresh = 255;
RNG g_rng(12345);//随机数生成器
Mat g_cannyMat_output;
vector>g_vContours;
vectorg_vHierarchy;
//--------------------【全局函数声明部分】----------------
// 描述:全局函数声明
//--------------------------------------------------------
void on_ThreshChange(int, void*);
static void ShowHelpText();
//--------------------【main()函数】-----------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//---------------------------------------------------------
int main(int argc, char** argv) {
//改变console字体颜色
system("color 1E");
//载入原图
g_srcImage = imread("lenna.jpg", 1);
if (!g_srcImage.data) { printf("读取图片错误 \n"); return false; }
//转换灰度并模糊化(平滑)降噪
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
blur(g_grayImage, g_grayImage, Size(3, 3));
//创建窗口
namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME1, g_srcImage);
//创建滚动条并初始化
createTrackbar("阈值", WINDOW_NAME1, &g_nThresh, g_nMaxThresh, on_ThreshChange);
on_ThreshChange(0, 0);//调用一次进行初始化
waitKey(0);
return 0;
}
//--------------------------【on_ThreshChange()函数】----------------------
// 描述:回调函数
//-----------------------------------------------------------------------
void on_ThreshChange(int, void*) {
//使用Canny检测边缘
Canny(g_grayImage,g_cannyMat_output,g_nThresh,g_nThresh*2,3);
//寻找轮廓
findContours(g_cannyMat_output, g_vContours, g_vHierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
//计算矩
vector mu(g_vContours.size());
for (unsigned int i = 0; i < g_vContours.size(); i++) {
mu[i] = moments(g_vContours[i],false);
}
//计算中心矩
vectormc(g_vContours.size());
for (unsigned int i = 0; i < g_vContours.size(); i++) {
mc[i] = Point2f(static_cast(mu[i].m10/mu[i].m00), static_cast(mu[i].m01 / mu[i].m00));
}
//绘制轮廓
Mat drawing = Mat::zeros(g_cannyMat_output.size(), CV_8UC3);
for (unsigned int i = 0; i < g_vContours.size(); i++) {
Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));//任意值
drawContours(drawing, g_vContours, i, color, 2, 8, g_vHierarchy, 0, Point());
circle(drawing, mc[i],4, color, -1, 8, 0);//绘制圆
}
//显示图像
namedWindow(WINDOW_NAME2, WINDOW_AUTOSIZE);
imshow(WINDOW_NAME2, drawing);
//通过m00计算轮廓面积并且和OpenCV函数比较
printf("\t输出内容:面积和轮廓长度\n");
for (unsigned int i = 0; i < g_vContours.size(); i++) {
printf(">通过m00计算出轮廓[%d]的面积:(M_00)=%.2f \n opencv函数计算出的面积=%.2f,长度:%.2f \n\n",i,mu[i].m00,
contourArea(g_vContours[i]),arcLength(g_vContours[i],true));
Scalar color = Scalar(g_rng.uniform(0, 255), g_rng.uniform(0, 255), g_rng.uniform(0, 255));//任意值
drawContours(drawing, g_vContours, i, color, 2, 8, g_vHierarchy, 0, Point());
circle(drawing, mc[i], 4, color, -1, 8, 0);//绘制圆
}
}
分水岭算法---是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学
上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域
称为集水盆,而集水盆的边界则形成分水岭。
分水岭表示的是输入图像的极大值点。
首先计算灰度图像的梯度,然后开始从用户指定点开始持续“灌注”盆地直到这些区域连成片。
基于这样产生的标记就可以把区域合并到一起,合并后的区域又通聚集的方式进行分割,好像
被“填充”起来一样。
实现分水岭算法:watershed()函数---- 一种基于标记的分割算法。
在把图像传给函数之前,我们需要大致勾画标记处图像中的期望进行分割的区域,它们被标记为正指数。
void watershed(InputArray image,InputOutArray markers);
参数一:输入图像
参数二:函数调用后的运算结果存入地,输入或输出32位单通道图像的标记结果。
分水岭算法综合示例:
//-----------------------【分水岭算法】-------------------
#include
#include
#include
#include
using namespace cv;
using namespace std;
//--------------------【宏定义部分】-----------------
// 描述:定义一些辅助宏
//---------------------------------------------------
#define WINDOW_NAME "【原始图窗口】" //为窗口标题定义的宏
//--------------------【全局变量声明部分】----------------
// 描述:全局变量声明
//--------------------------------------------------------
Mat g_maskImage, g_srcImage;
Point prevPt(-1,-1);
//--------------------【全局函数声明部分】----------------
// 描述:全局函数声明
//--------------------------------------------------------
static void ShowHelpText();
static void on_Mouse(int event,int x,int y,int flags,void*);
//--------------------【main()函数】-----------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//---------------------------------------------------------
int main(int argc, char** argv) {
//【1】载入原图
g_srcImage = imread("lenna.jpg");
if (!g_srcImage.data) { printf("读取图片错误 \n"); return false; }
imshow(WINDOW_NAME, g_srcImage);
Mat srcIamge, grayImage;
g_srcImage.copyTo(srcIamge);
cvtColor(g_srcImage,g_maskImage,COLOR_BGR2GRAY);
cvtColor(g_maskImage, grayImage,COLOR_GRAY2BGR);
g_maskImage = Scalar::all(0);
//【2】设置鼠标回调函数
setMouseCallback(WINDOW_NAME,on_Mouse,0);
//【3】轮询按键,进行处理
while (1) {
//获取键值
int c = waitKey(0);
//若按键键值为ESC时,退出
if ((char)c == 27)
break;
//按键键值为2时,恢复原图
if ((char)c == '2') {
g_maskImage = Scalar::all(0);
srcIamge.copyTo(g_srcImage);
imshow("image",g_srcImage);
}
//按键键值为1或者空格时,进行处理
if ((char)c == '1'|| (char)c == ' ') {
//定义一些参数
int i, j, compCount = 0;
vector> contours;
vector hierarchy;
//寻找轮廓
findContours(g_maskImage,contours,hierarchy,CV_RETR_CCOMP,CV_CHAIN_APPROX_SIMPLE);
//轮廓为空时的处理
if (contours.empty())
continue;;
//复制掩模
Mat maskImage(g_maskImage.size(),CV_32S);
maskImage = Scalar::all(0);
//循环绘制出轮廓
for (int index = 0; index >= 0;index=hierarchy[index][0],compCount++)
drawContours(maskImage,contours,index,Scalar::all(compCount+1),-1,8,hierarchy,INT_MAX);
//compCount为零时的处理
if (compCount == 0)
continue;
//生成随机颜色
vector colorTab;
for (i = 0; i < compCount; i++) {
int b = theRNG().uniform(0,255);
int g = theRNG().uniform(0, 255);
int r = theRNG().uniform(0, 255);
colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r));
}
//计算处理时间并输出到窗口中
double dTime = (double)getTickCount();
watershed(srcIamge,maskImage);
dTime=(double)getTickCount()-dTime;
printf("\t处理时间=%gms\n",dTime*1000./getTickFrequency());
//双层循环,将分水岭图像遍历存储到watersheImage中
Mat watershedImage(maskImage.size(),CV_8UC3);
for (i = 0; i < maskImage.rows;i++)
for (j = 0; j < maskImage.cols;j++) {
int index = maskImage.at(i, j);
if (index == -1)
watershedImage.at(i, j) = Vec3b(255, 255, 255);
else if(index<=0||index>compCount)
watershedImage.at(i, j) = Vec3b(0, 0, 0);
else
watershedImage.at(i, j) = colorTab[index-1];
}
//混合灰度图像和分水岭效果图并显示最终的窗口
watershedImage = watershedImage * 0.5 + grayImage * 0.5;
imshow("watershed transform", watershedImage);
}
}
return 0;
}
//--------------------------【on_Mouse()函数】----------------------
// 描述:鼠标消息回调函数
//-----------------------------------------------------------------------
static void on_Mouse(int event,int x,int y,int flags,void*){
//处理鼠标不在窗口中的情况
if (x < 0 || x >= g_srcImage.cols || y < 0 || y >= g_srcImage.rows)
return;
//处理鼠标左键相关消息
if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
prevPt = Point(-1,-1);
else if(event==EVENT_LBUTTONDOWN)
prevPt = Point(x, y);
//鼠标左键按下并移动,绘制出白色线条
else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON)) {
Point pt(x,y);
if (prevPt.x < 0)
prevPt = pt;
line(g_maskImage,prevPt,pt,Scalar::all(255),5,8,0);
line(g_srcImage, prevPt, pt ,Scalar::all(255), 5, 8, 0);
prevPt = pt;
imshow(WINDOW_NAME,g_srcImage);
}
}
#include
#include
#include
#include
using namespace cv;
using namespace std;
Vec3b RandomColor(int value);
int main(int argc, char* argv) {
Mat image = imread("lenna.jpg", 1);
imshow("原图像", image);
//灰度化,滤波,Canny边缘检测
Mat imageGray;
cvtColor(image, imageGray, CV_RGB2GRAY);//灰度转换
GaussianBlur(imageGray, imageGray, Size(5, 5), 2);
imshow("灰度图像", imageGray);
Canny(imageGray, imageGray, 80, 150);
imshow("canny图像", imageGray);
//查找轮廓
vector> contours;
vector hierarchy;
findContours(imageGray, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point());
Mat imageContours = Mat::zeros(image.size(), CV_8UC1);
Mat marks(image.size(), CV_32S);
marks = Scalar::all(0);
int index = 0;
int compCount = 0;
for (; index >= 0; index = hierarchy[index][0], compCount++)
{
//对marks进行标记,对不同区域的轮廓进行编号,相当于设置注水点,有多少轮廓,就有多少注水点
drawContours(marks, contours, index, Scalar::all(compCount + 1), 1, 8, hierarchy);
drawContours(imageContours, contours, index, Scalar(255), 1, 8, hierarchy);
}
//显示传入的矩阵marks
Mat marksShows;
convertScaleAbs(marks, marksShows);
imshow("marksShow", marksShows);
imshow("轮廓", imageContours);
watershed(image, marks);
//分水岭算法之后的矩阵marks
Mat afterWatershed;
convertScaleAbs(marks, afterWatershed);
imshow("分水岭处理过的图片", afterWatershed);
//对每一个区域进行颜色填充
Mat PerspectiveImage = Mat::zeros(image.size(), CV_8UC3);
for (int i = 0; i < marks.rows; i++)
{
for (int j = 0; j < marks.cols; j++)
{
int index = marks.at(i, j);
if (marks.at(i, j) == -1)
{
PerspectiveImage.at(i, j) = Vec3b(255, 255, 255);
}
else
{
PerspectiveImage.at(i, j) = RandomColor(index);
}
}
}
imshow("颜色填充后的图像", PerspectiveImage);
//分割并填充颜色的结果跟原始图像融合
Mat wshed;
addWeighted(image, 0.4, PerspectiveImage, 0.6, 0, wshed);
imshow("组合图片", wshed);
waitKey();
return 0;
}
Vec3b RandomColor(int value) {
value = value % 255;
RNG rng;
int aa = rng.uniform(0, value);
int bb = rng.uniform(0, value);
int cc = rng.uniform(0, value);
return Vec3b(aa, bb, cc);
}
图像修复就是利用那些已经被破坏区域的边缘,即边缘的颜色和结构,繁殖和混合到损坏的图像中,已达到图像修补的目的。
实现图像修补:inpaint()函数----用来从扫描的照片中清除灰尘和划痕,或者从静态图像或视频中去除不需要的物体。
void inpaint(
InputArray src, //输入图像
InputArray inpaintMask, //修复掩模。其中的非零像素表示需要修补的区域
OutputArray dst, //修复的结果图
double inpaintRadius, //需要修补的每个点的圆形邻域,为修复算法的参考半径
int flags //修补方法的标识符(INPAINT_NS---基于Navier-Stokes方程的方法,或INPAINT_TELEA---Alexandru Telea)
);
图像修补综合示例代码:
//-----------------------【图像修补】----------------------
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
//--------------------【宏定义部分】-----------------
// 描述:定义一些辅助宏
//---------------------------------------------------
#define WINDOW_NAME1 "【原始图窗口】" //为窗口标题定义的宏
#define WINDOW_NAME2 "【修补后的图像窗口】" //为窗口标题定义的宏
//--------------------【全局变量声明部分】----------------
// 描述:全局变量声明
//--------------------------------------------------------
Mat srcImage1, inpaintMask;
Point previousPoint(-1,-1);//原来的点坐标
//--------------------【全局函数声明部分】----------------
// 描述:全局函数声明
//--------------------------------------------------------
void On_Mouse(int event,int x,int y,int flags,void*);
static void ShowHelpText();
//--------------------【main()函数】-----------------------
// 描述:控制台应用程序的入口函数,我们的程序从这里开始
//---------------------------------------------------------
int main(int argc, char** argv) {
//改变console字体颜色
system("color 1A");
//载入原图
Mat srcImage = imread("juan.jpg", 1);
if (!srcImage.data) { printf("读取图片错误 \n"); return false; }
srcImage1 = srcImage.clone();
inpaintMask = Mat::zeros(srcImage1.size(),CV_8U);
//显示原图
imshow(WINDOW_NAME1,srcImage1);
namedWindow("yanma");
imshow("yanma", inpaintMask);
//设置鼠标回调函数
setMouseCallback(WINDOW_NAME1,On_Mouse,0);
//轮询按键,根据不同的按键进行处理
while (1)
{
//获取按键键值
char c = (char)waitKey();
//按键为2,恢复成原始图像
if (c=='2') {
inpaintMask = Scalar::all(0);
srcImage.copyTo(srcImage1);
imshow(WINDOW_NAME1,srcImage1);
}
//键值1或空格时,进行图像修补操作
if (c=='1'||c==' ') {
Mat inpaintedImage;
inpaint(srcImage1,inpaintMask,inpaintedImage,3,INPAINT_TELEA);
imshow(WINDOW_NAME2,inpaintedImage);
}
}
return 0;
}
//--------------------------【On_Mouse()函数】----------------------
// 描述:相应鼠标消息的回调函数
//-----------------------------------------------------------------------
static void On_Mouse(int event,int x,int y,int flags,void*) {
//鼠标左键弹起消息
if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON))
previousPoint = Point(-1,-1);
//鼠标左键按下消息
else if (event == EVENT_LBUTTONDOWN)
previousPoint = Point(x, y);
else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON))
{
Point pt(x,y);
if (previousPoint.x < 0)
previousPoint = pt;
//绘制白色线条
line(inpaintMask,previousPoint,pt,Scalar::all(255),1,8,0);
line(srcImage1, previousPoint, pt, Scalar::all(255), 1, 8, 0);
imshow(WINDOW_NAME1,srcImage1);
}
}