opencv:图像的基本变换
0.概述
圖像變換的基本原理都是找到原圖和目標(biāo)圖的像素位置的映射關(guān)系,這個(gè)可以用坐標(biāo)系來(lái)思考,在opencv中,
圖像的坐標(biāo)系是從左上角開(kāi)始(0,0),向右是x增加方向(cols),向下時(shí)y增加方向(rows)。
普通坐標(biāo)關(guān)系:
圖像坐標(biāo)關(guān)系:
1.圖像的平移
圖像的平移是比較簡(jiǎn)單的映射關(guān)系,對(duì)于原圖像的某個(gè)像素點(diǎn)位置(X0,Y0),向右平移100個(gè)像素的話,變換之后的目標(biāo)像素點(diǎn)位置(X = X0+100,Y),然后用原圖像的像素值填充目標(biāo)位置就可,因此我們需要將這種映射關(guān)系轉(zhuǎn)換一下,方便獲得原圖像素值,也就是X0 = X-100,這里X是已知的。
具體代碼如下:
void translation(cv::Mat & src, cv::Mat & dst, int dx, int dy) {const int rows = src.rows; // 獲得原圖的高度(y)const int cols = src.cols; // 獲得原圖的寬度(x)dst.create(rows, cols, src.type()); // 按照原圖大小和格式創(chuàng)建一個(gè)空白圖Vec3b *p; for (int Y = 0; Y < rows; ++Y) // 按行掃描{p = dst.ptr<Vec3b>(Y);for (int X = 0; X < cols; ++X){int X0 = X - dx; // 逆映射關(guān)系,求得原圖的位置int Y0 = Y - dy;if (X0 >= 0 && Y0 >= 0 && X0 < cols && Y0 < rows) // 防止越界{p[X] = src.ptr<Vec3b>(Y0)[X0]; // 將原圖的像素值賦給目標(biāo)位置}}}}2.圖像的縮放
這里暫時(shí)只貼出opencv的縮放接口:
void resize(InputArray src, //輸入圖像 OutputArray dst, // 輸出圖像 Size dsize, // 指定的輸出圖像的大小 double fx=0, // 橫向縮放比例 double fy=0, // 縱向縮放比例 int interpolation=INTER_LINEAR // 指定插值方式);3.圖像的旋轉(zhuǎn)
圖像旋轉(zhuǎn)矩陣的原理可以參考這里
基本映射關(guān)系:
我們只需要根據(jù)這個(gè)映射關(guān)系寫(xiě)就好,其中的dx和dy主要用來(lái)計(jì)算旋轉(zhuǎn)中心的,如果都是0的話圖像就是圍繞
圖像坐標(biāo)(0,0)來(lái)旋轉(zhuǎn),該公式中的W'和H'指的是目標(biāo)圖像的寬度和高度。
代碼:
void rotation(cv::Mat & src, cv::Mat & dst, int angle, cv::Point center = cv::Point(0, 0)) {// 計(jì)算角度的正余弦float sint = sin(angle*3.141592653 / 180); float cost = cos(angle*3.141592653 / 180);const int rows = src.rows; // rows == H (Y--->)const int cols = src.cols; // cols == W (X--->)// 計(jì)算旋轉(zhuǎn)中心的偏移float centerxScale = (float)center.x / cols; float centeryScale = (float)center.y / rows;float dx = -centerxScale * cols*cost - centeryScale * rows*sint + centerxScale * cols; // 根據(jù)映射公式float dy = centerxScale * cols*sint - centeryScale * rows*cost + centeryScale * rows;dst.create(rows, cols, src.type());Vec3b *p;for (int Y = 0; Y < rows; ++Y){p = dst.ptr<Vec3b>(Y);for (int X = 0; X < cols; ++X){int X0 = X*cost + Y*sint + dx; // 根據(jù)映射公式int Y0 = -X*sint + Y*cost + dy;if (X0 >= 0 && Y0 >= 0 && X0 < cols && Y0 < rows){p[X] = src.ptr<Vec3b>(Y0)[X0];}}}}4.圖像的翻轉(zhuǎn)
這里也只貼opencv的接口:
void flip(InputArray src, // 原圖像OutputArray dst, //目標(biāo)圖像 int flipCode // 翻轉(zhuǎn)方式,1:水平,0:垂直,-1:水平垂直 );5.圖像的錯(cuò)切
圖像的錯(cuò)切效果可以想象伸縮門(mén)中的菱形的變化:
不過(guò)對(duì)于x方向的錯(cuò)切,y方向的高度并不會(huì)變化。
貼代碼:
void shear(cv::Mat & src, cv::Mat & dst, float dx = 0,float dy = 0) // dx,dy為錯(cuò)切率 {const int rows = src.rows; // rows == H (Y--->)const int cols = src.cols; // cols == W (X--->)dst.create(rows, cols, src.type());Vec3b *p;for (int Y = 0; Y < rows; ++Y){p = dst.ptr<Vec3b>(Y);for (int X = 0; X < cols; ++X){int X0 = X + dx*Y;int Y0 = Y + dy*X;if (X0 >= 0 && Y0 >= 0 && X0 < cols && Y0 < rows){ p[X] = src.ptr<Vec3b>(Y0)[X0];}}}}效果圖(dx = 0.1,dy=0.1):
6.圖像的仿射變換
圖像的仿射變換其實(shí)就是以上基本變換的組合,仿射變換可以維持原圖的點(diǎn)線關(guān)系,例如平行和比例等。
示例代碼:
#include <opencv.hpp> #include <iostream> #include <imgproc.hpp>using namespace std; using namespace cv;int main() {Mat img = imread("img.jpg");Mat dst;Point2f affinePoints0[3] = { Point2f(100, 50), Point2f(100, 390), Point2f(600, 50) }; // 選取原圖像的映射點(diǎn)Point2f affinePoints1[3] = { Point2f(200, 100), Point2f(200, 300), Point2f(500, 50) }; // 選取目標(biāo)圖像的映射點(diǎn)Mat trans = getAffineTransform(affinePoints0, affinePoints1); // 獲得變換矩陣warpAffine(img, dst, trans, Size(img.cols, img.rows)); // 仿射變換for (int i = 0; i < 3; ++i) // 描點(diǎn){circle(img, affinePoints0[i], 5, Scalar(0, 255, 255), -1);circle(dst, affinePoints1[i], 5, Scalar(0, 255, 255), -1);}imshow("src", img);imshow("dst", dst);waitKey(0);return 0; }效果圖:
7.圖像的透視變換
圖像的透視變換和放射變換類似,不過(guò)選取的映射點(diǎn)為四個(gè)。
示例代碼:
#include <opencv.hpp> #include <iostream> #include <imgproc.hpp>using namespace std; using namespace cv;int main() {Mat img = imread("img.jpg");Mat dst;Point2f perspectivePoints0[4] = { Point2f(100, 50), Point2f(100, 390), Point2f(600, 50),Point2f(600, 800) }; // 選取原圖像的映射點(diǎn)Point2f perspectivePoints1[4] = { Point2f(200, 100), Point2f(200, 300), Point2f(500, 50), Point2f(600, 800) }; // 選取目標(biāo)圖像的映射點(diǎn)Mat trans = getPerspectiveTransform(perspectivePoints0, perspectivePoints1); // 獲得變換矩陣warpPerspective(img, dst, trans, Size(img.cols, img.rows)); // 透視變換for (int i = 0; i < 4; ++i) // 描點(diǎn){circle(img, perspectivePoints0[i], 5, Scalar(0, 255, 255), -1);circle(dst, perspectivePoints1[i], 5, Scalar(0, 255, 255), -1);}imshow("src", img);imshow("dst", dst);waitKey(0);return 0; }效果圖(額。):
轉(zhuǎn)載于:https://www.cnblogs.com/whlook/p/7302416.html
總結(jié)
以上是生活随笔為你收集整理的opencv:图像的基本变换的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: IOS和Android音频开发总结
- 下一篇: iOS开发人员不容错过的10大工具