Opencv 改进的外接矩形合并拼接方法
上一篇中的方法存在的问题是矩形框不够精确,而且效果不能达到要求
这里使用凸包检测的方法,并将原来膨胀系数由20缩小到5,达到了更好的效果
效果图:

效果图:

代码:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace cv;
using namespace std;
//设置全局参数
Mat srcImage, srcGray;
int thresh = ;
int max_thresh = ;
RNG rng();
Mat thresh_callback(int, void*)
{
Mat srcTemp = srcImage.clone();
Mat threMat;
//轮廓检测参数
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
//阈值化操作
threshold(srcGray, threMat, thresh, , THRESH_BINARY);
//轮廓检测
findContours(threMat, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(, ));
//凸包及缺陷检测参数
vector<vector<Point> > pointHull(contours.size());
vector<vector<int> > intHull(contours.size());
vector<vector<Vec4i> > hullDefect(contours.size());
for (size_t i = ; i < contours.size(); i++)
{
//Point类型凸包检测
convexHull(Mat(contours[i]), pointHull[i], false);
//int 类型凸包检测
convexHull(Mat(contours[i]), intHull[i], false);
//凸包缺陷检测
convexityDefects(Mat(contours[i]), intHull[i], hullDefect[i]);
}
//绘制凸包及缺陷检测
Mat drawing = Mat::zeros(threMat.size(), CV_8UC3);
for (size_t i = ; i < contours.size(); i++)
{
Scalar color = Scalar(rng.uniform(, ), rng.uniform(, ), rng.uniform(, ));
drawContours(drawing, contours, i, Scalar(,,), -, , vector<Vec4i>(), , Point());
drawContours(drawing, pointHull, i, Scalar(,,), -, , vector<Vec4i>(), , Point());
//绘制缺陷
size_t count = contours[i].size();
if (count < )
continue;
//设置凸包缺陷迭代器
vector<Vec4i>::iterator iterDefects = hullDefect[i].begin();
//遍历得到4个特征量
while (iterDefects != hullDefect[i].end())
{
Vec4i& v = (*iterDefects);
//起始位置
int startidx = v[];
Point ptStart(contours[i][startidx]);
//终止位置
int endidx = v[];
Point ptEnd(contours[i][endidx]);
//内凸壳最远的点缺陷
int faridx = v[];
Point ptFar(contours[i][faridx]);
//凸点之间的最远点
int depth = v[] / ;
//绘制相应的线与圆检测结果
if (depth > && depth < )
{
line(drawing, ptStart, ptFar, CV_RGB(,,), );
line(drawing, ptEnd, ptFar, CV_RGB(,,), );
}
iterDefects++;
}
}
return drawing;
}
Mat change(Mat src)
{
int cPointR,cPointG,cPointB,cPoint;
for(int i=; i<src.rows; i++)
{
for(int j=; j<src.cols; j++)
{
cPointB=src.at<Vec3b>(i,j)[]=src.at<Vec3b>(i,j)[];
cPointG=src.at<Vec3b>(i,j)[]=src.at<Vec3b>(i,j)[];
cPointR=src.at<Vec3b>(i,j)[]=src.at<Vec3b>(i,j)[];
if(cPointR>||cPointG>||cPointB>)
{
src.at<Vec3b>(i,j)[]=;
src.at<Vec3b>(i,j)[]=;
src.at<Vec3b>(i,j)[]=;
}
else
{
src.at<Vec3b>(i,j)[]=;
src.at<Vec3b>(i,j)[]=;
src.at<Vec3b>(i,j)[]=;
}
cPointB=src.at<Vec3b>(i,j)[]=src.at<Vec3b>(i,j)[];
cPointG=src.at<Vec3b>(i,j)[]=src.at<Vec3b>(i,j)[];
cPointR=src.at<Vec3b>(i,j)[]=src.at<Vec3b>(i,j)[];
}
}
return src;
}
///矩形测距
int Distance(Rect rect1,Rect rect2)
{
// 用于判断rect1在rect2的第三象限里 用于反转X轴用
bool isInversion;
// 保存两个比较的点
Point point1;
Point point2;
// 判断 rect1 在rect2的上面还是下面 也就是说是在第一、二象限还是在三四象限
if(rect1.y<rect2.y)
{
// 判断rect1 在rect2的左边还是右边 也就是说是在 一象限还是二象限
isInversion= rect1.x<rect2.x;
if(isInversion )
{
// 取rect1的右上点
point1 = Point(rect1.x+rect1.width,rect1.y+rect1.height);
// 取rect2的左下点
point2 = Point(rect2.x,rect2.y);
}
else
{
// 取rect1的左上点
point1 = Point(rect1.x,rect1.y+rect1.height);
// 取rect2的右下点
point2 = Point(rect2.x+rect2.width,rect2.y);
}
}
else
{
// 判断rect1 在rect2的左边还是右边 也就是说是在 三象限还是四象限
isInversion = rect1.x>rect2.x;
if(isInversion)
{
// 取rect2的右上点
point1 = Point(rect2.x+rect2.width,rect2.y+rect2.height);
// 取rect1的左下点
point2 = Point(rect1.x,rect1.y);
}
else
{
// 取rect2的左上点
point1 = Point(rect2.x,rect2.y+rect2.height);
// 取rect1的右下点
point2 = Point(rect1.x+rect1.width,rect1.y);
}
}
// 做向量减法
Point dPoint = point2 -point1;
// 如果反转x轴
dPoint.x = isInversion? dPoint.x:-dPoint.x;
// 如果这个向量在第三象限里 那么这两个矩形相交 返回-1
if(dPoint.x<&& dPoint.y<)
return -;
// 如果x<0 返回y
if(dPoint.x<)
return dPoint.y;
// 如果y小于0 返回x
if(dPoint.y<)
return dPoint.x;
// 返回这个向量的长度
return abs(sqrt((point1.x-point2.x)*(point1.x-point2.x)+(point1.y-point2.y)*(point1.y-point2.y)));
}
int main()
{
//freopen("stdout.txt","w",stdout);
///读图
//srcImage = imread("C:\\Users\\Administrator\\Desktop\\1-gl300c.png",1);
//srcImage = imread("C:\\Users\\Administrator\\Desktop\\2-P330D.png",1);
srcImage = imread("C:\\Users\\Administrator\\Desktop\\3-spark.png",);
Mat outImage=srcImage;
if (!srcImage.data)
return -; ///腐蚀去噪处理
Mat erosion_dst,temp;
int erosion_size=;
Mat element = getStructuringElement( MORPH_RECT,Size( *erosion_size + , *erosion_size+ ),
Point( erosion_size, erosion_size ) ); //腐蚀去噪处理参数
erode( srcImage,erosion_dst, element ); //腐蚀去噪处理
//imshow( "腐蚀去噪处理", erosion_dst ); ///像素变换
Mat change_dst=change(erosion_dst);
srcImage=erosion_dst; ///转灰度图
cvtColor(srcImage, srcGray, CV_BGR2GRAY);
blur(srcGray, srcGray, Size(, )); ///凸包检测
Mat image=thresh_callback(, );
//imwrite("C:\\Users\\Administrator\\Desktop\\image.png", image); ///转单通道灰度图
Mat imageSource;
cvtColor(image,imageSource,CV_BGR2GRAY);
blur(imageSource,image,Size(,));
threshold(image,image,,,CV_THRESH_OTSU); ///寻找最外层轮廓
vector<vector<Point> > contours0;
vector<Vec4i> hierarchy0;
findContours(image,contours0,hierarchy0,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point());
cout<<contours0.size()<<endl; ///连接矩形区域
for(int i=; i<contours0.size(); i++)
{
RotatedRect rect_i=minAreaRect(contours0[i]);
Point2f P_i[];
rect_i.points(P_i);
int lable=;
for(int j=i+; j<contours0.size(); j++)
{
RotatedRect rect_j=minAreaRect(contours0[j]);
Point2f P_j[];
rect_j.points(P_j);
double recArea_i=contourArea(contours0[i]);
double recArea_j=contourArea(contours0[j]);
//cout<<"两矩形坐标:("<<P_i[1].x<<","<<P_i[1].y<<") ("<<P_i[3].x<<","<<P_i[3].y<<") --> ("<<P_j[1].x<<","<<P_j[1].y<<") ("<<P_j[3].x<<","<<P_j[3].y<<") ";
Rect r_j = rect_j.boundingRect();
Rect r_i = rect_i.boundingRect();
//cout<<"两矩形面积:"<<recArea_i<<" -> "<<recArea_j<<" 距离:"<<Distance(r_i,r_j)<<" ";
if(Distance(r_i,r_j)<=&&(recArea_i<&&recArea_j<))
{
lable=;
int minx=min(P_i[].x,P_j[].x);
int maxx=max(P_i[].x,P_j[].x);
int miny=min(P_i[].y,P_j[].y);
int maxy=max(P_i[].y,P_j[].y);
rectangle(image,Point(minx,miny),Point(maxx,maxy),Scalar(,,),-,);//画实心矩形
//cout<<"yes";
}
//cout<<endl;
}
//cout<<"---------------------------------------------------"<<endl;
if(lable==&&contourArea(contours0[i])<)
rectangle(image,Point(P_i[].x,P_i[].y),Point(P_i[].x,P_i[].y),Scalar(,,),-,);
else
rectangle(image,Point(P_i[].x,P_i[].y),Point(P_i[].x,P_i[].y),Scalar(,,),-,);
}
//imwrite("C:\\Users\\Administrator\\Desktop\\image2.png", image); ///绘制轮廓
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours(image,contours,hierarchy,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point());
Mat imageContours=Mat::zeros(image.size(),CV_8UC1); //最小外接矩形画布
for(int i=; i<contours.size(); i++)
{
///绘制轮廓
//drawContours(imageContours,contours,i,Scalar(0,0,0),1,8,hierarchy);
///绘制轮廓的最小外结矩形
RotatedRect rect=minAreaRect(contours[i]);
Point2f P[];
rect.points(P); int minx=min(P[].x,P[].x)+;
int maxx=max(P[].x,P[].x)-;
int miny=min(P[].y,P[].y)+;
int maxy=max(P[].y,P[].y)-;
rectangle(outImage,Point(minx,miny),Point(maxx,maxy),Scalar(,,),,);//二值图绘线 }
imwrite("C:\\Users\\Administrator\\Desktop\\image.png", outImage); waitKey();
return ;
}
Opencv 改进的外接矩形合并拼接方法的更多相关文章
- Opencv 最小外接矩形合并拼接
前一篇画出了最小外接矩形,但是有时候画出来的矩形由于中间像素干扰或者是其他原因矩形框并不是真正想要的 如图1是一个信号的雨图,被矩形框分割成了多个小框: 需要合并矩形框达到的效果: 主要思想: 扫描两 ...
- Opencv绘制最小外接矩形、最小外接圆
Opencv中求点集的最小外结矩使用方法minAreaRect,求点集的最小外接圆使用方法minEnclosingCircle. minAreaRect方法原型: RotatedRect minAre ...
- opencv学习之路(26)、轮廓查找与绘制(五)——最小外接矩形
一.简介 二.轮廓最小外接矩形的绘制 #include "opencv2/opencv.hpp" using namespace cv; void main() { //轮廓最小外 ...
- opencv轮廓外接矩形
1.寻找轮廓 api void cv::findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray ...
- opencv学习之路(25)、轮廓查找与绘制(四)——正外接矩形
一.简介 二.外接矩形的查找绘制 #include "opencv2/opencv.hpp" using namespace cv; void main() { //外接矩形的查找 ...
- Opencv 图片边缘检测和最小外接矩形
#include "core/core.hpp" #include "highgui/highgui.hpp" #include "imgproc/i ...
- OpenCV代码:画出轮廓的外接矩形,和中心点
#include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include & ...
- OpenCV函数:提取轮廓相关函数使用方法
opencv中提供findContours()函数来寻找图像中物体的轮廓,并结合drawContours()函数将找到的轮廓绘制出.首先看一下findContours(),opencv中提供了两种定义 ...
- cv2.minAreaRect() 生成最小外接矩形
简介 使用python opencv返回点集cnt的最小外接矩形,所用函数为 cv2.minAreaRect(cnt) ,cnt是所要求最小外接矩形的点集数组或向量,这个点集不定个数. cv2 ...
随机推荐
- Python 综合应用小项目一
数据库报错重连机制 利用异常捕获来获取mysql断开的报错,然后再重连 import MySQLdb as mysql class DB: def __init__(self,host,user,pa ...
- Java中String类通过new创建和直接赋值字符串的区别
方式一:String a = “aaa” ; 方式二:String b = new String(“aaa”); 两种方式都能创建字符串对象,但方式一要比方式二更优. 因为字符串是保存在常量池中的,而 ...
- java基础语法中容易出错的细节
1 java中的数字默认类型为int **容易出现类型转换错误 long 定义的数字后面必须有 “l” “L” float 定义的数字后面必须有 “f” “F” java中比int表述范围大的数,不会 ...
- 浅谈抓取网页数据(奉上Demo)
Demo源码 背景 曾经在公司做过一个比价系统,就是抓取其它网站上商品的价格并和自己公司的商品进行对应,然后展示出来,给pm提供一个定价的参考.后来,有同事的朋友在找工作的时候,猎头让其做一个抓取去哪 ...
- day01_01.了解php
1.了解PHP 第一个程序 echo 'hello world'; 和python的区别,python是 print (hello world) 并且python结尾没有;2.X版本不需要加括号,但是 ...
- 九度oj 题目1552:座位问题
题目描述: 计算机学院的男生和女生共n个人要坐成一排玩游戏,因为计算机的女生都非常害羞,男生又很主动,所以活动的组织者要求在任何时候,一个女生的左边或者右边至少有一个女生,即每个女生均不会只与男生相邻 ...
- 九度oj 题目1362:左旋转字符串(Move!Move!!Move!!!)
题目描述: 汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果.对于一个给定的字符序列S,请你把其循环左移K位后的序列输出.例如,字符序列S=”ab ...
- 用js判断浏览器类型及设备
<!DOCTYPE html> <html> <head> <title>JS判断是什么设备是什么浏览器</title> <meta ...
- hdu5852 Intersection is not allowed! 【矩阵行列式】
题意 给出\(n*n\)网格\((n<=10^5)\) 顶部有\(K\)个起点,底部有\(K\)个相对应的终点 每次只能向下或向右走 求有多少种从各个起点出发到达对应终点且路径不相交的路径? 对 ...
- setsockopt等高级使用
参考: setsockopt函数使用http://hi.baidu.com/yelangdefendou/item/74161d0f384abd3c4ac4a316http://blog.csdn.n ...