傾斜變換將圖像沿水平或垂直方向進行剪切映射,產生平行四邊形視覺效果。

固定 y,x 隨 y 線性位移:x' = x + (height - y) * tan(θ)。輸出寬度需擴展:new_width = width + height * tan(θ)。
固定 x,y 隨 x 線性位移:y' = y + x * tan(θ)。輸出高度擴展:new_height = height + width * tan(θ)。
#define pi 3.1415926
int main() {
Mat Img = imread("4.jpg");
float theta = pi/6; // 30度
int width = Img.cols, height = Img.rows;
// 垂直傾斜:輸出圖像更高
int new_height = height + width * tan(theta) + 1;
int new_width = width;
Mat Img_V(new_height, new_width, CV_8UC3, Scalar(0));
for (int y = 0; y < new_height; ++y) {
for (int x = 0; x < new_width; ++x) {
// 反向映射:目標 (x,y) ← 源 (x, y - x*tanθ)
float Dis = x * tan(theta);
float new_y = y - Dis;
float new_x = x;
// 邊界檢查與雙線性插值
if (new_y >= 0 && new_y < height-1 && new_x >= 0 && new_x < width-1) {
int y1 = (int)new_y, x1 = (int)new_x;
float p = new_x - x1, q = new_y - y1;
for (int k = 0; k < 3; ++k) {
Img_V.at(y, x)[k] =
(1-p)*(1-q)*Img.at(y1, x1)[k] +
p*(1-q)*Img.at(y1, x1+1)[k] +
(1-p)*q*Img.at(y1+1, x1)[k] +
p*q*Img.at(y1+1, x1+1)[k];
}
}
}
}
imshow("Vertical Skew", Img_V);
imwrite("V.jpg", Img_V);
waitKey();
return 0;
}
theta 可做成 Trackbar 實時調節。OpenCV 內建 warpAffine 更高效:
Mat M = (Mat_(2,3) << 1, tan(theta), 0, // 水平傾斜矩陣
0, 1, 0);
warpAffine(Img, dst, M, Size(new_width, new_height), INTER_LINEAR, BORDER_CONSTANT);
生產環境首選 warpAffine,手寫循環適合教學理解原理。