OpenCV和C++實(shí)現(xiàn)圖像的翻轉(zhuǎn)(鏡像)、平移、旋轉(zhuǎn)、仿射與透視變換
一、翻轉(zhuǎn)(鏡像)
頭文件 quick_opencv.h:聲明類與公共函數(shù)
#pragma once #include <opencv2\opencv.hpp> using namespace cv; class QuickDemo { public: ... void flip_Demo(Mat& image); void rotate_Demo(Mat& image); void move_Demo(Mat& image); void Affine_Demo(Mat& image); void toushi_Demo(Mat& image); void perspective_detect(Mat& image); };
主函數(shù)調(diào)用該類的公共成員函數(shù)
#include <opencv2\opencv.hpp> #include <quick_opencv.h> #include <iostream> using namespace cv; int main(int argc, char** argv) { Mat src = imread("D:\\Desktop\\pandas.jpg"); if (src.empty()) { printf("Could not load images...\n"); return -1; } namedWindow("input", WINDOW_NORMAL); imshow("input", src); QuickDemo qk; ... qk.Affine_Demo(src); qk.move_Demo(src); qk.flip_Demo(src); qk.toushi_Demo(src); qk.perspective_detect(src); waitKey(0); destroyAllWindows(); return 0; }
源文件 quick_demo.cpp:實(shí)現(xiàn)類與公共函數(shù)
void QuickDemo::flip_Demo(Mat& image) { Mat dst0, dst1, dst2; flip(image, dst0, 0); flip(image, dst1, 1); flip(image, dst2, -1); imshow("dst0_上下翻轉(zhuǎn)", dst0); imshow("dst1_左右翻轉(zhuǎn)", dst1); imshow("dst2_對(duì)角線翻轉(zhuǎn)", dst2); //旋轉(zhuǎn)180度 }
二、仿射扭曲
二維圖像一般情況下的變換矩陣(旋轉(zhuǎn)+平移),當(dāng)我們只需要平移的時(shí)候,取 θ 的值為0,a和b的值就代表了圖像沿x軸和y軸移動(dòng)的距離;其中原圖 (原圖大小,不執(zhí)行縮放)
獲取變換矩陣
變換矩陣計(jì)算:
其中:
Mat getRotationMatrix2D( Point2f center, 源圖像中旋轉(zhuǎn)的中心
double angle, 角度以度為單位的旋轉(zhuǎn)角度。正值表示逆時(shí)針旋轉(zhuǎn)(坐標(biāo)原點(diǎn)假定為左上角)。
double scale 各向同性比例因子。
)
仿射扭曲函數(shù) warpAffine
函數(shù)簽名
void warpAffine( InputArray src, 輸入矩陣
OutputArray dst, 輸出矩陣
InputArray M, 2×3 變換矩陣
Size dsize, 輸出圖像大小
int flags = INTER_LINEAR, 插值方式:默認(rèn)線性插值
int borderMode = BORDER_CONSTANT, 邊緣處理方式
const Scalar& borderValue = Scalar() 邊緣填充值,默認(rèn)=0
);
保留所有原圖像素的旋轉(zhuǎn),原理:
旋轉(zhuǎn)
void QuickDemo::rotate_Demo(Mat& image) { Mat dst_0, dst_1, M; int h = image.rows; int w = image.cols; M = getRotationMatrix2D(Point(w / 2, h / 2), 45, 1.0); warpAffine(image, dst_0, M, image.size()); double cos = abs(M.at<double>(0, 0)); double sin = abs(M.at<double>(0, 1)); int new_w = cos * w + sin * h; int new_h = cos * h + sin * w; M.at<double>(0, 2) += (new_w / 2.0 - w / 2); M.at<double>(1, 2) += (new_h / 2.0 - h / 2); warpAffine(image, dst_1, M, Size(new_w, new_h), INTER_LINEAR, 0, Scalar(255, 255, 0)); imshow("旋轉(zhuǎn)演示0", dst_0); imshow("旋轉(zhuǎn)演示1", dst_1); }
依次為:原圖,旋轉(zhuǎn)45度,保留所有原圖像素的旋轉(zhuǎn)45度
平移
void QuickDemo::move_Demo(Mat& image) { Mat dst_move; Mat move_mat = (Mat_<double>(2, 3) << 1, 0, 10, 0, 1, 30);//沿x軸移動(dòng)10沿y軸移動(dòng)30 warpAffine(image, dst_move, move_mat, image.size()); imshow("dst_move", dst_move); double angle_ = 3.14159265354 / 16.0; cout << "pi=" << cos(angle_) << endl; Mat rota_mat = (Mat_<double>(2, 3) << cos(angle_), -sin(angle_), 1, sin(angle_), cos(angle_), 1); warpAffine(image, rotate_dst, rota_mat, image.size()); imshow("rotate_dst", rotate_dst); }
三、仿射變換
Mat getAffineTransform( 返回變換矩陣
const Point2f src[], 變換前三個(gè)點(diǎn)的數(shù)組
const Point2f dst[] 變換后三個(gè)點(diǎn)的數(shù)組
);
void
void QuickDemo::Affine_Demo(Mat& image) { Mat warp_dst; Mat warp_mat(2, 3, CV_32FC1); Point2f srcTri[3]; Point2f dstTri[3]; /// 設(shè)置源圖像和目標(biāo)圖像上的三組點(diǎn)以計(jì)算仿射變換 srcTri[0] = Point2f(0, 0); srcTri[1] = Point2f(image.cols - 1, 0); srcTri[2] = Point2f(0, image.rows - 1); for (size_t i = 0; i < 3; i++){ circle(image, srcTri[i], 2, Scalar(0, 0, 255), 5, 8); } dstTri[0] = Point2f(image.cols * 0.0, image.rows * 0.13); dstTri[1] = Point2f(image.cols * 0.95, image.rows * 0.15); dstTri[2] = Point2f(image.cols * 0.15, image.rows * 0.9); warp_mat = getAffineTransform(srcTri, dstTri); warpAffine(image, warp_dst, warp_mat, warp_dst.size()); imshow("warp_dst", warp_dst); }
四、透視變換
獲取透射變換的矩陣:
Mat getPerspectiveTransform( 返回變換矩陣
const Point2f src[], 透視變換前四個(gè)點(diǎn)的 數(shù)組
const Point2f dst[], 透視變換后四個(gè)點(diǎn)的 數(shù)組
int solveMethod = DECOMP_LU
)
透射變換
void warpPerspective( InputArray src, 原圖像
OutputArray dst, 返回圖像
InputArray M, 透視變換矩陣
Size dsize, 返回圖像的大?。▽?,高)
int flags = INTER_LINEAR, 插值方法
int borderMode = BORDER_CONSTANT, 邊界處理
const Scalar& borderValue = Scalar() 縮放處理
)
void QuickDemo::toushi_Demo(Mat& image) { Mat toushi_dst, toushi_mat; Point2f toushi_before[4]; toushi_before[0] = Point2f(122, 220); toushi_before[1] = Point2f(397, 121); toushi_before[2] = Point2f(133, 339); toushi_before[3] = Point2f(397, 218); int width_0 = toushi_before[1].x - toushi_before[0].x; int height_0 = toushi_before[1].y - toushi_before[0].y; int width_1 = toushi_before[2].x - toushi_before[0].x; int height_1 = toushi_before[2].y - toushi_before[0].y; int width = (int)sqrt(width_0 * width_0 + height_0 * height_0); int height = (int)sqrt(width_1 * width_1 + height_1 * height_1); Point2f toushi_after[4]; toushi_after[0] = Point2f(2, 2); // x0, y0 toushi_after[1] = Point2f(width+2, 2); // x1, y0 toushi_after[2] = Point2f(2, height+2); // x0, y1 toushi_after[3] = Point2f(width + 2, height + 2); // x1, y1 for (size_t i = 0; i < 4; i++){ cout << toushi_after[i] << endl; } toushi_mat = getPerspectiveTransform(toushi_before, toushi_after); warpPerspective(image, toushi_dst, toushi_mat, Size(width, height)); imshow("toushi_dst", toushi_dst); }
綜合示例
自動(dòng)化透視矯正圖像:
流程:
- 灰度化二值化
- 形態(tài)學(xué)去除噪點(diǎn)
- 獲取輪廓
- 檢測(cè)直線
- 計(jì)算直線交點(diǎn)
- 獲取四個(gè)透視頂點(diǎn)
- 透視變換
inline void Intersection(Point2i& interPoint, Vec4i& line1, Vec4i& line2) { // x1, y1, x2, y2 = line1[0], line1[1], line1[2], line1[3] int A1 = line1[3] - line1[1]; int B1 = line1[0] - line1[2]; int C1 = line1[1] * line1[2] - line1[0] * line1[3]; int A2 = line2[3] - line2[1]; int B2 = line2[0] - line2[2]; int C2 = line2[1] * line2[2] - line2[0] * line2[3]; interPoint.x = static_cast<int>((B1 * C2 - B2 * C1) / (A1 * B2 - A2 * B1)); interPoint.y = static_cast<int>((C1 * A2 - A1 * C2) / (A1 * B2 - A2 * B1)); } void QuickDemo::perspective_detect(Mat& image) { Mat gray_dst, binary_dst, morph_dst; // 二值化 cvtColor(image, gray_dst, COLOR_BGR2GRAY); threshold(gray_dst, binary_dst, 0, 255, THRESH_BINARY_INV | THRESH_OTSU); //形態(tài)學(xué)操作 Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5)); morphologyEx(binary_dst, morph_dst, MORPH_CLOSE, kernel, Point(-1, -1), 3); bitwise_not(morph_dst, morph_dst); imshow("morph_dst2", morph_dst); //輪廓查找與可視化 vector<vector<Point>> contours; vector<Vec4i> hierarches; int height = image.rows; int width = image.cols; Mat contours_Img = Mat::zeros(image.size(), CV_8UC3); findContours(morph_dst, contours, hierarches, RETR_TREE, CHAIN_APPROX_SIMPLE); for (size_t i = 0; i < contours.size(); i++){ Rect rect = boundingRect(contours[i]); if (rect.width > width / 2 && rect.width < width - 5) { drawContours(contours_Img, contours, i, Scalar(0, 0, 255), 2, 8, hierarches, 0, Point()); } } imshow("contours_Img", contours_Img); vector<Vec4i> lines; Mat houghImg; int accu = min(width * 0.5, height * 0.5); cvtColor(contours_Img, houghImg, COLOR_BGR2GRAY); HoughLinesP(houghImg, lines, 1, CV_PI / 180, accu, accu*0.6, 0); Mat lineImg = Mat::zeros(image.size(), CV_8UC3); for (size_t i = 0; i < lines.size(); i++){ Vec4i ln = lines[i]; line(lineImg, Point(ln[0], ln[1]), Point(ln[2], ln[3]), Scalar(0, 0, 255), 2, 8, 0); } // 尋找與定位上下左右四條直線 int delta = 0; Vec4i topline = { 0, 0, 0, 0 }; Vec4i bottomline; Vec4i leftline, rightline; for (size_t i = 0; i < lines.size(); i++) { Vec4i ln = lines[i]; delta = abs(ln[3] - ln[1]); // y2-y1 //topline if (ln[3] < height / 2.0 && ln[1] < height / 2.0 && delta < accu - 1) { if (topline[3] > ln[3] && topline[3] > 0) { topline = lines[i]; } else { topline = lines[i]; } } if (ln[3] > height / 2.0 && ln[1] > height / 2.0 && delta < accu - 1) { bottomline = lines[i]; } if (ln[0] < width / 2.0 && ln[2] < width / 2.0) { leftline = lines[i]; } if (ln[0] > width / 2.0 && ln[2] > width / 2.0) { rightline = lines[i]; } } cout << "topline: " << topline << endl; cout << "bottomline: " << bottomline << endl; cout << "leftline: " << leftline << endl; cout << "rightline: " << rightline << endl; // 計(jì)算上述四條直線交點(diǎn)(兩條線的交點(diǎn):依次為左上,右上,左下,右下) Point2i p0, p1, p2, p3; Intersection(p0, topline, leftline); Intersection(p1, topline, rightline); Intersection(p2, bottomline, leftline); Intersection(p3, bottomline, rightline); circle(lineImg, p0, 2, Scalar(255, 0, 0), 2, 8, 0); circle(lineImg, p1, 2, Scalar(255, 0, 0), 2, 8, 0); circle(lineImg, p2, 2, Scalar(255, 0, 0), 2, 8, 0); circle(lineImg, p3, 2, Scalar(255, 0, 0), 2, 8, 0); imshow("Intersection", lineImg); //透視變換 vector<Point2f> src_point(4); src_point[0] = p0; src_point[1] = p1; src_point[2] = p2; src_point[3] = p3; int new_height = max(abs(p2.y - p0.y), abs(p3.y - p1.y)); int new_width = max(abs(p1.x - p0.x), abs(p3.x - p2.x)); cout << "new_height = " << new_height << endl; cout << "new_width = " << new_width << endl; vector<Point2f> dst_point(4); dst_point[0] = Point(0,0); dst_point[1] = Point(new_width, 0); dst_point[2] = Point(0, new_height); dst_point[3] = Point(new_width, new_height); Mat resultImg; Mat wrap_mat = getPerspectiveTransform(src_point, dst_point); warpPerspective(image, resultImg, wrap_mat, Size(new_width, new_height)); imshow("resultImg", resultImg); }
關(guān)鍵步驟可視化
總結(jié)
到此這篇關(guān)于OpenCV和C++實(shí)現(xiàn)圖像的翻轉(zhuǎn)(鏡像)、平移、旋轉(zhuǎn)、仿射與透視變換的文章就介紹到這了,更多相關(guān)OpenCV和C++圖像翻轉(zhuǎn)平移旋轉(zhuǎn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于atoi()與itoa()函數(shù)的內(nèi)部實(shí)現(xiàn)方法詳解
本篇文章是對(duì)atoi()與itoa()函數(shù)的內(nèi)部實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C語(yǔ)言 數(shù)據(jù)存儲(chǔ)方式知識(shí)點(diǎn)詳解
在本篇文章里小編給大家整理的是關(guān)于C語(yǔ)言 數(shù)據(jù)存儲(chǔ)方式知識(shí)點(diǎn)詳解,有需要的朋友們可以學(xué)習(xí)參考下。2020-02-02C和MFC巧妙獲取外網(wǎng)IP的兩種實(shí)現(xiàn)方法
這篇文章主要介紹了C和MFC巧妙獲取外網(wǎng)IP的兩種實(shí)現(xiàn)方法,功能非常的實(shí)用,需要的朋友可以參考下2014-07-07