GetPixel和SetPixel的替代高效方法

flyingpig204 2010-12-13 06:52:12
加精
写的一个程序, 需要读取Bmp内的数据(Bmp用ACD See直接转换过来的, 应该是32位的), 并修改其内容, 开始使用GDI的GetPixel和SetPixel, 不需要转换, 但是效率太低了, 有没有直接读取HBitmap指向的内存区域, 可以直接对其进行读取和修改的办法?
...全文
5187 99 打赏 收藏 转发到动态 举报
写回复
用AI写文章
99 条回复
切换为时间正序
请发表友善的回复…
发表回复
直上云霄 2012-12-17
  • 打赏
  • 举报
回复
学习一下,顺便膜拜一下各位大神
j-k 2012-12-17
  • 打赏
  • 举报
回复
引用 6 楼 laviewpbt 的回复:
要显示CreateDIBSection创建的32位带ALPHA值的图像,有两种办法: 一、利用AlphaBlend函数,只似乎是GDI中唯一一个支持32位图像的函数,但是要正确输出图像,你还需要保证你的原始DC中的位图数据是PARGB格式。PARGB即Premultiply ARGB. 二:利用GDI+的DrawImage函数,先利用GDI+的函数GdipCrea……
用SetDIBitsToDevice或StretchDIBits不行吗?Jpeg的也可以显示。
jimette 2012-12-14
  • 打赏
  • 举报
回复
引用 3 楼 jameshooo 的回复:
GetDIBits也慢,涉及到图像数据的复制。 应该用CreateDIBSection创建一个HBITMAP,它给你返回图像缓冲区的地址,你可以任意修改数据。 创建一个内存DC,把这个DIBSECTION的HBITMAP选入DC,把你的图片绘制到这个DC,图像缓冲区中就是图片数据了,想怎么修改都行。
学习
xqhrs232 2012-10-26
  • 打赏
  • 举报
回复
真正找这方面的资料,记录一下,有时间好好看看!!!
eurekatony 2012-08-29
  • 打赏
  • 举报
回复
[Quote=引用 17 楼 的回复:]
C# code


Bitmap bitmap = new Bitmap(img);

int width = bitmap.Width;
int height = bitmap.Height;
BitmapData bmData = bitmap.LockBits(new Rectangl……
[/Quote]

效率最高,我用10000*1000 32arbg测试了下
耗时 218毫秒, 52楼的方法要656毫秒 ,用SetPixel需要22984毫秒
zhou_hui 2010-12-22
  • 打赏
  • 举报
回复
很好,很强大,学习一下
SKy_kid 2010-12-21
  • 打赏
  • 举报
回复
直接改Hbitmap啊,去掉头后和调色版的数据区得到buff,然后处理。
laviewpbt 2010-12-21
  • 打赏
  • 举报
回复

GBufferedHDC = ::CreateCompatibleDC(NULL);

////////////////////
BITMAPINFO info = {0};
info.bmiHeader.biSize = sizeof(info.bmiHeader);
info.bmiHeader.biWidth = SCREEN_WIDTH;
info.bmiHeader.biHeight = -SCREEN_HEIGHT;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = SCREEN_WIDTH * SCREEN_HEIGHT * 32 / 8;

// 创建一块内存纹理并获取其数据指针
void* pBits = NULL;
GBufferedHandle = ::CreateDIBSection(GBufferedHDC, &info, DIB_RGB_COLORS, &pBits, NULL, 0);
::SelectObject(GBufferedHDC, GBufferedHandle);

//here: "dib.dsBm.bmBits" will points to the pixels of hdib.
::GetObject(GBufferedHandle , sizeof(DIBSECTION), &GDIBSection);
//这里指向图像的内存区域
GDatas = (BYTE*)GDIBSection.dsBm.bmBits;


这段代码的

//here: "dib.dsBm.bmBits" will points to the pixels of hdib.
::GetObject(GBufferedHandle , sizeof(DIBSECTION), &GDIBSection);
//这里指向图像的内存区域
GDatas = (BYTE*)GDIBSection.dsBm.bmBits;

根本就没有必要啊,pBits就已经是DIBSECITON的内存首地址了。
zhan7505201 2010-12-19
  • 打赏
  • 举报
回复
好帖,学习。
flyingpig204 2010-12-19
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 laviewpbt 的回复:]

实际上,如果你已经用某些方式把一副图像加载到内存了,那么理论上最快的速度是直接访问这个内存,我们可以通过API函数 GetObject 得到一个Bitmap结构体信息。该结构体如下:
Public Type BITMAP '14 bytes
bmType As Long
bmWidth As Long
bmHeight As Long
……
[/Quote]

这个方法我使用过, 发现对已经加载的图像, 返回的bmBits数据全部是0, 并没有包含图像的数据, 不知道这是咋回事?
flyingpig204 2010-12-19
  • 打赏
  • 举报
回复
最近有事好几天没上CSDN了, 这个问题大家讨论的好热烈啊, 这个问题我解决了一部分了, 就是使用大家推荐的CreateDIBSection创建的HBITMAP来获取指向的内存

GBufferedHDC = ::CreateCompatibleDC(NULL);

////////////////////
BITMAPINFO info = {0};
info.bmiHeader.biSize = sizeof(info.bmiHeader);
info.bmiHeader.biWidth = SCREEN_WIDTH;
info.bmiHeader.biHeight = -SCREEN_HEIGHT;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = SCREEN_WIDTH * SCREEN_HEIGHT * 32 / 8;

// 创建一块内存纹理并获取其数据指针
void* pBits = NULL;
GBufferedHandle = ::CreateDIBSection(GBufferedHDC, &info, DIB_RGB_COLORS, &pBits, NULL, 0);
::SelectObject(GBufferedHDC, GBufferedHandle);

//here: "dib.dsBm.bmBits" will points to the pixels of hdib.
::GetObject(GBufferedHandle , sizeof(DIBSECTION), &GDIBSection);
//这里指向图像的内存区域
GDatas = (BYTE*)GDIBSection.dsBm.bmBits;


这里新建了一个HBITMAP, 并获取他的内存区域, 可以直接对GDatas进行操作. 现在遇到一个问题就是怎么对导入的图片创建DIBSection, 我之前根据其获取指向的内存区域, 获取的数据全部是0, 而不是图像的数据?

进过我的测试, 分别对GDI和GDI+采用相同方法(直接获取图像的内存区域, 并对其进行读写), GDI要比GDI+快很多, 貌似是DrawImage比BitBlt慢很多.
lanhuo1028120414 2010-12-19
  • 打赏
  • 举报
回复
很好很强大,值得研究一下哦,支持支持~
hnzlk 2010-12-18
  • 打赏
  • 举报
回复
收藏。。。
hankcs 2010-12-18
  • 打赏
  • 举报
回复
这类问题总算有个清晰的回答了
「已注销」 2010-12-18
  • 打赏
  • 举报
回复
收藏。。。
沧海遗珠 2010-12-18
  • 打赏
  • 举报
回复
要显示CreateDIBSection创建的32位带ALPHA值的图像,有两种办法:
一、利用AlphaBlend函数,只似乎是GDI中唯一一个支持32位图像的函数,但是要正确输出图像,你还需要保证你的原始DC中的位图数据是PARGB格式。PARGB即Premultiply ARGB.

二:利用GDI+的DrawImage函数,先利用GDI+的函数GdipCreateBitmapFromScan0将GDI对象转换为GDI+对象(注意这个函数的PixelFormat参数要设置为和你的GDI对象一致.然后就可以直接绘制到目标DC上了。

卧_槽 2010-12-17
  • 打赏
  • 举报
回复
位图就是一数组,获取数组首地址,跟据坐标计算数组位置,就得到数据了,想怎么改怎么改。
速度很快,几乎没有时间损失的啊。
whj1145 2010-12-17
  • 打赏
  • 举报
回复
iiiiibbvvf
maomaoyu8 2010-12-17
  • 打赏
  • 举报
回复
在讨论中学习。
zhao_yanping 2010-12-17
  • 打赏
  • 举报
回复
如果你用opencv的话就很容易了,先用cvLoadImage将图像加载进来,然后用cvGet2D获取图像灰度值,比如存放在s中,然后利用for就行行列循环,利用s.val[0],s.val[1],s.val[2],s.val[3]就可以取到灰度值了,我就是这样做的。
加载更多回复(51)

19,468

社区成员

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

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