位图操作。获取DIB后对其数据进行操作实现旋转!!!!

dhiway   2009-11-19 15:44 楼主
总算找到组织了!!

我最近在学习EVC下的位图操作。要实现位图的快速旋转。看了很多网上资料,很多事对DC中的像素进行操作的,实现的过程都很慢很慢,项目部能接受。

后来看到一些人说对DIB进行操作很快的实现,于是就模仿了一下,比像素操作时快了不少,但是还是有两个地方特别费时,百思不得其解,特此求教。


我是这样做的:

在内存DC:memDC中绘制东西,一般就是图片等内容。最后通过pdc->bitblt(0,0,w,h,memdc,0,0,srccopy);把东西绘制到屏幕。

现在我要在其中加入旋转,于是我先建立一个DIB并获得memDc中的数据,我是这样实现的:

HBITMAP hbitmap = createDIBSection(memDC.getsafehdc(),&bi,DIB_RGB_COLOR, (void **)&pbuffer, null,0);

其中,bi是先定义好了的位图信息结构BITMAPINFO,pbuffer是位图数据的地址指针。

再定义一个dc,选入这张刚创建的位图,hbitmap;

selectobject(dc.getsafehdc(),hbitmap);

然后给这个位图添加内容:

bitblt(dc.getsafehdc(),0,0,600,600,memdc.getsafehdc(),0,0,srccopy); 这句语句消耗大量的时间!!!!!!!!

就这样我获得了DIB数据的指针,就可以对其进行旋转的相关操作了。
之后再把旋转后的dib画回memDC中。

问题就是之前的拷贝数据的时候以及后来把DIB画回的时候都需要很长很长的时间,相对我的旋转算法长很多!!
请问是什么原因??
如果我避开这一步的话?怎么获得位图的数据进行旋转的操作呢?
时间紧迫请大家帮忙了

回复评论 (21)

怎么没人呢??
做嵌入式的就那么少啊?
点赞  2009-11-19 17:08
用IMAGE组件的ROTATE函数好了.
点赞  2009-11-20 10:00
点赞  2009-11-20 10:32
IIMAGE组件的ROTATE估计也快不到哪里去.它还是需要一个很费时的操作把数据转到IImage的object里面去
点赞  2009-11-20 11:02
楼主,我深入做过这方面的研究,旋转效率非常高,但限制于90/180/270度旋转,这在做看图的时候足够了,但如果您想任意角度旋转,无论如何都不会效率高的,光是sin,cos运算,还有浮点运算,以现在wince400M的CPU我觉得还不足以完成这些事情.

实现方法为:
采用CreateDibSection可以得到位图的每个点的像素,你把这些像素的内存重新组织一下就可以了,如果楼主研究透了位图里面的数据是如何存放的,相信这个问题也就解开了
点赞  2009-11-21 23:34
引用: 引用 5 楼 wceui 的回复:
楼主,我深入做过这方面的研究,旋转效率非常高,但限制于90/180/270度旋转,这在做看图的时候足够了,但如果您想任意角度旋转,无论如何都不会效率高的,光是sin,cos运算,还有浮点运算,以现在wince400M的CPU我觉得还不足以完成这些事情.

实现方法为:
采用CreateDibSection可以得到位图的每个点的像素,你把这些像素的内存重新组织一下就可以了,如果楼主研究透了位图里面的数据是如何存放的,相信这个问题也就解开了


wceUI你好:
    90度等特殊角度的旋转我也研究过几个例子,由于其计算相对简单,所以速度都是还可以接受的。我也是迫不得已才,项目要求才去做这个任意角度旋转的,我也知道wince下资源的有限问题,但是只能尽量的优化了。而且我需要旋转的还是大图,要是700*500这样的就一秒左右能完成,还勉强能接受。但是我要做的是1000*1000多点的图,这样时间就快接近两秒了。
    我用的也是CreateDibSection方法,其实我追踪过,大部分时间并不是花在计算浮点数上以及旋转算法上,而是用CreateDibSection生成DIB后往里面写入数据的过程:
我用的是bitblt函数,把内存中的CBitmap拷贝到我的DIB中。这个过程花费很大的时间。我仔细查过,是因为DDB和DIB格式不一样,这个函数要转化其数据,不是简单的内存拷贝。
  难度是有,资源也没办法改变,还是要去做。
  打家帮忙想想有什么快速的解决方法不。
点赞  2009-11-23 08:51
创建DIB的时候,使他的格式与DDB保持一致就可以提高速度了.
另外直接把位图的原始数据旋转后画到DC上,也比先把位图画到DC,然后从DC获取位图数据,旋转操作,再画到DC上能显著的提高速度.
点赞  2009-11-23 11:55
我给楼请再提一下意见,仅供参考
楼主需要注意你的屏幕的色深,一般来讲,现在wince上的屏幕都是用的565的位图(65535色),所以你在旋转之前,要保证图已经是565的了,
另如果做565的bitblt,我bitblt一个480x272的位图,差不多3ms左右.



引用: 引用 6 楼 daredjever 的回复:
引用 5 楼 wceui 的回复:
楼主,我深入做过这方面的研究,旋转效率非常高,但限制于90/180/270度旋转,这在做看图的时候足够了,但如果您想任意角度旋转,无论如何都不会效率高的,光是sin,cos运算,还有浮点运算,以现在wince400M的CPU我觉得还不足以完成这些事情.

  实现方法为:
  采用CreateDibSection可以得到位图的每个点的像素,你把这些像素的内存重新组织一下就可以了,如果楼主研究透了位图里面的数据是如何存放的,相信这个问题也就解开了


wceUI你好:
? ? 90度等特殊角度的旋转我也研究过几个例子,由于其计算相对简单,所以速度都是还可以接受的。我也是迫不得已才,项目要求才去做这个任意角度旋转的,我也知道wince下资源的有限问题,但是只能尽量的优化了。而且我需要旋转的还是大图,要是700*500这样的就一秒左右能完成,还勉强能接受。但是我要做的是1000*1000多点的图,这样时间就快接近两秒了。
? ? 我用的也是CreateDibSection方法,其实我追踪过,大部分时间并不是花在计算浮点数上以及旋转算法上,而是用CreateDibSection生成DIB后往里面写入数据的过程:
我用的是bitblt函数,把内存中的CBitmap拷贝到我的DIB中。这个过程花费很大的时间。我仔细查过,是因为DDB和DIB格式不一样,这个函数要转化其数据,不是简单的内存拷贝。
  难度是有,资源也没办法改变,还是要去做。
  打家帮忙想想有什么快速的解决方法不。
点赞  2009-11-23 13:16
引用: 引用 7 楼 reallyu 的回复:
创建DIB的时候,使他的格式与DDB保持一致就可以提高速度了.
另外直接把位图的原始数据旋转后画到DC上,也比先把位图画到DC,然后从DC获取位图数据,旋转操作,再画到DC上能显著的提高速度.


reallyu你好:
  现在慢就是因为DDB和DIB格式不一样,你说的使他们的格式一样就快了?那么保持一样是什么概念?我的DIB我就只设置了BITMAPINFO中的尺寸大小和bibitConut(我设的是24,我记得谁说过WINCE中内存中的位图就是24位的),其他的就没设置了。请问你说的格式保持一致怎么设置请你说仔细点行吗?我现在的理解是DDB和DIB格式肯定是不一样的,我设的24位的DIB存的肯定是RGB的值,但是内存中的DDB应该是索引值吧?不知道理解对不对
点赞  2009-11-23 14:35
引用: 引用 7 楼 reallyu 的回复:
创建DIB的时候,使他的格式与DDB保持一致就可以提高速度了.
另外直接把位图的原始数据旋转后画到DC上,也比先把位图画到DC,然后从DC获取位图数据,旋转操作,再画到DC上能显著的提高速度.


reallyu你好:
  现在慢就是因为DDB和DIB格式不一样,你说的使他们的格式一样就快了?那么保持一样是什么概念?我的DIB我就只设置了BITMAPINFO中的尺寸大小和bibitConut(我设的是24,我记得谁说过WINCE中内存中的位图就是24位的),其他的就没设置了。请问你说的格式保持一致怎么设置请你说仔细点行吗?我现在的理解是DDB和DIB格式肯定是不一样的,我设的24位的DIB存的肯定是RGB的值,但是内存中的DDB应该是索引值吧?不知道理解对不对

还有就是你说的绘图的过程,我这里必须这样来做,因为原始的位图是根据程序执行不断的绘制的,事先并不知道也不可获得,只能在程序中从一个绘制的DC中去取,旋转后再画回去。
点赞  2009-11-23 14:37
wceUI:
你说的这个我曾今留意过。但是我当时理解的是wince中的内存中的位图都是24位的啊。也就是真彩色的。还不知道你说的565色的情况。我去试试我的设备上Createcompatiblebitmap上产生的位图是什么样的再说。怎么会有565色呢?我看的都是1,4,8(256色),16,24位的啊。怎么设置DIB为565色呢?只有一个bibitconut参数啊
点赞  2009-11-23 14:43

  1.                 HDC dc = ::GetDC(NULL);
  2.                 int nBitsPixel = ::GetDeviceCaps(dc, BITSPIXEL);


用这个代码,看看返回的值是不是16
点赞  2009-11-23 16:59
DIB可以设置成565色的

    当压缩格式为   BI_BITFIELDS   时,在位图信息(即BITMAPINFOHEADER)后面接着三个DWORD型数据,就是掩码数据,   
  一般为:0xF800(兰色掩码),0x07E0(绿色掩码),0x001F(红色掩码),这是565的格式   
例子代码如下
BITMAPINFO *bitmapInfo = (BITMAPINFO*)malloc( sizeof(BITMAPINFO)+sizeof(RGBQUAD)*(255) );
  memset( bitmapInfo, 0, sizeof(BITMAPINFO)+sizeof(RGBQUAD)*(255) );
  bitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  bitmapInfo->bmiHeader.biWidth = m_uWidth;
  bitmapInfo->bmiHeader.biHeight = uLineCount*uLineHeight + m_uLineSpace*(uLineCount-1);
  bitmapInfo->bmiHeader.biPlanes = 1;
  bitmapInfo->bmiHeader.biBitCount = 16;
  bitmapInfo->bmiHeader.biCompression = BI_BITFIELDS;
  bitmapInfo->bmiHeader.biSizeImage = 0;

  bitmapInfo->bmiColors[0].rgbBlue   =   0;   
  bitmapInfo->bmiColors[0].rgbGreen   =   0xF8;   
  bitmapInfo->bmiColors[0].rgbRed   =   0;   
  bitmapInfo->bmiColors[0].rgbReserved   =   0;   
  bitmapInfo->bmiColors[1].rgbBlue   =   0xE0;   
  bitmapInfo->bmiColors[1].rgbGreen   =   0x07;   
  bitmapInfo->bmiColors[1].rgbRed   =   0;   
  bitmapInfo->bmiColors[1].rgbReserved   =   0;   
  bitmapInfo->bmiColors[2].rgbBlue   =   0x1F;   
  bitmapInfo->bmiColors[2].rgbGreen   =   0;   
  bitmapInfo->bmiColors[2].rgbRed   =   0;   
  bitmapInfo->bmiColors[2].rgbReserved   =   0;  
点赞  2009-11-23 18:09
目前大部分的wince设备都是16色 565的
也就是DDB的格式
点赞  2009-11-23 18:12

wceui你好:
    我查看了我的设备的位图格式,我用的是createcompatiblebitmap生成一个位图,查看其bibitcount为16!!!应该就是你说的
int nBitsPixel = ::GetDeviceCaps(dc, BITSPIXEL);
了吧!我之前一直以为是24...谢谢你提醒!只是16的结构没看过,这回又要学习了。
   
点赞  2009-11-24 09:40
引用: 引用 14 楼 reallyu 的回复:
目前大部分的wince设备都是16色 565的
也就是DDB的格式


reallyu你好:
   你的留言将给我莫大的帮助,虽然我现在看不懂。。。。16的位图结构没有看过。现在就你的留言和代码有几个问题请教下:
  1.你和wceui朋友都提到wince中位图是16位,565色,请问这个565和16是什么关系?
  2。如果按你的代码,我生成一个16位的与DDB一样的格式的DIB,那么我后来bitblt拷贝数据的时候就会很快了?wceui说做过,请问会快很多吗?有没有DDB之间的bitblt快?我这里对效率要求很高。
3.请问你给的代码中的BITMNAPINFO信息的设置中的图片高
uLineCount*uLineHeight + m_uLineSpace*(uLineCount-1);是什么意思?怎么来的?
4.在给BITMAPINFO分配内存的时候,为什么多加了255个RGBQUad结构?这个是代表所说的调色盘吗?给后面数据内容作为索引的?那么它在什么时候赋值,怎么赋值的呢?
5.bitmapinfo结构后面的掩码什么用?他们属于调色盘的一部分吗?还是单独的结构?看位图结构的时候没见过这部分。
6,用你给的bitmapinfo生成的DIB获得的数据室什么结构呢?多少bit代表一个像素的值?是16吗?那么这16bit怎么划分的?我要对其进行旋转操作怎么移动数据?我对24位操作的时候是每次移动对应地址的3字节数据!

这些问题我会自己先去查找答案的,毕竟16位的位图结构没看过,不过你有经验要是能指点操作的话会很快解决问题的。先谢谢了。
点赞  2009-11-24 09:53
16位565的意思就是 每两个字节表示一个颜色数据
其中 r 占5个bit, g 占6个bit, b 占5个bit, 一共是5+6+5=16bit,正好2个字节
bitmapInfo->bmiHeader.biHeight = uLineCount*uLineHeight + m_uLineSpace*(uLineCount-1);
这个是从别的代码中复制过来的,实际就是位图高度
需要注意的是位图数据存储时每行的所占字节好像是4字节对齐的,如果一行所占字节数不是4的倍数需要补齐,所以你截取的位图宽度最好是2或4的倍数,这样处理起来方便些,不需要考虑对齐问题.
调色板在低于8bpp的位图中才需要,16bpp和24bpp是没有调色盘的,你不需要考虑这个问题,这里调色板只是充当掩码的作用
掩码的作用就是指明这个16bpp的位图是565格式的,因为16bpp还有 555, 5551等格式, 555就是rgb各占5个bit,多余的1个bit没用,5551就是rgb各占5个bit,其中1是透明位
当DDB和DIB格式一致时,从DDB和DIB之间的转换就不需要多余的运算,可以显著的提高速度.
点赞  2009-11-24 11:59
reallyu你好:
今天那些问题我也自己查看很多资料,也大概看了一个明白,再加上你上面的解释,算是明朗了不少。16位的结构也看了一些说明。还有一个问题你没提到,就是BITMAPINFO分配内存的时候多了255个RGBQUAD结构,但是你说这个16位的是不需要调色盘的啊,而掩码也就占了三个RGBQUAD的大小的空间,其他的空间不就空了?

最后一点讨论:我旋转的时候也就两个字节两个字节的作为一个像素点的值来传递。但是我的旋转算法中有的点是没有相应的对应点的,我之前就给它填上背景色,(在24位的时候很容易赋值为背景色,因为用的是RGB结构),现在我想赋值背景色,是不是得根据这个掩码去计算出背景色在16位下的存储数据?
比如我的背景色是RGB(128,128,128),我就根据掩码把他转化成两个字节的数据?这个转化过程什么样的?掩码算法电脑会自己计算,但是我不知道规则。
不管怎么样,我先去动手试验下。写个程序测试一下。
点赞  2009-11-24 14:04
RGBQUAD结构的多少由BITMAPINFOHEADER 的biClrUsed决定的
算背景色其实也很容易,就是个RGB888到RGB565的转换,原理就是将RGB每个分量取出来,取高位,然后放到合适的位置,所有操作都可以用移位指令完成的
点赞  2009-11-24 14:46
12下一页
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复