幾何變換-平移、鏡像、轉置
文章目錄
圖像的幾何變換是在不改變圖像內容的前提下對圖像像素進行相對空間位置移動的一種處理方式,主要包括平移、鏡像、轉置、縮放和旋轉。
1 向前映射與向後映射
1.1 向前映射
圖像幾何變換用於改變圖像中像素與像素之間的空間關係,從而重構圖像的空間結構,達到處理圖像的目的。圖像幾何變換就是建立一種源圖像像素與變換後圖像像素之間的映射關係。通過這種映射關係能夠知道源圖像任意像素點變換後的座標,或者變換後圖像像素在源圖像中的座標位置,數學描述如下:
其中,、表示輸出圖像像素的座標,、表示輸入圖像像素的座標,而、表示兩種映射關係,通過輸入的、來確定相應的、。
只要給出了圖像上任意像素的座標,都能通過對應的映射關係獲得幾何變換後的像素座標位置。這種將輸入映射到輸出的過程成爲向前映射。
通過向前映射能夠確定源圖像在經過變換後各像素的座標由於多個輸入座標可以對應同一個輸出座標,所以向前映射是一個滿射。
向前映射主要存在以下問題:
- a) 浮點數座標
數字圖像像素座標是用離散的非負整數表示的,但通過向前映射函數變換後可能產生浮點數的座標,此時難以確定輸出像素的座標。 - b) 映射不完全和映射重疊
- (1) 映射不完全
映射不完全指輸入圖像的像素總數小於輸出圖像的像素總數,這會使得輸出圖像的部分像素與原始圖像沒有映射關係。 - (2) 映射重疊
映射重疊指輸入圖像中的多個像素,經過變換之後對應到輸出圖像中的同一個位置,此時難以確定輸出像素應該使用那個像素值。
- (1) 映射不完全
1.2 向後映射
向後映射的數學表示如下:
其中,、表示輸出圖像像素的座標,、表示輸入圖像像素的座標,而、表示兩種映射關係,通過輸出的、來確定相應的、。
向後映射與向前映射相反,通過輸出圖像像素座標反過來推算該像素在源圖像的座標位置,輸出圖像的每一個像素都能通過映射找到對應的位置,而不會產生映射不完全和映射重疊的問題。
1.3 適用性
向前映射有效率偏低、映射不完全等缺點,但在一些不改變圖像大小的幾何變換中,向前映射仍然可用。向後映射主要運用圖像的旋轉和縮放中,這些幾何變換都改變了圖像的大小,運用向後映射可以有效的解決大小改變產生的各類映射問題。
2 幾何變換的數學描述
由於幾何變換都具有統一的形式,可以記爲:
這就是向前映射的矩陣表示法。
這是向後映射的矩陣表示。
可以看出,向後映射的矩陣表示正好是向前映射的矩陣表示的逆變換。
3 平移
3.1 平移矩陣
圖像的平移變換是將圖像中所有像素的座標分別加上或減去指定的水平偏移量和垂直偏移量,從而使整張圖出現位移效果。
設爲水平偏移量,爲垂直偏移量,則平移變換的向後映射關係爲:
3.2 OpenCV實現
對於圖像平移操作,這裏我藉助OpenCV所提供的進行圖像矩陣變換的函數cv::warpAffine
函數來實現,該函數能夠根據輸入圖像和變換矩陣,得出變換後的圖像結果。所以,我們將重點放在如何生成變換矩陣上。
void CreateTranslateMatrix(float fXOffset, float fYOffset, cv::Mat& mat)
{
mat = cv::Mat::zeros(2, 3, CV_32F);
mat.at<float>(0, 0) = 1;
mat.at<float>(0, 2) = -fXOffset; //水平平移量
mat.at<float>(1, 1) = 1;
mat.at<float>(1, 2) = -fYOffset; //豎直平移量
}
//具體使用
cv::Mat mat_translate;
float fXOffset = 5;
float fYOffset = 10;
CreateTranslateMatrix(-50, 100, mat_translate);
cv::Mat res_translate;
cv::warpAffine(srcimg, res_translate, mat_translate, srcimg.size(),cv::INTER_LINEAR|cv::WARP_INVERSE_MAP);
cv::imshow("res_translate", res_translate);
注意,cv::warpAffine
要求變換矩陣爲2×3的矩陣。
將原圖向右水平平移50像素,向下垂直平移100像素之後的結果如下圖所示。
3.3 Matlab實現
%% 圖像平移
xoffset = 100;
yoffset = 50;
res_translate = zeros(size(srcimg));
res_translate = uint8(res_translate);
for i = 1:1:height
for j = 1:1:width
x =j - xoffset;
y = i - yoffset;
if x > 0 && x <=width && y > 0 && y <= height
res_translate(i,j,:)=srcimg(y,x,:);
end
end
end
figure(1),imshow(res_translate);
將原圖向右水平平移50像素,向下垂直平移100像素之後的結果如下圖所示。
4 鏡像
4.1 變換矩陣
圖像鏡像效果分爲水平鏡像和垂直鏡像,水平鏡像是將圖像以圖像垂直中線爲周,將圖像的所有像素對換;垂直鏡像是將圖像以圖像水平中線爲軸,將圖像所有像素對換。
設圖像寬度爲,高度爲,那麼圖像水平鏡像的向前映射關係爲
那麼水平鏡像的向後映射矩陣表示爲:
對於垂直鏡像,同樣可以得到它的變換關係和矩陣表達式:
那麼水平鏡像的向後映射矩陣表示爲:
4.2 OpenCV實現
//創建水平鏡像變換矩陣
void CreateMirrorXMatrix(cv::Mat& img, cv::Mat& mat)
{
int width = img.cols;
mat = cv::Mat::zeros(2, 3, CV_32F);
mat.at<float>(0, 0) = -1;
mat.at<float>(0, 2) = width-1;
mat.at<float>(1, 1) = 1;
mat.at<float>(1, 2) = 0;
}
//創建垂直鏡像變換矩陣
void CreateMirrorYMatrix(cv::Mat& img, cv::Mat& mat)
{
int height = img.rows;
mat = cv::Mat::zeros(2, 3, CV_32F);
mat.at<float>(0, 0) = 1;
mat.at<float>(0, 2) = 0;
mat.at<float>(1, 1) = -1;
mat.at<float>(1, 2) = height-1;
}
//調用過程如下
cv::Mat mat_XMirror;
CreateMirrorXMatrix(srcimg, mat_XMirror);
cv::Mat res_XMirror;
cv::warpAffine(srcimg, res_XMirror, mat_XMirror, srcimg.size(),cv::INTER_LINEAR|cv::WARP_INVERSE_MAP);
cv::imshow("res_XMirror", res_XMirror);
cv::Mat mat_YMirror;
CreateMirrorYMatrix(srcimg, mat_YMirror);
cv::Mat res_YMirror;
cv::warpAffine(srcimg, res_YMirror, mat_YMirror, srcimg.size(),cv::INTER_LINEAR|cv::WARP_INVERSE_MAP);
cv::imshow("res_YMirror", res_YMirror);
4.3 Matlab實現
%% 鏡像
res_XMirror =srcimg;
for i = 1:1:width
if i < width-i
temp = res_XMirror(:,i,:);
res_XMirror(:,i,:)=res_XMirror(:,width - i,:);
res_XMirror(:,width - i,:)=temp;
else
break;
end
end
figure(3),imshow(res_XMirror),title('水平鏡像結果圖');
res_YMirror =srcimg;
for i = 1:1:height
if i < height-i
temp = res_YMirror(i,:,:);
res_YMirror(i,:,:)=res_YMirror(height-i,:,:);
res_YMirror(height-i,:,:)=temp;
else
break;
end
end
figure(4),imshow(res_YMirror),title('垂直鏡像結果圖');
5 轉置
5.1 轉置矩陣
圖像轉置是將圖像的橫座標和縱座標交換位置,轉置的操作會使圖像的寬度和高度互換。映射矩陣如下:
5.2 OpenCV實現
兩種實現方式,第一種,按照常規套路,創建轉置變換矩陣,然後進行變換。注意調用cv::warpAffine
時的第四個參數,該參數指定了輸出圖像的大小,轉置操作需要對原圖的長寬互換。
//創建圖像轉矩矩陣
void CreateTransPositionMatrix(cv::Mat& mat)
{
mat = cv::Mat::zeros(2, 3, CV_32F);
mat.at<float>(0, 0) = 0;
mat.at<float>(0, 1) = 1;
mat.at<float>(1, 0) = 1;
mat.at<float>(1, 1) = 0;
}
cv::Mat mat_transposition;
CreateTransPositionMatrix(mat_transposition);
cv::Mat res_transposition1;
cv::warpAffine(srcimg, res_transposition1, mat_transposition, cv::Size(srcimg.rows, srcimg.cols),cv::INTER_LINEAR|cv::WARP_INVERSE_MAP);
第二種,直接將表示圖像的矩陣轉置。
cv::Mat res_transposition2;
res_transposition2 = srcimg.t();
5.3 Matlab實現
對於多通道圖像,無法直接使用MATLAB的轉置功能,因此分通道進行轉置。
%% 轉置
res_transposition = zeros(width,height,3);
res_transposition(:,:,1) = srcimg(:,:,1)';
res_transposition(:,:,2) = srcimg(:,:,2)';
res_transposition(:,:,3) = srcimg(:,:,3)';
res_transposition = uint8(res_transposition);
figure(5),imshow(res_transposition),title('轉置結果圖');