OpenCV实现图像校正功能

 更新时间:2021年05月21日 09:26:23   作者:基科菜鸡  
这篇文章主要为大家详细介绍了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);
}

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

相关文章

  • 基于C语言实现学生成绩管理系统

    基于C语言实现学生成绩管理系统

    这篇文章主要介绍了基于C语言实现学生成绩管理系统,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • 基于C语言实现简单的扫雷小游戏

    基于C语言实现简单的扫雷小游戏

    这篇文章主要为大家详细介绍了基于C语言实现简单的扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • C++中的类成员函数当线程函数

    C++中的类成员函数当线程函数

    这篇文章主要介绍了C++中的类成员函数当线程函数,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • C/C++中的atan和atan2函数实例用法

    C/C++中的atan和atan2函数实例用法

    在本篇文章里小编给大家分享的是一篇关于C/C++中的atan和atan2函数实例用法相关内容,有兴趣的朋友们可以学习下。
    2020-02-02
  • Qt获取git版本信息的具体方法

    Qt获取git版本信息的具体方法

    这篇文章主要介绍了Qt获取git版本信息的具体方法,今天又碰到这个问题了,想根据具体的git版本信息做代码问题确认,文中有详细的解决方案,具有一定的参考价值,需要的朋友可以参考下
    2024-04-04
  • C++深入浅出讲解内存四区与new关键字的使用

    C++深入浅出讲解内存四区与new关键字的使用

    内存四区,一个非常重要的知识点,搞懂了内存四区,才能更快的去搞懂指针。我们写的C语言代码,不夸张的说,都是直接或者间接的在操作内存。C语言之所以能够开发操作系统,就是指针的存在,而指针说白了就是地址,内存地址,指针变量说白了就是存储地址的变量
    2022-05-05
  • C++11中bind绑定器和function函数对象介绍

    C++11中bind绑定器和function函数对象介绍

    这篇文章主要介绍了C++11中bind绑定器和function函数对象介绍,绑定器,函数对象和lambda表达式只能使用在一条语句中,更多相关内容需要的小伙伴可以参考一下
    2022-07-07
  • C语言 实现遍历一个文件夹的所有文件

    C语言 实现遍历一个文件夹的所有文件

    这篇文章主要介绍了C语言 实现遍历一个文件夹的所有文件的相关资料,需要的朋友可以参考下
    2017-01-01
  • C++数据结构与算法的基础知识和经典算法汇总

    C++数据结构与算法的基础知识和经典算法汇总

    终是到了标志着大二结束的期末考试了,对于《算法设计与分析》这门课,我需要总结一下学过的所有算法的思想以及老师补充的关于两个复杂度和递归的概念思想,以及更深层次的理解,比如用画图的方式表达出来,我觉得可以用博客记录总结一下,分享给大家,希望能有所帮助
    2022-05-05
  • C语言数据结构经典10大排序算法刨析

    C语言数据结构经典10大排序算法刨析

    这篇文章主要介绍了C语言中常用的10种排序算法及代码实现,开发中排序的应用需要熟练的掌握,因为是基础内容,那C语言有哪些排序算法呢?本文小编就来详细说说,需要的朋友可以参考一下
    2022-02-02

最新评论