上一篇中的方法存在的问题是矩形框不够精确,而且效果不能达到要求

这里使用凸包检测的方法,并将原来膨胀系数由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 改进的外接矩形合并拼接方法的更多相关文章

  1. Opencv 最小外接矩形合并拼接

    前一篇画出了最小外接矩形,但是有时候画出来的矩形由于中间像素干扰或者是其他原因矩形框并不是真正想要的 如图1是一个信号的雨图,被矩形框分割成了多个小框: 需要合并矩形框达到的效果: 主要思想: 扫描两 ...

  2. Opencv绘制最小外接矩形、最小外接圆

    Opencv中求点集的最小外结矩使用方法minAreaRect,求点集的最小外接圆使用方法minEnclosingCircle. minAreaRect方法原型: RotatedRect minAre ...

  3. opencv学习之路(26)、轮廓查找与绘制(五)——最小外接矩形

    一.简介 二.轮廓最小外接矩形的绘制 #include "opencv2/opencv.hpp" using namespace cv; void main() { //轮廓最小外 ...

  4. opencv轮廓外接矩形

    1.寻找轮廓 api void cv::findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray ...

  5. opencv学习之路(25)、轮廓查找与绘制(四)——正外接矩形

    一.简介 二.外接矩形的查找绘制 #include "opencv2/opencv.hpp" using namespace cv; void main() { //外接矩形的查找 ...

  6. Opencv 图片边缘检测和最小外接矩形

    #include "core/core.hpp" #include "highgui/highgui.hpp" #include "imgproc/i ...

  7. OpenCV代码:画出轮廓的外接矩形,和中心点

    #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include & ...

  8. OpenCV函数:提取轮廓相关函数使用方法

    opencv中提供findContours()函数来寻找图像中物体的轮廓,并结合drawContours()函数将找到的轮廓绘制出.首先看一下findContours(),opencv中提供了两种定义 ...

  9. cv2.minAreaRect() 生成最小外接矩形

    简介   使用python opencv返回点集cnt的最小外接矩形,所用函数为 cv2.minAreaRect(cnt) ,cnt是所要求最小外接矩形的点集数组或向量,这个点集不定个数.   cv2 ...

随机推荐

  1. Activity树图

  2. PHP smarty模版引擎基本安装

    环境:  PHP5.2 以上版本 先去官网下载smarty模版引擎的库文件到你的电脑或服务器上 smarty官方网站库文件下载地址: https://www.smarty.net/download 下 ...

  3. 洛谷9月月赛II 赛后瞎写

    看错比赛时间了....结果发现的时候已经开始了半个小时,并且当时正准备睡午觉qwq 于是就水了个t1就 去睡 跑了 T2 写着写着然后看了一发评讲被辣鸡思路给绕了进去最后发现自己宛若一个智障 类似桶的 ...

  4. creat-react-app/dva静态项目,用nginx部署在次级域名路径(如a.com/sub/)需要注意的几点

    因为要把dist文件夹部署在一个域名的次级目录,没想到和运维同学一起折腾了一下午.. 放在这里备忘,也给后来的同学一些可查的中文资料: 1,dva/cra给你的模板index.html是在public ...

  5. [uiautomator篇][9]遇到问题

    1 (1) 修改apk的存储权限,不要创建文件会提示:文件找不到 (2) 退出应用 mDevice.executeShellCommand("am force-stop com.antutu ...

  6. springboot集成shiro——登陆记住我

    在shiro配置类中增加两个方法: com.resthour.config.shrio.ShiroConfiguration /** * cookie管理对象 * @return */ @Bean p ...

  7. SpriteKit-(SKNode)

    1.初始化 + (instancetype)node; + (nullable instancetype)nodeWithFileNamed:(NSString*)filename; 2.返回边界边框 ...

  8. java面试题之BIO、NIO、AIO的应用场景

    定义: 1.BIO:同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时,服务器就启动一个线程来处理,如果这个连接不处理任何事情会造成不必要的线程开销,可以通过线程池机制改善. 2.NI ...

  9. python 面向对象与类的基本知识

    一  什么是面向对象,面向对象与类的关系. 面向对象的程序设计是用来解决扩展性. 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象 ...

  10. bzoj 1137 [POI2009]Wsp 岛屿

    题目大意 Byteotia岛屿是一个凸多边形.城市全都在海岸上.按顺时针编号1到n.任意两个城市之间都有一条笔直的道路相连.道路相交处可以自由穿行.有一些道路被游击队控制了,不能走,但是可以经过这条道 ...