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

这里使用凸包检测的方法,并将原来膨胀系数由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. 29、在android中采用动画方案来弹出窗口

    1.自定义style 2.使用方法: buttonWhat.setOnClickListener(new OnClickListener() { @Override public void onCli ...

  2. Nginx从入门到放弃-第5章 Nginx架构篇

    5-1 Nginx常见问题_架构篇介绍 5-2 Nginx常见问题_多个server中虚拟主机读取的优先级 5-3 Nginx常见问题_多个location匹配的优先级1 5-4 Nginx常见问题_ ...

  3. [已解决]使用 apt-get update 命令提示 ...中被配置了多次

    报错:W: 目标 Sources (main/source/Sources) 在 /etc/apt/sources.list:2 和 /etc/apt/sources.list:7 中被配置了多次 v ...

  4. BZOJ2302 [HAOI2011]Problem c 【dp】

    题目 给n个人安排座位,先给每个人一个1~n的编号,设第i个人的编号为ai(不同人的编号可以相同),接着从第一个人开始,大家依次入座,第i个人来了以后尝试坐到ai,如果ai被占据了,就尝试ai+1,a ...

  5. BZOJ3990 [SDOI2015]排序 【搜索】

    题目 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<=N),第i中操作为将序列从左到 ...

  6. docker (centOS 7) 使用笔记2 - 使用nfs作为volume

    本次测试的服务器2台,服务器#1(centos7)最为docker容器所在的host,服务器#2(centos6)提供NFS服务 1. #2上配置NFS服务 (1) 安装nfs软件包 yum -y i ...

  7. QTREE系列题目总结

    $QTREE$ 就是一套树上数据结构练习题. 这套题貌似来源于 $SPOJ$,我是在 $luogu$ 看到的. $QTREE1$ 题意 一棵 $n$ 个点的带边权树,要求支持 单边改权值 和 询问路径 ...

  8. linux下定时任务设置

    原文http://www.blogjava.net/freeman1984/archive/2010/09/23/332715.html 觉这篇文章写的挺全的,把它拿过来存在博客里,方便以后查询. 为 ...

  9. poj 3293 Rectilinear polygon

    Rectilinear polygon Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2125   Accepted: 24 ...

  10. 【CF1028C】Rectangles(线段树)

    题意: n<=1e5,abs(x[i]),abs(y[i]<=1e9 思路:这是正解 离散后线段树强打,数据结构越学越傻 #include<cstdio> #include&l ...