OpenCV 可自动调整参数的透视变换
在shiter大牛的基础之上,对于他的程序做了一定的修改。
首先,通过两个循环使得霍夫变换两个参数:角度的分辨率和点个数的阈值可以变换,这样就不必对于每一张图像都手动的设置阈值。其次,过滤掉了两个距离很近的直线,使得能够正确找到物体的四个轮廓的直线。
- #include <opencv2/imgproc/imgproc.hpp>
- #include <opencv2/highgui/highgui.hpp>
- #include <iostream>
- #include <set>
- #pragma comment(lib,"opencv_core2413d.lib")
- #pragma comment(lib,"opencv_highgui2413d.lib")
- #pragma comment(lib,"opencv_imgproc2413d.lib")
- cv::Point2f center(0,0);
- cv::Point2f computeIntersect(cv::Vec4i a, cv::Vec4i b)
- {
- int x1 = a[0], y1 = a[1], x2 = a[2], y2 = a[3], x3 = b[0], y3 = b[1], x4 = b[2], y4 = b[3];
- float denom;
- if (float d = ((float)(x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4)))
- {
- cv::Point2f pt;
- pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
- pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
- return pt;
- }
- else
- return cv::Point2f(-1, -1);
- }
- //确定四个点的中心线
- void sortCorners(std::vector<cv::Point2f>& corners,
- cv::Point2f center)
- {
- std::vector<cv::Point2f> top, bot;
- for (int i = 0; i < corners.size(); i++)
- {
- if (corners[i].y < center.y)
- top.push_back(corners[i]);
- else
- bot.push_back(corners[i]);
- }
- corners.clear();
- if (top.size() == 2 && bot.size() == 2){
- cv::Point2f tl = top[0].x > top[1].x ? top[1] : top[0];
- cv::Point2f tr = top[0].x > top[1].x ? top[0] : top[1];
- cv::Point2f bl = bot[0].x > bot[1].x ? bot[1] : bot[0];
- cv::Point2f br = bot[0].x > bot[1].x ? bot[0] : bot[1];
- corners.push_back(tl);
- corners.push_back(tr);
- corners.push_back(br);
- corners.push_back(bl);
- }
- }
- //计算直线端点的距离
- bool Disserence(int a,int b)
- {
- if (a * a + b * b < 100)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- int main()
- {
- cv::Mat src = cv::imread("001.jpg");
- if (src.empty())
- return -1;
- cv::Mat bw;
- cv::cvtColor(src, bw, CV_BGR2GRAY);
- cv::blur(bw, bw, cv::Size(3, 3));
- cv::Canny(bw, bw, 100, 100, 3);
- std::vector<cv::Vec4i> lines;
- std::vector<cv::Point2f> corners;
- std::vector<cv::Point2f> approx;
- int HoughThre = 20;
- int HoughTheta = 30;
- /*
- void HoughLinesP(InputArray image,OutputArray lines, double rho, double theta, int threshold, double minLineLength=0,double maxLineGap=0 )
- image为输入图像,要求是8位单通道图像
- lines为输出的直线向量,每条线用4个元素表示,即直线的两个端点的4个坐标值
- rho和theta分别为距离和角度的分辨率
- threshold为阈值,即步骤3中的阈值
- minLineLength为最小直线长度,在步骤5中要用到,即如果小于该值,则不被认为是一条直线
- maxLineGap为最大直线间隙,在步骤4中要用到,即如果有两条线段是在一条直线上,但它们之间因为有间隙,所以被认为是两个线段,如果这个间隙大于该值,则被认为是两条线段,否则是一条。
- */
- for(;HoughTheta <= 180;HoughTheta = HoughTheta + 30)
- {
- HoughThre = 30;
- for(;HoughThre < 300;HoughThre++)
- {
- lines.clear();
- corners.clear();
- approx.clear();
- cv::HoughLinesP(bw, lines, 1, CV_PI/HoughTheta, HoughThre, 30, 50); //需要不断的变更霍夫变换的参数,才可以使得刚好找到四条直线,确定出边缘
- // Expand the lines
- for (int i = 0; i < lines.size(); i++)
- {
- cv::Vec4i v = lines[i];
- lines[i][0] = 0;
- lines[i][1] = ((float)v[1] - v[3]) / (v[0] - v[2]) * -v[0] + v[1];
- lines[i][2] = src.cols;
- lines[i][3] = ((float)v[1] - v[3]) / (v[0] - v[2]) * (src.cols - v[2]) + v[3];
- }
- //删除距离过近的两条直线
- std::set<int> ErasePt;
- for (int i = 0; i < lines.size(); i++)
- {
- for (int j = i + 1; j < lines.size(); j++)
- {
- if (Disserence(abs(lines[i][0] - lines[j][0]),abs(lines[i][1] - lines[j][1])) && (Disserence(abs(lines[i][2] - lines[j][2]),abs(lines[i][3] - lines[j][3]))))
- {
- ErasePt.insert(j);
- }
- }
- }
- // std::vector<cv::Vec4i>::iterator it = lines.end();
- int Num = lines.size();
- while (Num != 0)
- {
- std::set<int>::iterator j = ErasePt.find(Num);
- if (j != ErasePt.end())
- {
- lines.erase(lines.begin() + Num - 1);
- }
- Num--;
- }
- if (lines.size() != 4)
- {
- continue;
- }
- //计算直线的交点,保存在图像范围内的部分
- for (int i = 0; i < lines.size(); i++)
- {
- for (int j = i+1; j < lines.size(); j++)
- {
- cv::Point2f pt = computeIntersect(lines[i], lines[j]);
- if (pt.x >= 0 && pt.y >= 0 && pt.x <= src.cols && pt.y <= src.rows) //保证交点在图像的范围之内
- corners.push_back(pt);
- }
- }
- if (corners.size() != 4)
- {
- continue;
- }
- cv::approxPolyDP(cv::Mat(corners), approx, cv::arcLength(cv::Mat(corners), true) * 0.02, true);
- //if (approx.size() != 4)
- //{
- // std::cout << "The object is not quadrilateral!" << std::endl;
- // return -1;
- //}
- if (lines.size() == 4 && corners.size() == 4 && approx.size() == 4)
- {
- break;
- }
- // std::cout<<".";
- }
- std::cout<<std::endl<<"One Cycle";
- if (lines.size() == 4 && corners.size() == 4 && approx.size() == 4)
- break;
- if (HoughTheta == 180 && HoughThre >= 299)
- {
- return -1;
- }
- }
- cv::Mat dst = src.clone();
- //for (int i = 0; i < lines.size(); i++)
- //{
- // cv::Vec4i v = lines[i];
- // cv::line(dst, cv::Point(v[0], v[1]), cv::Point(v[2], v[3]), CV_RGB(0,255,0));
- //}
- //cvNamedWindow("image",0);
- //cv::imshow("image", dst);
- //cvWaitKey();
- // Get mass center
- for (int i = 0; i < corners.size(); i++)
- center += corners[i];
- center *= (1. / corners.size());
- sortCorners(corners, center);
- if (corners.size() == 0){
- std::cout << "The corners were not sorted correctly!" << std::endl;
- return -1;
- }
- // Draw lines
- for (int i = 0; i < lines.size(); i++)
- {
- cv::Vec4i v = lines[i];
- cv::line(dst, cv::Point(v[0], v[1]), cv::Point(v[2], v[3]), CV_RGB(0,255,0));
- }
- cvNamedWindow("image",0);
- cv::imshow("image", dst);
- cv::waitKey();
- // Draw corner points
- cv::circle(dst, corners[0], 3, CV_RGB(255,0,0), 2);
- cv::circle(dst, corners[1], 3, CV_RGB(0,255,0), 2);
- cv::circle(dst, corners[2], 3, CV_RGB(0,0,255), 2);
- cv::circle(dst, corners[3], 3, CV_RGB(255,255,255), 2);
- // Draw mass center
- cv::circle(dst, center, 3, CV_RGB(255,255,0), 2);
- cv::Mat quad = cv::Mat::zeros(300, 220, CV_8UC3);
- std::vector<cv::Point2f> quad_pts;
- quad_pts.push_back(cv::Point2f(0, 0));
- quad_pts.push_back(cv::Point2f(quad.cols, 0));
- quad_pts.push_back(cv::Point2f(quad.cols, quad.rows));
- quad_pts.push_back(cv::Point2f(0, quad.rows));
- cv::Mat transmtx = cv::getPerspectiveTransform(corners, quad_pts);
- cv::warpPerspective(src, quad, transmtx, quad.size());
- cv::imshow("image", dst);
- cv::imshow("quadrilateral", quad);
- cv::waitKey();
- return 0;
- }
结果图:
程序依然存在的问题是:对于一些测试的图片,依然无法找到物体四周的直线,也就做不了透视变换了。
OpenCV 可自动调整参数的透视变换的更多相关文章
- OpenCV 颜色空间转换参数CV_BGR2GRAY改变
OpenCV的颜色空间转换函数: C++: void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 ) 参数d ...
- opencv IplImage各参数详细介绍以及如何从一个JPEG图像数据指针转换得到IplImage
这篇文章里介绍得最清楚了.http://blog.chinaunix.net/uid-22682903-id-1771421.html 关于颜色空间 RGB颜色空间已经非常熟悉了.HSV颜色空间需要 ...
- opencv ORB各参数的含义
ORB中有很多参数可以设置,在OpenCV中它可以通过ORB来创建一个ORB检测器. ORB::ORB(int nfeatures=500, float scaleFactor=1.2f, int n ...
- 如何在pyqt中通过OpenCV实现对窗口的透视变换
窗口的透视变换效果 当我们点击UWP应用中的小部件时,会发现小部件会朝着鼠标点击位置凹陷下去,而且不同的点击位置对应着不同的凹陷情况,看起来就好像小部件在屏幕上不只有x轴和y轴,甚至还有一个z轴.要做 ...
- 【计算机视觉】OpenCV篇(5) - 仿射变换与透视变换
参考: 图像处理的仿射变换与透视变换(https://www.imooc.com/article/27535) http://ex2tron.wang/opencv-python-extra-warp ...
- OpenCV VideoCapture.get()参数详解
转自https://blog.csdn.net/u011436429/article/details/80604590 方便查阅
- OpenCV图像变换(仿射变换与透视变换)
仿射变换(affine transform)与透视变换(perspective transform)在图像还原.图像局部变化处理方面有重要意义.通常,在2D平面中,仿射变换的应用较多,而在3D平面中, ...
- OpenCV】透视变换 Perspective Transformation(续)
载分 [OpenCV]透视变换 Perspective Transformation(续) 分类: [图像处理] [编程语言] 2014-05-27 09:39 2776人阅读 评论(13) 收藏 举 ...
- OpenCV之Python学习笔记
OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...
随机推荐
- flink---实时项目----day03---1.练习讲解(全局参数,数据以parquet格式写入hdfs中) 2 异步查询 3 BroadcastState
1 练习讲解(此处自己没跑通,以后debug) 题目见flink---实时项目---day02 kafka中的数据,见day02的文档 GeoUtils package cn._51doit.flin ...
- flink01--------1.flink简介 2.flink安装 3. flink提交任务的2种方式 4. 4flink的快速入门 5.source 6 常用算子(keyBy,max/min,maxBy/minBy,connect,union,split+select)
1. flink简介 1.1 什么是flink Apache Flink是一个分布式大数据处理引擎,可以对有限数据流(如离线数据)和无限流数据及逆行有状态计算(不太懂).可以部署在各种集群环境,对各种 ...
- webpack打包报错 ERROR in ./js/ww.js from UglifyJs Unexpected token keyword «function», expected punc «,» [src/page/ww/view/xx/xx.vue:119,0][./js/ww.js:55218,17]
找了好多解决办法 你可以试着将babel-loader的exclude注释掉,然后看能否打包成功.如果可以,那就是这个问题.你只需要在vue.config.js中配置transpileDependen ...
- 基于war的Spring Boot工程
一.简介 前面创建的Spring Boot工程最终被打为了Jar包,是以可执行文件的形式出现的,其使用了Spring Boot内嵌的Tomcat作为Web服务器来运行web应用的.新版Dubbo的监控 ...
- 05 - Vue3 UI Framework - Button 组件
官网基本做好了,接下来开始做核心组件 返回阅读列表点击 这里 目录准备 在项目 src 目录下创建 lib 文件夹,用来存放所有的核心组件吧.然后再在 lib 文件夹下创建 Button.vue 文件 ...
- Boss直聘App上“天使投资、VC、PE” 与“A轮、B轮、C轮融资”的关系
我们经常看到朋友圈里某某公司获得了某轮融资,所谓的A轮B轮究竟是个什么概念呢?今天就跟小伙伴们分享一下A.B.C.D轮融资与天使投资.VC.PE的关系. 天使投资(AI):天使投资所投的是一些非常早期 ...
- <转>Hadoop入门总结
转自:http://www.cnblogs.com/skyme/archive/2012/06/01/2529855.html 第1章 引言 1.1 编写目的 对关于hadoop的文档及资料进行进一步 ...
- Vector Demo
/* * vectorDemo.cpp * * Created on: Jul 17, 2014 * Author: lichfeng */ #include<vector> #inclu ...
- 工时资源(Project)
<Project2016 企业项目管理实践>张会斌 董方好 编著 资源既然各种导入都会发生些不可描述的事,那就手工建立吧.但是问题又来了,资源还分种类的:工时资源.材料资源和成本资源. 好 ...
- Python基础入门(6)- 面向对象编程
1.初识面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本篇随笔将详细介绍Python的面向对象编程. 如果你以前没有接触过面向对象 ...