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 ...
随机推荐
- java web开发基础实例(javabean+jsp+servlet+jdbc)
JavaBean:用于传递数据,拥有与数据相关的逻辑处理 JSP:从Model接收数据并生成HTML Servlet:接收HTTP请求并控制Model和View jdbc:用于配置环境 一.[建立数据 ...
- 大数据学习——spark运营案例
iplocation需求 在互联网中,我们经常会见到城市热点图这样的报表数据,例如在百度统计中,会统计今年的热门旅游城市.热门报考学校等,会将这样的信息显示在热点图中. 因此,我们需要通过日志信息(运 ...
- TOJ 3581: 最简IPv6表示
3581: 最简IPv6表示 Time Limit(Common/Java):1000MS/3000MS Memory Limit:65536KByteTotal Submit: 121 ...
- java中equals和hashCode方法随笔二
前几天看了篇关于java中equals和hashCode方法的解析 1.Object类中的equals方法和hashCode方法. Object类中的equals和hashCode方法简单明了,所有的 ...
- poj 2499第K短路模板
第k*短路模板(单项边) #include <iostream> #include <cstdio> #include <algorithm> #include & ...
- c3p0-config.xml模板详解
c3p0-config.xml模板详解 <c3p0-config> <default-config> <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数.De ...
- JDBC 学习笔记(四)—— JDBC 加载数据库驱动,获取数据库连接
1. 加载数据库驱动 通常来说,JDBC 使用 Class 类的 forName() 静态方法来加载驱动,需要输入数据库驱动代表的字符串. 例如: 加载 MySQL 驱动: Class.forName ...
- 关于scarpy的一些说明
一 scrapy添加代理 1 内置代理:os.environ. 固定格式,不推荐 os.environ['http_proxy'] = "http://root:woshiniba@192 ...
- 外星人(bzoj 2749)
Description Input Output 输出test行,每行一个整数,表示答案. Sample Input 1 2 2 2 3 1 Sample Output 3 HINT Test< ...
- 快充 IC BQ25896 的 ICO (input current optimizer)
ICO (input current optimizer) 手機接上 adapter 後, 手機裡的 charger IC bq25896 開始向 adapter 抽取 current 供給 batt ...