1. 几许改换

图画的几许改换是指将一幅图画中的坐标方位映射到另一幅图画中的新坐标方位,其实质是改动像素的空间方位,估算新空间方位上的像素值。几许改换不改动图画的像素值,只是在图画平面上进行像素的重新安排。

以下是常用的几种几许改换:

  • 旋转:将图画旋转指定视点。
  • 缩放:按缩放因子调整图画巨细,使其变大或变小。
  • 平移:将图画从当前方位移动到新方位。
  • 错切:沿特定轴歪斜图画。
  • 仿射改换:一个更广泛的类别,包含单个改换中的缩放、旋转、错切和平移。
  • 透视改换:此改换模仿 3D 空间中的透视作用,答应进行更复杂的操作,例如校对由摄像机视点引起的歪曲。

几许改换一般运用数学函数和改换矩阵来完成。这些矩阵界说了原始图画中的每个像素如何映射到转化图画中的新方位。

2. 仿射改换

2.1 仿射改换

图画处理中的仿射改换是指对图画进行一次线性改换和平移,将其映射到另一个图画空间的过程。仿射改换能够坚持图画的“平直性”,即直线经过仿射改换后仍然为直线,平行线经过仿射改换后仍然为平行线。

一般,运用 2×3 巨细数组 M 来进行仿射改换。数组由两个矩阵 A、B 组成,其间矩阵 A(巨细为2×2)用于矩阵乘法,矩阵 B(巨细为2×1)用于向量加法。

A=∣a00a01a10a11∣A= begin{vmatrix} a_{00} & a_{01} \ a_{10} & a_{11} end{vmatrix}

B=∣b00b10∣B = begin{vmatrix} b_{00} \ b_{10} end{vmatrix}

M=∣AB∣=∣a00a01b00a10a11b10∣M = begin{vmatrix} A & B end{vmatrix} = begin{vmatrix} a_{00} & a_{01} & b_{00} \ a_{10} & a_{11} & b_{10} end{vmatrix}

原像素点坐标(x,y),经过仿射改换后的点的坐标是(u,v),则矩阵仿射改换基本算法原理:

∣uv∣=A∗∣xy∣+Bbegin{vmatrix} u \ v end{vmatrix} = A*begin{vmatrix} x \ y end{vmatrix} + B

其数学表达式如下:

{u=a00x+a01y+b00v=a10x+a11y+b10begin{cases} u = a_{00}x+a_{01}y+b_{00} \ v = a_{10}x+a_{11}y+b_{10} end{cases}

其间:

  • a00a_{00}a11a_{11} 代表缩放系数,操控图画在水平缓笔直方向上的缩放。
  • a01a_{01}a10a_{10} 代表错切系数,操控图画的水平缓笔直错切。
  • b00b_{00}b10b_{10} 代表平移系数,操控图画在水平缓笔直方向上的平移。

由于缩放和旋转是经过矩阵乘法来完成,平移是经过矩阵加法来完成的,将这几个操作都用一个矩阵完成所以结构出上面的 2×3 矩阵 M。

仿射改换是从二维坐标到二维坐标之间的线性改换,且为了坚持二维图画的“平直性”和“平行性”。咱们需求引进齐次坐标的概念,终究得到的齐次坐标矩阵表明方式为:

∣uv1∣=∣a00a01b00a10a11b10001∣∣xy1∣begin{vmatrix} u \ v \ 1 end{vmatrix} = begin{vmatrix} a_{00} & a_{01} & b_{00} \ a_{10} & a_{11} & b_{10} \ 0 & 0 & 1 end{vmatrix} begin{vmatrix} x \ y \ 1 end{vmatrix}

2.2 齐次坐标

在数学里,齐次坐标(homogeneous coordinates),或投影坐标(projective coordinates)是指一个用于投影几许里的坐标系统,好像用于欧氏几许里的笛卡儿坐标一般。齐次坐标可让包含无穷远点的点坐标以有限坐标表明。运用齐次坐标的公式一般会比用笛卡儿坐标表明更为简略,且更为对称。

引进齐次坐标的意图是为了更好的表明无限远(infinity)的坐标的概念,在欧式空间中,无限大或者无限小的坐标的并不存在,不能用数值表明。数学家 August Ferdinand Mbius(1) 提出了齐次坐标系,选用 N+1 个量来表明 N 维坐标。

例如,在二维齐次坐标系中,咱们引进一个量 w,将一个二维点 (x,y) 表明为 (X,Y,w) 的方式,其转化关系为

x=Xwx = frac{X}{w}

y=Ywy = frac{Y}{w}

其间,w 能够为恣意值。

在笛卡尔坐标系中以(1,2)为例,在齐次坐标系中能够用(1,2,1)表明,也能够用(2,4,2)表明,还能够用 (4,8,4),(8,16,8)…表明,即 (k,2k,k),k∈ R 这些点都映射到欧式空间中的一点,即这些点具有 尺度不变性(Scale Invariant),是“齐性的”(本家的),所以称之为齐次坐标

“齐次坐标表明是计算机图形学的重要手法之一,它既能够用来清晰区分向量和点,同时也更易用于进行仿射(线性)几许改换。”——出自《计算机图形学(OpenGL版)》的作者 F.S. Hill Jr.

经过齐次坐标还能够证明两条平行线能够相交,非常有意思。

3. 仿射改换中常见的改换方式

OpenCV 供给了 warpAffine() 函数完成仿射改换。它能够用于完成各种图画几许改换,例如平移、缩放、旋转、错切等。

void warpAffine( InputArray src, OutputArray dst,
                              InputArray M, Size dsize,
                              int flags = INTER_LINEAR,
                              int borderMode = BORDER_CONSTANT,
                              const Scalar& borderValue = Scalar());

第一个参数 src: 输入图画,能够是单通道或多通道图画。

第二个参数 dst: 输出图画,与输入图画同类型和巨细。

第三个参数 M: 仿射改换矩阵,2×3 的浮点数矩阵。

第四个参数 dsize: 输出图画的巨细。

第五个参数 flags: 插值方式,默认值为 INTER_LINEAR,表明运用双线性插值。

第六个参数 borderMode: 鸿沟形式,默认值为BORDER_CONSTANT,表明运用常量值填充鸿沟。

第七个参数 borderValue: 鸿沟填充值,默认值为0。

3.1 平移

图画平移的公式:

∣10tx01ty001∣∣xy1∣=∣x+txy+ty1∣begin{vmatrix} 1 & 0 & t_x \ 0 & 1 & t_y \ 0 & 0 & 1 end{vmatrix} begin{vmatrix} x \ y \ 1 end{vmatrix} = begin{vmatrix} x + t_x \ y + t_y \ 1 end{vmatrix}

下面的代码,别离完成了对图画沿着 x 轴、y 轴进行平移

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
    Mat src = imread(".../girl.jpg");
    imshow("src", src);
    int width = src.cols;
    int height = src.rows;
    Mat dst;
    Mat warp_matrix = (cv::Mat_<float>(2, 3) <<1, 0, 400, 0, 1, 0);
    warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    imshow("Shift along X-axis", dst);
    warp_matrix = (cv::Mat_<float>(2, 3) <<1, 0, 0, 0, 1, 400);
    cv::warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    cv::imshow("Shift along Y-axis", dst);
    waitKey(0);
    return 0;
}

OpenCV 笔记(25):图画的仿射改换

3.2 缩放

图画缩放的公式:

∣sx000sy0001∣∣xy1∣=∣x′y′1∣begin{vmatrix} s_x & 0 & 0 \ 0 & s_y & 0 \ 0 & 0 & 1 end{vmatrix} begin{vmatrix} x \ y \ 1 end{vmatrix} = begin{vmatrix} x’ \ y’ \ 1 end{vmatrix}

下面的代码,别离完成了对图画进行0.75和1.25倍的缩放。

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
    Mat src = imread(".../girl.jpg");
    imshow("src", src);
    int width = src.cols;
    int height = src.rows;
    // 设置缩放份额
    float scale = 0.75;
    Mat dst;
    Mat warp_matrix = (cv::Mat_<float>(2, 3) <<scale, 0, 0, 0, scale, 0);
    warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    imshow("Scale 0.75", dst);
    scale = 1.25;
    warp_matrix = (cv::Mat_<float>(2, 3) <<scale, 0, 0, 0, scale, 0);
    cv::warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    cv::imshow("Scale 1.25", dst);
    waitKey(0);
    return 0;
}

OpenCV 笔记(25):图画的仿射改换

3.3 旋转

图画旋转的公式:

∣cos()−sin()txsin()cos()ty001∣∣xy1∣=∣x′y′1∣begin{vmatrix} cos(theta) & -sin(theta) & t_x \ sin(theta) & cos(theta) & t_y \ 0 & 0 & 1 end{vmatrix} begin{vmatrix} x \ y \ 1 end{vmatrix} = begin{vmatrix} x’ \ y’ \ 1 end{vmatrix}

OpenCV 供给了更为简洁的 getRotationMatrix2D() 函数用于生成一个 2×3 的仿射改换矩阵,该矩阵能够用于对图画进行旋转操作。

Mat getRotationMatrix2D(Point2f center, double angle, double scale);

第一个参数 center: 图画旋转中心,以像素为单位。

第二个参数 angle: 旋转视点,以度为单位。逆时针方向为正。

第三个参数 scale: 旋转后的图画缩放份额。

下面的代码,展现了以图画的中心作为旋转中心,而且逆时针方向旋转45度。

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
    Mat src = imread(".../girl.jpg");
    imshow("src", src);
    int width = src.cols;
    int height = src.rows;
    Point center = Point(width / 2, height / 2);
    double angle = 45;
    double scale = 1.0;
    Mat dst;
    Mat warp_matrix = getRotationMatrix2D(center, angle, scale);
    warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    imshow("Rotate", dst);
    waitKey(0);
    return 0;
}

OpenCV 笔记(25):图画的仿射改换

3.4 错切

图画错切的公式:

∣1dx0dy10001∣∣xy1∣=∣x′y′1∣begin{vmatrix} 1 & d_x & 0 \ d_y & 1 & 0 \ 0 & 0 & 1 end{vmatrix} begin{vmatrix} x \ y \ 1 end{vmatrix} = begin{vmatrix} x’ \ y’ \ 1 end{vmatrix}

其间,

  • dx=tan()d_x = tan(theta),dy=0d_y = 0 时,沿 x 方向错切。
  • dx=0d_x = 0,dy=tan()d_y = tan(theta) 时,沿 y 方向错切。

下面的比如,展现图画的错切。

#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main() {
    Mat src = imread(".../girl.jpg");
    imshow("src", src);
    int width = src.cols;
    int height = src.rows;
    float a = 0.25;
    float b = 0.5;
    Mat dst;
    Mat warp_matrix = (cv::Mat_<float>(2, 3) <<1, a, 0, b, 1, 0);
    warpAffine(src, dst, warp_matrix, Size(width, height), INTER_LINEAR);
    imshow("Shearing", dst);
    waitKey(0);
    return 0;
}

OpenCV 笔记(25):图画的仿射改换

4. 总结

图画仿射改换是一种简略而有用的图画几许改换办法,在图画处理和计算机视觉领域有着广泛的应用。它能够用于图画矫正、增强、配准、组成、目标辨认和盯梢等多种使命。