YUV420(NV21或NV12)图像任意角度旋转的推导

一、坐标旋转:

假设我要沿着图像M的中心旋转角度b,那么需要先将图像M的中心移动到与坐标轴中心重合(否则将导致图像M沿坐标轴原点旋转):

然后假设原坐标(x,y)距离坐标轴原点距离为r,与x轴夹角a度,需要绕原点旋转b度,那么可有如下推导:

设宽高分别为w,h

原坐标为:

x = r * cos(a)

y = r * sin(a)

新坐标为

x_new = r * cos(a+b) = r*cos(a)*cos(b) - r*sin(a)*sin(b)

=(x-w/2)*cos(b) - (y-h/2)*sin(b)

y_new = r * sin(a+b) = r*sin(a)*cos(b) + r*cos(a)*sin(b)

=(y-h/2)*cos(b) + (x-w/2)*sin(b)

至此即可通过以上规律求得原图像中每一个二维坐标,在旋转后对应的新坐标,然后在新坐标中赋值原来的颜色值,即可实现普通图像的任意角度旋转

  • 新容器面积

由于旋转后的图像边角会超出原有的图像边框,因此需要重算旋转后图像的容器大小。

从图像可知,

width_new = |cos(b)*w| + |sin(b)*h|

height_new = |cos(b)*h| + |sin(b)*w|

  • 边框偏移

由于转换后的图像坐标部分在负坐标轴,原因如图:

(深灰色为新容器,浅灰色为旧容器)

所以需要通过加上偏移值使得移出负坐标变正。

从图易知,x偏移值为(width_new - w) / 2,记为offsetX, y偏移值为(height_new - h) / 2,记为offsetY,旋转后得到的坐标加上偏移值即可在新容器中完整包裹。

  • 填充方式

通过三角函数算出第一行的起点和终点,通过Bresenham直线算法算出符合w长度的一系列直线坐标,再算出最后一行的起点,从而求得每行x的偏移距离ddx和y偏移距离ddy,每行的坐标值除了加上offsetX和offsetY外,加上偏移距离ddx*当前已遍历行数和ddy*当前遍历行数,即可把旧容器的数据逐行转移到新容器中

  • 空洞现象以及处理方式

由于计算机图像是由无数像素组成,并非真正的连续量,因此倾斜的线条不一定总是能咬合完美,就入下图的情况:

此时旋转后的画面将会呈现无数空洞,非常难看,一个简单的间接办法是把源数据两行同一个x值的数据,求平均后填充于容器的x-1位置上,从而得到补全空洞,得到更优质的图像:

  • YUV420的旋转处理

对比位图和灰度图,YUV420格式的特殊之处在于其分为两层,一层为Y层表达亮度,

一层为UV层,每两行两列共4个y享有一对UV,因此UV填充时,一定要以U开头V结尾为一个单位,否则将会产生严重的色差;对应的行号也因为UV层高只有Y层的一半而要除以2。也因为这个原因,在新容器的宽度和高度上,若求得得数为奇数,则必须+1,以免读写出错。

若要旋转YUV420格式的图像,需要把容器的一维数组长度从[width_new * height_new]提升到[width_new * height_new * 3 / 2]以扩充出UV层的容器。

填充数据时,设当前遍历旧容器时的行为y,列为x,判断当前new_x%2是否等于0,若不是则不进行下一步,是则再判断x%2运算是否为0,是则取值x,记为uvX,如果不是话则uvX取值x-1。在遍历过程中,求得在新容器中偏移值分别为

[width_new * height_new + y_new / 2 * width_new + x_new] 和

[width_new * height_new + y_new / 2 * width_new + x_new + 1]

并把容器中这两个单元的值分别赋为旧容器的[w * h + y / 2 * w + uvX]和[w * h + y / 2 * w + uvX + 1]的值(row为当前遍历到源数据的第几行),这样即可以2个单元为一组地把UV数据写到新容器中。空洞的处理办法和第五部分一样。

最后实现效果如下:

输入原图:

旋转28度:

旋转90度:

实现代码已放到GitHub上,如果有用欢迎Star:

https://github.com/cjzjolly/rotateNV21AnyAngle

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值