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

解决方案 »

  1.   

    最简单的办法:
    如果不使用API,则set pic=loadpicture(bmpfile),然后使用point获得图片像素颜色,最后作比较。
    稍复杂的办法:
    创建一个内存DC,然后将该bmp选入DC,再用getpixels获得像素的颜色,最后比较。
    最高效还也较复杂的办法:
    重复上述步骤,但直接访问内存中的位图数据(可以使用模拟指针转换为VB的bytes数组),最后直接访问数组获得像素颜色并比较。
      

  2.   

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

  3.   

    直接按 BMP 文件格式读取数据:
    http://topic.csdn.net/t/20020409/20/634570.html
      

  4.   

    按照老鸟说的,直接分析BMP文件后读取像素效率最高,至于BMP文件格式,在《Win32 API大全》一书中有。
    我比较忙,一般都是偷偷上一会就下了,没时间给代码。其实有了思路,实现是很容易的。
      

  5.   

    谢谢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 XArrayDBPrivate 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记录像素
    这样毫无规律可言,请问这是怎么回事阿,本人之前未接触过图片处理这块,请各位大虾指教下!先谢谢了
      

  6.   

    说错了,后面的不是白色的RBG,是黑色的。
    还有此代码的控件有PictureBox和CommandBottom各一,另外tdbgDetail是TDBGrid,大家可以屏蔽掉,不用理会
      

  7.   

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

  8.   

    不要按固定格式计算 BytesPerLine,BITMAP.bmWidthBytes 就指定了每行的自己数。
    每个像素的位数也用 BITMAP.bmBitsPixel 判断一下,不一定都是 24 bits的。估计你计算的字节数比实际大,所以 GetBitmapBits 取得的数据只有前半段有效。
      

  9.   

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

  10.   


    谢谢你的解答,测试下果然都是32bits的,和windows、photoshop说的位深度不是同一个概念?
    还有BytesPerLine得到的是什么值?
      

  11.   

    UPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUPUP
      

  12.   

    BytesPerLine扫描线,是4字节对齐的,还是先看一下BITMAP结构吧,内存中与磁盘上基本一致,除了少几项头描述。