473,471 Members | 2,017 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Colour functions - RGB -> Greyscale (sloooww~...)

Robbie
180 New Member
Hi. I've made 2 functions which play around with colours.
They convert a 'colour number' (I don't know what the proper name for it is, so I call it this - the Long given back by RGB(), object.BackColor, etc, which represents a value of red, green and blue) into another 'colour number' but this is a greyscale version of it.

There are 2 functions - the first one 'decodes' the 'colour number' into the separate R G and B values. The second one uses these 3 values to create a single shade of grey from 0 to 255, and use VB's RGB() function to turn this into a true 'colour number' again.

These functions are part of a module which has 4 Global Longs:
ReturnR, ReturnG, ReturnB and ReturnY (Red, Green, Blue and Greyscale - they all range from only 0 to 255, but are Longs because they're faster, and the memory which would be saved by using Bytes is not really worth the loss in speed). These 4 Longs are set by functions which deal with colour.

This sub takes a 'colour number' and sets the R G and B Longs to what the 'colour number' represents:
Expand|Select|Wrap|Line Numbers
  1. Public Sub ColourToRGB(ColourNumberToConvert)
  2. 'WHEN THIS FUNCTION HAS FINISHED, THESE VARIABLES WILL
  3. 'GIVE YOU THE R, G AND B VALUES OF THE ORIGINAL COLOUR NUMBER:
  4. 'ReturnR - 0 -> 255 = Red value
  5. 'ReturnG - 0 -> 255 = Green value
  6. 'ReturnB - 0 -> 255 = Blue value
  7.  
  8.     Dim NumberLeftSoFar As Long
  9.     NumberLeftSoFar = ColourNumberToConvert
  10.  
  11.     ReturnB = Fix(NumberLeftSoFar / 256 / 256)
  12.     NumberLeftSoFar = NumberLeftSoFar - (ReturnB * (256 ^ 2))
  13.     ReturnG = Fix(NumberLeftSoFar / 256)
  14.     NumberLeftSoFar = NumberLeftSoFar - (ReturnG * 256)
  15.     ReturnR = NumberLeftSoFar
  16.  
  17. End Sub
This next function uses the one above to find out the R G and B values and work out a greyscale from them, and returns the greyscale 'colour number':
Expand|Select|Wrap|Line Numbers
  1. Public Function ColourToGreyscale(ColourNumber) As Long 'Long for speed!
  2. 'Convert a single pixel 'in colour' to greyscale
  3. 'It needs to be given the colour number, and will
  4. 'give back a colour number too.
  5. '
  6. '[Colour number] - a number given back by GetPixel(),
  7. 'RGB(), [object].BackColor, etc.
  8.  
  9.     ColourToRGB ColourNumber
  10.  
  11.     ReturnY = (ReturnR * 0.299) + (ReturnG * 0.587) + (ReturnB * 0.114)
  12.     ColourToGreyscale = RGB(ReturnY, ReturnY, ReturnY)
  13.  
  14. End Function
The functions work fine, but they are quite slow, and painfully slow when dealing with fairly large images.
To convert a whole picture (i.e. using the PictureBox), I call GetPixel over and over within 2 loops, CurrentScanX and CurrentScanY:
Expand|Select|Wrap|Line Numbers
  1.     Dim CurrentColour As Long
  2.     Dim CurrentScanX As Long
  3.     Dim CurrentScanY As Long
  4.  
  5. Dim UsingPicObj As PictureBox
  6. Dim UsinghDC As Long
  7. Set UsingPicObj = LoadedPic
  8.     UsinghDC = UsingPicObj.hDC
  9.  
  10. '- - - - - GREYSCALE AND STORING IMAGE
  11. '(Note, UsingPicObj's scalemode is set to 3, pixel)
  12.     For CurrentScanY = 0 To UsingPicObj.ScaleHeight - 1
  13.         For CurrentScanX = 0 To UsingPicObj.ScaleWidth - 1
  14.  
  15.             CurrentColour = GetPixel(UsinghDC, CurrentScanX, CurrentScanY)
  16.             UsingPicObj.PSet (CurrentScanX, CurrentScanY), ColourToGreyscale(CurrentColour)
  17.             If ReturnY < MinColour Then MinColour = ReturnY
  18.             If ReturnY > MaxColour Then MaxColour = ReturnY
  19.             PictureY(CurrentScanX + ((CurrentScanY + 1) * UsingPicObj.ScaleWidth)) = ReturnY
  20.  
  21.         Next CurrentScanX
  22.  
  23.     DoEvents
  24.     Next CurrentScanY
Note that as it's going through the X / Y loops, I'm also storing the greyscale value (0 -> 255) in a big array (PictureY) representing the greyscale of all pixels in the image. I use ReDim to make the array the correct size based on the width and height of the picture, before any of this happens.
Also I am storing the smallest and largest values of the greyscale in the picture.

To be able to use the GetPixel function, you need to declare it from a common Windows DLL:
Expand|Select|Wrap|Line Numbers
  1. Declare Function GetPixel Lib "GDI32" (ByVal hDC As Long, ByVal x As Long, _
  2.     ByVal y As Long) As Long

I've posted the code here in the hope that someone can think of any way at all to speed this up.

But, also I hope that it can benefit some people who need help working with colours. I also have a function to convert RGB -> HSV, if anyone is interested, but I don't need help with that so I won't post it.
(Maybe this could eventually become a VB article...?)

(By the way, this is in VB6)
Jul 7 '07 #1
6 2692
Killer42
8,435 Recognized Expert Expert
Hi Robbie.

I'm at work and due to finish lunch, so I can only make a couple of quick comments for now. Should be able to look through this in more detail this evening at home (I hope).
  1. Constants are faster then literals.
    In other words, where you are using 256, for example, use a named constant (Long type) whith a value of 256.
  2. Constants are a lot faster than calculations.
    Where you are doing things like = NumberLeftSoFar - (ReturnB * (256 ^ 2)) You should create a constant to use in place of "256 ^ 2". Not only is it much slower doing a calculation every time, but if I remember correctly, "powers" are a relatively slow calculation.
  3. Make sure your image has Scalemode = Pixel (3, I think). You should only be dealing with the visible pixels. If you are dealing with twips, you are probably doing something like 225 times as much work as necessary. This depends on your screen resolution, and possibly other things.
  4. As long as it works (test it first) integer division is generally faster.
    In other words, use "\" instead of "/" if the result you want is an integer (whole number) value.
  5. Lines 14 and 15 of your first Sub should be combined. You don't need to place the value into NumberLeftSoFar - just shove it straight into ReturnR and save one step.
  6. You will eventually run into a bug that I hit when playing with this stuff a while back. There are values which you cannot split up this way. That's because they are actually larger then a three-byte value. These are the "system colours", representing things like "window background" or "button face". There is a simple way to translate them to an actual colour value, but I don't recall it now. Don't worry though, we'll find it.
By the way, where did you get the weighting values from (the 0.299 and so on)? I've been wondering about them for a while, but keep forgetting to look them up.
Jul 9 '07 #2
Robbie
180 New Member
Hi Robbie.

I'm at work and due to finish lunch, so I can only make a couple of quick comments for now. Should be able to look through this in more detail this evening at home (I hope).
...
By the way, where did you get the weighting values from (the 0.299 and so on)? I've been wondering about them for a while, but keep forgetting to look them up.
Thanks!

I'm using constants now and have fixed the pointless lines 14 and 15.
I'm already using ScaleMode 3 (vbPixel) (although I did mention that in a comment of code before ^^;).

Integer division (a \ b) instead of Fix(a / b) resulted in some weird stuff. Different combinations of using it on the 2 lines involved everything turning out except for very light colours (they got converted to black), and ReturnR and ReturnG ending up less than 0, but seemingly a correct number (just -Number). Although it was a little faster.

I think I'm okay with not worrying about running into those System Colours, since I'm only using the function on colours returned by GetPixel(). But thanks for the warning on that in case I go on to use it for other things.

Sorry, I can't for the life of me remember where I got those weighting values. It was a site which was demonstrating how to convert colour to greyscale (you probably could've guessed :P) in some programming language (I think it wasn't VB). They were apparenly the values which worked best for that person.

However, I've found an article on Wikipedia which mentions values extremely close (probably just rounded):
http://en.wikipedia.org/wiki/Grayscale

Also if you're interested, I've found some weighting values for converting to Sepia tones:
http://en.wikipedia.org/wiki/Sepia_tone
Jul 9 '07 #3
Killer42
8,435 Recognized Expert Expert
Thanks for the info.

I guess I missed the reference to pixels in the comments. Like I said, I was in a hurry.

I hope to have time to look into this a bit more tonight, after work. I have done some similar stuff, and don't recall it being terribly slow. But then, I guess "slow" is a very subjective thing, and also depends on what you're doing (not to mention your hardware and what else is running on it).

I must have a look at those links when I have time.

Sorry to hear the integer division didn't work out.

As for the system colours, just try to keep it in the back of your mind, so when you eventually hit a weird negative (or impossibly large) colour value, you know what to look for. Also, I wondered - is there a particular reason why you used the API GetPixel function rather than VB's .Point method? (Note, Point does return system colours, so perhaps I should be avoiding it.)

Oh, yeah - I remember now. I wrote an assembler routine to pick apart a colour value into R/G/B components. Can't recall whether it was faster, though. I'll see whether I can track it down.
Jul 10 '07 #4
Killer42
8,435 Recognized Expert Expert
Sorry, in a rush again.

However, here's a quick sample I threw together. (It's probably exactly the same as what you've done). It seems reasonably quick, but hasn't been extensively performance-tested. This is the complete code module...

Expand|Select|Wrap|Line Numbers
  1. Option Explicit
  2.  
  3. ' Values produced...
  4. Public Red As Long, Green As Long, Blue As Long
  5.  
  6. ' Constants used in the calculations...
  7. Private Const GreenWeight As Long = &H100
  8. Private Const BlueWeight As Long = &H10000
  9.  
  10. Public Sub SplitColour(ByVal Colour As Long)
  11.   Blue = Colour \ BlueWeight
  12.   Colour = Colour - Blue * BlueWeight
  13.   Green = Colour \ GreenWeight
  14.   Red = Colour - Green * GreenWeight
  15. End Sub
Jul 10 '07 #5
Killer42
8,435 Recognized Expert Expert
You should specify the input parameters for your subs as Long. You haven't, so they are probably defaulting to Variant. Variants are considerably more "expensive" to deal with, so fixing this may provide a bit of a boost.

I would also lose the DoEvents between your two Next statements. Unless you really need the time-out for some visual feedback or something, it's just slowing things down. Perhaps do one at the end of the sub, in case it's called multiple times.
Jul 10 '07 #6
Killer42
8,435 Recognized Expert Expert
I don't know whether it will be of any interest, but here's a little program I wrote a year or two back to try and replicate the fade-to-grey effect that XP does when you say to shut down or log off. It's VB6 and should be self-contained. You ought to be able to load it into VB editor and run.
Attached Files
File Type: zip PicFader.zip (9.2 KB, 118 views)
Jul 11 '07 #7

Sign in to post your reply or Sign up for a free account.

Similar topics

129
by: Torbjørn Pettersen | last post by:
I've started cleaning up my HTML and implementing CSS. So far I've used FrontPage, but am switching over to DreamWeaver. Reading a bit on W3Schools.com and W3.org I see there are a lot of HTML...
9
by: Raj | last post by:
Hello Members, I wrote a program to convert a greyscale bitmap image in to monochrome bitmap image, a simple thresholding. Input:Greyscale image; Expected Output:Monochrome image Pseudocode:...
9
by: al jones | last post by:
Sorry, it's getting late and I'm tired. I'm trying to fill a richtect box with text derived from the array I was asking about earlier (thank you). I'm not sure what I'm seeing - since most of...
17
by: Sara | last post by:
Hi, I'm having a problem with my program and I think it stems from me not understand how to call a function and return a int value to main. What I have to do is create a program that runs...
1
by: JSievers | last post by:
Hallo. A good friend of me develops web suites, for example his own at: www.augenpunkte.de. As you can see there my friend is blind and also he uses a Braille-line to develop these projects. For...
1
by: tiwariprakash | last post by:
Hi I am trying to change the colour of cells based on the values of 2 other cells but I couldn't get the right VBA code for Excel 2003. Could you please help me with the following conditions: if...
23
by: Stanimir Stamenkov | last post by:
I want to find out whether the following usage of the "Bookmark" link type is o.k. An example could be seen at <http://www.geocities.com/stanio/more/horoskop.html>. The text is in Bulgarian and...
24
by: Chris F.A. Johnson | last post by:
On 2008-07-09, Denis McMahon wrote: If the left-hand column contains any text, use em rather than px to size it. In CSS, less is more. Most problems are caused by specifying too much rather...
0
by: Chris Rebert | last post by:
On Wed, Nov 19, 2008 at 11:24 PM, Barak, Ron <Ron.Barak@lsi.comwrote: As I believe someone else pointed out recently in a extremely similar thread, GzipFile apparently doesn't check that the...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and...
0
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.