自己动手,丰衣足食——一个简单却高效的图像旋转算法

原创 2006年06月24日 16:46:00
    这几天开始接触一个摄像头驱动程序,碰到了一个棘手的问题——就是摄像头出来的图像数据和LCD屏幕的分辨率倒是一致,但是宽和高刚好颠倒。比如,摄像头支持QVGA的分辨率,也就是得到的图像大小为320×240。LCD也刚好是QVGA的分辨率,不过它的尺寸为240×320。摄像头的数据必须旋转90度,才能正好放到LCD里面。旋转90度?那不是屏幕上显示的数据就是颠倒了的吗?呵呵,处理这个问题很简单,安装镜头的时候对应转一下就可以了,这样可以保证旋转了的数据刚好和取景的方向一致。不过,由于摄像头总线出来的数据必定是320个像素一行,此摄像头没有办法进行硬件变换,让出来的数据变成240个像素一行,这个转换就必须借助软件来完成了!
    用软件旋转有很多种做法,不管用什么做法,一定要保证效率很高,这样才有实用性。因为这个旋转实际上是为摄像头取景预览准备的,预览时的数据每秒15帧,数据流量还是比较大的,如果整个算法比较慢,预览本身就要耗费掉大量的CPU时间,势必影响CPU做其他同样重要的事情。而且,整个开发都是针对ARM进行的,在嵌入式平台上,每一点CPU资源,都要充分节省。我的朋友在之前用过两种算法,一种是直接像素拷贝,比如把坐标(a,b)的像素点拷贝到(b,a)处,一个双重循环下来,整个屏幕的内容都旋转了一遍。但是这样做一遍要100多个毫秒,想一想,每秒需要15帧的预览图像,这个值只能让系统显示几帧图像,且CPU也耗费了100%!由于是在INTEL的平台上面开发,所以我们自然想到了用INTEL的IPP函数进行旋转。不过得到的结果也不让人满意,因为INTEL没有提供单独大图像旋转函数,提供的函数是一个复合功能函数,在能够进行旋转的同时,还包含了RESIZE(调整图像大小)的功能,想必没有为这种旋转操作进行单独的优化,所以转一幅图像也要100毫秒左右。太慢,太慢!要么用汇编写一个函数?又觉得维护起来挺麻烦,不便于以后的移植。先还是考虑一下用纯C能不能把这个问题搞定吧。
    顺便说一下,我们处理的图像数据是YCbCr数据,每个通道的数据单独处理,每个像素占用1个字节。在32位处理器上面,一次读写4个字节可能是最高效的。考虑到ARM上面读写内存是系统效率的一个瓶颈(在其他系统上面也是如此),所以我们又把对前面的算法进行了改进。IPP函数我们没有办法改,所以就只有在自己的土办法上进行加工。以前一次写入1个像素,也就是1个字节,这次我们先算出4个相邻像素的值,然后一次性写入。得到的测试结果让我们鼓舞,成绩大概为80毫秒一帧。80毫秒!快了一些,但是远远不能满足我们的要求。
    但是我的信心还是得到了很大的提高,对性能的追求让我泡了一杯咖啡,端端正正地坐在办公桌前面,开始了新的思考当中。既然一次可以写入4个字节,那么一次也可以读出4个字节!我又重新调整了代码,由于读和写的方向不一致(一个是沿像素多的那个方向,一个是沿像素少的那个方向),所以要兼顾两个方向的读写,代码写起来就稍微繁杂一些,必须把屏幕划成4×4的小矩形块处理,处理的时候用到了大量的局部变量以及移位操作,看起来代码有点乱。但是得到的结果令我们惊叹——每帧数据处理只要26毫秒!这个值已经非常快了,不仅仅可以每秒处理足够多的帧数,且能够让CPU腾出更多的时间来干别的事情。它比一个单纯的memcpy操作慢不了多少。爽哉!
    为什么减少了读内存操作的次数,比增加了写内存操作的次数,给系统性能的提升更多呢?也许是一次读4个字节,更利于流水线的处理吧!呵呵
    当然,如果摄像头硬件支持图像90度旋转,也就没有上面这些过程了。我也最希望有“硬办法”解决这个问题,让CPU能够充分解放出来。硬的不行就来软的吧,呵呵,至于采用什么算法,一定要根据具体的条件来选择最合适的,这不,自己动手,丰衣足食。
   

自己动手,丰衣足食!Python3网络爬虫实战案例

第一章:环境配置; [1 r2 i0 H. C# R9 x: R 1 Python3+Pip环境配置  22:10  1 e$ z, ~' y. p  E 购买后请及时添加课程助手tianshan...
  • qq_36653286
  • qq_36653286
  • 2017年10月19日 13:53
  • 1040

自己动手实现一个简单的Ajax

         尽管Ajax(Aysnchronous Javascript and XML)不是一种标准化的技术,也不是一个全新的理念,但它确实已经以很快的速度改变了Web的访问体验,提供了一种相...
  • dragonforfly
  • dragonforfly
  • 2011年01月08日 17:41
  • 512

自己动手实现一个简单c编译器

这学期的编译课程设计需要做一个类c编译器,准确的说是完善上学期做的大实验。 上学期的实验中,使用antlr完成的编译器识别的语法很有限,基本上是个计算器的语法,于是这次决定弄语法一个更加完整。 语...
  • u012773099
  • u012773099
  • 2015年11月28日 10:37
  • 1394

自己动手,丰衣足食。

国家主席在富人的陪同下,接见了来访的美国总统夫妇。关于这则消息,有个大叔问我...
  • prsniper
  • prsniper
  • 2014年05月17日 12:29
  • 720

自己动手,丰衣足食

自从考了中口之后,便不断有人询问各种问题,有一些经验型的问题,比如如何准备,应试技巧,也有一些让我很无奈的问题,比如在哪里考试,考试形式等等。有一段时间我俨然一个中级口译答疑解惑员,认识的不认识的,熟...
  • wauwa
  • wauwa
  • 2012年09月25日 21:37
  • 1634

自己实现一个简单版的HashMap

public class MyHashMap { //默认初始化大小 16 private static final int DEFAULT_INITIAL_CAPACI...
  • uhgagnu
  • uhgagnu
  • 2017年03月03日 18:41
  • 552

《自己动手设计数据库》第一部分摘录

《自己动手设计数据库》第一部分摘录,简略了很多内容,仅作为笔记使用
  • YQXLLWY
  • YQXLLWY
  • 2016年10月21日 15:56
  • 1066

自己动手丰衣足食之下拉列表

源代码: Document
  • cometwo
  • cometwo
  • 2016年02月21日 18:25
  • 388

自己动手丰衣足食之三级联动

省:
  • cometwo
  • cometwo
  • 2016年03月10日 12:51
  • 518

自己动手写个spring IOC容器

前言 自定义IOC容器的基本架构 架构图解 基本思路 IOC容器实现图解 IOC容器实现 创建一个java工程 导入 dom4jjar 和 jaxenjar 创建测试用的类 创建Application...
  • u010837612
  • u010837612
  • 2016年02月18日 15:40
  • 3134
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:自己动手,丰衣足食——一个简单却高效的图像旋转算法
举报原因:
原因补充:

(最多只允许输入30个字)