数字图像处理(十五)图像旋转

数字图像处理(十五)图像旋转数字图像处理 图像旋转 图像旋转公式

大家好,欢迎来到IT知识分享网。


前言

  图像的旋转是指以图像中的某一点为原点以逆时针或者顺时针方向旋转一定的角度。通常是绕图像的起始点以逆时针进行旋转。


一、图像旋转算法

1.算法原理

  图像旋转计算公式如下: i ′ = i cos ⁡ θ − j sin ⁡ θ i’=i\cos\theta-j\sin \theta i=icosθjsinθ j ′ = i sin ⁡ θ + j cos ⁡ θ j’=i\sin\theta+j\cos\theta j=isinθ+jcosθ
其中, ( i , j ) (i,j) (i,j)是原图像 f ( i , j ) f(i,j) f(i,j)中的像素点坐标; ( i ′ , j ′ ) (i’,j’) (i,j)是对应像素点 ( i , j ) (i,j) (i,j)经过旋转变换后的图像 g ( i ′ , j ′ ) g(i’,j’) g(i,j)的坐标。

上面的这个公式是图像绕某一点O逆时针旋转 θ \theta θ度后的坐标。下面从数学角度推理下这个公式是如何来的。
在这里插入图片描述
原坐标点距离旋转中心的长度为 R R R,与 x x x轴的夹角记为 α \alpha α,逆时针旋转的角度为 θ \theta θ,旋转后得到的新的坐标点为 ( i ′ , j ′ ) (i’,j’) (i,j)
则可知
i = R cos ⁡ α j = R sin ⁡ α i = R\cos \alpha \\ j = R \sin \alpha i=Rcosαj=Rsinα
记为式(一)。
同时
i ′ = R cos ⁡ ( α + θ ) j ′ = R sin ⁡ ( α + θ ) i’=R\cos(\alpha+\theta) \\ j’=R\sin(\alpha+\theta) i=Rcos(α+θ)j=Rsin(α+θ)
记为式(二)。
由三角公式可得:
cos ⁡ ( α + θ ) = cos ⁡ α cos ⁡ θ − sin ⁡ α sin ⁡ θ sin ⁡ ( α + θ ) = sin ⁡ α cos ⁡ θ + cos ⁡ α sin ⁡ θ \cos(\alpha+\theta) = \cos\alpha \cos \theta – \sin \alpha \sin \theta \\ \sin(\alpha + \theta) = \sin \alpha \cos \theta + \cos \alpha \sin \theta cos(α+θ)=cosαcosθsinαsinθsin(α+θ)=sinαcosθ+cosαsinθ
记为式(三)。将式(一)与式(三)同时带入式(二)便可得到:
i ′ = i cos ⁡ θ − j sin ⁡ θ j ′ = i sin ⁡ θ + j cos ⁡ θ i’=i\cos\theta-j\sin \theta \\ j’=i\sin\theta+j\cos\theta i=icosθjsinθj=isinθ+jcosθ
如上便是逆时针旋转时的数学推理过程。












2. 一些需要注意的点

  1. 旋转只改变图像中像素的位置,不改变像素的值;
  2. 因为图像的坐标值只能是正整数,所以根据上式计算出的新的坐标位置还需要进行处理;
  3. 因为旋转后的图像中间会出现空白点,所以要插值法对空白点进行插值。常用的插值方法有邻近插值法,均值插值法;
  4. 因为旋转后图像的画布大小会发生变化,所以我们还要提前计算新图的画图大小。

3.举例

设原图为 f = [ f 11 f 12 f 13 f 21 f 22 f 23 f 31 f 32 f 33 ] f = \begin{bmatrix} f_{11} & f_{12} & f_{13}\\ f_{21} & f_{22} & f_{23}\\ f_{31} & f_{32} & f_{33}\\ \end{bmatrix} f=
f11f21f31f12f22f32f13f23f33

i i i构成的矩阵为: i = [ 1 1 1 2 2 2 3 3 3 ] i= \begin{bmatrix} 1 & 1 & 1\\ 2 & 2 & 2\\ 3 & 3 &3\\ \end{bmatrix} i=
123123123

j j j构成的矩阵为: j = [ 1 2 3 1 2 3 1 2 3 ] j= \begin{bmatrix} 1 & 2 & 3\\ 1 & 2 & 3\\ 1 & 2 & 3\\ \end{bmatrix} j=
111222333

假设此时要逆时针旋转30度,则根据上面的公式计算 i ′ i’ i j ′ j’ j
i ′ = i cos ⁡ 30 ° − j sin ⁡ 30 ° i’=i\cos30\degree-j\sin 30\degree i=icos30°jsin30° j ′ = i sin ⁡ 30 ° + j cos ⁡ 30 ° j’=i\sin30\degree+j\cos30\degree j=isin30°+jcos30°
如果要顺时针旋转30度,加个负号就可以了。
计算出的 i ′ i’ i构成的矩阵为:
i ′ = [ 0.4 − 0.1 − 0.6 1.2 0.7 0.2 2.1 1.6 1.1 ] i’= \begin{bmatrix} 0.4& -0.1 & -0.6\\ 1.2 & 0.7 & 0.2\\ 2.1 & 1.6 &1.1\\ \end{bmatrix} i=
0.41.22.10.10.71.60.60.21.1

此时我们可以看到 i ′ i’ i中出现了负数和小数,这在我们编程中是行不通的,所以我们将 i ′ i’ i这个矩阵先进行四舍五入。
i ′ = i ′ − min ⁡ ( i ′ ) = i ′ − ( − 0.6 ) = [ 0 0 − 1 1 1 0 2 2 1 ] i’=i’-\min(i’)=i’-(-0.6)=\begin{bmatrix} 0 & 0 & -1 \\ 1 & 1 & 0\\ 2 & 2 &1 \\ \end{bmatrix} i=imin(i)=i(0.6)=
012012101

又因为坐标没有负数,所以我们将 i ′ i’ i中的每个元素加上2变成正整数得
i ′ = [ 2 2 1 3 3 2 4 4 3 ] i’= \begin{bmatrix} 2& 2 & 1\\ 3 & 3 & 2\\ 4 &4 &3\\ \end{bmatrix} i=
234234123

同理可得 j ′ = [ 1 2 3 2 3 4 2 3 4 ] j’= \begin{bmatrix} 1 & 2 & 3 \\ 2 & 3 & 4 \\ 2 & 3 &4 \\ \end{bmatrix} j=
122233344












4. 均值插值法

二、编程实现

1.C++代码

int main() { 
      cv::Mat img = cv::imread("Lena.bmp"); cv::Mat gray_img(img.cols,img.rows, CV_8UC1); cv::cvtColor(img, gray_img, CV_BGR2GRAY); float theta =45; float curvature = theta / 180 * CV_PI; cv::Mat x = cv::Mat::zeros(img.size(), CV_32FC1); cv::Mat y = cv::Mat::zeros(img.size(), CV_32FC1); for (int row = 0; row < img.rows; row++) { 
      for (int col = 0; col < img.cols; col++) { 
      // 计算新的坐标 x.at<float>(row, col) = round(row * cos(curvature) - col * sin(curvature)); y.at<float>(row, col) = round(row * sin(curvature) + col * cos(curvature)); } } double x_min, x_max; double y_min, y_max; cv::minMaxLoc(x, &x_min, &x_max); cv::minMaxLoc(y, &y_min, &y_max); x = x - x_min; y = y - y_min; cv::minMaxLoc(x, &x_min, &x_max); // 画布的高 cv::minMaxLoc(y, &y_min, &y_max); // 画布的宽 cv::Mat dst = cv::Mat::zeros(x_max+1, y_max+1, CV_8UC1); //幕布 cv::Mat flag = cv::Mat::zeros(x_max + 1, y_max + 1, CV_8UC1); for (int row = 0; row < gray_img.rows; row++) { 
      for (int col = 0; col < gray_img.cols; col++) { 
      int i = (int)x.at<float>(row, col); int j = (int)y.at<float>(row, col); dst.at<uchar>(i, j) = gray_img.at<uchar>(row, col); flag.at<uchar>(i, j) = 1; } } //均值插值法对空穴进行插值 for (int row = 1; row < dst.rows-1; row++) { 
      for (int col = 1; col < dst.cols-1; col++) { 
      if (flag.at<uchar>(row, col - 1) == 1 && flag.at<uchar>(row, col + 1) == 1 && flag.at<uchar>(row - 1, col) == 1 && flag.at<uchar>(row + 1, col) == 1 && flag.at<uchar>(row, col) == 0) { 
      dst.at<uchar>(row, col) = uchar((dst.at<uchar>(row, col - 1) + dst.at<uchar>(row, col + 1) + dst.at<uchar>(row - 1, col) + dst.at<uchar>(row + 1, col)) / 4); } } } cv::imshow("input", gray_img); cv::imshow("output", dst); cv::waitKey(0); return 0; } 

2.实验结果

在这里插入图片描述


参考资料

1.数字图像处理基础.朱虹.

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/126854.html

(0)
上一篇 2025-09-15 16:20
下一篇 2025-09-15 16:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信