您好,登錄后才能下訂單哦!
一、 需求分析
首先是需求:
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ù):
進(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í)有所幫助,也希望大家多多支持億速云。
免責(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)容。