在shiter大牛的基础之上,对于他的程序做了一定的修改。 
首先,通过两个循环使得霍夫变换两个参数:角度的分辨率和点个数的阈值可以变换,这样就不必对于每一张图像都手动的设置阈值。其次,过滤掉了两个距离很近的直线,使得能够正确找到物体的四个轮廓的直线。

  1. #include <opencv2/imgproc/imgproc.hpp>
  2. #include <opencv2/highgui/highgui.hpp>
  3. #include <iostream>
  4. #include <set>
  5.  
  6. #pragma comment(lib,"opencv_core2413d.lib")
  7. #pragma comment(lib,"opencv_highgui2413d.lib")
  8. #pragma comment(lib,"opencv_imgproc2413d.lib")
  9.  
  10. cv::Point2f center(0,0);
  11.  
  12. cv::Point2f computeIntersect(cv::Vec4i a, cv::Vec4i b)
  13. {
  14. 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];
  15. float denom;
  16.  
  17. if (float d = ((float)(x1 - x2) * (y3 - y4)) - ((y1 - y2) * (x3 - x4)))
  18. {
  19. cv::Point2f pt;
  20. pt.x = ((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) / d;
  21. pt.y = ((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) / d;
  22. return pt;
  23. }
  24. else
  25. return cv::Point2f(-1, -1);
  26. }
  27.  
  28. //确定四个点的中心线
  29. void sortCorners(std::vector<cv::Point2f>& corners,
  30. cv::Point2f center)
  31. {
  32. std::vector<cv::Point2f> top, bot;
  33.  
  34. for (int i = 0; i < corners.size(); i++)
  35. {
  36. if (corners[i].y < center.y)
  37. top.push_back(corners[i]);
  38. else
  39. bot.push_back(corners[i]);
  40. }
  41. corners.clear();
  42.  
  43. if (top.size() == 2 && bot.size() == 2){
  44. cv::Point2f tl = top[0].x > top[1].x ? top[1] : top[0];
  45. cv::Point2f tr = top[0].x > top[1].x ? top[0] : top[1];
  46. cv::Point2f bl = bot[0].x > bot[1].x ? bot[1] : bot[0];
  47. cv::Point2f br = bot[0].x > bot[1].x ? bot[0] : bot[1];
  48.  
  49. corners.push_back(tl);
  50. corners.push_back(tr);
  51. corners.push_back(br);
  52. corners.push_back(bl);
  53. }
  54. }
  55.  
  56. //计算直线端点的距离
  57. bool Disserence(int a,int b)
  58. {
  59. if (a * a + b * b < 100)
  60. {
  61. return true;
  62. }
  63. else
  64. {
  65. return false;
  66. }
  67. }
  68.  
  69. int main()
  70. {
  71. cv::Mat src = cv::imread("001.jpg");
  72. if (src.empty())
  73. return -1;
  74.  
  75. cv::Mat bw;
  76. cv::cvtColor(src, bw, CV_BGR2GRAY);
  77. cv::blur(bw, bw, cv::Size(3, 3));
  78. cv::Canny(bw, bw, 100, 100, 3);
  79.  
  80. std::vector<cv::Vec4i> lines;
  81. std::vector<cv::Point2f> corners;
  82. std::vector<cv::Point2f> approx;
  83. int HoughThre = 20;
  84. int HoughTheta = 30;
  85. /*
  86. void HoughLinesP(InputArray image,OutputArray lines, double rho, double theta, int threshold, double minLineLength=0,double maxLineGap=0 )
  87. image为输入图像,要求是8位单通道图像
  88. lines为输出的直线向量,每条线用4个元素表示,即直线的两个端点的4个坐标值
  89. rho和theta分别为距离和角度的分辨率
  90. threshold为阈值,即步骤3中的阈值
  91. minLineLength为最小直线长度,在步骤5中要用到,即如果小于该值,则不被认为是一条直线
  92. maxLineGap为最大直线间隙,在步骤4中要用到,即如果有两条线段是在一条直线上,但它们之间因为有间隙,所以被认为是两个线段,如果这个间隙大于该值,则被认为是两条线段,否则是一条。
  93. */
  94. for(;HoughTheta <= 180;HoughTheta = HoughTheta + 30)
  95. {
  96. HoughThre = 30;
  97.  
  98. for(;HoughThre < 300;HoughThre++)
  99. {
  100. lines.clear();
  101. corners.clear();
  102. approx.clear();
  103. cv::HoughLinesP(bw, lines, 1, CV_PI/HoughTheta, HoughThre, 30, 50); //需要不断的变更霍夫变换的参数,才可以使得刚好找到四条直线,确定出边缘
  104.  
  105. // Expand the lines
  106. for (int i = 0; i < lines.size(); i++)
  107. {
  108. cv::Vec4i v = lines[i];
  109. lines[i][0] = 0;
  110. lines[i][1] = ((float)v[1] - v[3]) / (v[0] - v[2]) * -v[0] + v[1];
  111. lines[i][2] = src.cols;
  112. lines[i][3] = ((float)v[1] - v[3]) / (v[0] - v[2]) * (src.cols - v[2]) + v[3];
  113. }
  114.  
  115. //删除距离过近的两条直线
  116. std::set<int> ErasePt;
  117. for (int i = 0; i < lines.size(); i++)
  118. {
  119. for (int j = i + 1; j < lines.size(); j++)
  120. {
  121. 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]))))
  122. {
  123. ErasePt.insert(j);
  124. }
  125. }
  126. }
  127. // std::vector<cv::Vec4i>::iterator it = lines.end();
  128. int Num = lines.size();
  129. while (Num != 0)
  130. {
  131. std::set<int>::iterator j = ErasePt.find(Num);
  132. if (j != ErasePt.end())
  133. {
  134. lines.erase(lines.begin() + Num - 1);
  135. }
  136. Num--;
  137. }
  138. if (lines.size() != 4)
  139. {
  140. continue;
  141. }
  142.  
  143. //计算直线的交点,保存在图像范围内的部分
  144.  
  145. for (int i = 0; i < lines.size(); i++)
  146. {
  147. for (int j = i+1; j < lines.size(); j++)
  148. {
  149. cv::Point2f pt = computeIntersect(lines[i], lines[j]);
  150. if (pt.x >= 0 && pt.y >= 0 && pt.x <= src.cols && pt.y <= src.rows) //保证交点在图像的范围之内
  151. corners.push_back(pt);
  152. }
  153. }
  154. if (corners.size() != 4)
  155. {
  156. continue;
  157. }
  158.  
  159. cv::approxPolyDP(cv::Mat(corners), approx, cv::arcLength(cv::Mat(corners), true) * 0.02, true);
  160.  
  161. //if (approx.size() != 4)
  162. //{
  163. // std::cout << "The object is not quadrilateral!" << std::endl;
  164. // return -1;
  165. //}
  166.  
  167. if (lines.size() == 4 && corners.size() == 4 && approx.size() == 4)
  168. {
  169. break;
  170. }
  171. // std::cout<<".";
  172. }
  173.  
  174. std::cout<<std::endl<<"One Cycle";
  175. if (lines.size() == 4 && corners.size() == 4 && approx.size() == 4)
  176. break;
  177. if (HoughTheta == 180 && HoughThre >= 299)
  178. {
  179. return -1;
  180. }
  181. }
  182.  
  183. cv::Mat dst = src.clone();
  184. //for (int i = 0; i < lines.size(); i++)
  185. //{
  186. // cv::Vec4i v = lines[i];
  187. // cv::line(dst, cv::Point(v[0], v[1]), cv::Point(v[2], v[3]), CV_RGB(0,255,0));
  188. //}
  189.  
  190. //cvNamedWindow("image",0);
  191. //cv::imshow("image", dst);
  192. //cvWaitKey();
  193.  
  194. // Get mass center
  195. for (int i = 0; i < corners.size(); i++)
  196. center += corners[i];
  197. center *= (1. / corners.size());
  198.  
  199. sortCorners(corners, center);
  200. if (corners.size() == 0){
  201. std::cout << "The corners were not sorted correctly!" << std::endl;
  202. return -1;
  203. }
  204.  
  205. // Draw lines
  206. for (int i = 0; i < lines.size(); i++)
  207. {
  208. cv::Vec4i v = lines[i];
  209. cv::line(dst, cv::Point(v[0], v[1]), cv::Point(v[2], v[3]), CV_RGB(0,255,0));
  210. }
  211.  
  212. cvNamedWindow("image",0);
  213. cv::imshow("image", dst);
  214.  
  215. cv::waitKey();
  216. // Draw corner points
  217. cv::circle(dst, corners[0], 3, CV_RGB(255,0,0), 2);
  218. cv::circle(dst, corners[1], 3, CV_RGB(0,255,0), 2);
  219. cv::circle(dst, corners[2], 3, CV_RGB(0,0,255), 2);
  220. cv::circle(dst, corners[3], 3, CV_RGB(255,255,255), 2);
  221.  
  222. // Draw mass center
  223. cv::circle(dst, center, 3, CV_RGB(255,255,0), 2);
  224.  
  225. cv::Mat quad = cv::Mat::zeros(300, 220, CV_8UC3);
  226.  
  227. std::vector<cv::Point2f> quad_pts;
  228. quad_pts.push_back(cv::Point2f(0, 0));
  229. quad_pts.push_back(cv::Point2f(quad.cols, 0));
  230. quad_pts.push_back(cv::Point2f(quad.cols, quad.rows));
  231. quad_pts.push_back(cv::Point2f(0, quad.rows));
  232.  
  233. cv::Mat transmtx = cv::getPerspectiveTransform(corners, quad_pts);
  234. cv::warpPerspective(src, quad, transmtx, quad.size());
  235.  
  236. cv::imshow("image", dst);
  237. cv::imshow("quadrilateral", quad);
  238. cv::waitKey();
  239. return 0;
  240. }

结果图: 
 

  
程序依然存在的问题是:对于一些测试的图片,依然无法找到物体四周的直线,也就做不了透视变换了。

OpenCV 可自动调整参数的透视变换的更多相关文章

  1. OpenCV 颜色空间转换参数CV_BGR2GRAY改变

    OpenCV的颜色空间转换函数:   C++: void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0 )   参数d ...

  2. opencv IplImage各参数详细介绍以及如何从一个JPEG图像数据指针转换得到IplImage

    这篇文章里介绍得最清楚了.http://blog.chinaunix.net/uid-22682903-id-1771421.html 关于颜色空间  RGB颜色空间已经非常熟悉了.HSV颜色空间需要 ...

  3. opencv ORB各参数的含义

    ORB中有很多参数可以设置,在OpenCV中它可以通过ORB来创建一个ORB检测器. ORB::ORB(int nfeatures=500, float scaleFactor=1.2f, int n ...

  4. 如何在pyqt中通过OpenCV实现对窗口的透视变换

    窗口的透视变换效果 当我们点击UWP应用中的小部件时,会发现小部件会朝着鼠标点击位置凹陷下去,而且不同的点击位置对应着不同的凹陷情况,看起来就好像小部件在屏幕上不只有x轴和y轴,甚至还有一个z轴.要做 ...

  5. 【计算机视觉】OpenCV篇(5) - 仿射变换与透视变换

    参考: 图像处理的仿射变换与透视变换(https://www.imooc.com/article/27535) http://ex2tron.wang/opencv-python-extra-warp ...

  6. OpenCV VideoCapture.get()参数详解

    转自https://blog.csdn.net/u011436429/article/details/80604590 方便查阅

  7. OpenCV图像变换(仿射变换与透视变换)

    仿射变换(affine transform)与透视变换(perspective transform)在图像还原.图像局部变化处理方面有重要意义.通常,在2D平面中,仿射变换的应用较多,而在3D平面中, ...

  8. OpenCV】透视变换 Perspective Transformation(续)

    载分 [OpenCV]透视变换 Perspective Transformation(续) 分类: [图像处理] [编程语言] 2014-05-27 09:39 2776人阅读 评论(13) 收藏 举 ...

  9. OpenCV之Python学习笔记

    OpenCV之Python学习笔记 直都在用Python+OpenCV做一些算法的原型.本来想留下发布一些文章的,可是整理一下就有点无奈了,都是写零散不成系统的小片段.现在看 到一本国外的新书< ...

随机推荐

  1. flink---实时项目----day03---1.练习讲解(全局参数,数据以parquet格式写入hdfs中) 2 异步查询 3 BroadcastState

    1 练习讲解(此处自己没跑通,以后debug) 题目见flink---实时项目---day02 kafka中的数据,见day02的文档 GeoUtils package cn._51doit.flin ...

  2. 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是一个分布式大数据处理引擎,可以对有限数据流(如离线数据)和无限流数据及逆行有状态计算(不太懂).可以部署在各种集群环境,对各种 ...

  3. 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 ...

  4. 基于war的Spring Boot工程

    一.简介 前面创建的Spring Boot工程最终被打为了Jar包,是以可执行文件的形式出现的,其使用了Spring Boot内嵌的Tomcat作为Web服务器来运行web应用的.新版Dubbo的监控 ...

  5. 05 - Vue3 UI Framework - Button 组件

    官网基本做好了,接下来开始做核心组件 返回阅读列表点击 这里 目录准备 在项目 src 目录下创建 lib 文件夹,用来存放所有的核心组件吧.然后再在 lib 文件夹下创建 Button.vue 文件 ...

  6. Boss直聘App上“天使投资、VC、PE” 与“A轮、B轮、C轮融资”的关系

    我们经常看到朋友圈里某某公司获得了某轮融资,所谓的A轮B轮究竟是个什么概念呢?今天就跟小伙伴们分享一下A.B.C.D轮融资与天使投资.VC.PE的关系. 天使投资(AI):天使投资所投的是一些非常早期 ...

  7. <转>Hadoop入门总结

    转自:http://www.cnblogs.com/skyme/archive/2012/06/01/2529855.html 第1章 引言 1.1 编写目的 对关于hadoop的文档及资料进行进一步 ...

  8. Vector Demo

    /* * vectorDemo.cpp * * Created on: Jul 17, 2014 * Author: lichfeng */ #include<vector> #inclu ...

  9. 工时资源(Project)

    <Project2016 企业项目管理实践>张会斌 董方好 编著 资源既然各种导入都会发生些不可描述的事,那就手工建立吧.但是问题又来了,资源还分种类的:工时资源.材料资源和成本资源. 好 ...

  10. Python基础入门(6)- 面向对象编程

    1.初识面向对象 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本篇随笔将详细介绍Python的面向对象编程. 如果你以前没有接触过面向对象 ...