溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

OpenCV實(shí)現(xiàn)圖像校正功能

發(fā)布時(shí)間:2020-09-20 05:34:03 來(lái)源:腳本之家 閱讀:255 作者:基科菜雞 欄目:編程語(yǔ)言

一、 需求分析

首先是需求:

1、利用 OpenCV 里面的仿射變換函 數(shù)實(shí)現(xiàn)對(duì)圖像進(jìn)行一些基本的變換,如平移、旋轉(zhuǎn)、縮放
2、學(xué)習(xí)透視變換原理,對(duì)一個(gè)矩形進(jìn)行透視變換,并將變換結(jié)果繪制出來(lái)。先調(diào)用 OpenCV 函數(shù)實(shí)現(xiàn)透視變換,自己編寫(xiě)代碼實(shí)現(xiàn)透視變換。
3、識(shí)別一張傾斜拍攝的紙張,找出輪廓,提取出該紙張的位置
4、 假設(shè)你已通過(guò)圖像處理的算法找到發(fā)生形變的紙張的位置,那么對(duì)這個(gè)傾斜 紙張進(jìn)行變換,得到紙張的垂直視圖,實(shí)現(xiàn)文檔校準(zhǔn)。

然后是分析:

1、首先要調(diào)用OpenCV的函數(shù)對(duì)圖像進(jìn)行平移、旋轉(zhuǎn)、縮放變換,然后要進(jìn)行仿射變換和透視變換。
2、編程實(shí)現(xiàn)仿射變換和透視變換,注意到仿射變換是透視變換的一種,因此只需實(shí)現(xiàn)透視變換
3、 實(shí)現(xiàn)文檔校準(zhǔn):

(1)濾波??紤]到文檔中的字(噪點(diǎn)),同時(shí)采用均值濾波和閉運(yùn)算濾波。
(2)邊緣提取。利用庫(kù)函數(shù)提取邊緣信息
(3)邊緣識(shí)別。利用經(jīng)典霍夫變換,獲得邊界方程,并且計(jì)算出文檔的四個(gè)角的坐標(biāo)
(4)透視變換。調(diào)用庫(kù)函數(shù),實(shí)現(xiàn)文檔校準(zhǔn)

5、由于前三個(gè)需求與最后一個(gè)需求的源碼放在同一個(gè)工程中顯得不合適,因此,我將前三個(gè)需求的代碼和注釋放在了工程:作業(yè)2_2中,開(kāi)發(fā)環(huán)境是win10 vs2017,openCV3.43

二、 實(shí)現(xiàn)

注意:

以下的函數(shù)全部寫(xiě)在標(biāo)頭.h文件中,要在在main中調(diào)用標(biāo)頭.h文件中的函數(shù)才能完成功能
還有就是圖片輸入的路徑要改好。

1、工程:作業(yè)2_2的實(shí)現(xiàn)

(1)調(diào)用OpenCV內(nèi)的函數(shù),編寫(xiě)了一個(gè)main_transform函數(shù),在主函數(shù)調(diào)用它,輸入圖片后,同時(shí)將圖片縮小、平移、旋轉(zhuǎn)、透視和仿射變換,并且將圖片展示和保存下來(lái)(實(shí)際上后來(lái)openCV的仿射、透視我注釋掉了,不用它自帶的函數(shù)了)
都是直接調(diào)用函數(shù),沒(méi)什么好說(shuō)的。

下面分別是旋轉(zhuǎn)、透視、平移、縮小、仿射的效果圖:

(2)手動(dòng)實(shí)現(xiàn)仿射、透視變換函數(shù) toushibianhuan和toushibianhuan_gai_fangshebianhuan,并在main_transform中調(diào)用他們。

透視變換實(shí)現(xiàn):

注意到仿射變換是透視變換的特殊情況,因此只要實(shí)現(xiàn)了透視就可以實(shí)現(xiàn)仿射。

透視函數(shù)的實(shí)現(xiàn):

首先使用getPerspectiveTransform來(lái)獲取變換矩陣,然后看透視函數(shù)

toushibianhuan函數(shù)需要三個(gè)輸入?yún)?shù):

  • 第一個(gè)參數(shù):透視變換輸入的圖像矩陣,Mat
  • 第二個(gè)參數(shù):輸出圖像容器矩陣,Mat
  • 第三個(gè)參數(shù):變換矩陣,Mat

進(jìn)入函數(shù)后,首先定義出一個(gè)位置矩陣position_maxtri用以刻畫(huà)變換前圖像的位置,利用矩陣元素積,乘以變換矩陣后算出變換后的四個(gè)角的位置矩陣。

用Max、Min函數(shù)計(jì)算出圖像最高點(diǎn)、最低點(diǎn),進(jìn)而算出圖像的高和寬

然后,重點(diǎn)來(lái)了,定義、更新計(jì)算出兩個(gè)重映射矩陣。Map1是從原圖的x—>新圖x的映射,Map2是從原圖y—>新圖y的映射。

/*-----------------------------------------------------------------------------------------------------------------
Copyright (C),2018---, HUST Liu
 File name: image_solve.h
 Author: 劉峻源 Version: 1 Date: 2018.10.3
 ------------------------------------------------------------------------------------------------------------------
 Description:
 文檔矯正項(xiàng)目.cpp的主要函數(shù)儲(chǔ)存在這里

 
-------  -----------   ------------  ------------   -----------  ---------
函數(shù)說(shuō)明:comMatC用于連接矩陣
 toushibianhuan_gai_fangshebianhuan用于仿射變換
 toushibianhuan用于仿射變換
 main_transform 調(diào)用函數(shù)來(lái)處理圖像,包括平移、縮小、旋轉(zhuǎn)、仿射變換和透視變換
 input_solve 用以矯正文檔,包括打開(kāi)圖像、濾波、提取邊緣、繪制邊緣、透視變換矯正文檔
--------------------------------------------------------------------------------
 Others:NONE
 Function List: comMatC、toushibianhuan、toushibianhuan_gai_fangshebianhuan、input_solve
 --------------------------------------------------------------------------------
 history: NONE

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

/*-----------------------------------------------------------------
標(biāo)準(zhǔn)openCV開(kāi)頭         --
引用頭文件和命名空間        --
------------------------------------------------------------------*/
#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:
 第一個(gè)參數(shù):上面的矩陣,Mat
 第二個(gè)參數(shù):下面的矩陣,Mat
 第三個(gè)參數(shù):連接后的輸出容器,Mat
 Output:輸出連接后的矩陣
 Return:輸出矩陣
 Others:列數(shù)不一致會(huì)報(bào)錯(cuò)!
---------------------------------------------------------------------------------*/
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:實(shí)現(xiàn)透視變換功能 ,將input_image按tp_Transform_maxtri矩陣變換后輸出至另一圖像容器中
 -------------------------------------------------------------------------------
 Calls:max、min
 Called By:main_transform
 Table Accessed: NONE
 Table Updated: NONE
 ----------------------------------------------------------------------------------
 Input:
 第一個(gè)參數(shù):透視變換輸入的圖像矩陣,Mat
 第二個(gè)參數(shù):輸出圖像容器矩陣,Mat
 第三個(gè)參數(shù):變換矩陣,Mat
 Output:無(wú)返回值。在控制臺(tái)上打印出原圖的位置矩陣、變換后的圖像坐標(biāo)矩陣、變換矩陣
 Return:NONE
 Others:NONE
-----------------------------------------------------------------*/
void toushibianhuan(Mat input_image, Mat &output, Mat tp_Translater_maxtri)
{
 int qiu_max_flag;
 int j;
 int i;
 //定義頂點(diǎn)位置矩陣
 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;
 //打印并監(jiān)視三個(gè)矩陣
 cout << "coner_maxtri" << new_corner << ";" << endl << endl;
 cout << "pos_maxtri" << position_maxtri << ";" << endl << endl;
 cout << "T_maxtri" << tp_Translater_maxtri << ";" << endl << endl;
 //為了計(jì)算圖像高度,先初始化最高最低、最左最右點(diǎn)
 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));
 }
 //創(chuàng)建向前映射矩陣 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();
 //核心步驟,將映射陣用矩陣乘法更新出來(lái)
 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:實(shí)現(xiàn)仿射變換功能 ,將input_image按Translater_maxtri矩陣變換后輸出至另一圖像容器中
 ------------------------------------------------------------------------------------
 Calls:comMatC、max、min
 Called By:main_transform
 Table Accessed: NONE
 Table Updated: NONE
 ------------------------------------------------------------------------------------
 Input:
 第一個(gè)參數(shù):透視變換輸入的圖像矩陣,Mat
 第二個(gè)參數(shù):輸出圖像矩陣,Mat
 第三個(gè)參數(shù):變換矩陣,Mat
 Output:無(wú)返回值。在控制臺(tái)上打印出原圖的位置矩陣、變換后的圖像坐標(biāo)矩陣、變換矩陣
 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:實(shí)現(xiàn)縮小、平移、旋轉(zhuǎn)的仿射變換功能 ,加以展示且將圖片保存在當(dāng)前工程目錄下
 ---------------------------------------------------------------------------
 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:
 第一個(gè)參數(shù):float類(lèi)型的旋轉(zhuǎn)角度值(非弧度)
 第二個(gè)參數(shù):向右平移的像素,int類(lèi)型
 第三個(gè)參數(shù):向下平移的像素,int類(lèi)型
 第四個(gè)參數(shù):讀取圖像路徑,const char類(lèi)型
 第五個(gè)參數(shù):x方向伸縮比例,float類(lèi)型
 第六個(gè)參數(shù):y方向伸縮比例,float類(lèi)型
 Output:仿射變換、透視變換后的圖像保存于當(dāng)前工程目錄下,各參數(shù)已經(jīng)設(shè)置好,矯正效果不佳
 Return:無(wú)返回值
 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旋轉(zhuǎn).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:求兩直線的交點(diǎn)
 -----------------------------------------------------------------------------
 Calls: NONE
 Called By: input_solve
 Table Accessed: NONE
 Table Updated: NONE
 -----------------------------------------------------------------------------
 Input:
 第一個(gè)參數(shù):由兩點(diǎn)表示的類(lèi)型為Vec4i的直線A
 第二個(gè)參數(shù):由兩點(diǎn)表示的類(lèi)型為Vec4i的直線B
 Output:Point2f的點(diǎn)
 Return:Point2f的點(diǎn)
 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:用于打開(kāi)圖像、濾波、提取邊緣、繪制邊緣、透視變換矯正文檔的函數(shù)。注意,本函數(shù)中圖像
 處理過(guò)程中的參數(shù)已經(jīng)調(diào)整完畢
 ------------------------------------------------------------------------
 Calls: imread、resize、morphologyEx、blur、Canny、HoughLines、warpPerspective
 Called By: main
 Table Accessed: NONE
 Table Updated: NONE
 -------------------------------------------------------------------------
 Input:
 第一個(gè)參數(shù):輸入圖像的路徑
 Output:經(jīng)過(guò)文檔矯正后的圖像
 Return:NONE
 Others:矯正圖像保存于當(dāng)前目錄下:
 "C:/Users/liujinyuan/source/repos/作業(yè)2_2/作業(yè)2_2/task2_2矯正.png"
---------------------------------------------------------------*/
void input_solve(const char* image_road)
{
 //定義保存圖像參數(shù)向量
 vector<int> compression_params;
 compression_params.push_back(IMWRITE_PNG_COMPRESSION);
 compression_params.push_back(9);
 //獲取閉運(yùn)算濾波的核
 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);
 //閉運(yùn)算濾波
 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);
 //利用這個(gè)循環(huán),可以繪制霍夫變換獲取直線的效果圖,但是為了簡(jiǎn)潔性我暫時(shí)刪去了創(chuàng)建窗口繪制的代碼
 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);
 }
 }
 //獲取霍夫變換直線的交點(diǎn)
 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;
 //進(jìn)行透視變換
 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:文檔矯正項(xiàng)目.cpp
 Author: 劉峻源 Version: 1 Date:2018.10.3
 Description:
   Part1
 根據(jù)作業(yè)(2)中的任務(wù)(1)(2)
 做了以下工作:
 (1)經(jīng)過(guò)仿射變換,圖片縮小平移旋轉(zhuǎn)
 (2)調(diào)用函數(shù)進(jìn)行仿射、透視變換
 (3)實(shí)現(xiàn)函數(shù)來(lái)做透視變換、仿射變換
------------    ----------    -----------   --------------------   ---- 
 Part2
 根據(jù)作業(yè)(2)中的任務(wù)(3)(4)
 做了以下工作:
 (1)利用讀入灰度圖像,并且經(jīng)過(guò)濾波、邊緣提取、霍夫變換提取邊緣直線、得到
  紙張位置(即4個(gè)頂點(diǎn))
 (2)利用透視變換矯正文檔
---------  *  ----------  *  --------------- * --------------- * ---------
 具體的任務(wù)過(guò)程:
 Part1
 調(diào)用OpenCV內(nèi)的函數(shù),編寫(xiě)main_transform函數(shù)實(shí)現(xiàn)縮小、平移、旋轉(zhuǎn)和仿射變換功能
 (實(shí)際上后來(lái)openCV的仿射、透視我注釋掉了,不用它的函數(shù)了)
 實(shí)現(xiàn)仿射、透視變換函數(shù) toushibianhuan、toushibianhuan_gai_fangshebianhuan,并在main_transform
 中調(diào)用
 注意:在main中調(diào)用標(biāo)頭.h文件中的main_transfom函數(shù)實(shí)現(xiàn)縮小、平移、旋轉(zhuǎn)和仿射、透視變換?。?!
------------    ----------   ------------------    -----------------  ---------
 任務(wù)過(guò)程:
 Part2
 在input_solve中,利用imread讀入灰度圖,調(diào)用blur、morphologyEx濾波,利用canny提取
 邊緣,調(diào)用HoughLines獲取邊緣直線,調(diào)用getCrossPoint獲取直線交點(diǎn),調(diào)用
 getPerspectiveTransform獲取變換矩陣,調(diào)用warpPerspective實(shí)現(xiàn)透視變換
 注意:編寫(xiě)input_solve函數(shù)來(lái)實(shí)現(xiàn)處理功能,本cpp是在main中調(diào)用標(biāo)頭.h 中的input_solve函數(shù)?。?!
------------------------------------------------------------------------------------------
 Others:  圖像輸入路徑:作業(yè)2_2/作業(yè)2_2/task2.png
 輸出圖像保存路徑:工程文件夾:作業(yè)2_2/作業(yè)2_2
 注意:在其他環(huán)境運(yùn)行時(shí)一定要弄好更改讀入路徑?。。?!
 May Function List: main、main_transform、input_solve
-----------------------------------------------------------------------------------------------
 History:
 as folwing
 ----- -------------   ----------------   ------------------  --------------  -----
 1.2018.10.3 
 2.by 劉峻源
 3.description:在工程作業(yè)2_1中將 comMatC、toushibianhuan、toushibianhuan_gai_fangshebianhuan移入頭文件
 image_solve.h中
 ----- -------------   ----------------   ------------------  --------------  -----
 1.2018.10.4
 2.by 劉峻源
 3.description:在工程作業(yè)2_2中將 main_transfom寫(xiě)入main,去掉main_transform函數(shù)的waitKey(0)

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


 /*-----------------------------------------------------------------
  標(biāo)準(zhǔn)openCV開(kāi)頭     --
---------------------------------------------------------------------
引用頭文件和命名空間        --
------------------------------------------------------------------*/

#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "標(biāo)頭.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);
}

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持億速云。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI