datahacker.rs@gmail.com

OpenCV #003 Pixel Intensity Changes and Adding Watermarks

OpenCV #003 Pixel Intensity Changes and Adding Watermarks

Digital Image Processing using OpenCV (Python & C++)

Highlight: In this blog post, we will explain how to scale the pixel’s intensity and make the image brighter and/or darker. We will show how to add logos onto a given image. This is known as a watermark, and we will also show how to add it in a transparent mode. Finally, we show-off with some cool effects for beginners, such as fading in and out.

Tutorial Overview:

  1. Increase the intensity values of all pixels
  2. Decrease the intensity values of all pixels
  3. Creating a watermark
  4. Creating a transparent watermark
  5. Fading in and out effect on an image

1. Increasing the intensity values of all pixels

After we load the image, we can multiply its pixel’s values with a scalar. Note that multiplying the image with a constant value greater than 1 produces a brighter image. In our example case, we multiplied the intensity values by 1.03, thereby making the photo brighter.

If you use a higher constant value, you might notice some washed out effects in certain areas. This happened when some value been multiplied by the constant reached values above 255. That is, OpenCV truncates these values to 255, since an image is represented as an 8-bit binary digit.

Let’s have a look at the following example. We are making a loop of 50 iteration, where we gradually brighten the image. Pretty nice, huh? 🙂

Increase pixel values on an image c++ and python
Increasing the pixel values in a given image

Python

C++

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main() {
    
    cv::Mat img;
    
    // using the following argument we will load a preprocessed image
    // in this case RGB image will be converted into a gray scale image
    img = cv::imread("sophie_turner.jpg", IMREAD_GRAYSCALE);
    
    // changing some grayscale pixel values
    for (int k = 0; k<50; k++) {

        for(int j=0;j<img.rows;j++){

            for (int i=0;i<img.cols;i++){

                // prevents that multiplication with 1.03, creates a number larger than 255
                if (img.at<uchar>(j,i) < (255-30)){ 

                    img.at<uchar>(j,i) = img.at<uchar>(j,i) * 1.03; //white       
                
                }
            }   
        }
        cv::imshow("Updated",img);
        cv::waitKey(40);
    }

   return 0;    
}

2. Decreasing the intensity values of all pixels

To decrease the pixels intensity level, or to make the image darker, we will multiply pixel values with a constant value less than 1. For instance, we can use a value of 0.97. If we repeat this multiplication in a loop, for lets says 50 times, we can get interesting visual effects. See below! 🙂

Decrease pixel values on an image c++ and python
Decreasing the pixel values in a given image

Python

C++

#include <opencv2/opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

int main() {
    
    cv::Mat img;
    
    // using the following argument we will load a preprocessed image
    // in this case RGB image will be converted into a gray scale image
    img = cv::imread("sophie_turner.jpg", IMREAD_GRAYSCALE) ;
    
    // changing some grayscale pixel values
    for (int k = 0; k<50; k++) {
        
        for(int j=0;j<img.rows;j++){

            for (int i=0;i<img.cols;i++){
            
                img.at<uchar>(j,i) = img.at<uchar>(j,i) * 0.97 ; //darker
            }

        }

        cv::imshow("Updated",img);
        cv::waitKey(40);
    }
    return 0;    
}

3. Creating a watermark

Now let’s say, that you want to stamp your photographs with your brand logo, name, or another identifying mark, you can add what is called a watermark.

How is this done ?

After selecting an image to be processed, a logo image can be stamped onto it.


Watermark added onto an image

Python

C++

#include <opencv2/opencv.hpp>
  
using namespace std;
using namespace cv;
 
 
int main()
{
    // loading images
    Mat image = imread("sophie_turner.jpg",1);
    Mat logo = imread("datahacker.png",1);
 
    // initialization
    char file_name[100];
 
    // checking shapes
    cout << "Width : " << image.cols << endl;
    cout << "Height : " << image.rows << endl;
 
    cout << "Width : " << logo.cols << endl;
    cout << "Height : " << logo.rows << endl;
 
    // our starting coordinates
    int x = image.cols-logo.cols;
    int y = image.rows-logo.rows;
 
    // our image region of interest
    Mat imageROI = image(cv::Rect(x,y,logo.cols,logo.rows));
     
    // add the logo onto the image
    addWeighted(imageROI,1,logo,1,0.,imageROI);
     
    namedWindow("output",CV_WINDOW_AUTOSIZE);
    cv::imshow("output",image);
    cv::waitKey(0); // wait for a key pressed
    cv::destroyAllWindows();
 
    // save image
    sprintf(file_name, "added_logo.jpg");
    imwrite(file_name, image);
 
    cv::destroyAllWindows();
}

4. Creating a transparent watermark

Before we proceed further, let’s clarify what the mask is. In simple words, a mask selects a region of an image that we would like to process, whereas the other parts of the image we wish to remain unchanged. To accomplish this we usually create the image of the same size as our image of interest. We may place 1s to select our region of interest, whereas 0s will be placed on the remaining pixel locations.

 Even further, it is interesting to note that .png image type has four channels. The fourth channel is the alpha value, and it may have values from 0 to 1.  In images with an alpha channel, each pixel has not only has a color value, but also a numerical transparency. This can assist us to create very interesting effects.

 Finally, a transparent watermark can be created without the need for the alpha channel value (c++). In this case, we have only used two binary values for defining a mask. We have added a black text, whereas the white values of the logo image did not affect the original image. 

Transparent watermark added onto an image

Python

C++

#include <opencv2/opencv.hpp>
  
using namespace cv;
using namespace std;
 
int main() {
 
    // file name
    char file_name[100];
 
    // read the image and logo
    cv::Mat image=  cv::imread("sophie_turner.jpg", 1); 
    cv::Mat logo=  cv::imread("datahacker.png", 1); 
 
    // our starting coordinates
    int x = image.cols-logo.cols;
    int y = image.rows-logo.rows;
 
    // define image ROI at image bottom-right
    Mat imageROI= image(cv::Rect(x,y, logo.cols, logo.rows));
 
    // here we inverted the color (so all black are now white and all white are now black)
    cv::Mat invSrc =  cv::Scalar::all(255) - logo;
 
    // use the logo as a mask (must be gray-level)
    cv::Mat mask(invSrc);
 
    // insert by copying only at locations of non-zero mask
    invSrc.copyTo(imageROI, mask);
 
    cv::imshow("Image", image); // show the image
    cv::namedWindow("Image"); 
    cv::waitKey(0); // wait for a key pressed
    cv::destroyAllWindows();
 
    // save image
    sprintf(file_name, "added_transperant_logo.jpg");
    imwrite(file_name, image);
 
    return 0;
}

5. Fading in and out effect on an image

This is one of my favourites. Manipulating the pixel values in each color channel \((R, G, B)\) produces quite interesting results, like the image below. A fade-in/fade-out effect in color is created by accessing every pixel in the channel and multiplying it with a constant value. In this example, 1.02/1.03 values were used.

Fading in and out an image c++ and python
Fading in and out effect on an image

Python

C++

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;
int main() {
    
    Mat original;
    
    original = cv::imread("sophie_turner.jpg", IMREAD_COLOR);
    
    // a loop that iteratively increases/decreases certain color channels
    // we create a fade-in/fade-out effect in color. 
    for (int k = 0; k<50; k++) {
    
        for (int r=0; r<original.rows; r++){
        
            for (int c=0; c< original.cols; c++){
            
  
                // have a look how we are going to process a color image.
                // we will use Vec3b
                // in this case we can treat a single position as a vector of 3 bytes (b)
                // try for yourself how changing some values produce different examples

                original.at<Vec3b>(r, c) [0]= original.at<Vec3b>(r, c)[0]  * 0.f;
                original.at<Vec3b>(r, c) [1]= original.at<Vec3b>(r, c)[1]  * 1.03f;
                original.at<Vec3b>(r, c) [2]= original.at<Vec3b>(r, c)[2]  / 1.02f;
            }
        }

        cv::imshow("Updated",original);
        cv::waitKey(40);
    }
    
    return 0;    
    
}

Summary

In this blog post, we learned how to scale the intensity of pixel values, creating a watermark by adding a transparent logo, fade in and out effects on a photograph. If you like this post, please make sure to share this post with your mates getting started on digital image processing. In the next post, we will talk more about some common type of noise we can have on an image.

More resources on the topic:

For more resources about image processing, check these other sites.

 

Leave a Reply

Your email address will not be published. Required fields are marked *

5 × 5 =