Android Question [B4X] [Solved] Get a list of colours in a bitmap

John Naylor

Active Member
Licensed User
Longtime User
Using the code given here I create a small bitmap (320 x 240) with 16 colours from a a larger full colour bitmap.

Is there an easy (fast) way to get a list of what each of those colours are in argb format?
 

John Naylor

Active Member
Licensed User
Longtime User
Here's some more detail for anyone that can help.

I'm using the following on a 16 color bitmap.

B4X:
Sub GetColours (bmp As B4XBitmap) As List
   
    Dim l As List
    l.Initialize
   
    Dim x As Int
   
    Dim bc As BitmapCreator = CreateBC(bmp)
   
    For x = 0 To bc.mWidth - 1                'Create a list of all the colors in the bitmap
        For y = 0 To bc.mHeight - 1
            l.add (Bit.ToHexString (bc.GetColor(x,y)))
        Next
    Next
   
    l = RemoveDuplicates (l)

    Return l
   
End Sub

Sub RemoveDuplicates(pList As List) As List            'Get rid of the duplicates
    If pList = Null Or Not(pList.IsInitialized) Then Return pList
 
    Dim lstNew As List : lstNew.Initialize
    Dim objItem As Object
   
    For i = 0 To pList.Size - 1
        objItem = pList.Get(i)
        If lstNew.IndexOf(objItem) = - 1 Then
            lstNew.Add(objItem)
        End If
    Next
 
    Return lstNew
End Sub


No matter what image I put into ImageView1 (I pass that bitmap into the GetColours sub) I seem to get the same 8 colors once duplicates are removed. I was expecting 16 different ones of course.
 
Upvote 0

Star-Dust

Expert
Licensed User
Longtime User
Use a map instead of a list. Color will be the key. You won't need to check for duplicates.

In any case in the value of each key you can insert the number of times that color is used

But if you want to use a Litst, the duplicate check list you can do it while loading colors and not with a second loop
 
Upvote 1

John Naylor

Active Member
Licensed User
Longtime User
Use a map instead of a list. Color will be the key. You won't need to check for duplicates.

In any case in the value of each key you can insert the number of times that color is used

But if you want to use a Litst, the duplicate check list you can do it while loading colors and not with a second loop
Oush! Great suggestion with using the map - FAR better.

I'm still getting the same values for any image I process though.
 
Upvote 0

John Naylor

Active Member
Licensed User
Longtime User
Trying to upload a demo project - 3k - getting this.
Capture.PNG
 
Upvote 0

John Naylor

Active Member
Licensed User
Longtime User
Without a demo here's what I have.

Layout has 2 x ImageView and a button. ImageView1 has a bitmap assigned.


B4X:
Sub Class_Globals
    Private Root As B4XView
    Private xui As XUI
    Private ImageView1 As B4XView
    Private ImageView2 As B4XView
  

End Sub

Public Sub Initialize
    B4XPages.GetManager.LogEvents = True
End Sub

'This event will be called once, before the page becomes visible.
Private Sub B4XPage_Created (Root1 As B4XView)
    Root = Root1
    Root.LoadLayout("MainPage")
End Sub

'You can see the list of page related events in the B4XPagesManager object. The event name is B4XPage.

Private Sub Button1_Click
    Dim bmp As B4XBitmap
  
    Dim colourlist As Map
    colourlist.Initialize
  
    bmp = ImageView1.GetBitmap
    bmp = bmp.Resize (320, 240, True)
  
    bmp = BinColors (bmp)                'Change bitmap to 16 colours
  
    colourlist = GetColours (bmp)

    bmp = bmp.Resize (ImageView2.Width, ImageView2.Height,True)        'resize and display image
    ImageView2.SetBitmap (bmp)
  
    Log (colourlist)        'Always the same no matter what bitmap I use
  
  
End Sub



Private Sub CreateBC(bmp As B4XBitmap) As BitmapCreator
    Dim bc As BitmapCreator
    bc.Initialize(bmp.Width / bmp.Scale, bmp.Height / bmp.Scale)
    bc.CopyPixelsFromBitmap(bmp)
    Return bc
End Sub

Public Sub BinColors (bmp As B4XBitmap) As B4XBitmap
  
    Dim bc As BitmapCreator = CreateBC(bmp)
    Dim argb As ARGBColor
  
  
    For x = 0 To bc.mWidth - 1
        For y = 0 To bc.mHeight - 1
            bc.GetARGB(x, y, argb)
            argb.r = argb.r - (argb.r Mod 128)
            argb.g = argb.g - (argb.g Mod 128)
            argb.b = argb.b - (argb.b Mod 128)
            bc.SetARGB(x, y, argb)
        Next
    Next
    Return bc.Bitmap
  
End Sub

Sub GetColours (bmp As B4XBitmap) As Map
  
    Dim m As Map
    m.Initialize
  
    Dim x As Int
  
    Dim bc As BitmapCreator = CreateBC(bmp)
  
    For x = 0 To bc.mWidth - 1                'Create a list of all the colors in the bitmap
        For y = 0 To bc.mHeight - 1
            m.Put (Bit.ToHexString (bc.GetColor(x,y)), Bit.ToHexString (bc.GetColor(x,y)))
        Next
    Next
  
    Return m
  
End Sub

I suppose I could tweak it to add the functionality of GetColours into BinColours but hey - It's not working yet!
 
Upvote 0

John Naylor

Active Member
Licensed User
Longtime User
Thanks @Erel that's got it.

[Edit] adjusted for b4j too - same result there.
 

Attachments

  • SwatchTest.zip
    447.7 KB · Views: 114
Last edited:
Upvote 0

JordiCP

Expert
Licensed User
Longtime User
The routine you are using produces exactly 8 colors, since each component is reduced to 0 or 128, that is, 2 possible values, so pow(2,3)=8

If you want exactly 16 colors, one of the possibilities is to give a higher 'weight' to the green component, which is the one that usually holds more color information

B4X:
    For x = 0 To bc.mWidth - 1
        For y = 0 To bc.mHeight - 1
            bc.GetARGB(x, y, argb)
            argb.r = argb.r - (argb.r Mod 128)      '<-- results in 0 or 128
            argb.g = argb.g - (argb.g Mod 64)      '<--- will result in 0,64,128 or 192
            argb.b = argb.b - (argb.b Mod 128)    '<-- results in 0 or 128
            bc.SetARGB(x, y, argb)
        Next
    Next

So, you'll have 2*4*2 = 16 possible colors
 
Upvote 1

John Naylor

Active Member
Licensed User
Longtime User
The routine you are using produces exactly 8 colors, since each component is reduced to 0 or 128, that is, 2 possible values, so pow(2,3)=8

If you want exactly 16 colors, one of the possibilities is to give a higher 'weight' to the green component, which is the one that usually holds more color information

B4X:
    For x = 0 To bc.mWidth - 1
        For y = 0 To bc.mHeight - 1
            bc.GetARGB(x, y, argb)
            argb.r = argb.r - (argb.r Mod 128)      '<-- results in 0 or 128
            argb.g = argb.g - (argb.g Mod 64)      '<--- will result in 0,64,128 or 192
            argb.b = argb.b - (argb.b Mod 128)    '<-- results in 0 or 128
            bc.SetARGB(x, y, argb)
        Next
    Next

So, you'll have 2*4*2 = 16 possible colors
Brilliant thank's @JordiCP and everyone else. That seems to have done the trick nicely.
 
Upvote 0
Top