33
votes

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?

4

4 Answers

43
votes

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);
}
18
votes

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/

2
votes

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)
1
votes

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;