关于bitmap每行字节数的问题

x___f__ 2010-01-16 05:20:57
我在 何斌 的 VISUAL C++数字图像处理 中第二章有个疑问:

*******************************
biSizeImage = biWidth' * biHeight
这里的biWidth'是大于或等于离4最近的整倍数,如biWidth = 241,那么biWidth' = 244.

在构建自己的DIB时#define WIDTHBYTES(bits) = (((bits) + 31)/32*4)
这里的bits为:BITMAPINFOHEADER里的biWidth.
最后数据大小直接为WIDTHBYTES(biWidth)*(biBitCount)*BiHeight
******************
其中一段源程序为
**********************
// 计算DIB大小时,最简单的方法是调用GlobalSize()函数。但是全局内存大小并
// 不是DIB真正的大小,它总是多几个字节。这样就需要计算一下DIB的真实大小。
// 文件头大小+颜色表大小
// (BITMAPINFOHEADER和BITMAPCOREHEADER结构的第一个DWORD都是该结构的大小)
dwDIBSize = *(LPDWORD)lpBI + ::PaletteSize((LPSTR)lpBI);

// 计算图像大小
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
{
// 对于RLE位图,没法计算大小,只能信任biSizeImage内的值
dwDIBSize += lpBI->biSizeImage;
}
else
{
// 象素的大小
DWORD dwBmBitsSize;

// 大小为Width * Height
dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;

// 计算出DIB真正的大小
dwDIBSize += dwBmBitsSize;

// 更新biSizeImage(很多BMP文件头中biSizeImage的值是错误的)
lpBI->biSizeImage = dwBmBitsSize;
}


// 计算文件大小:DIB大小+BITMAPFILEHEADER结构大小
bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER);
***************************************
我想问:
① biWidth = 241 指的是像素数目还是字节数目,应该是字节数吧?
②#define WIDTHBYTES(bits) = (((bits) + 31)/32*4)中后面bits应该单位为像素,前面求得的结果应该直接变成了字节吧?
③// 大小为Width * Height
dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * lpBI->biHeight;
其中dwBmBitsSize的单位是字节,而lpBI->biHeight的单位是像素,WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI-> biBitCount)) 的单位是字节,怎么能直接相加呢?
④ 在一个帖子中看到bitmap每行字节数DataSizePerLine= (biWidth* biBitCount+31)/8; 这个和WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) 求得的结果是一致的么?我算时遇到了整除的问题就是后面的乘法不能移到整除号的前面,不知道如何求证是一致的?
...全文
551 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
lambochan 2010-01-17
  • 打赏
  • 举报
回复
当然是后面那个快了,不过那并没有实质意义,因为可能整个代码内估计就只调用一两次那个公式,优化它而快一两个时钟周期对现在的cpu来说完全没有意义,但写成那样对于代码维护也不利,可以说因少失大.

花时间优化这个,还不如去考虑如何优化那些频繁调用或者是多层循环嵌套的代码.
x___f__ 2010-01-17
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 lambochan 的回复:]
后5位清0想当于作了两次位移(假如无符号数没溢出的话,估计区区位图行字节数,怎么都不会溢出的吧):
sorry,这句手快写错了,因为是先右移5后左移5,所以怎么都不会溢出.汗~~
[/Quote]
谢谢你的提醒,你说的我都明白了!
还有最后一个问题就是:
从速度上来讲,#define WIDTHBYTES(bits) = (((bits) + 31)/32*4)
WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount))

((((biWidth * biBitCount) + 31) & ~31) >> 3)
哪个快呢?我想是后一个吧,要不也不会这么写成这么难懂的形式。
x___f__ 2010-01-17
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 lambochan 的回复:]
它和这个可以说没啥不同:
((((biWidth * biBitCount) +32) / 32 ) * 4)


又发现一个错误(3楼那把31写成32了 -_-"  ),随手写真的多错漏,hohoho,nnd.
[/Quote]
嗯,都知道了,谢谢您的耐心回答!
lambochan 2010-01-17
  • 打赏
  • 举报
回复
后5位清0想当于作了两次位移(假如无符号数没溢出的话,估计区区位图行字节数,怎么都不会溢出的吧):
sorry,这句手快写错了,因为是先右移5后左移5,所以怎么都不会溢出.汗~~
lambochan 2010-01-17
  • 打赏
  • 举报
回复
它和这个可以说没啥不同:
((((biWidth * biBitCount) + 32) / 32 ) * 4)


又发现一个错误(3楼那把31写成32了 -_-" ),随手写真的多错漏,hohoho,nnd.
lambochan 2010-01-17
  • 打赏
  • 举报
回复
((((biWidth * biBitCount) + 31) & ~31) >> 3)
那是偶见过的另外三种正确写法的其中一种,也是最难明白的一种,恐怕你问10个人中,9个是不知道为啥是那样写的,要么就是乱答的..

我试解释一下吧: (解释不对或者看不明白你就当偶乱答好了,hoho)

它的前半部分和上面那个#define并无不同,就说说"~31"吧,31求反可得32位整数(2进制):
11111111111111111111111111100000B,任何会编程的人一看这个数就知道,用一个数(num)和它与(&)的话,后5位必定被它清0,而其它位没有变化,而一个重要的概念就是:
后5位清0想当于作了两次位移(假如无符号数没溢出的话,估计区区位图行字节数,怎么都不会溢出的吧):
num >>= 5;
num <<= 5;
没错,这基本上就是( num & ~31 )的操作,看出端倪没?
yes, num >>= 5 实际上就是除以32;而num <<= 5实际上就是乘以32,而>> 3实际上是除以8. (不明白的话请去翻书)
ok,整条公式已经可以简单转换为:
((((biWidth * biBitCount) + 31) / 32 * 32 ) / 8)
它和这个可以说没啥不同:
((((biWidth * biBitCount) + 32) / 32 ) * 4)
不信的话,求求就知道了...

last : 另外两种写法我就不说了,其实你也只要找一种正确的来写就可以了,只要不是写成问题4那种"想当然"的就ok.

good luck, byebye~
x___f__ 2010-01-16
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 lambochan 的回复:]
4:那估计是乱写的,正确是不能把 (xx)/32*4写成(xx)/8的,在计算机那是不相等的,举例:
width = 2,bpp = 8那么行字节数应该是
(2*8+31)/32*4 得4个字节.
(2*8+31)/8    得5个字节.
有少少常识的都知道,上面那个是对的,下面那个是错的,原因那些家伙根本不理解"对齐"的意思,片面地把"/32*4"合成为"/8"来误人误已. hoho.
[/Quote]
这次又是您及时回答我的问题,谢谢!
前三个问题您回答的现在完全理解,第四个问题我也赞同您的观点,但是我把它与http://topic.csdn.net/u/20100114/21/0A67123E-1407-4FC0-B4E0-6D27FB8626C2.html
( “bitmap每行字节数搞不懂,急~~~”)这个帖子整合不到一块去,或许这和我不懂它里面((((biWidth * biBitCount) + 31) & ~31) >> 3)的 符号& ~ 有关。请您可以帮我解释一下,好吗?
lambochan 2010-01-16
  • 打赏
  • 举报
回复
1:biWidth = 241 是位图的宽度而不是字节数目
2:(bits)其实需要输入:(biWidth * biBitCount),
3:WIDTHBYTES()根据输入(biWidth*biBitCount)而得出行字节数,而扫描行字节数乘以扫描行总数(位图的高度biHeight),就得出位数据的实际字节数目,估计你是理解错误了.
4:那估计是乱写的,正确是不能把 (xx)/32*4写成(xx)/8的,在计算机那是不相等的,举例:
width = 2,bpp = 8那么行字节数应该是
(2*8+31)/32*4 得4个字节.
(2*8+31)/8 得5个字节.
有少少常识的都知道,上面那个是对的,下面那个是错的,原因那些家伙根本不理解"对齐"的意思,片面地把"/32*4"合成为"/8"来误人误已. hoho.

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧