OpenCV实现图像校正功能

一、 需求分析

首先是需求:

1、利用 OpenCV 里面的仿射变换函 数实现对图像进行一些基本的变换,如平移、旋转、缩放
2、学习透视变换原理,对一个矩形进行透视变换,并将变换结果绘制出来。先调用 OpenCV 函数实现透视变换,自己编写代码实现透视变换。
3、识别一张倾斜拍摄的纸张,找出轮廓,提取出该纸张的位置
4、 假设你已通过图像处理的算法找到发生形变的纸张的位置,那么对这个倾斜 纸张进行变换,得到纸张的垂直视图,实现文档校准。

然后是分析:

1、首先要调用OpenCV的函数对图像进行平移、旋转、缩放变换,然后要进行仿射变换和透视变换。
2、编程实现仿射变换和透视变换,注意到仿射变换是透视变换的一种,因此只需实现透视变换
3、 实现文档校准:

(1)滤波。考虑到文档中的字(噪点),同时采用均值滤波和闭运算滤波。
(2)边缘提取。利用库函数提取边缘信息
(3)边缘识别。利用经典霍夫变换,获得边界方程,并且计算出文档的四个角的坐标
(4)透视变换。调用库函数,实现文档校准

5、由于前三个需求与最后一个需求的源码放在同一个工程中显得不合适,因此,我将前三个需求的代码和注释放在了工程:作业2_2中,开发环境是win10 vs2017,openCV3.43

二、 实现

注意:

以下的函数全部写在标头.h文件中,要在在main中调用标头.h文件中的函数才能完成功能
还有就是图片输入的路径要改好。

1、工程:作业2_2的实现

(1)调用OpenCV内的函数,编写了一个main_transform函数,在主函数调用它,输入图片后,同时将图片缩小、平移、旋转、透视和仿射变换,并且将图片展示和保存下来(实际上后来openCV的仿射、透视我注释掉了,不用它自带的函数了)
都是直接调用函数,没什么好说的。

下面分别是旋转、透视、平移、缩小、仿射的效果图:

(2)手动实现仿射、透视变换函数 toushibianhuan和toushibianhuan_gai_fangshebianhuan,并在main_transform中调用他们。

透视变换实现:

注意到仿射变换是透视变换的特殊情况,因此只要实现了透视就可以实现仿射。

透视函数的实现:

首先使用getPerspectiveTransform来获取变换矩阵,然后看透视函数

toushibianhuan函数需要三个输入参数:

  • 第一个参数:透视变换输入的图像矩阵,Mat
  • 第二个参数:输出图像容器矩阵,Mat
  • 第三个参数:变换矩阵,Mat

进入函数后,首先定义出一个位置矩阵position_maxtri用以刻画变换前图像的位置,利用矩阵元素积,乘以变换矩阵后算出变换后的四个角的位置矩阵。

用Max、Min函数计算出图像最高点、最低点,进而算出图像的高和宽

然后,重点来了,定义、更新计算出两个重映射矩阵。Map1是从原图的x—>新图x的映射,Map2是从原图y—>新图y的映射。

/*-----------------------------------------------------------------------------------------------------------------
Copyright (C),2018---, HUST Liu
 File name: image_solve.h
 Author: 刘峻源 Version: 1 Date: 2018.10.3
 ------------------------------------------------------------------------------------------------------------------
 Description:
 文档矫正项目.cpp的主要函数储存在这里

-------  -----------   ------------  ------------   -----------  ---------
函数说明:comMatC用于连接矩阵
 toushibianhuan_gai_fangshebianhuan用于仿射变换
 toushibianhuan用于仿射变换
 main_transform 调用函数来处理图像,包括平移、缩小、旋转、仿射变换和透视变换
 input_solve 用以矫正文档,包括打开图像、滤波、提取边缘、绘制边缘、透视变换矫正文档
--------------------------------------------------------------------------------
 Others:NONE
 Function List: comMatC、toushibianhuan、toushibianhuan_gai_fangshebianhuan、input_solve
 --------------------------------------------------------------------------------
 history: NONE

-------------------------------------------------------------------------------------*/

/*-----------------------------------------------------------------
标准openCV开头         --
引用头文件和命名空间        --
------------------------------------------------------------------*/
#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <imgproc.hpp>
using namespace std;
using namespace cv;

/*-------------------------------------------------------------------------------
Function: comMatC
 Description:上下连接矩阵,并输出
 --------------------------------------------------------------------------------
 Calls:Create、copyTo
 Called By: main_transform
 Table Accessed: NONE
 Table Updated: NONE
 --------------------------------------------------------------------------------
 Input:
 第一个参数:上面的矩阵,Mat
 第二个参数:下面的矩阵,Mat
 第三个参数:连接后的输出容器,Mat
 Output:输出连接后的矩阵
 Return:输出矩阵
 Others:列数不一致会报错!
---------------------------------------------------------------------------------*/
Mat comMatC(Mat Matrix1, Mat Matrix2, Mat &MatrixCom)
{
 CV_Assert(Matrix1.cols == Matrix2.cols);
 MatrixCom.create(Matrix1.rows + Matrix2.rows, Matrix1.cols, Matrix1.type());
 Mat temp = MatrixCom.rowRange(0, Matrix1.rows);
 Matrix1.copyTo(temp);
 Mat temp1 = MatrixCom.rowRange(Matrix1.rows, Matrix1.rows + Matrix2.rows);
 Matrix2.copyTo(temp1);
 return MatrixCom;
}

/*--------------------------------------------------------------------------------
Function: toushibianhuan
 Description:实现透视变换功能 ,将input_image按tp_Transform_maxtri矩阵变换后输出至另一图像容器中
 -------------------------------------------------------------------------------
 Calls:max、min
 Called By:main_transform
 Table Accessed: NONE
 Table Updated: NONE
 ----------------------------------------------------------------------------------
 Input:
 第一个参数:透视变换输入的图像矩阵,Mat
 第二个参数:输出图像容器矩阵,Mat
 第三个参数:变换矩阵,Mat
 Output:无返回值。在控制台上打印出原图的位置矩阵、变换后的图像坐标矩阵、变换矩阵
 Return:NONE
 Others:NONE
-----------------------------------------------------------------*/
void toushibianhuan(Mat input_image, Mat &output, Mat tp_Translater_maxtri)
{
 int qiu_max_flag;
 int j;
 int i;
 //定义顶点位置矩阵
 Mat position_maxtri(3, 4, CV_64FC1, Scalar(1));
 position_maxtri.at < double >(0, 0) = 0;
 position_maxtri.at < double >(1, 0) = 0;
 position_maxtri.at < double >(1, 1) = 0;
 position_maxtri.at < double >(0, 2) = 0;
 position_maxtri.at < double >(1, 2) = input_image.rows;
 position_maxtri.at < double >(0, 3) = input_image.cols;
 position_maxtri.at < double >(1, 3) = input_image.rows;
 position_maxtri.at < double >(0, 1) = input_image.cols;
 Mat new_corner = tp_Translater_maxtri * position_maxtri;
 //打印并监视三个矩阵
 cout << "coner_maxtri" << new_corner << ";" << endl << endl;
 cout << "pos_maxtri" << position_maxtri << ";" << endl << endl;
 cout << "T_maxtri" << tp_Translater_maxtri << ";" << endl << endl;
 //为了计算图像高度,先初始化最高最低、最左最右点
 double max_kuan = new_corner.at < double >(0, 0) / new_corner.at < double >(2, 0);
 double min_kuan = new_corner.at < double >(0, 0) / new_corner.at < double >(2, 0);
 double max_gao = new_corner.at < double >(1, 0) / new_corner.at < double >(2, 0);
 double min_gao = new_corner.at < double >(1, 0) / new_corner.at < double >(2, 0);
 for (qiu_max_flag = 1; qiu_max_flag < 4; qiu_max_flag++)
 {
 max_kuan = max(max_kuan,
 new_corner.at < double >(0, qiu_max_flag) / new_corner.at < double >(2, qiu_max_flag));
 min_kuan = min(min_kuan,
 new_corner.at < double >(0, qiu_max_flag) / new_corner.at < double >(2, qiu_max_flag));
 max_gao = max(max_gao,
 new_corner.at < double >(1, qiu_max_flag) / new_corner.at < double >(2, qiu_max_flag));
 min_gao = min(min_gao,
 new_corner.at < double >(1, qiu_max_flag) / new_corner.at < double >(2, qiu_max_flag));
 }
 //创建向前映射矩阵 map1, map2
 output.create(int(max_gao - min_gao), int(max_kuan - min_kuan), input_image.type());
 Mat map1(output.size(), CV_32FC1);
 Mat map2(output.size(), CV_32FC1);
 Mat tp_point(3, 1, CV_32FC1, 1);
 Mat point(3, 1, CV_32FC1, 1);
 tp_Translater_maxtri.convertTo(tp_Translater_maxtri, CV_32FC1);
 Mat Translater_inv = tp_Translater_maxtri.inv();
 //核心步骤,将映射阵用矩阵乘法更新出来
 for (i = 0; i < output.rows; i++)
 {
 for (j = 0; j < output.cols; j++)
 {
 point.at<float>(0) = j + min_kuan;
 point.at<float>(1) = i + min_gao;
 tp_point = Translater_inv * point;
 map1.at<float>(i, j) = tp_point.at<float>(0) / tp_point.at<float>(2);
 map2.at<float>(i, j) = tp_point.at<float>(1) / tp_point.at<float>(2);
 }
 }

 remap(input_image, output, map1, map2, CV_INTER_LINEAR);
}

/*--------------------------------------------------------------------------------
Function: toushibianhuan_gai_fangshebianhuan
 Description:实现仿射变换功能 ,将input_image按Translater_maxtri矩阵变换后输出至另一图像容器中
 ------------------------------------------------------------------------------------
 Calls:comMatC、max、min
 Called By:main_transform
 Table Accessed: NONE
 Table Updated: NONE
 ------------------------------------------------------------------------------------
 Input:
 第一个参数:透视变换输入的图像矩阵,Mat
 第二个参数:输出图像矩阵,Mat
 第三个参数:变换矩阵,Mat
 Output:无返回值。在控制台上打印出原图的位置矩阵、变换后的图像坐标矩阵、变换矩阵
 Return:NONE
 Others:NONE
-------------------------------------------------------------------------------*/
void toushibianhuan_gai_fangshebianhuan(Mat input_image, Mat &output, Mat Translater_maxtri)
{
 int width = 0;
 int height = 0;
 Mat tp_Translater_maxtri;
 Mat position_maxtri(3, 4, CV_64FC1, Scalar(1));
 Mat one_vector(1, 3, CV_64FC1, Scalar(0));
 one_vector.at<double>(0, 2) = 1.;
 comMatC(Translater_maxtri, one_vector, tp_Translater_maxtri);
 position_maxtri.at < double >(1, 1) = 0;
 position_maxtri.at < double >(0, 2) = 0;
 position_maxtri.at < double >(0, 0) = 0;
 position_maxtri.at < double >(1, 0) = 0;
 position_maxtri.at < double >(0, 3) = input_image.cols;
 position_maxtri.at < double >(1, 3) = input_image.rows;
 position_maxtri.at < double >(0, 1) = input_image.cols;
 position_maxtri.at < double >(1, 2) = input_image.rows;
 Mat new_corner = tp_Translater_maxtri * position_maxtri;
 cout << "coner_maxtri" << new_corner << ";" << endl << endl;
 cout << "pos_maxtri" << position_maxtri << ";" << endl << endl;
 cout << "T_maxtri" << tp_Translater_maxtri << ";" << endl << endl;
 double max_kuan = new_corner.at < double >(0, 0) / new_corner.at < double >(2, 0);
 double min_kuan = new_corner.at < double >(0, 0) / new_corner.at < double >(2, 0);
 double max_gao = new_corner.at < double >(1, 0) / new_corner.at < double >(2, 0);
 double min_gao = new_corner.at < double >(1, 0) / new_corner.at < double >(2, 0);
 for (int flag = 1; flag < 4; flag++)
 {
 max_kuan = max(max_kuan, new_corner.at < double >(0, flag) / new_corner.at < double >(2, flag));
 min_kuan = min(min_kuan, new_corner.at < double >(0, flag) / new_corner.at < double >(2, flag));
 max_gao = max(max_gao, new_corner.at < double >(1, flag) / new_corner.at < double >(2, flag));
 min_gao = min(min_gao, new_corner.at < double >(1, flag) / new_corner.at < double >(2, flag));
 }
 output.create(int(max_gao - min_gao), int(max_kuan - min_kuan), input_image.type());
 Mat map1(output.size(), CV_32FC1);
 Mat map2(output.size(), CV_32FC1);
 Mat tp_point(3, 1, CV_32FC1, 1);
 Mat point(3, 1, CV_32FC1, 1);
 tp_Translater_maxtri.convertTo(tp_Translater_maxtri, CV_32FC1);
 Mat Translater_inv = tp_Translater_maxtri.inv();
 for (int i = 0; i < output.rows; i++)
 {
 for (int j = 0; j < output.cols; j++)
 {
 point.at<float>(1) = i + min_gao;
 point.at<float>(0) = j + min_kuan;
 tp_point = Translater_inv * point;
 map1.at<float>(i, j) = tp_point.at<float>(0) / tp_point.at<float>(2);
 map2.at<float>(i, j) = tp_point.at<float>(1) / tp_point.at<float>(2);
 }
 }
 remap(input_image, output, map1, map2, CV_INTER_LINEAR);
}

/*------------------------------------------------------------------------------
Function: main_transform
 Description:实现缩小、平移、旋转的仿射变换功能 ,加以展示且将图片保存在当前工程目录下
 ---------------------------------------------------------------------------
 Calls: resize、 warpAffine、 Size 、 Scalar 、getRotationMatrix2D、 namedWindow、
 toushibianhuan_gai_fangshebianhuan、 imshow、 imwrite、waitKey、printf、warpPerspective、fangshebianhuan
 Called By: main
 Table Accessed: NONE
 Table Updated: NONE
 --------------------------------------------------------------------------------
 Input:
 第一个参数:float类型的旋转角度值(非弧度)
 第二个参数:向右平移的像素,int类型
 第三个参数:向下平移的像素,int类型
 第四个参数:读取图像路径,const char类型
 第五个参数:x方向伸缩比例,float类型
 第六个参数:y方向伸缩比例,float类型
 Output:仿射变换、透视变换后的图像保存于当前工程目录下,各参数已经设置好,矫正效果不佳
 Return:无返回值
 Others:NONE
---------------------------------------------------------------------------*/
void main_transform(float angle, int right_translate, int down_translate,
 const char* road_read_image, float x_tobe, float y_tobe)
{
 Point2f input_image1[3] = { Point2f(50,50),Point2f(200,50),Point2f(50,200) };
 Point2f dst1[3] = { Point2f(0,100),Point2f(200,50),Point2f(180,300) };
 Point2f input_image[4] = { Point2f(100,50),Point2f(100,550),Point2f(350,50),Point2f(350,550) };
 Point2f dst[4] = { Point2f(100,50),Point2f(340,550),Point2f(350,80),Point2f(495,550) };
 Mat kernel2 = getPerspectiveTransform(input_image, dst);
 Mat kernel = getAffineTransform(input_image1, dst1);
 Mat one_vector(1, 3, CV_64FC1, Scalar(0));
 Mat Temp_kernel;
 one_vector.at<double>(0, 2) = 1.;
 comMatC(kernel, one_vector, Temp_kernel);
 float all_tobe = x_tobe / 2 + y_tobe / 2;
 Mat old_image = imread(road_read_image);
 Mat new_min_image;
 Mat new_translation_image;
 Mat rotate_image;
 Mat translater(2, 3, CV_32F, Scalar(0));
 Mat rotater;
 Mat fangshe_image;
 Mat toushi_image;
 vector<int> compression_params;
 resize(old_image, new_min_image, Size(), x_tobe, y_tobe, INTER_CUBIC);
 translater.at<float>(0, 0) = 1;
 translater.at<float>(1, 1) = 1;
 translater.at<float>(0, 2) = right_translate;
 translater.at<float>(1, 2) = down_translate;
 warpAffine(new_min_image, new_translation_image, translater,
 Size(new_min_image.cols*1.5, new_min_image.rows*1.5));
 Point rotate_center = Point(new_translation_image.cols / 3, new_translation_image.rows / 2);
 rotater = getRotationMatrix2D(rotate_center, angle, all_tobe);
 warpAffine(new_translation_image, rotate_image, rotater, Size(),
 INTER_CUBIC | CV_WARP_FILL_OUTLIERS, BORDER_CONSTANT, Scalar(0));
 //warpAffine(new_translation_image, fangshe_image, kernel, Size(new_translation_image.cols*1.5, new_translation_image.rows*1.5));
 //这是OpenCV自带的仿射变换.........
 compression_params.push_back(IMWRITE_PNG_COMPRESSION);
 toushibianhuan_gai_fangshebianhuan(new_translation_image, fangshe_image, kernel);
 toushibianhuan(fangshe_image, toushi_image, kernel2);

 //warpPerspective(fangshe_image, toushi_image, kernel2, Size(new_translation_image.cols, new_translation_image.rows));
 //这是openCV的透视变换
 compression_params.push_back(9);
 namedWindow("new_min_image");
 imshow("new_min_image", new_min_image);
 imwrite("task2_1放缩.png", old_image, compression_params);
 namedWindow("new_translation_image");
 imshow("new_translation_image", new_translation_image);
 bool flags = imwrite("task2_1平移.png", new_translation_image, compression_params);
 namedWindow("rotate_image");
 imshow("rotate_image", rotate_image);
 imwrite("task2_1旋转.png", rotate_image, compression_params);
 namedWindow("fangshe_image");
 imshow("fangshe_image", fangshe_image);
 imwrite("task2_1仿射.png", fangshe_image, compression_params);
 namedWindow("toushi_image");
 imshow("toushi_image", toushi_image);
 imwrite("task2_1透视.png", toushi_image, compression_params);
 printf("%d", flags);

}

/*----------------------------------------------------------------------------
Function: getCrossPoint
 Description:求两直线的交点
 -----------------------------------------------------------------------------
 Calls: NONE
 Called By: input_solve
 Table Accessed: NONE
 Table Updated: NONE
 -----------------------------------------------------------------------------
 Input:
 第一个参数:由两点表示的类型为Vec4i的直线A
 第二个参数:由两点表示的类型为Vec4i的直线B
 Output:Point2f的点
 Return:Point2f的点
 Others:NONE
--------------------------------------------------------------------------------*/
Point2f getCrossPoint(Vec4i LineA, Vec4i LineB)
{
 double ka, kb;
 //求出LineA斜率
 ka = (double)(LineA[3] - LineA[1]) / (double)(LineA[2] - LineA[0]);
 //求出LineB斜率
 kb = (double)(LineB[3] - LineB[1]) / (double)(LineB[2] - LineB[0]); 

 Point2f crossPoint;
 crossPoint.x = (ka*LineA[0] - LineA[1] - kb * LineB[0] + LineB[1]) / (ka - kb);
 crossPoint.y = (ka*kb*(LineA[0] - LineB[0]) + ka * LineB[1] - kb * LineA[1]) / (ka - kb);
 return crossPoint;
}

/*----------------------------------------------------------------------
Function: input_solve
 Description:用于打开图像、滤波、提取边缘、绘制边缘、透视变换矫正文档的函数。注意,本函数中图像
 处理过程中的参数已经调整完毕
 ------------------------------------------------------------------------
 Calls: imread、resize、morphologyEx、blur、Canny、HoughLines、warpPerspective
 Called By: main
 Table Accessed: NONE
 Table Updated: NONE
 -------------------------------------------------------------------------
 Input:
 第一个参数:输入图像的路径
 Output:经过文档矫正后的图像
 Return:NONE
 Others:矫正图像保存于当前目录下:
 "C:/Users/liujinyuan/source/repos/作业2_2/作业2_2/task2_2矫正.png"
---------------------------------------------------------------*/
void input_solve(const char* image_road)
{
 //定义保存图像参数向量
 vector<int> compression_params;
 compression_params.push_back(IMWRITE_PNG_COMPRESSION);
 compression_params.push_back(9);
 //获取闭运算滤波的核
 Mat element = getStructuringElement(MORPH_RECT, Size(5, 5));
 Mat new_min_image;
 Mat last_kernel;
 //获取灰度图
 Mat old_image = imread(image_road,0);
 vector<Vec2f>lines;
 vector<Vec2f>coners;
 vector<Vec4i>lines_2pt(10);
 Point pt1, pt2,pt3,pt4,pt5,pt6;
 Mat last_image;
 Mat new_min_image2;
 resize(old_image, new_min_image, Size(), 0.5, 0.5, INTER_CUBIC);
 resize(old_image, new_min_image2, Size(), 0.5, 0.5, INTER_CUBIC);
 //闭运算滤波
 morphologyEx(new_min_image, new_min_image, MORPH_CLOSE, element);
 blur(new_min_image,new_min_image,Size(10,10));
 Canny(new_min_image, new_min_image,8.9,9,3 );
 HoughLines(new_min_image,lines,1,CV_PI/180,158,0,0);
 //利用这个循环,可以绘制霍夫变换获取直线的效果图,但是为了简洁性我暂时删去了创建窗口绘制的代码
 for (rsize_t i = 0 ; i < lines.size(); i++)
 {
 if (i!=lines.size()-2)
 {
 float zhongxinjuli = lines[i][0], theta = lines[i][1];
 double cos_theta = cos(theta), sin_theta = sin(theta);
 double x0 = zhongxinjuli * cos_theta, y0 = zhongxinjuli * sin_theta;
 pt1.x = cvRound(x0 - 1000 * sin_theta);
 pt1.y = cvRound(y0 + 1000 * cos_theta);
 pt2.x = cvRound(x0 + 1000 * sin_theta);
 pt2.y = cvRound(y0 - 1000 * cos_theta);
 line(new_min_image, pt1, pt2, Scalar(255, 255, 255), 1, LINE_AA);
 }
 }
 //获取霍夫变换直线的交点
 for (rsize_t flag = 0,flag2=0; flag < lines.size(); flag++)
 {
 if (flag != lines.size() - 2)
 {
 float zx_juli = lines[flag][0], theta2 = lines[flag][1];
 double cos_theta2 = cos(theta2), sin_theta2 = sin(theta2);
 double x1 = zx_juli * cos_theta2, y1 = zx_juli * sin_theta2;
 lines_2pt[flag2][0]= cvRound(x1 - 1000 * sin_theta2);
 lines_2pt[flag2][1] = cvRound(y1 +1000 * cos_theta2);
 lines_2pt[flag2][2] = cvRound(x1 + 1000 * sin_theta2);
 lines_2pt[flag2][3] = cvRound(y1 - 1000 * cos_theta2);
 flag2++;
 }
 }
 for(int flag3=0;flag3<4;flag3++)
 {
 cout << "line_vector=" <<lines_2pt [flag3] << " ; " << endl;
 }
 pt3=getCrossPoint(lines_2pt[0],lines_2pt[1]);
 cout << "pt3=" << pt3 << " ; " << endl;
 pt4 = getCrossPoint(lines_2pt[1], lines_2pt[2]);
 cout << "pt4=" << pt4 << " ; " << endl;
 pt5 = getCrossPoint(lines_2pt[2], lines_2pt[3]);
 cout << "pt5=" << pt5<< " ; " << endl;
 pt6= getCrossPoint(lines_2pt[3], lines_2pt[0]);
 cout << "pt6=" << pt6 << " ; " << endl;
 //进行透视变换
 Point2f point_set[4] = { pt3,pt6,pt4,pt5 };
 Point2f point_set_transform[4] = { Point2f(50,50),Point2f(500,50) ,Point2f(50,600),Point2f(500,600) };
 last_kernel = getPerspectiveTransform(point_set,point_set_transform);
 warpPerspective(new_min_image2, last_image, last_kernel, Size(old_image.cols, old_image.rows));
 namedWindow("new_min_image");
 //绘制最终效果图
 imshow("new_min_image", last_image);
 imwrite("task2_2矫正.png", last_image, compression_params);
 waitKey(0);
}
/*-------------------------------------------------------------------------------------------------------------------------------------
Copyright (C),2018---, HUST Liu
 File name:文档矫正项目.cpp
 Author: 刘峻源 Version: 1 Date:2018.10.3
 Description:
   Part1
 根据作业(2)中的任务(1)(2)
 做了以下工作:
 (1)经过仿射变换,图片缩小平移旋转
 (2)调用函数进行仿射、透视变换
 (3)实现函数来做透视变换、仿射变换
------------    ----------    -----------   --------------------   ----
 Part2
 根据作业(2)中的任务(3)(4)
 做了以下工作:
 (1)利用读入灰度图像,并且经过滤波、边缘提取、霍夫变换提取边缘直线、得到
  纸张位置(即4个顶点)
 (2)利用透视变换矫正文档
---------  *  ----------  *  --------------- * --------------- * ---------
 具体的任务过程:
 Part1
 调用OpenCV内的函数,编写main_transform函数实现缩小、平移、旋转和仿射变换功能
 (实际上后来openCV的仿射、透视我注释掉了,不用它的函数了)
 实现仿射、透视变换函数 toushibianhuan、toushibianhuan_gai_fangshebianhuan,并在main_transform
 中调用
 注意:在main中调用标头.h文件中的main_transfom函数实现缩小、平移、旋转和仿射、透视变换!!!
------------    ----------   ------------------    -----------------  ---------
 任务过程:
 Part2
 在input_solve中,利用imread读入灰度图,调用blur、morphologyEx滤波,利用canny提取
 边缘,调用HoughLines获取边缘直线,调用getCrossPoint获取直线交点,调用
 getPerspectiveTransform获取变换矩阵,调用warpPerspective实现透视变换
 注意:编写input_solve函数来实现处理功能,本cpp是在main中调用标头.h 中的input_solve函数!!!
------------------------------------------------------------------------------------------
 Others:  图像输入路径:作业2_2/作业2_2/task2.png
 输出图像保存路径:工程文件夹:作业2_2/作业2_2
 注意:在其他环境运行时一定要弄好更改读入路径!!!!
 May Function List: main、main_transform、input_solve
-----------------------------------------------------------------------------------------------
 History:
 as folwing
 ----- -------------   ----------------   ------------------  --------------  -----
 1.2018.10.3
 2.by 刘峻源
 3.description:在工程作业2_1中将 comMatC、toushibianhuan、toushibianhuan_gai_fangshebianhuan移入头文件
 image_solve.h中
 ----- -------------   ----------------   ------------------  --------------  -----
 1.2018.10.4
 2.by 刘峻源
 3.description:在工程作业2_2中将 main_transfom写入main,去掉main_transform函数的waitKey(0)

 ----- -------------   ----------------   ------------------  --------------  -----
 --------------------------------------------------------------------------------*/

 /*-----------------------------------------------------------------
  标准openCV开头     --
---------------------------------------------------------------------
引用头文件和命名空间        --
------------------------------------------------------------------*/

#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "标头.h"
using namespace std;
using namespace cv;
int main()
{
 main_transform(90, 0, 100, "task2.png", 0.5, 0.5);
 input_solve("task2.png");
 waitKey(0);
}

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

(0)

相关推荐

  • Opencv透视变换综合实例详解

    本文实例为大家分享了Opencv透视变换综合实例的具体代码,供大家参考,具体内容如下 案例背景:对下面发生畸变的图像进行校正 方案思路:灰度二值化分割,闭操作,寻找轮廓,霍夫直线检测,直线排序,直线方程,直线交点,透视矩阵,透视变换. #include<opencv2\opencv.hpp> using namespace cv; using namespace std; int main(int arc, char** argv) { Mat src = imread("1.jpg

  • OpenCV实现图像校正功能

    一. 需求分析 首先是需求: 1.利用 OpenCV 里面的仿射变换函 数实现对图像进行一些基本的变换,如平移.旋转.缩放 2.学习透视变换原理,对一个矩形进行透视变换,并将变换结果绘制出来.先调用 OpenCV 函数实现透视变换,自己编写代码实现透视变换. 3.识别一张倾斜拍摄的纸张,找出轮廓,提取出该纸张的位置 4. 假设你已通过图像处理的算法找到发生形变的纸张的位置,那么对这个倾斜 纸张进行变换,得到纸张的垂直视图,实现文档校准. 然后是分析: 1.首先要调用OpenCV的函数对图像进行平

  • python opencv实现图像边缘检测

    本文利用python opencv进行图像的边缘检测,一般要经过如下几个步骤: 1.去噪 如cv2.GaussianBlur()等函数: 2.计算图像梯度 图像梯度表达的是各个像素点之间,像素值大小的变化幅度大小,变化较大,则可以认为是出于边缘位置,最多可简化为如下形式: 3.非极大值抑制 在获得梯度的方向和大小之后,应该对整幅图像做一个扫描,去除那些非边界上的点.对每一个像素进行检查,看这个点的梯度是不是周围具有相同梯度方向的点中最大的.如下图所示: 4.滞后阈值 现在要确定那些边界才是真正的

  • Python Opencv实现图像轮廓识别功能

    本文实例为大家分享了python opencv识别图像轮廓的具体代码,供大家参考,具体内容如下 要求:用矩形或者圆形框住图片中的云朵(不要求全部框出) 轮廓检测 Opencv-Python接口中使用cv2.findContours()函数来查找检测物体的轮廓. import cv2 img = cv2.imread('cloud.jpg') # 灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.th

  • java通过jni调用opencv处理图像的方法

    1. 建立java文件 public class getImageFeature { static{ System.loadLibrary("getImageFeatureDll"); } public native int getImageFeatureByName(String filename); public native int getImageFeatureByMemory(); public static void main(String[] args) { getIma

  • Opencv实现图像灰度线性变换

    本文实例为大家分享了Opencv实现图像灰度线性变换的具体代码,供大家参考,具体内容如下 通过图像灰度线性变换提高图像对比度和亮度,原图像为src,目标图像为dst,则dst(x,y) = * src(x,y) + . 不仅对单通道图像可以做灰度线性变换,对三通道图像同样可以. #include<opencv2/opencv.hpp>; #include<iostream> using namespace cv; using namespace std; int main(int

  • python opencv对图像进行旋转且不裁剪图片的实现方法

    最近在做深度学习时需要用到图像处理相关的操作,在度娘上找到的图片旋转方法千篇一律,旋转完成的图片都不是原始大小,很苦恼,于是google到歪果仁的网站扒拉了一个方法,亲测好用,再次嫌弃天下文章一大抄的现象,虽然我也是抄歪果仁的. 废话不多说了,直接贴代码了. def rotate_bound(image, angle): # grab the dimensions of the image and then determine the # center (h, w) = image.shape[

  • Java OpenCV实现图像镜像翻转效果

    本文实例为大家分享了Java OpenCV实现图像镜像翻转效果的具体代码,供大家参考,具体内容如下 主要使用OpenCV的flip()方法,可以实现图像的垂直.水平以及同时垂直镜像翻转. flip是Core的静态方法,用法为: public static void flip(Mat src, Mat dst, int flipCode) 参数说明: src:输入图像: dst:输出图像: flipCode: = 0 图像向下翻转 > 0 图像向右翻转 < 0 图像同时向下向右翻转 代码如下:

  • OpenCV计算图像的水平和垂直积分投影

    本文实例为大家分享了OpenCV计算图像的水平和垂直积分投影的具体代码,供大家参考,具体内容如下 #include <cv.h> #include <highgui.h> #pragma comment( lib, "cv.lib" ) #pragma comment( lib, "cxcore.lib" ) #pragma comment( lib, "highgui.lib" ) int main() { IplIma

  • Python+OpenCV实现图像融合的原理及代码

    根据导师作业安排,在学习数字图像处理(刚萨雷斯版)第六章 彩色图像处理 中的彩色模型后,导师安排了一个比较有趣的作业: 融合原理为: 1 注意:遥感原RGB图image和灰度图Grayimage为测试用的输入图像: 2 步骤:(1)将RGB转换为HSV空间(H:色调,S:饱和度,V:明度): (2)用Gray图像诶换掉HSV中的V: (3)替换后的HSV转换回RGB空间即可得到结果. 书上只介绍了HSI彩色模型,并没有说到HSV,所以需要网上查找资料. Python代码如下: import cv

  • Python OpenCV处理图像之滤镜和图像运算

    本文实例为大家分享了Python OpenCV处理图像之滤镜和图像运算的具体代码,供大家参考,具体内容如下 0x01. 滤镜 喜欢自拍的人肯定都知道滤镜了,下面代码尝试使用一些简单的滤镜,包括图片的平滑处理.灰度化.二值化等: import cv2.cv as cv image=cv.LoadImage('img/lena.jpg', cv.CV_LOAD_IMAGE_COLOR) #Load the image cv.ShowImage("Original", image) grey

随机推荐