zoukankan      html  css  js  c++  java
  • 图片旋转操作的分析及实现

    1. 目的

    把一副图片顺时针旋转任意角度θ。

    2. 分析

    假设有如下(w*h)大小的图片,用黑色坐标系标注,原图在该坐标系下的各点也用黑色标识。

    在数字图像处理中,一副图片默认的原点是左上角的端点,例如原图中的O点。如果用该点为对称点进行旋转,则在旋转角度过大的情形下,会使旋转后的图片大部分甚至全部都落在当前区域之外,由此造成区域的重新计算,以及映射坐标的重新计算。例如,如果将原图以O作为对称点进行顺时针旋转90度,则整个图片已经全部处于当前区域之外,当然,可以通过三角计算得出各顶点的坐标,但是为了得到最终的结果,还是要进行坐标平移,平移之后还要进行新顶点坐标的计算,不过并不能说明不可行,只是步骤不够简洁。为了避免过于复杂的区域和映射坐标的计算,将图片的对称中心移至O’(h/2,w/2)处,以该点作为对称中心进行图片旋转,无论以多大角度进行操作,四个顶点坐标仍然大致处于一个“可控”范围内。

    图1. 坐标系变换

    假设有点P(a,b)在旧坐标系下,把其坐标变换到新坐标系下的P(x,y),在此假设下,x表示该点所在的高度,y表示该点所在的宽度,变换公式为(1)。

       (1)

    假设在新坐标系下有点P(x,y),如图2所示。

    图2. 直角坐标系下的某点P(x,y)

    则该点在极坐标下的坐标为公式(2)。

       (2)

    如果把该点沿顺时针旋转θ度,则可以得到P’(x’,y’)为公式(3)。

       (3)

    改写为矩阵乘法的形式,得到公式(4)。

       (4)

    那么在新坐标系下,原图的左上P1(-h/2,-w/2),右上P2(-h/2,w/2),左下P3(h/2,-w/2),右下P4(h/2,w/2)沿顺时针旋转θ角度后的新点分别假设为P1’(x1,y2),P2’(x2,y2),P3’(x3,y3)和P4’(x4,y4)。

    由上面的坐标变换公式(4)可以得到四个新点的坐标分别为公式(5)-(8)。

       (5)

       (6)

       (7)

       (8)

    把到现在为止的步骤都叠加在一张图片中,得到图3。

    图3. 旋转前图为黑色,旋转后为黄色

    根据图中旋转后的图形区域,可以得到旋转后图形的外接矩形的宽w’和高h’为公式(9)。

       (9)

    最后推导原直角坐标系下的点P(a,b)和平移旋转后的最终位置点P’(x’,y’)之间坐标值的数量关系,根据(1)和(4),可以得到以下关系为公式(10)。

       (10)

    (10)简化可以得到公式(11)。

       (11)

    公式(11)是一个从原图映射到旋转后的最终结果图的数量关系。

    直接使用公式(11)就可以进行图像旋转的操作,不过同时也可以看出这里有一个问题,因为图像的坐标都是整型,而上面的公式中有浮点操作,当然即使没有浮点操作也会有这个问题,所以无法保证用原图的坐标在运算后覆盖所有新图中的坐标,所以在这种映射关系下,会造成结果图像内容中出现很多背景色的槽点。

    为了解决公式(11)造成的槽点问题,需要把映射关系换一下,也就是将新图中的坐标映射到旋转前的旧图中,但是这样也会有问题,原因也是浮点操作取整的结果,也就是映射后的点可能对应旧图中的几个点,采用权重的办法取最合适的点解决这个问题。公式(12)就是从新图中的坐标映射到旧图的推导关系。

       (12)

    3. 实验效果图

    图4是旋转操作前的原图。

    图4. 旋转前的图片

    图5是使用公式(11)进行旋转操作后的图,放大后可以看到图片区域中有许多背景颜色的槽点。

    图5. 使用公式(11)顺时针旋转65度的图

    图6是使用公式(12)进行旋转操作后的图片,可以看到整体效果比图5好了很多。

    图6. 使用公式(12)顺时针旋转65度的图

    4. 总结

    总体来说,图像的操作其实都是数学和计算机的结合,物理偶尔会出现一下,公式的推导还是需要一点细心的,多使用矩阵乘法的形式来表示方程组可以使得公式看起来更加直观。

    使用公式(11)进行操作的代码可以参考GitHub

    使用公式(12)进行操作的代码可以参考GitHub

  • 相关阅读:
    懒加载
    通过Xib自定义控件
    自定义控件
    swiper_banner图的封装
    uni-app中封装的search和scroll-view
    使用git从创建仓库或项目到push到远程并创建分支常用命令
    随手封装一个简单的日期组件(基于ele-ui的基础上)
    封装的一个时间条插件
    websocket的封装2
    websocket的封装1(做vue中的通信经常也是大概率用到的)
  • 原文地址:https://www.cnblogs.com/flyingpeguin/p/3561512.html
Copyright © 2011-2022 走看看