前一篇画出了最小外接矩形,但是有时候画出来的矩形由于中间像素干扰或者是其他原因矩形框并不是真正想要的

如图1是一个信号的雨图,被矩形框分割成了多个小框:

需要合并矩形框达到的效果:

主要思想:

扫描两次最小外接矩形,第一次扫描出的矩形是图一的小矩形,遍历vector指定一个合并最大距离(假设是80),达到指定距离使用画矩形函数将这两个矩形占据的组合区域染成实心矩形。

第二次扫描直接扫描之前画的实心矩形图确定最终边框

过程图 膨胀处理和像素翻转:

代码:

#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
#include "iostream"
#include "cmath"
using namespace std;
using namespace cv;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 ;
} 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)[];
//cout<<"("<<cPointB<<","<<cPointG<<","<<cPointR<<")"<<" ";
}
//cout<<endl;
}
return src;
}
//imageOut 原图 ; dilation_dst膨胀图 ;imageSource单通道灰度图 ; imageTemp白图
int main(int argc,char *argv[])
{ //freopen("stdout.txt","w",stdout);
///读图 读入一个3通道彩图
Mat imageOut=imread(argv[],); //读入一个3通道彩图
Mat grayImage;cvtColor(imageOut,grayImage,CV_BGR2GRAY); //存一个灰度图
//imshow("3通道彩图",imageOut);
Mat imageTemp=imread("C:\\Users\\Administrator\\Desktop\\Rec\\temp.png",); //读一个大小一样的白图
///腐蚀去噪处理
Mat erosion_dst,temp;
int erosion_size=;
Mat element = getStructuringElement( MORPH_RECT,Size( *erosion_size + , *erosion_size+ ),
Point( erosion_size, erosion_size ) ); //腐蚀去噪处理参数
erode( imageOut,erosion_dst , element );//腐蚀去噪处理
//imshow( "腐蚀去噪处理", erosion_dst );
imwrite("C:\\Users\\Administrator\\Desktop\\Rec\\erosion_dst.png", erosion_dst);
///像素变换
Mat change_dst=change(erosion_dst);
//imshow( "像素变换", change_dst );
imwrite("C:\\Users\\Administrator\\Desktop\\Rec\\change_dst.png", change_dst);
///单通道灰度图
Mat imageSource;
cvtColor(change_dst,imageSource,CV_BGR2GRAY); //转换为单通道灰度图
//imshow("单通道灰度图",imageSource); ///接下来对imageSource单通道灰度图做处理
Mat image;
blur(imageSource,image,Size(,));
threshold(image,image,,,CV_THRESH_OTSU);
//imshow("image",image);
//imwrite("C:\\Users\\Administrator\\Desktop\\Rec\\myimage.png", image); ///寻找最外层轮廓
vector<vector<Point> > contours0;
vector<Vec4i> hierarchy0;
findContours(image,contours0,hierarchy0,RETR_EXTERNAL,CHAIN_APPROX_NONE,Point());
//imshow("最外层轮廓",image); ///连接矩形区域///////////////////////////////////////////////////////////////////
//Mat RECtest=imread("C:\\Users\\Administrator\\Desktop\\Rec\\temp.png",0);
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);
rectangle(image,Point(P_i[].x,P_i[].y),Point(P_i[].x,P_i[].y),Scalar(,,),-,);
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[3].x-P_i[2].x)*(P_i[1].y-P_i[2].y)<<" -> "<<(P_j[3].x-P_j[2].x)*(P_j[1].y-P_j[2].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)<=)
{
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(,,),-,);//画实心矩形
//rectangle(RECtest,Point(minx,miny),Point(maxx,maxy),Scalar(0,0,0),-1,1);
//cout<<minx<<","<<miny<<" "<<maxx<<","<<maxy<<endl;
//line(image,P_i[2],P_j[0],Scalar(0,0,0),1); //画线
//line(RECtest,P_i[2],P_j[0],Scalar(0,0,0),1);
//cout<<"yes";
}
//cout<<endl;
/*rect_i=rect_j;
for(int k=0;k<=3;k++)
{
P_i[k].x=P_j[k].x;
P_i[k].y=P_j[k].y;
}*/
}
//cout<<"---------------------------------------------------"<<endl;
}
//imwrite("C:\\Users\\Administrator\\Desktop\\Rec\\RECtest.png", RECtest);
///////////////////////////////////////////////////////////////////
/*
*/
///////////////////////////////////////////////////////////////////
//imshow("实心矩形",image);
//imwrite("C:\\Users\\Administrator\\Desktop\\Rec\\images.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(,,),,,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(grayImage,Point(minx,miny),Point(maxx,maxy),Scalar(,,),,);//二值图绘线
rectangle(imageOut,Point(minx,miny),Point(maxx,maxy),Scalar(,,),,);//原图绘线
rectangle(imageTemp,Point(minx,miny),Point(maxx,maxy),Scalar(,,),,);//白图 }
imwrite("C:\\Users\\Administrator\\Desktop\\Rec\\new1.png", grayImage);
imwrite("C:\\Users\\Administrator\\Desktop\\Rec\\new2.png", imageOut);
imwrite("C:\\Users\\Administrator\\Desktop\\Rec\\new3.png", imageTemp);
waitKey();
return ;
}

Opencv 最小外接矩形合并拼接的更多相关文章

  1. Opencv 改进的外接矩形合并拼接方法

    上一篇中的方法存在的问题是矩形框不够精确,而且效果不能达到要求 这里使用凸包检测的方法,并将原来膨胀系数由20缩小到5,达到了更好的效果 效果图: 效果图: 代码: #include <open ...

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

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

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

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

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

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

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

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

  6. opencv轮廓外接矩形

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

  7. BZOJ 1185: [HNOI2007]最小矩形覆盖-旋转卡壳法求点集最小外接矩形(面积)并输出四个顶点坐标-备忘板子

    来源:旋转卡壳法求点集最小外接矩形(面积)并输出四个顶点坐标 BZOJ又崩了,直接贴一下人家的代码. 代码: #include"stdio.h" #include"str ...

  8. OpenCV 求外接矩形以及旋转角度

    程序没有写完整,大概功能就是实现了,希望大家分享学习,把他改对 // FindRotation-angle.cpp : 定义控制台应用程序的入口点. // // findContours.cpp : ...

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

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

随机推荐

  1. day01_02.php的开发环境准备

    PHP开发环境的准备 此套课程推荐xampp,也就是Apache+Mysql+PHP 但是我自己的机器装的是wamp环境,稍微有一些不一样,但是不影响使用

  2. 让 PHP COOKIE 立即生效(不用刷新就可以使用)

    <?php function set_my_cookie($, $path = '', $domain = '') { $_COOKIE[$var] = $value; setcookie($v ...

  3. 微信小程序开发 -- 手机振动

    wx.vibrateLong(OBJECT) wx.vibrateLong(OBJECT) 方法使手机发生较长时间的振动(400ms) OBJECT参数说明: 参数名 类型 必填 说明 success ...

  4. Deep Android Malware Detection小结

    题目:Deep Android Malware Detection 作者:Niall McLaughlin, Jesus Martinez del Rincon, BooJoong Kang 年份:2 ...

  5. webapi同时支持post和get报404错误

    文章:webapi设置一个Action同时支持get和post请求 这篇文章,有提供方法.参数前加上[FromUri] [AcceptVerbs("GET", "POST ...

  6. 1.ABP使用boilerplate模版创建解决方案

    1.到ABP框架的官网(http://www.aspnetboilerplate.com/),自动生成一个解决方案 每步注解: 第一步:AngularJS是一款比较火的SPA(Single Page ...

  7. 【Luogu】P2486染色(树链剖分)

    题目链接 线段树维护左端颜色,右端颜色,颜色段数量. 合并的时候看左子树的右端颜色是不是等于右子树的左端颜色,如果等于那么颜色段数量要-1S 然后在树剖跳链的时候搞同样的操作qwq 然后就没有然后了 ...

  8. HDU——1393Weird Clock(水题,注意题意)

    Weird Clock Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Tota ...

  9. 如何在 Windows 上 使用 ONLYOFFICE 协作编辑文档

    ONLYOFFICE Document Server提供文档协作的服务功能,支持Word,Excel和PowerPoint的协作.但是这里告诉我们,需要进行文档管理和存储的二次开发. Please n ...

  10. 如何在Windows上卸载DB2

    怎么在Windows下正确卸载DB2: http://www.360doc.com/content/11/1117/16/7485728_165237689.shtml ↑↑↑ 上面的文章挺复杂,我没 ...