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 ...
随机推荐
- webdriver高级应用-使用JavaScript操作页面元素
Webdriver搞不定的,需要用js,无需引入有关js的包就可用 在WebDriver脚本代码中执行JavaScript代码,来实现对页面元素的操作.此方法主要用于解决在某些情况下,页面元素的.cl ...
- python week08 并发编程之多进程--实践部分
一 multiprocessing模块介绍 python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程.P ...
- day05_05 for循环、break语句
1.0 输入用户名,密码练习 _user = "alex" _passwd = "abc123" username = input("Username ...
- Shape,expand_dims,slice基本用法
import tensorflow as tf t = tf.constant([[[1, 1, 1], [2, 2, 2]], [[3, 3, 3], [4, 4, 4]], [[5, 5, 5], ...
- 深入新版BS4源码 探索flex和工程化sass奥秘
你可能已经听说了一个“大新闻”:Bootstrap4 合并了代号为#21389的PR,宣布放弃支持IE9,并默认使用flexbox弹性盒模型.这标志着:1)前端开发全面步入“现代浏览器”的时代进一步来 ...
- [转] Makefile 基础 (2) —— Makefile 总述
该篇文章为转载,是对原作者系列文章的总汇加上标注. 支持原创,请移步陈浩大神博客:(最原始版本) http://blog.csdn.net/haoel/article/details/2886 我转自 ...
- 解决 Jackson反序列化 Unexpected token ... , expected VALUE_STRING: need JSON String that contains type id (for subtype of ...)
首先检查是否是 objectMapper.enableDefaultTyping(); 的受害者.优先考虑删除该配置. 使用Jackson把数组的json字符串反序列化为List时候报了个JsonMa ...
- The Luckiest number(hdu 2462)
给定一个数,判断是否存在一个全由8组成的数为这个数的倍数 若存在则输出这个数的长度,否则输出0 /* 个人感觉很神的一道题目. 如果有解的话,会有一个p满足:(10^x-1)/9*8=L*p => ...
- javaweb学习总结(十五)——JSP基础语法(转)
任何语言都有自己的语法,JAVA中有,JSP虽然是在JAVA上的一种应用,但是依然有其自己扩充的语法,而且在JSP中,所有的JAVA语句都可以使用. 一.JSP模版元素 JSP页面中的HTML内容称之 ...
- 【CF1020C】Elections(贪心)
题意: Berland地区的腐败现象非常常见. 马上有一场选举,你事先知道了选民和政党的数量,分别为 n 和 m ,对于每一位选民,你知道他将要选举哪一个政党, 不过,每一位选民都会在接受一定数额的金 ...