# B4J Question[Solved] Wand tool

#### jroriz

##### Active Member

to

Is it possible to create something like a wand tool?

I need to change all the yellow pixels, and then pixels "close to yellow", to black.
Then all the rest to white.

I was trying using BitmapCreator, and comparing pixel by pixel. But i could not figure out how to detect a range of pixels that are close to yellow.

I think this is a hard one...

#### Roycefer

##### Well-Known Member
There are a few ways to think about the "closeness" of a color to another color. A simple method that might work for you is to consider the RGB color space as a 3-dimensional euclidean space and just calculate distances using Pythagorean Theorem:
B4X:
``Dim colorDist As Double = Sqrt(Power(r1-r2,2)+Power(g1-g2,2)+Power(b1-b2,2))``
Then you can select a maximum permissible distance.

There are more sophisticated ways that involve conversion to HSB color space or treating RGB color space as a vector space and taking inner products. If the Pythagorean Theorem method doesn't suit your needs, we can explore the more sophisticated solutions.

Note that in the example picture you posted, the non-yellow pixels are all black. If this is representative of the real images you have to use, then it will be easier to just detect black pixels and turn them white and non-black pixels to black.

#### MarkusR

##### Well-Known Member
But i could not figure out how to detect a range of pixels that are close to yellow.
yellow is just red+green

#### Sandman

##### Well-Known Member
It might help more if you described how you plan to use the resulting image. I come from a Photoshop background (GIMP nowadays) so I tend to think more in that way than a strictly mathematical way that @Roycefer described.

So, if you plan to use the resulting image as something you just display or perhaps place on top of another image, I would do this to get a perfect result.

1. Starting image

2. Throw away all colour, making it grayscale

3. Invert it

4. Adjusting the Levels by setting the background to white (this is not same as working with brightness, the latter destroys image data, Levels ”stretches” the available data)

(In this specific case I didn't have to set the blackpoint, the yellow was good enough to work with)

5. And, if that's what you’re aiming for, multiplying the image into another picture:

#### MarkusR

##### Well-Known Member
it would look better with a lossless format like png.
grey = (r+g+b) / 3

B4X:
``````Sub Process_Globals

Private xui As XUI
Private ImageView1 As ImageView
Private ImageView2 As ImageView
...

Sub Test

Dim Bitmap1 As B4XBitmap = xui.LoadBitmap(File.DirAssets,"clock.png")

ImageView1.SetImage(Bitmap1) '< a ImageView in layout

Dim bc As BitmapCreator
bc.Initialize(Bitmap1.Width,Bitmap1.Height)
bc.CopyPixelsFromBitmap(Bitmap1)

Dim x As Int
Dim y As Int
Dim pixel As ARGBColor
For x = 0 To bc.mWidth-1
For y = 0 To bc.mHeight-1
bc.GetARGB(x,y,pixel)
If pixel.r > 64 And pixel.b < 64 Then
pixel.r = pixel.r / 2
pixel.g = pixel.g / 4
pixel.b = pixel.b / 4
Else
pixel.r =255
pixel.g =255
pixel.b =255
End If
bc.SetARGB(x,y,pixel)
Next
Next

ImageView2.SetImage(bc.Bitmap) '< a ImageView in layout

Bitmap1 = bc.Bitmap
Dim Out As OutputStream
Log(File.DirTemp)
Out = File.OpenOutput(File.DirTemp, "Output.png", False)
Bitmap1.WriteToStream(Out, 100, "PNG")
Out.Close

End Sub``````

Last edited:

#### jroriz

##### Active Member
There are a few ways to think about the "closeness" of a color to another color. A simple method that might work for you is to consider the RGB color space as a 3-dimensional euclidean space and just calculate distances using Pythagorean Theorem:
B4X:
``Dim colorDist As Double = Sqrt(Power(r1-r2,2)+Power(g1-g2,2)+Power(b1-b2,2))``
Then you can select a maximum permissible distance.

There are more sophisticated ways that involve conversion to HSB color space or treating RGB color space as a vector space and taking inner products. If the Pythagorean Theorem method doesn't suit your needs, we can explore the more sophisticated solutions.

Note that in the example picture you posted, the non-yellow pixels are all black. If this is representative of the real images you have to use, then it will be easier to just detect black pixels and turn them white and non-black pixels to black.
It was perfect, using the first suggestion (from Roycefer). I did not test the others, but I greatly appreciate it!
The result was better than I expected.
The code I got is below. If anyone can improve it, I'm grateful.
Thank you all. This forum is simply fantastic!

Final code:

B4X:
``````Sub Clean(Whichcolor As Int, bc As BitmapCreator)

Dim x, y As Int
Dim ProtectedColor, ARGB As ARGBColor

bc.ColorToARGB(Whichcolor, ProtectedColor)

For x = 0 To bc.mWidth-1
For y = 0 To bc.mHeight-1

bc.GetARGB(x, y, ARGB)
Dim colorDist As Double = Sqrt(Power(ProtectedColor.r-ARGB.r,2)+Power(ProtectedColor.g-ARGB.g,2)+Power(ProtectedColor.b-ARGB.b,2))

If colorDist > 200 Then
bc.SetColor(x,y,xui.Color_White)
Else
bc.SetColor(x,y,xui.Color_black)
End If
Next
Next

End Sub``````
How to call: Clean(xui.Color_white, bc), where bc is bitmapcreator.

Last edited: