Change Contrast of Image or Video


Changing the contrast is also a point operation on each pixel. The easiest way to increase the contrast of an image is, multiplying each pixel value by a number larger than 1.

                         new_img (i, j) = img(i, j) * c                     c > 1


The easiest way to decrease the contrast is, multiplying each pixel value by a number smaller than 1.

                         new_img (i, j) = img(i, j) * c                     c < 1



There are more advance methods to adjust contrast of an image such as histogram equalization. Such method adjust the contrast of an image such that color distribution is balanced equally. We will discuss the histogram equalization in the next lesson.


e.g- Say, this is your original image
Example Image
Example Image



By multiplying each pixel value by 2, you can effectively double the contrast of an image. Here is the image of which the contrast is increased. 
I have considered this image as a 8 bit unsigned image. So, any pixel value should be from 0 to 255. If the resulting image has values more than 255, it should be rounded off to 255.


Contrast Increased
Contrast Increased


By multiplying each pixel value by 0.5, you can effectively halve the contrast of an image. Here is the image of which contrast is decreased.


Contrast Decreased
Contrast Decreased


Change Contrast of an Image

How to increase or decrease the contrast of an image is demonstrated in the following OpenCV C++ example. Keep in mind that this is the very basic way of changing contrast. In the next lesson, I'll show you how to change the contrast using histogram equalization.

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "opencv2/highgui/highgui.hpp"
#include <iostream>


using namespace cv;

using namespace std;

int main( int argc, const char** argv )

{

Mat img = imread("MyPic.JPG", CV_LOAD_IMAGE_COLOR); //open and read the image


if (img.empty())
{
cout << "Image cannot be loaded..!!" << endl;
return -1;
}

Mat imgH;
img.convertTo(imgH, -1, 2, 0); //increase the contrast (double)

Mat imgL;
img.convertTo(imgL, -1, 0.5, 0); //decrease the contrast (halve)

//create windows
namedWindow("Original Image", CV_WINDOW_AUTOSIZE);
namedWindow("High Contrast", CV_WINDOW_AUTOSIZE);
namedWindow("Low Contrast", CV_WINDOW_AUTOSIZE);

//show the image
imshow("Original Image", img);
imshow("High Contrast", imgH);
imshow("Low Contrast", imgL);

waitKey(0); //wait for key press

destroyAllWindows(); //destroy all open windows

return 0;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
You can download this OpenCV visual c++ project from here. (The downloaded file is a compressed .rar folder. So, you have to extract it using Winrar or other suitable software)

Here is the original image.

Original Image
Original Image

Here is the image of which contrast is increased by the OpenCV program.
Contrast is increased with OpenCV
Contrast is increased with OpenCV


Here is the image of which contrast is decreased by the OpenCV program.

Contrast is decreased with OpenCV
Contrast is decreased with OpenCV

New OpenCV methods

  • void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 )
This OpenCV function converts  image into another format with scaling. Scaling is done according to the following formula.
                                              m[i,j] = alfa * img[i,j] + beta

Here is the parameters of this function
    • OutputArray m - Store the converted image
    • int rtype - Depth of the output image. If the value of rtype is negative, output type is same as the input image. I have used a negative value in the above program because I don't want to change the depth of the original image. Possible inputs to this parameter
      • CV_8U
      • CV_32S
      • CV_64F
      • -1
Complete list of depths can be found in Basics of OpenCV API
    • double alpha - Multiplication factor; Every pixel will be multiplied by this value
    • double beta - This value will be added to very pixels after multiplying with the above value.
Here is the formula again. Here m[i, j] means a pixel at ith row and jth column.
                              m[i,j] = alfa * img[i,j] + beta


Change the Contrast of a Video

It is similar to the above program except that you have to change the contrast for each and every frame of the video. Here is the example OpenCV program.

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "opencv2/highgui/highgui.hpp"
#include <iostream>

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
    VideoCapture cap("C:/Users/SHERMAL/Desktop/SampleVideo.wmv"); // open the video file for reading

    if ( !cap.isOpened() )  // if not success, exit program
    {
         cout << "Cannot open the video file" << endl;
         return -1;
    }

    //create windows
    namedWindow("Original Video",CV_WINDOW_AUTOSIZE); 
    namedWindow("Contrast Increased",CV_WINDOW_AUTOSIZE); 
    namedWindow("Contrast Decreased",CV_WINDOW_AUTOSIZE); 

    while (1)
    {
        Mat frame;

        bool bSuccess = cap.read(frame); // read a new frame from video

         if (!bSuccess) //if not success, break loop
        {
cout << "Cannot read the frame from video file" << endl;
break;
        }

Mat imgH;
frame.convertTo(imgH, -1, 2, 0); //increase the contrast (double)

Mat imgL;
frame.convertTo(imgL, -1, 0.5, 0); //decrease the contrast (halve)

//show the image
        imshow("Original Video", frame); 
imshow("Contrast Increased", imgH); 
imshow("Contrast Decreased", imgL); 

       if (waitKey(30) == 27) //wait for 'esc' key press for 30 ms. If 'esc' key is pressed, break loop
        {
                cout << "esc key is pressed by user" << endl; 
                break
        }
    }
    return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
You can download this OpenCV visual c++ project from here. (The downloaded file is a compressed .rar folder. So, you have to extract it using Winrar or other suitable software)

All the OpenCV methods in the above example program have been discussed in previous lessons. So, I am not going to repeat them again.





7 comments:

  1. This has been extremely helpful. All other programs that I encountered to change contrast of the image involved accessing each pixel of the image and applying the formula new_img (i, j) = img(i, j) * c .
    Even in opencv docs uses the formula mentioned earlier. The formula approach didn't work for me, but this did and I'm delighted. Thanks!

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
    Replies
    1. (you forgot to adjust the brightness to compensate for the multiplication)

      #define NA -1 // indicator that value is [N]ot [A]vailable or [N]ot [A]pplicable
      #define MIX(v1,v2,ratio) (v1+(v2-v1)*ratio) // Mix two numbers according to a floating point ratio 0..1 (being 0%..100%)
      #define MINMAX(min,max,v) ((v)<(min) ? (min) : (v)>(max) ? (max) : (v)) // Limit value inside given valid range

      double multiplier = (double)MINMAX(-100,100,contrast)/100.; // convert range -100..100 -> -1..1
      double alpha = multiplier>0 ? MIX(1.0, 2.0, multiplier) : MIX(1.0, 0.5, -multiplier); // 0.5 will halve the contrast while 2.0 will double the contrast
      double beta = multiplier>0 ? MIX(0.0, -0.5, multiplier) : MIX(0.0, 0.25, -multiplier); // compensate brightness accordingly to get the original average
      cv::Mat(src).convertTo(cv::Mat(dst), NA, alpha, beta);

      Delete
  3. Its simply great tutorial
    Can you right a tutorial about depth calculation using single camera. using simple pinhole camera model.
    it will be helpful for me.

    ReplyDelete
  4. This is not a contrast transformation, simply brightness by multiplication.
    When you increase the contrast, a dark pixel will get darker and a white pixel will get whiter.
    In other words you would some kind of formula like:
    pixel x; (range 0-255)
    x'=x*(1+(x-128)/256))
    Please dont misinform people on the internet

    ReplyDelete
    Replies
    1. It is indeed a contrast transformation because the distance between dark and bright pixels increases by the multiplication factor.

      Let's say you have a brighter pixel with value 100 and a darker pixel with value 10.
      Then: distance = 100 - 10 = 90
      However if you multiply all pixels by e.g. 2
      Then: new distance = 200 - 20 = 180 = 2 * old distance
      So you've actually doubled the distance between dark and bright pixels.

      The problem with this approach is that you increase all pixel values which means that more pixels reach a value > 255.
      In this example all values > 255 are set to 255 (i.e. white).
      That's why we can't see the river in the transformed example image.

      If you increase your factor (because you want more contrast) you'll get a completely white image very soon. (Instead of an image with high contrast)

      Instead of making all pixels brighter (some more some less), you could indeed separate pixels into dark and bright pixels (depending on a threshold or formula like you suggested) and then make the bright pixels brighter and the dark pixels darker.

      Delete
  5. Can anyone tell me the equivalent of "im2double" function of MATLAB. How can we do it using opencv

    --
    Abdul Wahab

    ReplyDelete