文档章节

用openCV取出图片中的四边形

请输入昵称被使用了
 请输入昵称被使用了
发布于 2017/04/26 19:21
字数 1178
阅读 2472
收藏 1

1、下载Visual Studio2013 :http://pan.baidu.com/s/1qYmAZJe ,直接解压安装;

2、下载openCV: https://sourceforge.net/projects/opencvlibrary/files/ ;建议下载3.0版本的,3.1以后的版本里面不再有x86,但是vs2013中不支持V14的编译器,所以需要注意vs和opencv的版本对应,负责容易出现未知问题; 此处请参考: http://blog.csdn.net/poem_qianmo/article/details/19809337

3、配置vs: http://blog.csdn.net/u013105549/article/details/50493069

4、注意: 引用照片时请注意照片路径: 问题基本是图片路径的问题。应将程序相应的图像放置在工程目录下(和cpp源文件同一目录下)。: http://blog.csdn.net/ture_dream/article/details/52600897

4、截取四边形原理: http://www.cnblogs.com/frombeijingwithlove/p/4226489.html 

http://vitrum.github.io/2015/07/28/Opencv-%E5%BA%94%E7%94%A8%EF%BC%8C%E5%9B%BE%E7%89%87%E9%87%8C%E5%8F%96%E5%87%BA%E5%9B%9B%E8%BE%B9%E5%BD%A2/

5、截取的具体代码:

//
//  opencv.cpp
//  功能: 图片里取出四边形
//  环境搭建: 
//  参考地址:http://vitrum.github.io/2015/07/28/Opencv-%E5%BA%94%E7%94%A8%EF%BC%8C%E5%9B%BE%E7%89%87%E9%87%8C%E5%8F%96%E5%87%BA%E5%9B%9B%E8%BE%B9%E5%BD%A2/ 
//  
//


#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>


using namespace cv;
using namespace std;

/**
* 边缘检测
* @param gray - grayscale input image
* @param canny - output edge image
*/
void getCanny(Mat gray, Mat &canny) {
	Mat thres;
	double high_thres = threshold(gray, thres, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU), low_thres = high_thres * 0.5;
	Canny(gray, canny, low_thres, high_thres);
}

struct Line {
	Point _p1;
	Point _p2;
	Point _center;

	Line(Point p1, Point p2) {
		_p1 = p1;
		_p2 = p2;
		_center = Point((p1.x + p2.x) / 2, (p1.y + p2.y) / 2);
	}
};

bool cmp_y(const Line &p1, const Line &p2) {
	return p1._center.y < p2._center.y;
}

bool cmp_x(const Line &p1, const Line &p2) {
	return p1._center.x < p2._center.x;
}

/**
* Compute intersect point of two lines l1 and l2
* @param l1
* @param l2
* @return Intersect Point
*/
Point2f computeIntersect(Line l1, Line l2) {
	int x1 = l1._p1.x, x2 = l1._p2.x, y1 = l1._p1.y, y2 = l1._p2.y;
	int x3 = l2._p1.x, x4 = l2._p2.x, y3 = l2._p1.y, y4 = l2._p2.y;
	if (float d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4)) {
		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;
	}
	return Point2f(-1, -1);
}

void scan(String file, bool debug = false) {

	// 读入原图
	Mat img = imread(file);
	
	Mat img_proc;
	int w = img.size().width, h = img.size().height, min_w = 200;
	// 计算缩放比例
	double scale = min(10.0, w * 1.0 / min_w);
	int w_proc = w * 1.0 / scale, h_proc = h * 1.0 / scale;
	// 缩小图片分辨率,提高计算速度
	resize(img, img_proc, Size(w_proc, h_proc));
	Mat img_dis = img_proc.clone();

	/*获取纸的四个边*/
	
	Mat gray, canny;
	cvtColor(img_proc, gray, CV_BGR2GRAY);
	// 用canny算子进行边缘检测
	getCanny(gray, canny);

	// w_proc 就是缩小后的画面宽度,20是把间距20以内的线段延长拼接为一条直线
	vector<Vec4i> lines;
	vector<Line> horizontals, verticals;
	HoughLinesP(canny, lines, 1, CV_PI / 180, w_proc / 3, w_proc / 3, 20);
	for (size_t i = 0; i < lines.size(); i++) {
		Vec4i v = lines[i];
		double delta_x = v[0] - v[2], delta_y = v[1] - v[3];
		Line l(Point(v[0], v[1]), Point(v[2], v[3]));
		// get horizontal lines and vertical lines respectively
		if (fabs(delta_x) > fabs(delta_y)) {
			horizontals.push_back(l);
		}
		else {
			verticals.push_back(l);
		}
		// for visualization only
		if (debug)
			line(img_proc, Point(v[0], v[1]), Point(v[2], v[3]), Scalar(0, 0, 255), 1, CV_AA);
	}

	// 边缘情况下,当没有足够的线检测
	if (horizontals.size() < 2) {
		if (horizontals.size() == 0 || horizontals[0]._center.y > h_proc / 2) {
			horizontals.push_back(Line(Point(0, 0), Point(w_proc - 1, 0)));
		}
		if (horizontals.size() == 0 || horizontals[0]._center.y <= h_proc / 2) {
			horizontals.push_back(Line(Point(0, h_proc - 1), Point(w_proc - 1, h_proc - 1)));
		}
	}
	if (verticals.size() < 2) {
		if (verticals.size() == 0 || verticals[0]._center.x > w_proc / 2) {
			verticals.push_back(Line(Point(0, 0), Point(0, h_proc - 1)));
		}
		if (verticals.size() == 0 || verticals[0]._center.x <= w_proc / 2) {
			verticals.push_back(Line(Point(w_proc - 1, 0), Point(w_proc - 1, h_proc - 1)));
		}
	}
	// 按中心点排序
	sort(horizontals.begin(), horizontals.end(), cmp_y);
	sort(verticals.begin(), verticals.end(), cmp_x);
	// for visualization only
	if (debug) {
		line(img_proc, horizontals[0]._p1, horizontals[0]._p2, Scalar(0, 255, 0), 2, CV_AA);
		line(img_proc, horizontals[horizontals.size() - 1]._p1, horizontals[horizontals.size() - 1]._p2, Scalar(0, 255, 0), 2, CV_AA);
		line(img_proc, verticals[0]._p1, verticals[0]._p2, Scalar(255, 0, 0), 2, CV_AA);
		line(img_proc, verticals[verticals.size() - 1]._p1, verticals[verticals.size() - 1]._p2, Scalar(255, 0, 0), 2, CV_AA);
	}

	/* 透视变换 */

	// define the destination image size: A4 - 200 PPI
	int w_a4 = 1654, h_a4 = 2339;
	//int w_a4 = 595, h_a4 = 842;
	Mat dst = Mat::zeros(h_a4, w_a4, CV_8UC3);

	// 求四顶点坐标 corners of destination image with the sequence [tl, tr, bl, br]
	vector<Point2f> dst_pts, img_pts;
	dst_pts.push_back(Point(0, 0));
	dst_pts.push_back(Point(w_a4 - 1, 0));
	dst_pts.push_back(Point(0, h_a4 - 1));
	dst_pts.push_back(Point(w_a4 - 1, h_a4 - 1));

	// corners of source image with the sequence [tl, tr, bl, br]
	img_pts.push_back(computeIntersect(horizontals[0], verticals[0]));
	img_pts.push_back(computeIntersect(horizontals[0], verticals[verticals.size() - 1]));
	img_pts.push_back(computeIntersect(horizontals[horizontals.size() - 1], verticals[0]));
	img_pts.push_back(computeIntersect(horizontals[horizontals.size() - 1], verticals[verticals.size() - 1]));

	// 转换成原始图像比例尺
	for (size_t i = 0; i < img_pts.size(); i++) {
		// for visualization only
		if (debug) {
			circle(img_proc, img_pts[i], 10, Scalar(255, 255, 0), 3);
		}
		img_pts[i].x *= scale;
		img_pts[i].y *= scale;
	}

	// 得到的变换矩阵 用getPerspectiveTransform计算转化矩阵,再用warpPerspective调用转化矩阵进行拉伸
	Mat transmtx = getPerspectiveTransform(img_pts, dst_pts);

	// 应用透视变换
	warpPerspective(img, dst, transmtx, dst.size());

	// 保存照片到本地
	imwrite("dst.jpg", dst);

	// for visualization only
	if (debug) {
		namedWindow("dst", CV_WINDOW_KEEPRATIO);
		imshow("src", img_dis);
		imshow("canny", canny);
		imshow("img_proc", img_proc);
		imshow("dst", dst);
		waitKey(0);
	}
}

int main(int argc, char** argv) {
	string img_path[] = { "6.jpg", "images/doc2.jpg", "images/doc3.jpg" };
	scan(img_path[0]);
	return 0;
}

效果:

原图:

识别结果:

© 著作权归作者所有

请输入昵称被使用了
粉丝 2
博文 67
码字总数 113687
作品 0
朝阳
程序员
私信 提问
opencv3.x + MFC显示图片

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/byxdaz/article/details/88091164 opencv3.X + MFC显示图片 使用opencv和MFC显示图片的方法大致分为以下几种:...

byxdaz
03/03
0
0
OpenCV中几何形状识别与测量

经常看到有学习OpenCV不久的人提问,如何识别一些简单的几何形状与它们的颜色,其实通过OpenCV的轮廓发现与几何分析相关的函数,只需不到100行的代码就可以很好的实现这些简单几何形状识别与...

gloomyfish
2018/04/16
0
0
VS2010 / MFC + OpenCV 2.4.1打开图片

Windows 7 x64,VS2010 / MFC + OpenCV 2.4.1打开图片显示到Picture控件中。 OpenCV 2.2、OpenCV 2.3同样适用。 工具/原料 WinXP / Win7 x86 / x64 OpenCV 2.2 / 2.3 / 2.4 Visual Studio 20......

LMcallme
2013/04/11
1K
0
视频人脸检测——Dlib版(六)

往期目录 视频人脸检测——Dlib版(六) OpenCV添加中文(五) 图片人脸检测——Dlib版(四) 视频人脸检测——OpenCV版(三) 图片人脸检测——OpenCV版(二) OpenCV环境搭建(一) 更多更...

王磊的博客
2018/05/11
0
0
图片人脸检测——OpenCV版(二)

图片人脸检测 人脸检测使用到的技术是OpenCV,上一节已经介绍了OpenCV的环境安装,点击查看. 往期目录 视频人脸检测——Dlib版(六) OpenCV添加中文(五) 图片人脸检测——Dlib版(四) 视...

王磊的博客
2018/04/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。 一、ThreadPoolTaskExecutor 本文采用 Executors 的工厂...

CREATE_17
今天
5
0
CSS盒子模型

CSS盒子模型 组成: content --> padding --> border --> margin 像现实生活中的快递: 物品 --> 填充物 --> 包装盒 --> 盒子与盒子之间的间距 content :width、height组成的 内容区域 padd......

studywin
今天
7
0
修复Win10下开始菜单、设置等系统软件无法打开的问题

因为各种各样的原因导致系统文件丢失、损坏、被修改,而造成win10的开始菜单、设置等系统软件无法打开的情况,可以尝试如下方法解决 此方法只在部分情况下有效,但值得一试 用Windows键+R打开...

locbytes
昨天
8
0
jquery 添加和删除节点

本文转载于:专业的前端网站➺jquery 添加和删除节点 // 增加一个三和一节点function addPanel() { // var newPanel = $('.my-panel').clone(true) var newPanel = $(".triple-panel-con......

前端老手
昨天
8
0
一、Django基础

一、web框架分类和wsgiref模块使用介绍 web框架的本质 socket服务端 与 浏览器的通信 socket服务端功能划分: 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 根据用户访问...

ZeroBit
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部