Opencv透视变换综合实例详解

所属分类: 软件编程 / C 语言 阅读数: 110
收藏 0 赞 0 分享

本文实例为大家分享了Opencv透视变换综合实例的具体代码,供大家参考,具体内容如下

案例背景:对下面发生畸变的图像进行校正

方案思路:灰度二值化分割,闭操作,寻找轮廓,霍夫直线检测,直线排序,直线方程,直线交点,透视矩阵,透视变换。

#include<opencv2\opencv.hpp>
using namespace cv;
using namespace std;
int main(int arc, char** argv) { 
 Mat src = imread("1.jpg");
 namedWindow("input", CV_WINDOW_AUTOSIZE);
 imshow("input", src);
 //灰度化
 Mat grayImg;
 cvtColor(src, grayImg, CV_BGR2GRAY);
 
 //二值化
 Mat binaryImg;
 threshold(grayImg, binaryImg, 0, 255, THRESH_BINARY_INV | THRESH_OTSU);
 
 //闭操作
 Mat kernel = getStructuringElement(MORPH_RECT,Size(3,3));
 morphologyEx(binaryImg, binaryImg, MORPH_CLOSE,kernel,Point(-1,-1) ,3);
 imshow("output", binaryImg);
 
 //寻找轮廓
 Mat draw = Mat::zeros(src.size(), CV_8UC3);
 vector<vector<Point>>contours;
 findContours(binaryImg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point());
 for (int i = 0; i < contours.size(); i++) {
 Rect rect = boundingRect(contours[i]);
 if (rect.width < src.cols / 2 && rect.height < src.rows / 2)continue;
 drawContours(draw, contours, i, Scalar(0, 0, 255), 2);
 }
 imshow("output2", draw);
 
 //霍夫直线检测
 vector<Vec4i> lines;
 cvtColor(draw, draw, CV_BGR2GRAY);
 HoughLinesP(draw, lines, 1, CV_PI / 180, src.rows/2,src.rows/2,0);
 Mat draw2 = Mat::zeros(src.size(), CV_8UC3);
 for (int j = 0; j < lines.size(); j++) {
 Vec4i ln = lines[j];
 line(draw2, Point(ln[0], ln[1]), Point(ln[2], ln[3]), Scalar(0, 255, 0), 2); 
 }
 printf("number of line:%d\n", lines.size());
 imshow("output3", draw2);
 
 //寻找与定位直线
 Vec4i topLine,bottomLine,leftLine,rightLine;
 for (int j = 0; j < lines.size(); j++) {
 Vec4i ln = lines[j];
 if (ln[1] < src.rows / 2 && ln[3] < src.rows / 2) {
  topLine = ln;
 }
 if (ln[1] > src.rows / 2 && ln[3] > src.rows / 2) {
  bottomLine = ln;
 }
 if (ln[0] < src.cols / 2 && ln[2] < src.cols / 2) {
  leftLine = ln;
 }
 if (ln[0] > src.cols / 2 && ln[2] > src.cols / 2) {
  rightLine = ln;
 }
 }
 cout << "topLine:p1(x,y)=" << topLine[0] << "," << topLine[1]<<" " << "p2(x,y)=" << topLine[2] << "," << topLine[3] << endl;
 cout << "bottomLine:p1(x,y)=" << bottomLine[0] << "," << bottomLine[1] << " " << "p2(x,y)=" << bottomLine[2] << "," << bottomLine[3] << endl;
 cout << "leftLine:p1(x,y)=" << leftLine[0] << "," << leftLine[1] << " " << "p2(x,y)=" << leftLine[2] << "," << leftLine[3] << endl;
 cout << "rightLine:p1(x,y)=" << rightLine[0] << "," << rightLine[1] << " " << "p2(x,y)=" << rightLine[2] << "," << rightLine[3] << endl;
 
 //求解直线方程
 float k1, c1;
 k1 = float((topLine[3] - topLine[1])) / float(topLine[2] - topLine[0]);
 c1 = topLine[1] - k1*topLine[0];
 float k2, c2;
 k2 = float((bottomLine[3] - bottomLine[1])) / float(bottomLine[2] - bottomLine[0]);
 c2 = bottomLine[1] - k2*bottomLine[0];
 float k3, c3;
 k3 = float((leftLine[3] - leftLine[1])) / float(leftLine[2] - leftLine[0]);
 c3 = leftLine[1] - k3*leftLine[0];
 float k4, c4;
 k4 = float((rightLine[3] - rightLine[1])) / float(rightLine[2] - rightLine[0]);
 c4 = rightLine[1] - k4*rightLine[0];
 
 //求解直线交点
 Point p1;
 p1.x = (int)((c1 - c3) / (k3 - k1));
 p1.y = (int)(k1*p1.x + c1);
 Point p2;
 p2.x = (int)((c1 - c4) / (k4 - k1));
 p2.y = (int)(k1*p2.x + c1);
 Point p3;
 p3.x = (int)((c2 - c4) / (k4 - k2));
 p3.y = (int)(k2*p3.x + c2);
 Point p4;
 p4.x = (int)((c2 - c3) / (k3 - k2));
 p4.y = (int)(k2*p4.x + c2);
 cout << "左上角:" << p1.x << "," << p1.y << endl;
 cout << "右上角:" << p2.x << "," << p2.y << endl;
 cout << "右下角:" << p3.x << "," << p3.y << endl;
 cout << "左下角:" << p4.x << "," << p4.y << endl;
 
 //画出交点
 circle(draw2, p1, 2, Scalar(0, 0, 255));
 circle(draw2, p2, 2, Scalar(0, 0, 255));
 circle(draw2, p3, 2, Scalar(0, 0, 255));
 circle(draw2, p4, 2, Scalar(0, 0, 255));
 imshow("output4", draw2);
 
 //透视变换
 vector<Point2f> srcCorners(4);
 srcCorners[0] = p1;
 srcCorners[1] = p2;
 srcCorners[2] = p3;
 srcCorners[3] = p4;
 vector<Point2f> dstCorners(4);
 dstCorners[0] = Point(0, 0);
 dstCorners[1] = Point(src.cols, 0);
 dstCorners[2] = Point(src.cols, src.rows);
 dstCorners[3] = Point(0, src.rows); 
 Mat warpMartrix = getPerspectiveTransform(srcCorners, dstCorners);//Mat warpMartrix = findHomography(srcCorners, dstCorners); 
 Mat result = Mat::zeros(src.size(), -1);
 warpPerspective(src, result, warpMartrix, result.size(),INTER_LINEAR);
 imshow("output5", result);
 waitKey(0);
 return 0; 
}

原图像

二值化闭操作

寻找轮廓

霍夫直线

直线及其交点

效果图

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

更多精彩内容其他人还在看

用标准c++实现string与各种类型之间的转换

这个类在头文件中定义, < sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本
收藏 0 赞 0 分享

C++如何通过ostringstream实现任意类型转string

再使用整型转string的时候感觉有点棘手,因为itoa不是标准C里面的,而且即便是有itoa,其他类型转string不是很方便。后来去网上找了一下,发现有一个好方法
收藏 0 赞 0 分享

C/C++指针小结

要搞清一个指针需要搞清指针的四方面的内容:指针的类型,指针所指向的类型,指针的值或者叫指针所指向的内存区,还有指针本身所占据的内存区
收藏 0 赞 0 分享

C++ 类的静态成员深入解析

在C++中类的静态成员变量和静态成员函数是个容易出错的地方,本文先通过几个例子来总结静态成员变量和成员函数使用规则,再给出一个实例来加深印象
收藏 0 赞 0 分享

C++类的静态成员初始化详细讲解

通常静态数据成员在类声明中声明,在包含类方法的文件中初始化.初始化时使用作用域操作符来指出静态成员所属的类.但如果静态成员是整型或是枚举型const,则可以在类声明中初始化
收藏 0 赞 0 分享

C++类静态成员与类静态成员函数详解

静态成员不可在类体内进行赋值,因为它是被所有该类的对象所共享的。你在一个对象里给它赋值,其他对象里的该成员也会发生变化。为了避免混乱,所以不可在类体内进行赋值
收藏 0 赞 0 分享

C++中的friend友元函数详细解析

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。友元函数的特点是能够访问类中的私有成员的非成员函数。友元函数从语法上看,它与普通函数一样,即在定义上和调用上与普通函数一样
收藏 0 赞 0 分享

static全局变量与普通的全局变量的区别详细解析

以下是对static全局变量与普通的全局变量的区别进行了详细的分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助
收藏 0 赞 0 分享

C++ explicit关键字的应用方法详细讲解

C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢?下面就让我们一起来看看这方面的知识吧
收藏 0 赞 0 分享

教你5分钟轻松搞定内存字节对齐

随便google一下,人家就可以跟你解释的,一大堆的道理,我们没怎么多时间,讨论为何要对齐.直入主题,怎么判断内存对齐规则,sizeof的结果怎么来的,请牢记以下3条原则
收藏 0 赞 0 分享
查看更多