37

I would like to know how to draw semi-transparent shapes in OpenCV, similar to those in the image below (from http://tellthattomycamera.wordpress.com/)

enter image description here

I don't need those fancy circles, but I would like to be able to draw a rectangle, e.g, on a 3 channel color image and specify the transparency of the rectangle, something like

rectangle (img, Point (100,100), Point (300,300), Scalar (0,125,125,0.4), CV_FILLED);

where 0,125,125 is the color of the rectangle and 0.4 specifies the transparency. However OpenCV doesn't have this functionality built into its drawing functions. How can I draw shapes in OpenCV so that the original image being drawn on is partially visible through the shape?

Bull
  • 11,771
  • 9
  • 42
  • 53
Bokonon
  • 391
  • 1
  • 5
  • 8

4 Answers4

46

The image below illustrates transparency using OpenCV. You need to do an alpha blend between the image and the rectangle. Below is the code for one way to do this.

enter image description here

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int main( int argc, char** argv )
{
    cv::Mat image = cv::imread("IMG_2083s.png"); 
    cv::Mat roi = image(cv::Rect(100, 100, 300, 300));
    cv::Mat color(roi.size(), CV_8UC3, cv::Scalar(0, 125, 125)); 
    double alpha = 0.3;
    cv::addWeighted(color, alpha, roi, 1.0 - alpha , 0.0, roi); 

    cv::imshow("image",image);
    cv::waitKey(0);
}
Bull
  • 11,771
  • 9
  • 42
  • 53
  • 2
    Thanks for the reply and for your patience, but I solved it in another way, using the function addWeighted. Like this: cap >> img; img.copyTo (copy); rectangle (copy, Point (100,100), Point (300.300), Scalar (0,125,125), CV_FILLED, CV_AA, 0); addWeighted (copy, 0.4, 0.1 to 0 .4,0 img, img); imshow("img",img); – Bokonon Jun 30 '14 at 18:42
  • 2
    @Bull, i had a query, you are not using `image` Mat object in `addWeighted` function call, how is it updating to image? Thanks – Prakash M Dec 26 '16 at 14:30
  • 3
    @Prakash The data in `roi` is a rectangular slice of the data in `image`. That is, if you read from `roi` you are reading from `image`, if you modify `roi` you are also modifying `image`. – Bull Dec 26 '16 at 15:44
  • 1
    How would one do this for any arbitrary shape or polygon? I tried this `cv::Mat roi = image(cv::Mat(points));` (where `points` is a vector of cv::Point) but it didn't work. – Olivia Stork Jan 17 '18 at 21:30
  • 1
    @OliviaStork, easy way would be use answer of Alexander Taubenkorb and replace call to cv::rectangle() by code to draw arbitrary shape in overlay. – Bull Feb 22 '18 at 23:59
  • 1
    @Bull I tried that, I tried drawing an arbitrary shape by creating a cv::Mat from from a vector of cv::Point. It didn't work. Can you get it to work? – Olivia Stork Mar 28 '18 at 16:30
  • I got it working. I have added it as an answer. Let me know if anyone faces any difficulty. – Safwan Mar 13 '19 at 06:02
20

In OpenCV 3 this code worked for me:

cv::Mat source = cv::imread("IMG_2083s.png");
cv::Mat overlay;
double alpha = 0.3;

// copy the source image to an overlay
source.copyTo(overlay);

// draw a filled, yellow rectangle on the overlay copy
cv::rectangle(overlay, cv::Rect(100, 100, 300, 300), cv::Scalar(0, 125, 125), -1);

// blend the overlay with the source image
cv::addWeighted(overlay, alpha, source, 1 - alpha, 0, source);

Source/Inspired by: http://bistr-o-mathik.org/2012/06/13/simple-transparency-in-opencv/

Alexander Taubenkorb
  • 3,031
  • 2
  • 28
  • 30
3

Adding to Alexander Taubenkorb's answer, you can draw random (semi-transparent) shapes by replacing the cv::rectangle line with the shape you want to draw.

For example, if you want to draw a series of semi-transparent circles, you can do it as follows:

cv::Mat source = cv::imread("IMG_2083s.png");  // loading the source image
cv::Mat overlay;  // declaring overlay matrix, we'll copy source image to this matrix
double alpha = 0.3;  // defining opacity value, 0 means fully transparent, 1 means fully opaque

source.copyTo(overlay);  // copying the source image to overlay matrix, we'll be drawing shapes on overlay matrix and we'll blend it with original image

// change this section to draw the shapes you want to draw
vector<Point>::const_iterator points_it;  // declaring points iterator
for( points_it = circles.begin(); points_it != circles.end(); ++points_it )  // circles is a vector of points, containing center of each circle
    circle(overlay, *points_it, 1, (0, 255, 255), -1);  // drawing circles on overlay image


cv::addWeighted(overlay, alpha, source, 1 - alpha, 0, source);  // blending the overlay (with alpha opacity) with the source image (with 1-alpha opacity)
Safwan
  • 3,300
  • 1
  • 28
  • 33
1

For C++, I personally like the readability of overloaded operators for scalar multiplication and matrix addition:

... same initial lines as other answers above ...

// blend the overlay with the source image
source = source * (1.0 - alpha) + overlay * alpha;
MaRib
  • 31
  • 4