Recently I was asked to make a control for a button similar to the Windows 7 taskbar buttons. I needed to pull the dominant color. To meet our needs, we had to do the following:
> Skip any pixels which are black, white, or have an alpha of 0
> Weight the remaining pixels by their alpha. If there's alot of blue, but it's partly transparent, it should be weighted less then a red color which was fully opaque.
> Round the RGB values to the nearest 10. So an RGB of 215,215,82 would count as 220,220,80. Visibly, there's not much difference, but it deals with instances where there's only a little bit of blue, and alot of red, but the red comes in many similar shades.
Quickly, this is what I finally came up with. The
RGBIndex
processes the bitmap with the
GetDominantColor
function, and holds the color tallys in the Items collection. The indiviual
RGBItems
contain the RGB values and counts.
There is some math that's done to handle the rounding to 10s which would not be necessary if you changed it to give each RGB it's own index.
Public Class RGBIndex
Public Items As New Collection
Public Sub AddItem(ByVal R As Integer, ByVal G As Integer, ByVal B As Integer, ByVal Count As Single)
If (R = 0 And G = 0 And B = 0) Or (R >= 25 And G >= 25 And B >= 25) Then
Exit Sub
End If
For Each i As RGBItem In Items
If i.R = R And i.G = G And i.B = B Then
i.Count += Count
Exit Sub
End If
Next
Dim i2 As New RGBItem(R, G, B, Count)
Items.Add(i2)
End Sub
Public Function GetDominantColor(ByVal Image As Bitmap) As Color
If Image Is Nothing Then
Return Color.White
End If
For i As Integer = 0 To Image.Width - 1
For j As Integer = 0 To Image.Height - 1
Dim c As Color = Image.GetPixel(i, j)
If c.A = 255 Then
AddItem(c.R / 10, c.G / 10, c.B / 10, c.A / 255)
End If
Next
Next
If Items.Count = 0 Then
Return Color.White
End If
Dim Dominant As RGBItem = Items(1)
For Each i As RGBItem In Items
If i.Count > Dominant.Count Then
Dominant = i
End If
Next
Return Dominant.ReturnColor
End Function
End Class
Public Class RGBItem
Public R As Integer
Public G As Integer
Public B As Integer
Public Count As Single = 0
Public Sub New(ByVal R1 As Integer, ByVal G1 As Integer, ByVal B1 As Integer, ByVal Count1 As Single)
R = R1
G = G1
B = B1
Count = Count1
End Sub
Public Function ReturnColor() As Color
Dim R1 As Integer = 10 * R
Dim G1 As Integer = 10 * G
Dim B1 As Integer = 10 * B
If R1 > 255 Then
R1 = 255
End If
If G1 > 255 Then
G1 = 255
End If
If B1 > 255 Then
B1 = 255
End If
Return Color.FromArgb(R1, G1, B1)
End Function
End Class
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.