In this recipe we will cover
basic image color transformations using the Surface
class for pixel manipulation.
To change the values of contrast and brightness we will use InterfaceGl
covered in Chapter 2, Preparing for Development in the Setting up GUI for parameters tweaking recipe. We will need a sample image to proceed with; save it in your assets
folder as image.png
.
We will create an application with simple GUI for contrast and brightness manipulation on the sample image. Perform the following steps to do so:
#include "cinder/gl/gl.h" #include "cinder/gl/Texture.h" #include "cinder/Surface.h" #include "cinder/ImageIo.h"
float mContrast,mContrastOld; float mBrightness,mBrightnessOld; Surface32f mImage, mImageOutput;
setup
method an image is loaded for processing and the Surface
object is prepared to store processed image:mImage = loadImage( loadAsset("image.png") ); mImageOutput = Surface32f(mImage.getWidth(), mImage.getHeight(), false);
setWindowSize(1025, 512); mContrast = 0.f; mContrastOld = -1.f; mBrightness = 0.f; mBrightnessOld = -1.f;
InterfaceGl
window:mParams.addParam("Contrast", &mContrast, "min=-0.5 max=1.0 step=0.01"); mParams.addParam("Brightness", &mBrightness, "min=-0.5 max=0.5 step=0.01");
update
method as follows:if(mContrastOld != mContrast || mBrightnessOld != mBrightness) { float c = 1.f + mContrast; Surface32f::IterpixelIter = mImage.getIter(); Surface32f::IterpixelOutIter = mImageOutput.getIter(); while( pixelIter.line() ) { pixelOutIter.line(); while( pixelIter.pixel() ) { pixelOutIter.pixel(); // contrast transformation pixelOutIter.r() = (pixelIter.r() - 0.5f) * c + 0.5f; pixelOutIter.g() = (pixelIter.g() - 0.5f) * c + 0.5f; pixelOutIter.b() = (pixelIter.b() - 0.5f) * c + 0.5f; // brightness transformation pixelOutIter.r() += mBrightness; pixelOutIter.g() += mBrightness; pixelOutIter.b() += mBrightness; } } mContrastOld = mContrast; mBrightnessOld = mBrightness; }
draw
method:gl::draw(mImage); gl::draw(mImageOutput, Vec2f(512.f+1.f, 0.f));
The most important part is
inside the update
method. In step 6 we checked if the parameters for contrast and brightness had been changed. If they have, we iterate through all the pixels of the original image and store recalculated color values in mImageOutput
. While modifying the brightness is just increasing or decreasing each color component, calculating contrast is a little more complicated. For each color component we are using the multiplying formula, color = (color - 0.5) * contrast + 0.5, where contrast is a number between 0.5 and 2. In the GUI we are setting a value between -0.5 and 1.0, which is more natural range; it is then recalculated at the beginning of step 6. While processing the image we have to change color value of all pixels, so later in step 6, you can see that we iterate through
later columns of each row of the pixels using two while
loops. To move to the next row we invoked the line
method on the Surface
iterator and then the pixel
method to move to the next pixel of the current row. This method is much faster than using, for example, the getPixel
and setPixel
methods.
Our application is rendering the original image on the left-hand side and the processed image on the right-hand side, so you can compare the results of color adjustment.
3.138.34.80