OpenCV  3.2.0
Open Source Computer Vision
Changing the contrast and brightness of an image!

Goal

In this tutorial you will learn how to:

Theory

Note
The explanation below belongs to the book Computer Vision: Algorithms and Applications by Richard Szeliski

Image Processing

Pixel Transforms

Brightness and contrast adjustments

Code

Explanation

  1. We begin by creating parameters to save \(\alpha\) and \(\beta\) to be entered by the user:
    double alpha;
    int beta;
  2. We load an image using cv::imread and save it in a Mat object:
    Mat image = imread( argv[1] );
  3. Now, since we will make some transformations to this image, we need a new Mat object to store it. Also, we want this to have the following features:
    • Initial pixel values equal to zero
    • Same size and type as the original image
      Mat new_image = Mat::zeros( image.size(), image.type() );
      We observe that cv::Mat::zeros returns a Matlab-style zero initializer based on image.size() and image.type()
  4. Now, to perform the operation \(g(i,j) = \alpha \cdot f(i,j) + \beta\) we will access to each pixel in image. Since we are operating with BGR images, we will have three values per pixel (B, G and R), so we will also access them separately. Here is the piece of code:
    for( int y = 0; y < image.rows; y++ ) {
    for( int x = 0; x < image.cols; x++ ) {
    for( int c = 0; c < 3; c++ ) {
    new_image.at<Vec3b>(y,x)[c] =
    saturate_cast<uchar>( alpha*( image.at<Vec3b>(y,x)[c] ) + beta );
    }
    }
    }
    Notice the following:
    • To access each pixel in the images we are using this syntax: image.at<Vec3b>(y,x)[c] where y is the row, x is the column and c is R, G or B (0, 1 or 2).
    • Since the operation \(\alpha \cdot p(i,j) + \beta\) can give values out of range or not integers (if \(\alpha\) is float), we use cv::saturate_cast to make sure the values are valid.
  5. Finally, we create windows and show the images, the usual way.
    namedWindow("Original Image", 1);
    namedWindow("New Image", 1);
    imshow("Original Image", image);
    imshow("New Image", new_image);
Note
Instead of using the for loops to access each pixel, we could have simply used this command:
image.convertTo(new_image, -1, alpha, beta);
where cv::Mat::convertTo would effectively perform *new_image = a*image + beta*. However, we wanted to show you how to access each pixel. In any case, both methods give the same result but convertTo is more optimized and works a lot faster.

Result