| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2574 人关注过本帖
标题:[讨论]给大家出一个算法方面的问题
取消只看楼主 加入收藏
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
结帖率:95.65%
收藏
 问题点数:0 回复次数:8 
[讨论]给大家出一个算法方面的问题
简单的说,就是,图像的旋转问题,要求能做到90度的旋转,并且要求对内存的占用最小。更加精确的描述如下:
1. 对原始图像IMAGE,其宽度分别为w和h,其图像数据存放在pdata所指向的缓冲区中,以一维的形式按行顺序存放,可以用一个三元组来描述这个图像 IMAGE(w, h, pdata);
2. 要求对IMAGE进行顺时针90度旋转的操作,并且使用最少的内存

这个问题提出的背景是,在一款数码产品上,可用内存只有20MB,当显示2000x2000x24bit的位图的时候,就会占用12MB左右的内存,如果使用常规的图片旋转算法,即另外创建一个同样大小但宽高相反的位图,然后计算旋转后的像素点到新的位图中。这样就会出现内存不足而无法旋转的问题。
传统的算法在理解和实现上都非常容易,但是要求申请与原位图同样大小的缓冲区,导致在空间上的开销太大。

大家不要小看这个问题,我仔细思考过,要在这个问题上节省空间真的很难。从理论上讲,这个问题是有解的,而且可以完全做到不申请任何额外的内存空间,即只对原始图像的pdata所指向的缓冲区进行操作,但是要写成通用性的代码的话,我现在都还没有想到一个好的算法。关键是要保证操作过程中图像数据不会因为被新的图像数据覆盖而丢失掉。并且还要保证旋转后的图像数据也是按行顺序存放。
想了半天,感觉如果不借助大量额外的缓冲区,这个问题似乎无解。
大家一起讨论下,帮忙想想办法。
我刚开始想到一个办法就是对矩阵做一次转置处理,然后再做一次水平翻转就可以了,但是这个算法只适用于宽高相等的位图。对于宽高不等的图像,要考虑更多的问题。
搜索更多相关主题的帖子: 内存 算法 三元 数码 图像 
2007-08-08 21:10
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
收藏
得分:0 
举个例子:
原始图像
a b c d
e f g h
i j k l
int w = 4;
int h - 3;
BYTE pdata[] = { a, b, c, d, e, f, g, h, i, j, k, l };

旋转后的图像
i e a
j f b
k g c
l h d
int w = 3;
int h = 4;
BYTE pdata[] = { i, e, a, j, f, b, k, g, c, l, h, d };

2007-08-08 21:25
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
收藏
得分:0 

实现如下的函数
void RotBitmap(BYTE *pdata, int *w, int *h);
要求空间上的开销尽量小。

2007-08-08 21:28
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
收藏
得分:0 
这个跟图像处理关系不大,主要是看如果移动pdata中的元素。
2007-08-08 21:31
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
收藏
得分:0 
Jig能否精确的刻画一下你的算法。
2007-08-08 22:49
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
收藏
得分:0 
Jig的算法时间复杂度还是有点高,而且这里要求处理的数据量很大。2440的主频为400MHz,如果使用传统算法,在旋转1000x1000大小的图片就需要2s左右的时间。如果采用Jig的算法,在处理更大的图片时,则会需要更多的时间,恐怕给用户的感觉就是像死机一样了。
还来我想了,用临时文件来存放大量的数据,临时文件将会保存到SD卡上,这样文件的长度可以说是不受限制。旋转时,先把结果数据写到临时文件,然后再从临时文件读回数据。想来似乎可行,后来试验了一下,发现SD卡的读写速度跟不上,目前SD卡的读写速度能到达1MB/s(这个已经是我经过许多优化才取得的成果),这样算下来,旋转一个图片消耗在文件读写上的时间就需要20s以上,这是无法接受的。
2007-08-10 19:20
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
收藏
得分:0 
到目前为止,还是没有找到更好的旋转算法。这个算法对时间和空间的要求都比较高。
2007-08-10 19:21
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
收藏
得分:0 
不过这个问题到后面有了新的解决办法。
其实项目需要完成的是一个图片浏览器,能够支持 JPEG 和 BMP 图片的浏览。BMP 的显示可以借助 WinCE API 来实现,JPEG 图片的解码则选用了 Independent JPEG Group 的一个 JPEG Codec。数码产品的 LCD 屏只有 480x272 大小。浏览器中,提供了图片原始大小、图片缩放、旋转等功能,在图片不能完全显示时,给出水平滚动条和垂直滚动条供用户拖动。在调用 JPEG 解码库时,根据图片的原始大小创建了一个位图对象,然后将 JPEG 图片解码到这个位图对象中。因此对于大尺寸的 JPEG 图片,就需要占用很大的内存。然而,实际的 LCD 只有 480x272 大小。因此,我们打算,在 JPEG 解码的时候,就对尺寸的图片进行缩放,缩放到合适的尺寸,使其既能保证内存足够,又能保证显示效果。因为在浏览大尺寸图片时,其实图片都要经过缩放处理(都是缩小),因此,对于大尺寸的图片在解码时就进行缩放处理,几乎不过影响用户浏览图片的效果,只会在图片原始大小,或者放大时,会有图片质量上的损失。
根据这个思路,我们将图片浏览器可用的内存空间定为8MB,其中4MB用于位图的存放,另外4MB则是用于旋转等处理的临时缓冲区。在遇到大图片时,先判断其所需要的内存是否大于4MB,如果是,就在解码时进行缩放处理。然后,剩下的问题就已经不是问题了。
也不必去研究前面的算法如何实现。当然,工程上的实现往往都是这样,尽量避开技术难点,采用最直接、最简单的办法解决问题。
然而,如果是单纯将这个问题当作算法来研究的话,我认为还是有价值的。我也会继续思考这个问题的解决办法。大家也帮忙想想。
2007-08-10 19:49
RockCarry
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:13
帖 子:662
专家分:58
注 册:2005-8-5
收藏
得分:0 
大概懂了 hjj1123 的算法原理。即找一个起始点,计算出其旋转以后的坐标,根据这个坐标,计算出旋转后在数组中的实际偏移地址,然后将这个地址上的元素与起始点的元素进行交换。然后再对起始点进行处理,此时起始点保存的数据实际上是前面交换过来的数据,这个数据在原始图像中的坐标也可以算出来,然后来根据这个坐标计算出旋转以后的坐标,然后再如此重复。
2007-08-11 13:56
快速回复:[讨论]给大家出一个算法方面的问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017398 second(s), 8 queries.
Copyright©2004-2025, BCCN.NET, All Rights Reserved