Smooth color conversion algorithm

I am looking for a general algorithm for a smooth transition between two colors.

For example, this image is taken from Wikipedia and shows the transition from orange to blue.

enter image description here

When I try to do the same with my code (C ++), the first idea that came to mind was to use the HSV color space, but the annoying display between the colors.

enter image description here

What is a good way to achieve this? Does this seem to be due to a decrease in contrast, or perhaps using a different color space?

+8
c ++ colors
source share
5 answers

In the past, I have done a bunch of such things. Smoothing can be done in different ways, but the way they are probably doing it here is a simple linear approach. This means that for each component R, G and B, they simply calculate the equation "y = m * x + b", which connects the two points and uses this to find the components between them.

m[RED] = (ColorRight[RED] - ColorLeft[RED]) / PixelsWidthAttemptingToFillIn m[GREEN] = (ColorRight[GREEN] - ColorLeft[GREEN]) / PixelsWidthAttemptingToFillIn m[BLUE] = (ColorRight[BLUE] - ColorLeft[BLUE]) / PixelsWidthAttemptingToFillIn b[RED] = ColorLeft[RED] b[GREEN] = ColorLeft[GREEN] b[BLUE] = ColorLeft[BLUE] 

Any new color in between now:

 NewCol[pixelXFromLeft][RED] = m[RED] * pixelXFromLeft + ColorLeft[RED] NewCol[pixelXFromLeft][GREEN] = m[GREEN] * pixelXFromLeft + ColorLeft[GREEN] NewCol[pixelXFromLeft][BLUE] = m[BLUE] * pixelXFromLeft + ColorLeft[BLUE] 

There are many mathematical ways to create a transition, and we really want to understand which transition you really want to see. If you want to see the exact transition from the above image, you should look at the color values ​​of this image. I wrote the program back in time to look at such images and display the values ​​there graphically. Here is the output of my program for the above pseudocolor scale.

enter image description here

Based on the graph view, it is more complex than linear, as I said above. The blue component looks mostly linear, red can be emulated linear, but the green color looks more rounded. We could do a mathematical analysis of green to better understand its mathematical function and use it instead. You may find that linear interpolation with an increase in slope between 0 and ~ 70 pixels with a linear decreasing slope after pixel 70 is good enough.

If you look at the bottom of the screen, this program gives some statistics for each color component, such as min, max and average, as well as the number of pixels in width.

+11
source share

A simple linear interpolation of the values ​​of R, G, B will do this.

trumpetlicks showed that the image used is not pure linear interpolation. But I think interpolation gives you the effect you are looking for. Below I will show an image with linear interpolation at the top and the original image at the bottom.

Top half linear interpolation, bottom half original

And here is the code (Python) that created it:

 for y in range(height/2): for x in range(width): p = x / float(width - 1) r = int((1.0-p) * r1 + p * r2 + 0.5) g = int((1.0-p) * g1 + p * g2 + 0.5) b = int((1.0-p) * b1 + p * b2 + 0.5) pix[x,y] = (r,g,b) 
+8
source share

HSV color space is not a good color space for smooth transitions. This is due to the fact that the h value, a hue, is used only for the arbitrary determination of different colors around the "color wheel". This means that if you walk between two colors that are far apart on the wheel, you will have to plunge into a bunch of other colors. Not smooth.

It would be much wiser to use RGB (or CMYK). These “component” color spaces are best defined to make smooth transitions, because they represent how much of each “component” color is required.

Linear jump (see @trumpetlicks answer) for each component value, R, G and B should look "pretty good". Something more than “pretty good” will require a person to actually change the values, because there are differences and asymmetries in how our eyes perceive color values ​​in different color groups, which are not represented in either RBG or CMYK (or any standard).

The Wikipedia image uses an algorithm that Photoshop uses. Unfortunately, this algorithm is not publicly available.

+5
source share

I studied this to build an algorithm that takes a grayscale image as input and calculates it beautifully according to the color palette

■■■■ Enter grayscale ■■■■ Output signal ■■■■■■■■■■■■■■■■■■

enter image description here enter image description here

Like many other solutions, the algorithm uses linear interpolation to transition between colors. In your example, smooth_color_transition() should be called with the following arguments:

 QImage input("gradient.jpg"); QVector<QColor> colors; colors.push_back(QColor(242, 177, 103)); // orange colors.push_back(QColor(124, 162, 248)); // blue-ish QImage output = smooth_color_transition(input, colors); output.save("output.jpg"); 

A comparison of the source image of the VS-output according to the algorithm can be seen below:

enter image description here (output)

enter image description here (original)

Visual artifacts that can be observed at the exit are already present in the entrance (shades of gray). The input image received these artifacts when it was resized to 189x51.

Here is another example that was created with a more complex color palette:

■■■■ Enter grayscale ■■■■ Output signal ■■■■■■■■■■■■■■■■■■

k6K5K.pngMg8DH.png

+4
source share

It seems to me that it would be easier to create a gradient using RGB values. First you must calculate the color change for each value depending on the width of the gradient. The following pseudo code must be executed for the values ​​of R, G, and B.

 if (redValue1 == redValue2) { redDifference = 0 } else { redDifference = absoluteValue(redValue1 - redValue2) / widthOfGradient } if (redValue1 > redValue2) { redDifference *= -1 } 

Then you can visualize each pixel with these values:

 for (int i = 0; i < widthOfGradient; i++) { int r = round(redValue1 + (i * redDifference)) // ...repeat for green and blue drawLine(i, r, g, b) } 

I know that you indicated that you are using C ++, but I created a JSFiddle demonstrating this, working with your first gradient as an example: http://jsfiddle.net/eumf7/

+3
source share

All Articles