Link to home
Start Free TrialLog in
Avatar of dbrckovi
dbrckoviFlag for Croatia

asked on

Algorythm which will display all RGB colors in a Picture box

Hi!

I need an algorythm which will display RGB colors in a rectangle organised in a color pallete like in Paint or similar program.
I don't need all colors (255*255*255), becouse monitor doesn't have so much pixels, but every n'th color from a pallete, so user can click on a color which they wan't to work with.

If possible, I would like to have an algorythm which will do the oposite thing: when user types in a Red, Green and Blue values, algorythm would return x and y position of that color in a palette ( or the nearest one )

I have been playing with algorythms for some time now, and I managed to get all colors, but they  are not organised as I have expected them to be.
Here's what I have by now:      place 3 buttons and a picturebox on a form
--------------------------------------------------------------------------------------------------------------------------
Private Sub Command1_Click()
    For coly = 0 To 15
        For colx = 0 To 15
            For r = 0 To 255 Step 5
                For g = 0 To 255 Step 5
                Picture1.PSet (r / 5 + colx * 51, g / 5 + coly * 51), RGB(r, g, b)
                DoEvents
                Next g
            Next r
            b = b + 1
        Next colx
    Next coly
    Form1.Caption = "Done"
End Sub

Private Sub Command2_Click()
    For x = 0 To 765
        For y = 0 To 765
            myColor = myColor + 28
            Picture1.PSet (x, y), myColor
        Next y
    Next x
End Sub

Private Sub Command3_Click()
    For x = 0 To 765
        For y = 0 To 765
            myColor = x * y * 28
            Picture1.PSet (x, y), myColor
        Next y
    Next x
End Sub

Private Sub Form_Load()
    Form1.ScaleMode = 3
    Picture1.ScaleMode = 3
    Picture1.Width = 765
    Picture1.Height = 765
    Me.WindowState = 2
End Sub
---------------------------------------------------------------------------------------------

Do you have some other ideas?
Avatar of EDDYKT
EDDYKT
Flag of Canada image

When the user click on the pixel box, just do

Private Declare Function GetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long) As Long


Private Sub Picture1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
On Error Resume Next
Debug.Print GetPixel(Picture1.hdc, X, Y)
End Sub
Avatar of dbrckovi

ASKER

This isn't what I wanted.      I wan't the oposite.

I wan't the function which will give X and Y coordinates of a pixel whoose color matches the given Red, Green and Blue ( or which is the closest to given values )

To be able to do this, I need to create souch picture ( color pallete ) which will be used for containing as much colors as possible.

I can thing of two approaches:
 - To copy and paste souch picture from Paint, but then I don't know the algorythm how was this palette created, so I can't figure the way how to retrieve the position of specific color
    I could create a loop which will look through all colors (pixels) in the picturebox in order to find a match, but this is too slow
 - I coud create my own palette, once, save it as BMP, and the n use it as a picture in picturebox
   That way I would know where my pixels are, and it would be easier to write algorythm which will do the oposite.


P.S. I don't wan't to use already built sollutions in form of ActiveX or similar, becouse I need to be able to transfer this code to other platforms and languages ( Linux, DOS, PS2 eventualy )
Is it easier to use dialogbox?
Right now I'm trying to create a circular pallete, where center would be white, and borders of the circle would be black.

Then I would make 3 loops each would do a full circle around.

First would start at 0 degrees, and loop to 180. At each step it would draw a blue line from center to the top, but with smaller amount of blue each time. At 180 deg it would draw (0,0,0), and then,
again raise the amount of blue from 180 to 360.

I'll do the same for green and red but they would start from 120 and 240 degrees respectively.

I still have no idea how will this look, but at the moment it looks promissing.
It is easier for Visual Basic and Windows-based languages, but other platforms won't support it.

Maybe I should have asked this Q in Programming section, but at the moment I understand Visual Basic the best, so I choose to ask it here.
The one way I can think of is use collection to store the color and location

use RGB as your key for fast search

in order to use collection you should be able to find out the location


ie

Private Sub Command1_Click()
Dim col As New Collection

    For x = 0 To 7
        For y = 0 To 7
           
           
            mycolor = mycolor + 28
           
            col.Add CStr(x & "~" & y & "~" & mycolor), CStr(mycolor)
        Next y
    Next x
For Each a In col
Debug.Print a
Next

It would make a search faster once I have colors organised properly.
But I don't have this at the moment.

Maybe I could paste the pallete from paint and store the colors in array or collection like you mentioned.
But the search would still be noticable without having a function which will calculate the corrext position (maybe in one line)

I started to think about alternatives.

Like in Photoshop. It has 3 scrollbars used to define 3 primary colors ( R,G,B )

But each scroll bar is not painted with one solid color, but with a scale of colors which represents what would the final color be if the slider would be placed to that position.
As I scroll one of the scrollbars, other two would change their color scale accordingly.

Few examples:
1) All 3 scrollbars are set to 0    (Final color is black)
    "Red"       - scrollbar has colors from black to red
    "Green"    - from Black to Green
    "Blue"      - from Black To Blue

2) Red scrollbar is set to 255 while other two to 0       (Final color is red)
    Red        - form Black To Red
    Green     - from red to yellow
    Blue        - from red to magenta

3) All 3 set to 255:                                                   ( Final color is white )
    Red        - cyan to white
    Green     - magenta to white
    Blue        - yellow to white
-------------------------------------------------------------------------------------------------------
I hope you understood what I mean.           (I know it is not the best explanation, but my english is limited)

Can you think of a fast algorythm which will do that?

Even if I make function which will do that, drawing would take too long. Photoshop does calculation + drawing for each bar almost "instantly".
This simple code takes almost 1/2 seconds to execute on my comp, even without any calculation.

    For x = 0 To 255
        For y = 1 To 25
            PSet (x * Screen.TwipsPerPixelX, (100 + y) * Screen.TwipsPerPixelX), RGB(x, 0, 0)
            PSet (x * Screen.TwipsPerPixelX, (130 + y) * Screen.TwipsPerPixelX), RGB(0, x, 0)
            PSet (x * Screen.TwipsPerPixelX, (160 + y) * Screen.TwipsPerPixelX), RGB(0, 0, x)
        Next y
    Next x

How can I make this faster?             I can make dimensions of each bar smaller, but there must other way.

I mean 10 years old games could draw whole screen 10+ times in a second without accelerator, and this puny 3 * 255 * 25  pixels take 0.5 sec's to draw.
I tried declaring x as byte, but then I get Owerflow error on the last     Next x     in a loop.  ????

I guess I'm too tired for this now. More I try, more weird problems I have. I mean, what is wrong with looping a byte from 0 to 255? Isn't a byte's value range from 0 to 255?
Avatar of zzzzzooc
zzzzzooc

>> How can I make this faster?

PSet is slow and if the DC of the object has to constantly redraw what's being painted, it'll be even more slow. Most graphics-intensive applications do their processing of the bits in memory and then paint the image out from memory (a lot faster). If your palette won't be too intensive, you can still use what PSet uses (SetPixel) for appropriate speeds.

Private Declare Function SetPixel Lib "gdi32" (ByVal hdc As Long, ByVal X As Long, ByVal Y As Long, ByVal crColor As Long) As Long
Private Sub Command1_Click()
    Me.AutoRedraw = True
    For X = 0 To 255
        For Y = 1 To 25
            SetPixel Me.hdc, X, (30 + Y), RGB(X, 0, 0)
            SetPixel Me.hdc, X, (60 + Y), RGB(0, X, 0)
            SetPixel Me.hdc, X, (90 + Y), RGB(0, 0, X)
        Next Y
    Next X
    Me.Refresh
End Sub

I checked the times it took for the above and the one you used. (about 0.03 seconds for mine to draw and 0.17 seconds for yours.) So.. about 5x faster and when you work with memory-bitmaps/memory-dcs, it'd probably be more significantly faster.
ASKER CERTIFIED SOLUTION
Avatar of zzzzzooc
zzzzzooc

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks.

The world seems a lot more clearer after a full night sleep.
I completely forgot about line function yesterday. It works even faster than SetPixel.

This is it now:

    For lPosX = 0 To 255
            lRGB1 = RGB(lPosX, HScroll1(1).Value, HScroll1(2).Value)
            lRGB2 = RGB(HScroll1(0).Value, lPosX, HScroll1(2).Value)
            lRGB3 = RGB(HScroll1(0).Value, HScroll1(1).Value, lPosX)
            Call SetPixel(Picture1(0).hdc, lPosX, lPosY, lRGB1)
            Call SetPixel(Picture1(1).hdc, lPosX, lPosY, lRGB2)
            Call SetPixel(Picture1(2).hdc, lPosX, lPosY, lRGB3)
            Picture1(0).Line (lPosX * 15, 0)-(lPosX * 15, 20 * 15), lRGB1
            Picture1(1).Line (lPosX * 15, 0)-(lPosX * 15, 20 * 15), lRGB2
            Picture1(2).Line (lPosX * 15, 0)-(lPosX * 15, 20 * 15), lRGB3
    Next lPosX

I still don't understand why byte won't loop from 0 to 255, but I'll ask it in another question.
>> I still don't understand why byte won't loop from 0 to 255

After x reaches 255, it'll execute "Next x" and then be directed to the For statement where it will stop since it has reached 255. However, when it reaches "Next x", it'll still increment to 256 before getting to the For statement.. the reason for your overflow.

This will error:
    Dim x As Byte
    For x = 0 To 255
       
    Next x

This will not since we exit For before it reaches "Next x":
    Dim x As Byte
    For x = 0 To 255
        If x = 255 Then
            MsgBox "Reached 255.. manually exit For"
            Exit For
        End If
    Next x


Btw, you should have asked more in this question if you weren't fully satisfied (Grade B).
I originaly wanted an algorythm which will create a color pallete and one or two functions which will be able to calculate x and y positions of desired color ( without searching )
But noone responded to this.  EDDYKT scratched the surface of the problem, but it wasn't what I wanted.

This 3-scroll bars sollution is only an alternative.

I gave it a B grade only becouse it is not the answer to my original question.

I'll make up for this "point-loos" by accepting the other 0-255 question.
>> I gave it a B grade only becouse it is not the answer to my original question.

Understandable but you could have asked for more. :) I don't have any problem expanding.

>> I'll make up for this "point-loos" by accepting the other 0-255 question.

I have no worries about the points. Was just curious about your grade.

Good luck.
>> I have no worries about the points. Was just curious about your grade.

Since all PAQ-ed questions go in search, someone may look for this, and then find out that answer is not what was originaly asked.
"B" grade will tell them that answer may not be wxactly what they expect.

No hard feelings!

Regards!
Title:
"Algorythm which will display all RGB colors in a Picture box"

Question:
"...I don't need all colors "

They wouldn't have found out anyways since your question doesn't match the title. 16 million pixels in a PictureBox.. :P No worries at all though. As said, I understood the reason for the grade after you mentioned it to me. My last reply.