Archive for the ‘computer programming’ Category.

Red-Green-Blue To Red-Yellow-Blue - Part 1

I already solved this once, a long while back.  And it was handy code to have.  But unfortunately I lost the code.  So now I’m re-solving the problem.  How do you convert from a red-green-blue color scheme (that typically used by computers) into a red-yellow-blue “primary colors” color scheme (that typically used by artists)?

I guess I should explain why this is useful.  From the time we’re born our mommies and daddies give us primary colors of red, yellow, and blue.  And we know that yellow and blue make green.  And that the opposite of red is green.  They’re complementary colors.  Anyone who has ever painted, drawn, etc. knows it.  Anyone who has ever taken even a basic art class knows it.  Heck, anyone who’s ever peed into a toiled filled with blue water knows it.  Primary and secondary colors are all around us.  From the day we’re born to the day we die, it’s the color system we know like the backs of our hands.

But those of us who have done graphics work on computers know that colors don’t work that way … on a computer.  Computers don’t use this color system.  Computers use a red, green, and blue color system.  It’s based on light wavelengths.  Red plus green makes yellow.  The opposite color of red is cyan, not green.  (Hence the other related color system based on the opposites of rgb: cyan, magenta, and yellow or cmy.)  It makes sense to anyone who understands light wavelengths, like a scientist.  But to a graphical artist trying to do work on a computer it can be downright confusing if not insanely ludicrous.  I mean just try taking your painting and doing a color inversion.  It doesn’t come out anything like you’d expect.  Your years of artistic knowledge completely fail you when you hop onto a computer.  All because computer monitors are based on light, so computers have always, from the very beginning, been designed in a way to display the proper images on your monitor; not to help you paint a picture.

Now you’d think that every graphics program ever written would therefor have a way to switch from the rgb color system to the ryb color system, because surely graphical artists use graphics programs, right?

Strangely, I’ve yet to see it.  Granted, it’s been a while since I looked at the biggies like Photoshop and Paint Shop Pro (I have used both in the past).  These days I’ve been using GIMP, because it’s free, and once you get used to the eccentricities, it’s darn near as good as Photoshop at nearly everything.

But where I’ve really needed it is in writing GUIs.  Say you’ve got a GUI where you’re describing a crystal.  You want a way to pick the crystal’s color.  You make buttons to choose colors.  Well the names of the colors on the buttons is great, but wouldn’t it be even neater to colorize the buttons themselves?  It’s easy enough to do.  (At least when using Trolltech’s Qt.  MFC makes it a tad more of a challenge.)  So you set the background color of the button widgets to the color defined by the button text.  It’s insanely easy, and pretty effective … for most colors.  But then there’s that nagging problem, some background colors make black text kind of hard to read.  Especially, you know, black.  Black on black is a bit of a challenge to read.  So you want to make the text always a good color.

Now, you can write an algorithm to calculate the luminosity of the rgb value and determine if white or black would contrast more against the button.  Which works.  But it’s kind of a … kluge.  It doesn’t look nearly as professional as it should.

So you take it one step further.  You use an algorithm to get the contrasting color of the rgb value.  It works.  But looks positively awful.  Because scientifically we know the opposing light wavelength to red is cyan, artistically, our whole life tells us that the opposite color of red is green.  And so the rgb-inverse method grates on our sensibilities.  It makes for readable text, but psychologically drives us nuts.

Which is what brings us to the ultimate solution: a rgb to ryb color system change.  Because once we work in an ryb color system, then the inverse of red really is green.  It does wonders for our GUIs, making the text readable and comforting in its simple “rightness”.  And maybe one day it’ll bring relief to graphical artists on computers when you can switch from rgb to ryb in GIMP or Photoshop and suddenly everything makes sense.

So that’s the explanation.  What’s the solution?  I did it once before.  I know I can solve it again.  Here’s what I’ve got so far just scrawling on some paper:

Step 1: Remove the luminosity.   I remember this clearly.  I remember in my first attempt at solving this years back, it took me a while to figure out that you really absolutely need to do this first and foremost, or else your colors will come out in all of the wrong shades.  This part is simple.  Given that red, green, and blue are input variables for your rgb color that you’re converting into an ryb system:


white = min(red, green, blue)
red -= white
green -= white
blue -= white

Now your rgb values contain no white value in them.  You’re working on converting pure color.  So you can take the next step, determining how much raw yellow there is, and how much of the green value is actually representative of the color green:


yellow_part = min(red, green) # In rgb red and green combine in equal parts to make yellow.  So we have to determine how much yellow there is.
green_part = max(0, green - yellow_part) # Now that we know how much yellow there is, we can take the raw yellow away from the green value to determine how much raw green is truly in the green value.

This next step I haven’t tested out yet.  I know that I’m not 100% certain that it’s a final solution because I know that at the very least I haven’t normalized the end values back into the proper scale.  What do I mean?  Well in an ryb system green is essentially yellow plus blue.  But we also have a blue value.  So in a worst-case scenario, we have a maximum blue value of 1/2 green plus blue.  In OpenGL where you’ve got a component scale of 1.0 maximum in rgb, this means blue could have a maximum value of 1.5 in ryb.  So you’ve got to re-scale the values after converting their components.  As I said, I don’t have that worked into the formula yet, but I do have part of the formula:


half_green = green_part / 2 # We know that green needs to be divided into equal parts of blue and yellow, so to optimize the code we calculate half of the remaining green component.
red = red - yellow_part
yellow = yellow_part + half_green
blue = blue + half_green

So at this point you should have the raw component color parts of a red, yellow, and blue color system.  Next up is normalizing the values back to the same scale as was used in the rgb system, and then putting the luminosity back in by re-adding the white value.  Do this and you should be done converting rgb to ryb.  Sometime when I get around to reinstalling Python + PyQt and/or some version of Visual Studio on my computer I may even get around to finishing the conversion code (and testing) in a follow-up Part 2 blog entry.

Examples Of My Work

I know I don’t often discuss what I do.  Lately I’m working by contract.  But let me give you an idea of some of the work that I’ve done in the past at Bruker AXS Inc.  In that I wanted it to be a page that’s attached to my advertisement for myself, I’m going to give you a link now to that page.

Examples of my work.

It gives you a fair idea of the kind of neat work I did, a lot of which were 3D visualization tools for single crystal x-ray diffraction data.  Of course I also got to play with other neat things, like software for ACOS smartcards, software for controlling a liquid nitrogen low-temperature crystal cooling device, software for network camera streaming, and all sorts of cool geeky stuff.  But if there’s one thing that I take pride in, it’s my ability, my drive, to create intuitive easy-to-use GUIs that make customers happy and give them the confidence to use the software to its fullest.

Documentation - Programmers PLEASE Internally Document Your Code!

Okay, so basically, this is just another rant in the long line of rants that no one listens to in life. Still, it’s my blog and if I want to rant, I can. So nya!

For a while I’ve had my head buried in someone else’s code. Ugh. Yeah. We’ve all been there. (We as in programmers at least.) When you’re lucky there’s good use of whitespace, good use of descriptive naming, and so the code pretty much documents itself. If you’re really freaking lucky there’s even enough comments added to the code that you get a good idea of what’s going on. And if you’re really really lottery-winning damned lucky there’s clear and concise internal documentation.

I admit, I’m not always nice enough to go the whole nine yards. Sometimes I skimp, because the code working is more of a priority than the code being maintainable.

But still, I’m a nice guy. I’ve been around the block long enough to know that I won’t always be the one maintaining my code. And sometimes even when I am, code can get complex enough that I won’t necessarily remember all of the ins and outs a year or two later. So I generally make an effort to internally document my code.

I wish everyone was as nice.

As I said, I had my head buried in someone else’s code. Code that, while (mostly) functional, is only a step away from the vagueness of formulaic programming. Code that (and mind you, this is in Python) uses lists (Python’s version of arrays) to store random variables in, like they were freaking FORTRAN common blocks! And I’m not even sure the author knew what a comment character looked like when he wrote it all.

Yes, it was that nerfed. No, I’m not exaggerating. Ye gods I wish I was.

And all I could think about as I added internal documentation and renamed variables to be self-documenting as I wheedled my way deeper and deeper into the code that wasn’t working right, was “Why the hell couldn’t this code be a little easier to maintain?!

Ugh.

Still, having once upon a time, strangely timed right before male pattern baldness and grey hairs began creeping in, I had the joy of performing tasks like converting 16-bit x86 Assembly code to 32-bit and finding C++ libraries that could replace as much of the Assembly code as possible. Assembly code that wasn’t documented. Used in FORTRAN 76 code with that reverse if-goto logic because it didn’t have if-then-else logic yet. FORTRAN code where sometimes the authors commented according to that reverse logic, and sometimes according to modern order … only without saying so. So you never knew if a comment was explaining as it was, or as it should be - but wasn’t. FORTRAN code with common blocks that didn’t even always match up correctly. And spaghetti goto and continue statements all over the place. That in turn used the undocumented Assembly code.

I think it’s safe to say I’ve seen hell. And so my recent delve into someone else’s Python code could at least be said to be more like purgatory. Or maybe more like the second or third circle of Dante’s hell.

And then as I returned to some of my own code to work on adding new features, I found this lovely refreshing oasis of reason and sanity.

If there’s one message, even just one little message, that I could get across to all computer programmers the world over, it is this:

DOCUMENT YOUR DAMN CODE!!!

Thank you.

Python - Not Quite Perfect … But Darn Good

For the last few years I’ve been working heavily in the Python programming language. It’s an absolutely wonderful language and I do love it so. Besides forcing good indentation practices and being otherwise good with whitespace, it also is a wonderfully clever little language with many neat tricks that a seasoned programmer can appreciate.

However, it’s not all sunshine and lollipops.

For being an interpreted language, most of it runs quite fast. And where its speed does fail, there’s always writing libraries in C++ and then wrapping it in Python to use in your Python code. So most of the time it has a wonderful performance if you know what you’re doing.

Just recently though, while working on some string code to remove ASCII characters 128-255 from strings, as these beyond-standard-ASCII characters don’t translate to Unicode, I am reminded of one of Pythons massive failings. It handles strings for sh_t.

Don’t get me wrong. Python has all sorts of neat methods and functions for string manipulation. It’s quite handy really. But it’s s…l…o…w. Something about the way that Python assigns a new string variable is just darn slow. And nearly every string operation requires you to assign a new string variable as each function / method returns a string that is your results. So when all of your functions return a new string, and creating new strings in Python is slow … you see how this is a very bad combination.

For example, the code I was working on. A really neat Pythonic way of doing things results in the function:

def stripBadASCII1(contents):
    if not contents: return contents
    return “”.join([c for c in contents if ord(c) < 128])

This strange looking code goes through contents character by character and only joins the characters below ASCII 128 to the returned string. Simple. Neat. Effective. But keep in mind, the way Python works, for each new character joined to the string, it has to create a whole new string. And in Python this is molasses in January slow.

Now another method, a little more mundane in concept, goes like this:

def stripBadASCII2(contents):
    if not contents: return contents
    for i in range(128,256):
        contents = contents.replace(chr(i), “”)
    return contents

You see, the concept of this one is easier to follow. It replaces all bad ASCII characters in the string with an empty string, which effectively strips those characters from the string. Looping 128 times through the string for each bad ASCII character. Ugly. Messy. And yet, because it moves string contents in chunks instead of character by character, the number of new string operations is greatly reduced. So even though it loops 128 times through, where as the other function only executes once, it still manages to run faster for all of its seemingly slow 128 loops.

When I ran function 1, the character by character approach, through the contents of a test file typically used in the code this function is being written for, on average it took about 0.1 seconds.

When I ran function 2 through the same contents, using the seemingly slower 128 loop approach, it took on average 0.06 seconds.

Okay, so four hundredths of a second doesn’t seem like much of a difference. But the longer the string processed through these functions, the larger that difference will get. And more to the point, this my friends is how bad Python is at handling strings. A single pass through, character by character, is almost twice as slow as 128 loops through with chunks of characters processed together. Ouch. This certainly isn’t the C++ approach to strings.

So that’s one of Python’s major failings, is it’s string handling performance. Python has another major performance failing as well. Even though it can create and manage threads, it doesn’t ever use more than one processor. So if you have a multi-core CPU, you only use one core. If you have a multi-processor PC, it only uses one processor. If you have a dual CPU quadcore PC with a total of eight cores, it still runs on just one core of one processor. No matter how many threads your Python code contains. Ouch!

In fact, because of the overhead of thread management, and because it only runs on one CPU, Python actually runs slower the more threads you give it to handle. Yikes!

In the old days when multi-CPU computers were rare and multiple cores per CPU was unheard of, this was not a problem. Today is not those old days. Today two, three, and four core CPUs are common for desktops. Heck, I just built my hun’s new budget computer with a dualcore Celeron. So more than anything, this is really an issue Python needs to fix, and soon. They’ve put this one off far too long already.

A workaround is to try and develop your code as multi-process not multi-threaded. Or in other words break the program down into independent sub-programs that the main program can spawn as needed. There are memory sharing techniques that can be used for inter-process communication. It’s ugly. It’s messy. But being independent Python processes, they should spread across multiple CPUs/cores like a normal multi-threaded program would. Still, it’s very far from an ideal solution. It is just another messy workaround.

So that, my friends, is the down side of Python. It’s a wonderful language, but no language is perfect. They each have their own strengths and weaknesses, and Python is no exception.