【100分】如果获取位图颜色比例

windfeel2008 2010-03-29 11:52:26

如何根据一个BMP图片获得这个图片各种颜色占的比率,比如上图(请看图的时候忽略白色线,实际图是无白色线的):
浅灰:25%
深灰:25%
深蓝:25%
浅蓝:25%
我有个想法,就是把位图读到一个二维数组,然后再计算,但是我没做个类似操作,希望各位大侠能示范下!最好提供源码,谢谢!
■■■■

...全文
206 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
lyserver 2010-03-30
  • 打赏
  • 举报
回复
我记得我以前写过一个图片比较的代码,在我的资源里,写得不是很准确,但可以给你一些启发,你不妨下载看一下。
lyserver 2010-03-30
  • 打赏
  • 举报
回复
BytesPerLine扫描线,是4字节对齐的,还是先看一下BITMAP结构吧,内存中与磁盘上基本一致,除了少几项头描述。
贝隆 2010-03-30
  • 打赏
  • 举报
回复
UPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUP
windfeel2008 2010-03-30
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 tiger_zhao 的回复:]
不要按固定格式计算 BytesPerLine,BITMAP.bmWidthBytes 就指定了每行的自己数。
每个像素的位数也用 BITMAP.bmBitsPixel 判断一下,不一定都是 24 bits的。

估计你计算的字节数比实际大,所以 GetBitmapBits 取得的数据只有前半段有效。
[/Quote]

谢谢你的解答,测试下果然都是32bits的,和windows、photoshop说的位深度不是同一个概念?
还有BytesPerLine得到的是什么值?
windfeel2008 2010-03-30
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 lyserver 的回复:]
跟像素无关,跟颜色深度有关,32位真彩色用4bytes表示一个像素,24位用3bytes,如此类推,而你循环时步长为4,则把图片都视作了32位,这样一来结果肯定有问题。
最简单的办法,创建一个内存DC和一幅32位颜色的内存位图,再把VB的图片对象使用Render方法渲染到内存DC中,这样就可以把所有图片都转换为32位的位图,然后再对内存位图进行操作,而不是对源图进行操作,结果就对了。
另外,这……
[/Quote]
首先谢谢你的回复
你说的颜色深度,我之前看资料的时候也看过,但是我试着用32位和24位,步长4得到的结果都一样,当时我还觉得纳闷呢?!
我现在测试用的都是24位的,用步长4读出来的RBG值都是对的阿,用步长3反而不对阿。。
究竟怎么回事阿?越弄越迷糊了,呵呵,怎么理论和我的测试效果不一样?
Tiger_Zhao 2010-03-30
  • 打赏
  • 举报
回复
不要按固定格式计算 BytesPerLine,BITMAP.bmWidthBytes 就指定了每行的自己数。
每个像素的位数也用 BITMAP.bmBitsPixel 判断一下,不一定都是 24 bits的。

估计你计算的字节数比实际大,所以 GetBitmapBits 取得的数据只有前半段有效。
lyserver 2010-03-30
  • 打赏
  • 举报
回复
跟像素无关,跟颜色深度有关,32位真彩色用4bytes表示一个像素,24位用3bytes,如此类推,而你循环时步长为4,则把图片都视作了32位,这样一来结果肯定有问题。
最简单的办法,创建一个内存DC和一幅32位颜色的内存位图,再把VB的图片对象使用Render方法渲染到内存DC中,这样就可以把所有图片都转换为32位的位图,然后再对内存位图进行操作,而不是对源图进行操作,结果就对了。
另外,这一类的操作,位图格式最准确,JPEG误差最大。
windfeel2008 2010-03-30
  • 打赏
  • 举报
回复
说错了,后面的不是白色的RBG,是黑色的。
还有此代码的控件有PictureBox和CommandBottom各一,另外tdbgDetail是TDBGrid,大家可以屏蔽掉,不用理会

windfeel2008 2010-03-30
  • 打赏
  • 举报
回复
谢谢lyserver以及其他各位的解答,现在去研究BMP格式比较费时,时间不够了,我现在用API来,代码如下:

Private Type BITMAP
bmType As Long
bmWidth As Long
bmHeight As Long
bmWidthBytes As Long
bmPlanes As Integer
bmBitsPixel As Integer
bmBits As Long
End Type
Private Declare Function GetObject Lib "gdi32" Alias "GetObjectA" (ByVal hObject As Long, ByVal nCount As Long, lpObject As Any) As Long
Private Declare Function GetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Private Declare Function SetBitmapBits Lib "gdi32" (ByVal hBitmap As Long, ByVal dwCount As Long, lpBits As Any) As Long
Dim PicBits() As Byte
Dim PicInfo As BITMAP
Dim Cnt As Long
Dim BytesPerLine As Long
Dim xArrayx As XArrayDB

Private Sub Command1_Click()
Dim iRow As Long

GetObject Pic.Image, Len(PicInfo), PicInfo
BytesPerLine = (PicInfo.bmWidth * 3 + 3) And &HFFFFFFFC
ReDim PicBits(1 To BytesPerLine * PicInfo.bmHeight * 3) As Byte
GetBitmapBits Pic.Image, UBound(PicBits), PicBits(1)
Set xArrayx = New XArrayDB
xArrayx.Clear
xArrayx.ReDim 1, 1, 1, 3
xArrayx(1, 1) = Format(CStr(PicBits(3)), "000") & Format(CStr(PicBits(2)), ",000") & Format(CStr(PicBits(1)), ",000")
Debug.Print Format(CStr(PicBits(3)), "000") & Format(CStr(PicBits(2)), ",000") & Format(CStr(PicBits(1)), ",000")
xArrayx(1, 2) = Format(CStr(255 - PicBits(3)), "000") & Format(CStr(255 - PicBits(2)), ",000") & Format(CStr(255 - PicBits(1)), ",000")
xArrayx(1, 3) = 1
For Cnt = 5 To UBound(PicBits) Step 4
Debug.Print Format(CStr(PicBits(Cnt + 2)), "000") & Format(CStr(PicBits(Cnt + 1)), ",000") & Format(CStr(PicBits(Cnt)), ",000")
iRow = xArrayx.Find(1, 1, Format(CStr(PicBits(Cnt + 2)), "000") & Format(CStr(PicBits(Cnt + 1)), ",000") & Format(CStr(PicBits(Cnt)), ",000"))
If iRow > 0 Then
xArrayx(iRow, 3) = Val(xArrayx(iRow, 3)) + 1
Else
xArrayx.ReDim 1, xArrayx.UpperBound(1) + 1, 1, 3
xArrayx(xArrayx.UpperBound(1), 1) = Format(CStr(PicBits(Cnt + 2)), "000") & Format(CStr(PicBits(Cnt + 1)), ",000") & Format(CStr(PicBits(Cnt)), ",000")
xArrayx(xArrayx.UpperBound(1), 2) = Format(CStr(255 - PicBits(Cnt + 2)), "000") & Format(CStr(255 - PicBits(Cnt + 1)), ",000") & Format(CStr(255 - PicBits(Cnt)), ",000")
xArrayx(xArrayx.UpperBound(1), 3) = 1
End If
Next Cnt
Set tdbgDetail.Array = xArrayx
tdbgDetail.ReBind
tdbgDetail.Refresh
End Sub

效率还可以,暂时满足现阶段的要求,但是我又遇到一个新问题,我在测试的时候用了几张小图
一张2×2像素的,得到的前面1/3的内容每四位记录一个点的RBG(前3位为对应颜色的G、B、R值,第4位为0,应该是分隔符),后面的2/3全部都是白色的RBG,不知道是记录什么的.。。
然后我再测试一张4×2像素的图,结果发现前面的4/9记录像素信息,后面5/9全部是黑色的RBG...
再试6×2像素,前面2/5记录像素,
再试8×2像素,前面4/9记录像素,
再试10×2像素,前面10/19记录像素。。。
这样毫无规律可言,请问这是怎么回事阿,本人之前未接触过图片处理这块,请各位大虾指教下!先谢谢了
嗷嗷叫的老马 2010-03-30
  • 打赏
  • 举报
回复
.....如何是如何变成如果的?见过非常多了...
lyserver 2010-03-29
  • 打赏
  • 举报
回复
最简单的办法:
如果不使用API,则set pic=loadpicture(bmpfile),然后使用point获得图片像素颜色,最后作比较。
稍复杂的办法:
创建一个内存DC,然后将该bmp选入DC,再用getpixels获得像素的颜色,最后比较。
最高效还也较复杂的办法:
重复上述步骤,但直接访问内存中的位图数据(可以使用模拟指针转换为VB的bytes数组),最后直接访问数组获得像素颜色并比较。
贝隆 2010-03-29
  • 打赏
  • 举报
回复
学习了!这篇帖子相当有技术含量。
lyserver 2010-03-29
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 windfeel2008 的回复:]
lyserver你好!
用:set pic=loadpicture(bmpfile),然后使用point获得图片像素颜色
这个方法非常慢,你说的另外几种方法能提供下源代码吗?
[/Quote]
按照老鸟说的,直接分析BMP文件后读取像素效率最高,至于BMP文件格式,在《Win32 API大全》一书中有。
我比较忙,一般都是偷偷上一会就下了,没时间给代码。其实有了思路,实现是很容易的。
chinaboyzyq 2010-03-29
  • 打赏
  • 举报
回复
mark~
Tiger_Zhao 2010-03-29
  • 打赏
  • 举报
回复
直接按 BMP 文件格式读取数据:
http://topic.csdn.net/t/20020409/20/634570.html
windfeel2008 2010-03-29
  • 打赏
  • 举报
回复
lyserver你好!
用:set pic=loadpicture(bmpfile),然后使用point获得图片像素颜色
这个方法非常慢,你说的另外几种方法能提供下源代码吗?
第二章EasyDraw是一个简单的绘图软件,这个实例会综合运用本章所介绍了Visual C++ 2005的基础知识。EasyDraw拥有以下功能:1.直线、矩形、椭圆的绘制。2.可以更改绘制线条的类型、宽度、颜色。第三章ColorPicker是一个基于对话框的应用程序,它具有以下功能:1. 色彩编辑功能用户可以通过可以调整R、G、B的值来编辑颜色,亦可通过调整H、S、V的值来选取颜色颜色编辑的结果会马上反馈到颜色面板和颜色预览框中。2.RGB颜色空间和HSV颜色空间的转换当改变RGB值,会得到相应的HSV值,并进行显示,反之亦然。3.取色功能取色功能包含“面板取色”和“屏幕取色”。面板取色就是用户可以在颜色面板中单击鼠标左键,选取目标点所表示的某种颜色。屏幕取色则是允许用户获取整个屏幕上的任意一点的颜色值。用户可以将鼠标移动到需要获取颜色的地方,然后按a键或A键即可以获取该点颜色值。第四章JpegDecoder类主要用于Jpeg文件的解码。使用方法十简单,只需要利用GetJPEGBuffer函数返回解码后的像素数组。在第三篇的实例MagicHouse中就需要使用这个类。第五章 MyDib类主要用于处理设备无关位图DIB。Example目录:第六章该目录包含了本章6.4节和6.5节的全部实例代码。pic.jpg的辨率为96像素每英寸pic_72.jpg的辩率为72像素每英寸Color.h,Color.cpp:包含了6.5节处理图像的色彩的全部函数Example_GIF目录:它是本章6.6节播放GIF动画的工程,用于播放GIF动画。注意:gif文件必须和生成的exe文件位于同一目录下,gif文件必须改名为pic.gif。第七章TestOpenCV是一个应用OpenCV提供的函数进行图片显示和保存的应用程序,注意TestOpenCV需要OpenCV提供的库支持,因此请首先到相关网站上下载并安装OpenCV第八章本章实例是一个类似ACDSee的图像浏览工具——GraphShower。GraphShower主要实现如下功能:⑴ 类似ACDSee的图片浏览功能。用户只需要打开一个图片,就能利用菜单栏、工具栏或者快捷键快捷的浏览该图像所在目录的所有图像。使用方法与ACDSee类似。⑵ 图像的缩放显示功能。图像可以支持以下四种显示模式:① 原始大小:以原始大小显示图像。如果图像大小比视图小,则显示在正中;如果图像比视图大,则显示部图像。用户可以利用鼠标拖动图像以显示其它部。 ② 适合宽度:保持图像长宽比例缩放图像,使图像宽度等于视图宽度。③ 适合高度:保持图像长宽比例缩放图像,使图像高度等于视图高度。④ 适合屏幕:自动判断图像的显示方式,使图像能在当前视图上完整显示。⑶ 特效显示。GraphShower支持以下特效:向下扫描、垂直双重扫描、向右移动、水平双重移动、垂直百叶窗、水平百叶窗、垂直栅条、水平栅条、马赛克和雨滴。⑷ 文件目录窗口。通过目录树可以直接打开图像文件。⑸ 位图浏览窗口。以缩略图的形式显示图像。第九章"MagicHouse框架"目录:含有MagicHouse的原始框架,该框架是在GrahpShower的基础上完成的。"MagicHouse"目录:在MagicHouse原始框架下添加了“点运算”的功能。GrayOperator.h和GrayOperator.cpp包含了第9章点运算的全部函数。第十章MagicHouse目录:在第9章MagicHouse的基础上添加了“几何变换”的功能。其中GeoOperator.h和GeoOperator.cpp包含了第10章几何变换的全部函数。Example目录:包含10.7节全部代码。第十一章在第10章MagicHouse的基础上添加了“图像增强”的功能。其中improve.h和improve.cpp包含了第10章图像增强的所有函数。不少函数可以动态设置参数,从而获得不同的效果。本章实例仅简单调用了图像增强的函数。第12章在第11章MagicHouse的基础上添加了“滤镜”的功能。至此,MagicHouse的全部功能就实现了。其中Filter.h和Filter.cpp包含了第11章滤镜的所有函数。第十五章FaceDetection是一个静态人脸检测程序,注意FaceDetection需要OpenCV提供的库支持,因此请首先到相关网站上下载并安装OpenCV,此外本程序需要导入一个类器文件haarcascade_frontalface_alt.xml,该文件在OpenCV中提供,请读者将该文件复制到程序同一目录下,程序即可正确运行。
Visual C++数字图像处理开发入门与编程实践
第二章EasyDraw是一个简单的绘图软件,这个实例会综合运用本章所介绍了Visual C++ 2005的基础知识。EasyDraw拥有以下功能:
1.直线、矩形、椭圆的绘制。
2.可以更改绘制线条的类型、宽度、颜色

第三章ColorPicker是一个基于对话框的应用程序,它具有以下功能:
1. 色彩编辑功能
用户可以通过可以调整R、G、B的值来编辑颜色,亦可通过调整H、S、V的值来选取颜色颜色编辑的结果会马上反馈到颜色面板和颜色预览框中。
2.RGB颜色空间和HSV颜色空间的转换
当改变RGB值,会得到相应的HSV值,并进行显示,反之亦然。
3.取色功能
取色功能包含“面板取色”和“屏幕取色”。面板取色就是用户可以在颜色面板中单击鼠标左键,选取目标点所表示的某种颜色。屏幕取色则是允许用户获取整个屏幕上的任意一点的颜色值。用户可以将鼠标移动到需要获取颜色的地方,然后按a键或A键即可以获取该点颜色值。
第四章
JpegDecoder类主要用于Jpeg文件的解码。
使用方法十简单,只需要利用GetJPEGBuffer函数返回解码后的像素数组。在第三篇的实例MagicHouse中就需要使用这个类。

第五章 MyDib类主要用于处理设备无关位图DIB。
Example目录:

第六章
该目录包含了本章6.4节和6.5节的全部实例代码。
pic.jpg的辨率为96像素每英寸
pic_72.jpg的辩率为72像素每英寸
Color.h,Color.cpp:包含了6.5节处理图像的色彩的全部函数

Example_GIF目录:
它是本章6.6节播放GIF动画的工程,用于播放GIF动画。
注意:gif文件必须和生成的exe文件位于同一目录下,gif文件必须改名为pic.gif。
第七章
TestOpenCV是一个应用OpenCV提供的函数进行图片显示和保存的应用程序,注意TestOpenCV需要OpenCV提供的库支持,因此请首先到相关网站上下载并安装OpenCV
第八章
本章实例是一个类似ACDSee的图像浏览工具——GraphShower。GraphShower主要实现如下功能:
⑴ 类似ACDSee的图片浏览功能。用户只需要打开一个图片,就能利用菜单栏、工具栏或者快捷键快捷的浏览该图像所在目录的所有图像。使用方法与ACDSee类似。
⑵ 图像的缩放显示功能。图像可以支持以下四种显示模式:
① 原始大小:以原始大小显示图像。如果图像大小比视图小,则显示在正中;如果图像比视图大,则显示部图像。用户可以利用鼠标拖动图像以显示其它部
② 适合宽度:保持图像长宽比例缩放图像,使图像宽度等于视图宽度。
③ 适合高度:保持图像长宽比例缩放图像,使图像高度等于视图高度。
④ 适合屏幕:自动判断图像的显示方式,使图像能在当前视图上完整显示。
⑶ 特效显示。GraphShower支持以下特效:向下扫描、垂直双重扫描、向右移动、水平双重移动、垂直百叶窗、水平百叶窗、垂直栅条、水平栅条、马赛克和雨滴。
⑷ 文件目录窗口。通过目录树可以直接打开图像文件。
位图浏览窗口。以缩略图的形式显示图像。
第九章
"MagicHouse框架"目录:
含有MagicHouse的原始框架,该框架是在GrahpShower的基础上完成的。

"MagicHouse"目录:
在MagicHouse原始框架下添加了“点运算”的功能。
GrayOperator.h和GrayOperator.cpp包含了第9章点运算的全部函数。
第十章
MagicHouse目录:
在第9章MagicHouse的基础上添加了“几何变换”的功能。
其中GeoOperator.h和GeoOperator.cpp包含了第10章几何变换的全部函数。

Example目录:
包含10.7节全部代码。
第十一章
在第10章MagicHouse的基础上添加了“图像增强”的功能。
其中improve.h和improve.cpp包含了第10章图像增强的所有函数。不少函数可以动态设置参数,从而获得不同的效果。本章实例仅简单调用了图像增强的函数。
第12章
在第11章MagicHouse的基础上添加了“滤镜”的功能。至此,MagicHouse的全部功能就实现了。
其中Filter.h和Filter.cpp包含了第11章滤镜的所有函数。
第十五章
FaceDetection是一个静态人脸检测程序,注意FaceDetection需要OpenCV提供的库支持,因此请首先到相关网站上下载并安装OpenCV,此外本程序需要导入一个类器文件haarcascade_frontalface_alt.xml,该文件在OpenCV中提供,请读者将该文件复制到程序同一目录下,程序即可正确运行。

809

社区成员

发帖
与我相关
我的任务
社区描述
VB 多媒体
社区管理员
  • 多媒体
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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