首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VB >

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

2012-12-16 
【100分】如果获取位图颜色比例如何根据一个BMP图片获得这个图片各种颜色占的比率,比如上图(请看图的时候忽

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

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


[最优解释]
最简单的办法:
如果不使用API,则set pic=loadpicture(bmpfile),然后使用point获得图片像素颜色,最后作比较。
稍复杂的办法:
创建一个内存DC,然后将该bmp选入DC,再用getpixels获得像素的颜色,最后比较。
最高效还也较复杂的办法:
重复上述步骤,但直接访问内存中的位图数据(可以使用模拟指针转换为VB的bytes数组),最后直接访问数组获得像素颜色并比较。
[其他解释]
lyserver你好!
用:set pic=loadpicture(bmpfile),然后使用point获得图片像素颜色
这个方法非常慢,你说的另外几种方法能提供下源代码吗?
[其他解释]
直接按 BMP 文件格式读取数据:
http://topic.csdn.net/t/20020409/20/634570.html
[其他解释]
mark~
[其他解释]

引用:
lyserver你好!
用:set pic=loadpicture(bmpfile),然后使用point获得图片像素颜色
这个方法非常慢,你说的另外几种方法能提供下源代码吗?

按照老鸟说的,直接分析BMP文件后读取像素效率最高,至于BMP文件格式,在《Win32 API大全》一书中有。
我比较忙,一般都是偷偷上一会就下了,没时间给代码。其实有了思路,实现是很容易的。
[其他解释]
学习了!这篇帖子相当有技术含量。
[其他解释]
谢谢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记录像素。。。
这样毫无规律可言,请问这是怎么回事阿,本人之前未接触过图片处理这块,请各位大虾指教下!先谢谢了
[其他解释]
说错了,后面的不是白色的RBG,是黑色的。
还有此代码的控件有PictureBox和CommandBottom各一,另外tdbgDetail是TDBGrid,大家可以屏蔽掉,不用理会


[其他解释]
跟像素无关,跟颜色深度有关,32位真彩色用4bytes表示一个像素,24位用3bytes,如此类推,而你循环时步长为4,则把图片都视作了32位,这样一来结果肯定有问题。
最简单的办法,创建一个内存DC和一幅32位颜色的内存位图,再把VB的图片对象使用Render方法渲染到内存DC中,这样就可以把所有图片都转换为32位的位图,然后再对内存位图进行操作,而不是对源图进行操作,结果就对了。
另外,这一类的操作,位图格式最准确,JPEG误差最大。
[其他解释]
不要按固定格式计算 BytesPerLine,BITMAP.bmWidthBytes 就指定了每行的自己数。
每个像素的位数也用 BITMAP.bmBitsPixel 判断一下,不一定都是 24 bits的。

估计你计算的字节数比实际大,所以 GetBitmapBits 取得的数据只有前半段有效。
------其他解决方案--------------------


引用:
跟像素无关,跟颜色深度有关,32位真彩色用4bytes表示一个像素,24位用3bytes,如此类推,而你循环时步长为4,则把图片都视作了32位,这样一来结果肯定有问题。
最简单的办法,创建一个内存DC和一幅32位颜色的内存位图,再把VB的图片对象使用Render方法渲染到内存DC中,这样就可以把所有图片都转换为32位的位图,然后再对内存位图进行操作,而不是对源图进行操作,结果就对了。
另外,这……

首先谢谢你的回复
你说的颜色深度,我之前看资料的时候也看过,但是我试着用32位和24位,步长4得到的结果都一样,当时我还觉得纳闷呢?!
我现在测试用的都是24位的,用步长4读出来的RBG值都是对的阿,用步长3反而不对阿。。
究竟怎么回事阿?越弄越迷糊了,呵呵,怎么理论和我的测试效果不一样?

[其他解释]
引用:
不要按固定格式计算 BytesPerLine,BITMAP.bmWidthBytes 就指定了每行的自己数。
每个像素的位数也用 BITMAP.bmBitsPixel 判断一下,不一定都是 24 bits的。

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


谢谢你的解答,测试下果然都是32bits的,和windows、photoshop说的位深度不是同一个概念?
还有BytesPerLine得到的是什么值?
[其他解释]
UPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUP
[其他解释]
BytesPerLine扫描线,是4字节对齐的,还是先看一下BITMAP结构吧,内存中与磁盘上基本一致,除了少几项头描述。
[其他解释]
我记得我以前写过一个图片比较的代码,在我的资源里,写得不是很准确,但可以给你一些启发,你不妨下载看一下。

[其他解释]
.....如何是如何变成如果的?见过非常多了...

热点排行