数字图像处理——图像的几何变换

数字图像处理——图像的几何变换

几何变换不改变像素值,而是改变像素所在的位置。

它包括两个独立的算法:

  • 空间变换算法
  • 插值算法

分类

  1. 从图像类型上

    1. 二维图像
    2. 三维图像
    3. 从三维到二维平面投影变换
  2. 从变换的性质
    1. 基本变换:平移,比例缩放,旋转,镜像,错切
    2. 复合变换

图像的平移

在同一坐标系下,设\(P_0(x_0,y_0)\) ,经过水平偏移量\(\triangle x\) ,垂直偏移量\(\triangle y\),得到平移之后的坐标:

\[
\begin{cases}
x = x_0 + \triangle x \y = y_0 + \triangle x \\end{cases}
\]

用矩阵变换表示为:

\[
\begin{bmatrix}
x \y\1
\end{bmatrix}
=
\begin{bmatrix}
1 &0 & \triangle x \0 & 1 & \triangle y \0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x_0 \y_0 \1
\end{bmatrix}
\]

求逆?不妨将偏移量直接取负。

我们把变换矩阵求逆之后可以观察一下:

\[
\begin{bmatrix}
x_0 \y_0 \1
\end{bmatrix}
=
\begin{bmatrix}
1 &0 & -\triangle x \0 & 1 & -\triangle y \0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \y\1
\end{bmatrix}
\]

其实也就是

\[
\begin{cases}
x = x_0 + \triangle x \y = y_0 + \triangle x \\end{cases}
\Rightarrow
\begin{cases}
x_0 = x - \triangle x \y_0 = y - \triangle x \\end{cases}
\]

图像的镜像

  1. 水平镜像
  2. 垂直镜像

设图像宽度为\(Width\),高度为\(Height\)

那么水平镜像的坐标变化为

\[
\begin{cases}
x = Width - x_0 \y = y_0\\end{cases}
\]

变换矩阵:

\[
\begin{bmatrix}
x \y\1
\end{bmatrix}
=
\begin{bmatrix}
-1 &0 & Width \0 & 1 & 0\0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x_0 \y_0 \1
\end{bmatrix}
\]

求逆:

\[
\begin{bmatrix}
x_0 \y_0 \1
\end{bmatrix}
=
\begin{bmatrix}
-1 &0 &Width\0 & 1 & 0 \0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
x \y\1
\end{bmatrix}
\]

void translateTransformSize(Mat const &src, Mat & dst, int dx, int dy){
    int rows = src.rows + dx;
    int cols = src.cols + dy;
    dst.create(rows, cols, src.type());
    for (int i = 0; i < rows; i++){
        for (int j = 0; j < cols; j++){
            int x0 = i - dx;
            int y0 = j - dy;
            if (x0 >= 0 && y0 >= 0 && x0 < src.cols && y0 < src.rows)
                dst.at<Vec3b>(i, j) = src.at<Vec3b>(x0, y0);
        }
    }
}

图像的缩放

将给定图像在 \(x\) 轴方向按比例缩放\(f_x\) 倍,在\(y\) 轴方向按比例缩放\(f_y\)倍,从而获得一副新的图像。

  • 若 \(f_x = f_y\) ,则这样的比例缩放为图像的全比例缩放。
  • 若\(f_x != f_y\) , 则产生几何畸变

坐标的缩放变化:

\[
\begin{cases}
x = f_x x_0\y = f_y y_0
\end{cases}
\]

其反变换:

\[
\begin{cases}
x_0 = \frac{x}{f_x}\y_0 = \frac{y}{f_y}
\end{cases}
\]

void zoom(Mat& src, Mat &dst, double sx, double sy){
    // 缩放之后的大小
    int rows = (src.rows * sx + 0.5);
    int cols = (src.cols * sy + 0.5);
    dst.create(rows, cols, src.type());
    Vec3b * p;
    for (int i = 0; i < rows; i++){

        int row = (i / sx + 0.5);
        if (row >= src.rows)
            row--;
        Vec3b *origin = src.ptr<Vec3b>(row);
        p = dst.ptr<Vec3b>(i);
        for (int j = 0; j < cols; j++){
            int col = (j / sy + 0.5);
            if (col >= src.cols)
                col--;
            p[j] = origin[col];
        }
    }
}

图像的旋转

设顺时针旋转\(\theta\) 角后对应点为\(P(x,y)\)

\[
\begin{cases}
x_0 = rcos\alpha \y_0 = rsin\alpha
\end{cases}
\]

\[
\begin{cases}
x = rcos(\alpha - \theta) = rcos\alpha cos \theta + rsin\alpha sin \theta = x_0cos\theta + y_0sin\theta \y = rsin(\alpha - \theta) = rsin\alpha cos \theta - r cos \alpha sin \theta = -x_0sin\theta + y_0cos\theta
\end{cases}
\\Downarrow
\\begin{cases}
x = x_0cos\theta + y_0sin\theta \y = -x_0sin\theta + y_0cos\theta
\end{cases}
\]

矩阵变换:

\[
\begin{bmatrix}
x&y&1
\end{bmatrix}
=
\begin{bmatrix}
x_0&y_0&1
\end{bmatrix}
\begin{bmatrix}
cos\theta & -sin\theta & 0\sin\theta & cos\theta & 0\0 & 0 & 1
\end{bmatrix}
\]

其逆运算矩阵为

\[
\begin{bmatrix}
x_0&y_0&1
\end{bmatrix}
=
\begin{bmatrix}
x&y&1
\end{bmatrix}
\begin{bmatrix}
cos\theta & sin\theta & 0\-sin\theta & cos\theta & 0\0 & 0 & 1
\end{bmatrix}
\]

以上是以旋转中心为原点的坐标系下,坐标的变换,在实际图像中,我们一般是以某个点作为旋转中心来进行旋转的,而原图的坐标系是以左上角为坐标原点的,所以我们要通过转换坐标系来将坐标调整到以旋转中心为原点的坐标系中

假设在原坐标系下坐标为\((x',y')\) ,在旋转坐标系下坐标为\((x,y)\),旋转中心在原坐标系下为\((a_0,b_0)\)

\[
\begin{cases}
x = x' - a_0\y = -y' + b_0
\end{cases}
\]

矩阵变换:

\[
\begin{bmatrix}
x&y&1
\end{bmatrix}
=
\begin{bmatrix}
x'&y'&1
\end{bmatrix}
\begin{bmatrix}
1&0&0\0&-1&0\-a_0&b_0&1
\end{bmatrix}
\]

其逆变换:

\[
\begin{bmatrix}
x‘&y’&1
\end{bmatrix}
=
\begin{bmatrix}
x&y&1
\end{bmatrix}
\begin{bmatrix}
1&0&0\0&-1&0\a_0&b_0&1
\end{bmatrix}
\]

现在求P在原坐标系旋转前坐标\((x_0,y_0)\)和旋转后坐标\((x,y)\)的关系。其中\((c,d)\)为旋转后的坐标中心,\((a,b)\)为在原坐标系中的旋转中心

\[
\begin{bmatrix}
x&y&1
\end{bmatrix}
=
\begin{bmatrix}
x_0&y_0&1
\end{bmatrix}
\begin{bmatrix}
1&0&0\0&-1&0\-a&b&1
\end{bmatrix}
\begin{bmatrix}
cos\theta & -sin\theta & 0\sin\theta & cos\theta & 0\0 & 0 & 1
\end{bmatrix}
\begin{bmatrix}
1&0&0\0&-1&0\c&d&1
\end{bmatrix}
\]

\[
\Downarrow
\]

\[
\begin{bmatrix}
x&y&1
\end{bmatrix}
=
\begin{bmatrix}
x_0&y_0&1
\end{bmatrix}
\begin{bmatrix}
cos\theta & sin\theta &0\-sin\theta & cos\theta & 0\-a~cos\theta + b~sin\theta + c & -a~sin\theta - b~cos\theta + d & 1
\end{bmatrix}
\]

\[
\Downarrow
\]

\[
\begin{bmatrix}
x_0&y_0&1
\end{bmatrix}
=
\begin{bmatrix}
x&y&1
\end{bmatrix}
\begin{bmatrix}
cos\theta & -sin\theta &0\sin\theta & cos\theta & 0\-c~cos\theta - d~sin\theta + a & -c~sin\theta - d~cos\theta + b & 1
\end{bmatrix}
\]

接下来的问题是,如何确定旋转之后的坐标中心?
很容易想到,图像旋转之后,图像的大小会变(如果要显示完整图像),而旋转中心是始终在中心的,所以我们可以通过计算四个角旋转后的坐标,确定旋转之后的图片大小,进而确定旋转之后的坐标中心(左上角)

已知旋转前的旋转中心坐标:

\[
a = {width-1\over 2}\~\b = {height-1\over 2}
\]

通过上面的旋转坐标计算,我们很容易的可以求出来四个角旋转之后的坐标,分别是:\((x1',y1'),(x2',y2'),(x3',y3'),(x4',y4')\)。则旋转后图像宽度和高度为:

\[
width' = max(|x1'-x3'|,|x2'-x4'|)\height' = max(|y1'-y3'|,|y2'-y4'|)
\]

请读者想一下这里为什么这么计算宽度和高度?

进而可以得知旋转之后的坐标中心

\[
c = {width'-1\over 2}\~\d = {height'-1\over 2}
\]

//该函数是将point顺时针旋转 angle
Point2d coordinates(Point2d point, double angle){
    const double cosAng = cos(angle);
    const double sinAng = sin(angle);
    int x = point.x;
    int y = point.y;
    int x1 = x * cosAng + y * sinAng;
    int y1 = -x * sinAng + y * cosAng;
    Point2d res = Point2d(x1, y1);
    return res;
}

//旋转主体函数
void rotate(Mat& src, Mat& dst, Point2d center, double angle){
    const double cosAng = cos(angle);
    const double sinAng = sin(angle);
       //请留意这里的坐标运算
    Point2d leftTop(-center.x, center.y); //(0,0)
    Point2d rightTop(src.cols - center.x, center.y); // (width,0)
    Point2d leftBottom(-center.x, -src.rows + center.y); //(0,height)
    Point2d rightBottom(src.cols - center.x, -src.rows + center.y); // (width,height)

    //以center为中心旋转后四个角的坐标
    Point2d transLeftTop, transRightTop, transLeftBottom, transRightBottom;
    transLeftTop = coordinates(leftTop, angle);
    transRightTop = coordinates(rightTop, angle);
    transLeftBottom = coordinates(leftBottom, angle);
    transRightBottom = coordinates(rightBottom, angle);

    double left = min({ transLeftTop.x, transRightTop.x, transLeftBottom.x, transRightBottom.x });
    double right = max({ transLeftTop.x, transRightTop.x, transLeftBottom.x, transRightBottom.x });
    double top = max({ transLeftTop.y, transRightTop.y, transLeftBottom.y, transRightBottom.y });
    double down = min({ transLeftTop.y, transRightTop.y, transLeftBottom.y, transRightBottom.y });

    //得到新图像的宽度和高度
    int width = (fabs(left - right) + 0.5);
    int height = (fabs(top - down) + 0.5);

    dst.create(width, height, src.type());

       //num1与num2是为了方便矩阵运算(因为每次计算都有这两个值)
    const double num1 = -abs(left) * cosAng - abs(top) * sinAng + center.x;
    const double num2 = abs(left) * sinAng - abs(top) * cosAng + center.y;

    Vec3b *p;
    for (int i = 0; i < height; i++)
    {
        p = dst.ptr<Vec3b>(i);
        for (int j = 0; j < width; j++)
        {
            int x = static_cast<int>(j  * cosAng + i * sinAng + num1 + 0.5);
            int y = static_cast<int>(-j * sinAng + i * cosAng + num2 + 0.5);
            if (x >= 0 && y >= 0 && x < src.cols && y < src.rows)
                p[j] = src.ptr<Vec3b>(y)[x];
        }
    }
}

图像的错切

错切之后

x方向的错切

\[
\begin{cases}
x'=x+d_xy\y'=y
\end{cases}
\]

y方向的错切

\[
\begin{cases}
x'=x\y'=y + d_yx
\end{cases}
\]

初次总结,还有很多的不足,请各位看客多多包涵,小生会更加努力学习!

原文地址:https://www.cnblogs.com/1625--H/p/11594946.html

时间: 2024-10-10 20:59:18

数字图像处理——图像的几何变换的相关文章

数字图像处理学习笔记之一 DIP绪论与MATLAB基础

写在前面的话 数字图像处理系列的学习笔记是作者结合上海大学计算机学院<数字图像处理>课程的学习所做的笔记,使用参考书籍为<冈萨雷斯数字图像处理(第二版)(MATLAB版)>,同时学习过程中会参考网络学习资源.对于数字图像处理的学习不可能仅仅依靠作者所写的这一系列笔记,而是需要花时间和精力学习,本文只可作参考和交流之用.由于涉及此学科不久,在学习过程中难免存在错误,请读者不吝赐教. 数字图像处理绪论 数字图像处理(DIP)的研究目标和处理对象: DIP的研究目标是获取信息,处理对象是

数字图像处理 第三版 第一章笔记

1. 数字图像和数字图像处理 图像可定义为一个函数,其自变量是坐标,因变量是灰度值. 当自变量和因变量全是离散值时,则称该图像是数字图像. 数字图像由有限数量的元素组成,这些元素成为像素,每个像素都有特定的位置和灰度值. 数字图像处理是指借助数字计算机来处理数字图像. 从图像处理到计算机视觉是一个连续的统一体. 典型地,将统一体分为三种计算处理,即初级.中级和高级. (1)低级处理涉及初级操作,如降噪.增强.锐化.输入输出都是图像. (2)中级处理涉及诸多任务,如分割.分类和识别等.输入为图像,

【数字图像处理】六.MFC空间几何变换之图像平移、镜像、旋转、缩放详解

本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行讲解,主要通过MFC单文档视图实现显示BMP图片空间几何变换,包括图像平移.图形旋转.图像反转倒置镜像和图像缩放的知识.同时文章比较详细基础,没有采用GDI+获取矩阵,而是通过读取BMP图片信息头和矩阵像素实现变换,希望该篇文章对你有所帮助,尤其是初学者和学习图像处理的学生. [数字图像处理]一.MFC详解显示BMP格式图片 [数字图像处理]二.MFC单文档分割窗口显示图片 [数字图像处

【数字图像处理】七.MFC图像增强之图像普通平滑、高斯平滑、Laplacian、Sobel、Prewitt锐化详解

本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行讲解,主要通过MFC单文档视图实现显示BMP图像增强处理,包括图像普通平滑.高斯平滑.不同算子的图像锐化知识.希望该篇文章对你有所帮助,尤其是初学者和学习图像处理的学生. [数字图像处理]一.MFC详解显示BMP格式图片 [数字图像处理]二.MFC单文档分割窗口显示图片 [数字图像处理]三.MFC实现图像灰度.采样和量化功能详解 [数字图像处理]四.MFC对话框绘制灰度直方图 [数字图像

数字图像处理 CImage类的使用与封装(jpg png gif tif bmp等格式图像的加载、数据读写、保存等功能)

引入CImage类的原因 原有的CBitmap 类只能处理BMP格式的图片,非常受限.而CImage可以处理JPGE.GIF.BMP.PNG等多种格式图片,扩展了图片处理功能且能与CBitmap 进行转换( 因为所载入的位图句柄都是HBITMAP,所以可相互转换),因此引入CImage类进行图像处理. CImage类简介 CImage是MFC和ATL共享的新类,它能从外部磁盘中调入一个JPEG.GIF.BMP和PNG格式的图像文件加以显示,而且这些文件格式可以相互转换. CImage提供增强型的

【数字图像处理】五.MFC图像点运算之灰度线性变化、灰度非线性变化、阈值化和均衡化处理具体解释

本文主要讲述基于VC++6.0 MFC图像处理的应用知识,主要结合自己大三所学课程<数字图像处理>及课件进行解说.主要通过MFC单文档视图实现显示BMP图片点运算处理.包含图像灰度线性变换.灰度非线性变换.图像阈值化处理.图像均衡化处理等知识,并结合前一篇论文灰度直方图进行展示 .同一时候文章比較具体基础,希望该篇文章对你有所帮助,尤其是刚開始学习的人和学习图像处理的学生. [数字图像处理]一.MFC具体解释显示BMP格式图片 [数字图像处理]二.MFC单文档切割窗体显示图片 [数字图像处理]

数字图像处理之python篇四:图像中的像素访问

前面的一些例子中,我们都是利用Image.open()来打开一幅图像,然后直接对这个PIL对象进行操作.如果只是简单的操作还可以,但是如果操作稍微复杂一些,就比较吃力了.因此,通常我们加载完图片后,都是把图片转换成矩阵来进行更加复杂的操作. python中利用numpy库和scipy库来进行各种数据操作和科学计算.我们可以通过pip来直接安装这两个库 pip install numpy pip install scipy 以后,只要是在python中进行数字图像处理,我们都需要导入这些包: fr

【数字图像处理之(二)】图像的分类

在计算机中,按照颜色和灰度的多少可以将图像分为灰度图像.二值图像.索引图像和RGB图像四种基本类型.在计算机中,通常是以数组(或矩阵)的形式储存图像的. 灰度图像: 灰度图像矩阵元素的取值范围通常为[0,255].因此其数据类型一般为8位无符号整数的[uint8],这就是人们经常提到的256灰度图像."0"表示纯黑色,"255"表示纯白色,中间的数字从小到大表示由黑到白的过渡色. 然而,在某些领域(例如医学成像),要求提供超出[uint8]的动态范围:会采用[uin

数字图像处理_图像二值化_jzcjedu

皮卡丘:“师兄! ” 师兄:“干嘛…?” 皮卡丘:“你帮我看看这个,这是我打车的发票,看起来有点不太清晰,老板说不给我报销…” 师兄:“你仿佛在特意逗我笑,这不是很清楚嘛!!! ” 皮卡丘:“我老板有强迫症,他说这个扫描之后不清楚,让我弄清晰点再给他,不然就不给我钱.师兄,你一定要帮我呀,不然以后都不能打车了.” 师兄:“不急,我先看看,我记得当初张康老师教过我对于这种信噪比很高的图像你要提取出想要的信息的话用二值化处理又简单又方便.“ 皮卡丘:“这样啊,快弄给我看看.“ 稍等,我开一下MATL