blImageBlending — Emulating photoshop’s blending modes in opencv

This entry is part 9 of 17 in the series blImageAPI -- BarbatoLabs Image API

Introduction

When playing with images or videos, we often need to blend multiple images together, whether it’s for changing the color of an object, or if we’re experimenting with some fancy masking, blending is our friend.

Photoshop offers several ways to blend two images, which they call: blending modes.

As part of the blImageAPI series, in this article, I present a collection of functions that I have developed to emulate photoshop’s blending modes, based on algorithms that I got from various sources.

All the functions keep track of their dependencies, use inline commenting, and are collected in the header file blImageBlending.hpp included in the blImageAPI, available in the downloads section.

Note:  All the functions presented here, account for all different depths and number of channels. The images can even be of different sizes.


The following snippet is used to test the various blending modes. It loads a pattern and blends it with a webcam feed. Each function shows the resulting output.

The pattern used is the following:

int main(int argc, char *argv[])
{
    // Connect to the webcam
    blCaptureDevice Webcam;
    Webcam.ConnectToWebcam(0);

    // The webcam frame (in grayscale)
    blImage< blColor3<float> > Frame;

    // Load an image of a pattern
    // to overlay on the webcam frame
    blImage< blColor3<float> > Pattern;
    Pattern.LoadImageFromFile("C:/Documents and Settings/VBarbato/Desktop/Pattern.png");

    // Show the pattern image
    cvShowImage("Pattern Image",Pattern);

    // The patter image blended with
    // the webcam frame image
    blImage< blColor3<float> > BlendedFrame;

    // Create a key variable to
    // quit program when user
    // hits the 'q' key
    int key = 'a';

    // Loop through and keep querying
    // frames from webcam until user
    // hits the 'q' key
    while(key != 'q')
    {
        // Query a frame from the webcam
        Webcam.QueryFrame(Frame);

        // Show frame
        cvShowImage("WebcamColor",Frame);

        // Blend pattern with frame
        // (Use any of the blending functions
        // here interchangibly)
        BlendMultiply(Frame,Pattern,BlendedFrame);

        // Show the blended frame
        cvShowImage("Blended Frame",BlendedFrame);

        // Wait for a key
        key = cvWaitKey(1);
    }
}

Functions

The list of functions will be continuously updated as I develop more of them, and/or as I fix bugs, so check back here often for changes.

Check this website for an explanation of what the blending modes do.

Note:  Each function that follows comes with a supporting pixel function that calculates the pixel values and takes care of different depths and number of channels.

For example, the BlendMultiply function comes with the BlendMultiplyPixel function, and so on.

BlendMultiply

BlendMultiplyPixel and BlendMultiply Functions (Click to see code...)

The resulting output when using BlendMultiply:

BlendScreen

BlendScreenPixel and BlendScreen Functions (Click to see code…)

The resulting output when using BlendScreen:

BlendDarken

BlendDarkenPixel and BlendDarken Functions (Click to see code…)

The resulting output when using BlendDarken:

BlendLighten

BlendLightenPixel and BlendLighten Functions (Click to see code…)

The resulting output when using BlendLighten:

BlendDifference

BlendDifferencePixel and BlendDifference Functions (Click to see code…)

The resulting output when using BlendDifference:

BlendLinearDodge

BlendLinearDodgePixel and BlendLinearDodge Functions (Click to see code…)

The resulting output when using BlendLinearDodge:

BlendOverlay

BlendOverlayPixel and BlendOverlay Functions (Click to see code…)

The resulting output when using BlendOverlay:

BlendHardLight

BlendHardLight is the same as BlendOverlay but the base and top images are reversed

BlendHardLight Function (Click to see code…)

The resulting output when using BlendHardLight:

BlendLinearBurn

BlendLinearBurnPixel and BlendLinearBurn Functions (Click to see code…)

The resulting output when using BlendLinearBurn:

Downloads

I have put all the files into a zip file which can be downloaded here. All you have to do is extract it somewhere, let’s say in a directory called blImageAPI, and then include the blImageAPI.hpp file as follows:

#include "blImageAPI/blImageAPI.hpp"
using namespace blImageAPI;

Note:  Everything is declared in a namespace blImageAPI, and such you would use it as: blImageAPI::blImage

blImageAPI.zip -- Ver Jun/06/2011 1:43pm (5060)

Updates

The list of functions will be continuously updated as I implement more blending modes, and/or as I fix bugs, so check back here often for changes.

  1. Dec/29/2010 — Corrected the “Overlay” and “Hard Light” methods. Now they look good.
  2. Dec/29/2010 — Changed the “Hard Light” method again to account for images of different sizes.
  3. Dec/29/2010 — Added the “Linear Burn” method.

About Vincenzo Barbato

Known to his friends as Enzo, he's an outside-the-box engineer/researcher whose interests and expertise span many fields, including controls systems, multi-physics simulations, mechatronics, oil technologies, data analysis and machine vision just to name a few.

Refusing to grow up, he's on a continuous journey to develop simple and creative solutions that have the power of disrupting industries by optimizing systems and processes.

Married to a beautiful wife, with two beautiful daughters and two identical twin boys, his home is a never ending chaotic fountain of inspiration.

His outlook on life:

"Never blindly accept what you're told, listen, but then question, with curiosity, creativity and collaboration we can change the world"

About Enzo

Known to his friends as Enzo, he's an outside-the-box engineer/researcher whose interests and expertise span many fields, including controls systems, multi-physics simulations, mechatronics, oil technologies, data analysis and machine vision just to name a few. Refusing to grow up, he's on a continuous journey to develop simple and creative solutions that have the power of disrupting industries by optimizing systems and processes. Married to a beautiful wife, with two beautiful daughters and two identical twin boys, his home is a never ending chaotic fountain of inspiration. His outlook on life: "Never blindly accept what you're told, listen, but then question, with curiosity, creativity and collaboration we can change the world"

7 Comments

  1. Pingback: blImagePencilSketch — A quick algorithm to turn an image or video into pencil sketch using opencv | BarbatoLabs

  2. thanks a lot for this. These bending APIs are of great help.

    I was successfully able to call your APIs but facing one minor problem:
    I am loading an image into IplImage and then converting it into a BlImage, IplImage comes fine but when I display BIImage on the screen it comes changed.
    Here I have uploaded the two images(original and changed):
    http://s1096.photobucket.com/albums/g331/king-kazma/

    it would be very kind of you if you could let me know what might be going wrong here.

    I am using the same code except I am calling std::tr1::shared_ptr instead of boost::shared_ptr.

    • ram,

      can you post a snippet of your code? Looking at the posted image, I cannot tell what you’re defining as “wrong”.

      You also mention loading an IplImage and then converting it to a blImage. You should just use the constructors as follows:

      // Load an image from disk
      IplImage* MyImage = NULL;
      MyImage = cvLoadImage("Filepath");
      
      // Load the image into a blImage
      blImage<unsigned char> Image1(MyImage);
      
      // Load the image into a different blImage
      // making it a color float
      blImage< blColor3<float> > Image2(MyImage);
      
  3. Hi Enzo, Thanks for your help. Here is my code, I am compiling it with iOS sdk version 4.0: ———–*————— //getting IplImage from UIImage IplImage *lenaImg = [self CreateIplImageFromUIImage:lenaUIImg]; blImageAPI::blImage< blImageAPI::blColor3<float> > Pattern; ///works fine if I display lenaImg ///imageView.image = [self UIImageFromIplImage: lenaImg]; //getting blImage from IplImage Pattern = blImageAPI::blImage< blImageAPI::blColor3<float> > (lenaImg); //displaying blImage imageView.image = [self UIImageFromIplImage:Pattern]; ———–*—————    When I mentioned about the wrong image what I meant is that there are two images that I have uploaded in the above link, the first one is the lenaImg and second one is the screenshot of Pattern image which is different from original image even though I am not really doing any processing. I tried changing blColor3<float> to blColor4<float> but i just got grey screen, no image. I also tried using your suggested code (changing blColor3 to <unsigned char>) but got a black screen.

    • Ram,

      The blImage can be used interchangeably with IplImage*, one way you could check is to print some random pixel values of the images and make sure that they match, like the following:

      blImage< blColor3<unsigned char> > Pattern(lenaImg);
      
      CvScalar lenaImgColor = cvGet2D(lenaImg,100,100);
      
      cout << "Pattern(100,100) = " << Pattern[100][100] << "\n";
      cout << "lenaImg(100,100) = (" << lenaImgColor.val[0] << "," << lenaImgColor.val[1] << "," << lenaImgColor.val[2] << ")\n";
      

      Now if the image values match, then that means you are correctly initializing blImage.

      NOTE: Although I am not familiar with the iOS SDKs, I suspect that when using a blImage with the UIImageFromIplImage function, you should cast the blImage to an IplImage* pointer like the following:

      (UIImage *)UIImageFromIplImage:(IplImage *)Pattern;

      Look at the following link for reference:
      http://sites.google.com/site/iprinceps/Home/iphone-1/converting-images-between-uiimage-and-iplimage

      Good luck, and let me know what you find.

  4. Thanks alot Enzo, really appreciate your help. I finally got the code working by using blColor3<unsigned char> as per your suggestion.

  5. Hi Enzo,
    It seems your page doesn’t work any more. When I click to see the code, I just get a weird frame at the top with html codes. Tested in Chrome and FF.

    int main(int argc, char *argv[])
    {
    // Connect to the webcam
    blCaptureDevice Webcam;
    Webcam.ConnectToWebcam(0);
    // The webcam frame (in grayscale)
    blImage< blColor3<float> > Frame;
    // Load an image of a pattern
    // to overlay on the webcam frame
    blImage< blColor3<float> > Pattern;
    Pattern.LoadImageFromFile("C:/Documents and Settings/VBarbato/Desktop/Pattern.png");
    // Show the pattern image
    cvShowImage("Pattern Image",Pattern);
    // The patter image blended with
    // the webcam frame image
    blImage< blColor3<float> > BlendedFrame;
    // Create a key variable to
    // quit program when user
    // hits the ‘q’ key
    int key = ‘a’;
    // Loop through and keep querying
    // frames from webcam until user
    // hits the ‘q’ key
    while(key != ‘q’)
    {
    // Query a frame from the webcam
    Webcam.QueryFrame(Frame);
    // Show frame
    cvShowImage("WebcamColor",Frame);
    // Blend pattern with frame
    // (Use any of the blending functions
    // here interchangibly)
    BlendMultiply(Frame,Pattern,BlendedFrame);
    // Show the blended frame
    cvShowImage("Blended Frame",BlendedFrame);
    // Wait for a key
    key = cvWaitKey(1);
    }
    }

Leave a Reply

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