OpenCV探索之路(八):重映射与仿射变换
重映射
重映射就是把一幅圖像中某個(gè)位置的像素放置到另一個(gè)圖片中指定位置的過程。
用一個(gè)數(shù)學(xué)公式來表示就是:
其中的 f 就是映射方式,也就說,像素點(diǎn)在另一個(gè)圖像中的位置是由 f 來計(jì)算的。
在OpenCV中,用的是remap函數(shù)實(shí)現(xiàn)重映射。
基本重映射
#include <iostream> #include <opencv2\opencv.hpp> #include <opencv2\imgproc\imgproc.hpp> #include <opencv2\highgui\highgui.hpp>using namespace cv; using namespace std;//基本重映射實(shí)驗(yàn)int main() {Mat srcImage = imread("2.jpg");if (!srcImage.data){cout << "找不到這張圖片!" << endl;return -1;}imshow("Src Pic", srcImage);Mat dstImage, map_x, map_y;dstImage.create(srcImage.size(), srcImage.type());//創(chuàng)建和原圖一樣的效果圖map_x.create(srcImage.size(), CV_32FC1);map_y.create(srcImage.size(), CV_32FC1);//遍歷每一個(gè)像素點(diǎn),改變map_x & map_y的值,實(shí)現(xiàn)翻轉(zhuǎn)180度for (int j = 0; j < srcImage.rows; j++){for (int i = 0; i < srcImage.cols; i++){map_x.at<float>(j, i) = static_cast<float>(i);map_y.at<float>(j, i) = static_cast<float>(srcImage.rows - j);}}//進(jìn)行重映射操作remap(srcImage, dstImage, map_x, map_y, INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));imshow("重映射效果圖", dstImage); waitKey();return 0; }map_x與map_y分別代表目標(biāo)圖中的(x,y)點(diǎn)在原圖中的x坐標(biāo)(由map_x提供)與y坐標(biāo)(由map_y提供)。
運(yùn)行效果,圖像翻轉(zhuǎn)了。
仿射變換
仿射變換指的是一個(gè)向量空間進(jìn)行一次線性變換并接上一個(gè)平移,變換為另一個(gè)向量空間的過程。
圖像進(jìn)行仿射變換后,有以下幾個(gè)特點(diǎn):
二維圖形之間的相對(duì)位置關(guān)系保持不變,平行線依舊是平行線,且直線上的點(diǎn)的位置順序保持不變。
一個(gè)任意的仿射變換都可以表示為乘以一個(gè)矩陣(線性變換)接著再加上一個(gè)向量(平移)的形式。
三種常見形式:
- 旋轉(zhuǎn),rotation(線性變換)
- 平移,translation(向量加)
- 縮放,scale(線性變換)
仿射變換本質(zhì)是一個(gè)2* 3的矩陣M乘上原圖的每個(gè)坐標(biāo),得到目標(biāo)圖的對(duì)應(yīng)點(diǎn)坐標(biāo)。2*3矩陣M中的2表示目標(biāo)點(diǎn)坐標(biāo)的x與y,3中的第三維是平移分量。因此需要做的就是找到矩陣M,OpenCV提供 getAffineTransform 求出仿射變換, getRotationMatrix2D 來獲得旋轉(zhuǎn)矩陣。
這里簡(jiǎn)單說說仿射變換是怎么做到的。
現(xiàn)在有兩幅圖像(如下圖),圖像二是圖像一經(jīng)過放射變化得來的。那問題來了,我們?cè)趺磸倪@兩個(gè)圖像信息里挖掘出兩圖之間的映射關(guān)系?
很簡(jiǎn)單,只要在圖像一種拿出三個(gè)點(diǎn)(1,2,3),圖像二也拿出對(duì)應(yīng)的三個(gè)點(diǎn)(1,2,3),就可以求出兩圖間的映射關(guān)系!
OpenCV通過兩個(gè)函數(shù)的組合使用來實(shí)現(xiàn)仿射變換:
- 使用warpAffine來實(shí)現(xiàn)簡(jiǎn)單重映射
- 使用getRotationMatrix2D來獲得旋轉(zhuǎn)矩陣
兩種仿射變換的效果如下。
有沒有發(fā)現(xiàn)圖片進(jìn)行仿射變換后的背景被填充為黑色了?其實(shí)這個(gè)背景色是可以調(diào)的,像這樣:
warpAffine(dst_warp, dst_warpRotateScale, M2, src.size(), 1, 0, Scalar(11,111, 211));//利用Scalar來填充不同顏色背景然后背景色就變成這樣子了:
最后寫一個(gè)對(duì)圖片旋轉(zhuǎn)任何角度的代碼。
#include <opencv2/core/core.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream>using namespace cv; using namespace std;#define PIC_BEGIN_NUM 100 //這里定義你的起始圖片編號(hào) #define ANGLE_START -45 //旋轉(zhuǎn)角度的開始 #define ANGLE_END 0 //旋轉(zhuǎn)角度的結(jié)束 #define ANGLE_STEP 2 //旋轉(zhuǎn)角度步長(zhǎng)int main(int argc, char **argv) {//Read a single-channel imageconst char* filename = "lol9.jpg";Mat srcImg = imread(filename, 1);imshow("source", srcImg);Point center(srcImg.cols / 2, srcImg.rows / 2); //圖片中心為旋轉(zhuǎn)點(diǎn)char file[20];int count = PIC_BEGIN_NUM; Mat tmpimg; for (int tmp = ANGLE_START; tmp < ANGLE_END; tmp += ANGLE_STEP){Mat rotMatS = getRotationMatrix2D(center, tmp, 0.5); //圖片縮小到原來的0.5倍warpAffine(srcImg, tmpimg, rotMatS, srcImg.size(), 1, 0, Scalar(0, 0, 0));//填充黑色背景 sprintf(file, "%d.jpg", count++); //旋轉(zhuǎn)圖片以1.jpg 2.jpg 的名字格式保存imwrite(file, tmpimg);}waitKey(0);return 0; }這里的代碼實(shí)現(xiàn)對(duì)圖片旋轉(zhuǎn)2度、4度...45度的功能,并將這些旋轉(zhuǎn)后的圖像保存先來。
然后文件夾下就出現(xiàn)旋轉(zhuǎn)好的圖片了!
轉(zhuǎn)載于:https://www.cnblogs.com/xieyulin/p/7060913.html
總結(jié)
以上是生活随笔為你收集整理的OpenCV探索之路(八):重映射与仿射变换的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringMVC中@GetMappin
- 下一篇: js知识点分享