Opencv 最小外接矩形合并拼接
前一篇画出了最小外接矩形,但是有时候画出来的矩形由于中间像素干扰或者是其他原因矩形框并不是真正想要的
如图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 最小外接矩形合并拼接的更多相关文章
- Opencv 改进的外接矩形合并拼接方法
上一篇中的方法存在的问题是矩形框不够精确,而且效果不能达到要求 这里使用凸包检测的方法,并将原来膨胀系数由20缩小到5,达到了更好的效果 效果图: 效果图: 代码: #include <open ...
- opencv学习之路(26)、轮廓查找与绘制(五)——最小外接矩形
一.简介 二.轮廓最小外接矩形的绘制 #include "opencv2/opencv.hpp" using namespace cv; void main() { //轮廓最小外 ...
- Opencv 图片边缘检测和最小外接矩形
#include "core/core.hpp" #include "highgui/highgui.hpp" #include "imgproc/i ...
- Opencv绘制最小外接矩形、最小外接圆
Opencv中求点集的最小外结矩使用方法minAreaRect,求点集的最小外接圆使用方法minEnclosingCircle. minAreaRect方法原型: RotatedRect minAre ...
- cv2.minAreaRect() 生成最小外接矩形
简介 使用python opencv返回点集cnt的最小外接矩形,所用函数为 cv2.minAreaRect(cnt) ,cnt是所要求最小外接矩形的点集数组或向量,这个点集不定个数. cv2 ...
- opencv轮廓外接矩形
1.寻找轮廓 api void cv::findContours( InputOutputArray image, OutputArrayOfArrays contours, OutputArray ...
- BZOJ 1185: [HNOI2007]最小矩形覆盖-旋转卡壳法求点集最小外接矩形(面积)并输出四个顶点坐标-备忘板子
来源:旋转卡壳法求点集最小外接矩形(面积)并输出四个顶点坐标 BZOJ又崩了,直接贴一下人家的代码. 代码: #include"stdio.h" #include"str ...
- OpenCV 求外接矩形以及旋转角度
程序没有写完整,大概功能就是实现了,希望大家分享学习,把他改对 // FindRotation-angle.cpp : 定义控制台应用程序的入口点. // // findContours.cpp : ...
- opencv学习之路(25)、轮廓查找与绘制(四)——正外接矩形
一.简介 二.外接矩形的查找绘制 #include "opencv2/opencv.hpp" using namespace cv; void main() { //外接矩形的查找 ...
随机推荐
- luogu2473 [SCOI2008]奖励关
题解参照这里 每个研究完记得乘一个1/n,这是乘了概率. #include <iostream> #include <cstdio> using namespace std; ...
- web前端开发小结
1.浏览器内核 IE-----Trident Edge-----EdgeHTML Firefox-----Gecko Safari-----Webkit Chrome-----Blink(Webkit ...
- STP
生成树协议 spanning-tree protocol 网络中额外添加的链路连接着路由器和交换机 会引起流量的环路 当一个交换机的连接丢失时 另一条链路能快速地取代失败的链路 并且不 ...
- RabbitMQ的应用场景以及基本原理介绍(转)
1.背景 RabbitMQ是一个由erlang开发的AMQP(Advanved Message Queue)的开源实现. 2.应用场景 2.1异步处理 场景说明:用户注册后,需要发注册邮件和注册短信, ...
- Bootstrap-datepicker 用法
<div class="input-group input-daterange"> <input type="text" id="s ...
- 设计模式(二 & 三)工厂模式:1-简单工厂模式
模拟场景: 需要构造一个运算器(Operation),分别负责加减乘除的运算功能. 思想: 这里需要构造四个 Operation,可以使用 Factory 去统一创建这四个对象. 所需要构造的对象是运 ...
- 【Luogu】P3761城市(dfs)
题目链接 emmm我思维好水…… 想了一会lct发现好像不对,然后开始转DP稍微有一点思路,然后看了题解…… 首先可以枚举边,然后原树被你拆成了两个子树. 设D1D2是两个子树的直径,W1W2是子树内 ...
- 【Luogu】P4363一双木棋(状压爆搜)
题目链接 唉,只有AC了这道题才会感叹考场上没有想出解法的我是多么智障. 我甚至连任何想法都没有. 天啊我当时到底在想些什么. AC这道题我就能进前15了诶. 我们发现只要确定了轮廓线那么此时的状态就 ...
- Luogu【P1880】石子合并(环形DP)
先放上luogu的石子合并题目链接 这是一道环形DP题,思想和能量项链很像,在预处理过程中的手法跟乘积最大相像. 用一个m[][]数组来存储石子数量,m[i][j]表示从第 i 堆石子到第 j 堆石子 ...
- Java面试题之Array和ArrayList的区别
Array和ArrayList的区别: 1.Array类型的变量在声明的同时必须进行实例化(至少得初花数组的大小),而ArrayList可以只是先声明: 2.Array始终是连续存放的:而ArrayL ...