본문으로 바로가기

Smooth color transition algorithm

category 개발언어/c++ 2016. 7. 16. 23:51

 

색상을 부드럽게 처리하는 방법을 고민하다 인터넷에서 검색해 둔 것이 있는데

실제 적용은 해보지 않았지만 참고 자료로 남겨 둔다.

          

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

When I try to do the same using my code (C++), first idea that came to mind is using the HSV color space, but the annoying in-between colors show-up.

What is the good way to achieve this ? Seems to be related to diminution of contrast or maybe use a different color space ?

I have done tons of these in the past. The smoothing can be performed many different ways,

but the way they are probably doing here is a simple linear approach.

This is to say that for each R, G, and B component, they simply figure out the "y = m*x + b" equation that connects the two points, and use that to figure out the components in between.

    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 is 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, what we really want to do is understand what transition you really want to see. If you want to see the exact transition from the above image, it is worth looking at the color values of that image. I wrote a program way back in time to look at such images and output there values graphically. Here is the output of my program for the above pseudocolor scale.

    

Based upon looking at the graph, it IS more complex than a linear as I stated above. The blue component looks mostly linear, the red could be emulated to linear, the green however looks to have a more rounded shape. We could perform mathematical analysis of the green to better understand its mathematical function, and use that instead. You may find that a linear interpolation with an increasing 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 statistical measures of each color component, such as min, max,

and average, as well as how many pixels wide the image read was.

 

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

trumpetlicks has shown that the image you used is not a pure interpolation. But I think an interpolation gives you the effect you're looking for. Below I show an image with a linear interpolation on top and your original image on the bottom.

And here's the (Python) code that produced 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)
				

 

 

Seems to me like it would be easier to create the gradient using RGB values. You should first calculate the change in color for each value based on the width of the gradient. The following pseudocode would need to be done for R, G, and B values.

if (redValue1 == redValue2) {

    redDifference = 0
					

} else {

    redDifference = absoluteValue(redValue1 - redValue2) / widthOfGradient

}

 

if (redValue1 > redValue2) {

    redDifference *= -1
					

}
				

You can then render each pixel with these values like so:

for (int i = 0; i < widthOfGradient; i++) {


					int r = round(redValue1 + (i * redDifference)


					// ...repeat for green and blue
					

 

    drawLine(i, r, g, b)

}