1

I draw objects on IplImage like this:

cvLine(image, point_1, point_2, color, thickness, CV_AA); // Line
cvCircle(mage, point, radius, color, thickness, CV_AA); // Circle
// and some others...

How can I draw them translucent? cv::Scalar does not support alpha channel, if I understand correctly. I found something similar, but not quite appropriate: link. Here we are talking about translucenty IplImage, not about the objects on it.

garbart
  • 465
  • 4
  • 19
  • 2
    From OpenCV 2.4.13.7 documentation [Drawing Function](https://docs.opencv.org/2.4/modules/core/doc/drawing_functions.html): _**Note:** The functions do not support alpha-transparency when the target image is 4-channel. In this case, the `color[3]` is simply copied to the repainted pixels. Thus, if you want to paint semi-transparent shapes, you can paint them in a separate buffer and then blend it with the main image._ – HansHirse May 20 '19 at 04:32
  • 2
    also, if you use C++ **do not** use the C API is deprecated. i.e. IplImage should be `cv::Mat` and `cvLine` should be `cv::line` and so on. cv::Scalar has 4 values, I do not see a problem of it supporting Alpha, maybe is the drawing function per se as HansHirse pointed out – api55 May 20 '19 at 05:47

1 Answers1

2

So, I tested it now with IplImage and cv::Mat, and both cvCircle and cv::circle don't support drawing semi-transparent objects. I used OpenCV 3.4.0, since this version still supports the old C API.

Let's have a look at the following code:

// IplImage - doesn't work
IplImage* ipl = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 4);
cvSet(ipl, CvScalar(255, 0, 0, 255));
cvCircle(ipl, CvPoint(100, 100), 50, CvScalar(0, 0, 255, 128), CV_FILLED);

// cv::Mat - doesn't work
cv::Mat img = cv::Mat(201, 201, CV_8UC4, cv::Scalar(255, 0, 0, 255));
cv::circle(img, cv::Point(100, 100), 50, cv::Scalar(0, 0, 255, 128), cv::FILLED);

We create a blue 4-channel image with zero transparency, and draw a red circle with 0.5 transparency. In both cases, we get the following output:

False output

We see, that the part of red circle actually "replaces" the pixel values in the original blue image.

So, for IplImage as well as for cv::Mat we need to use blending, e.g. using addWeighted. Let's have a look at this code:

// IplImage - works
IplImage* iplBG = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvSet(iplBG, CvScalar(255, 0, 0));
IplImage* iplFG = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvSet(iplFG, CvScalar(0, 0, 0));
cvCircle(iplFG, CvPoint(100, 100), 50, CvScalar(0, 0, 255), CV_FILLED);
IplImage* iplOut = cvCreateImage(cvSize(201, 201), IPL_DEPTH_8U, 3);
cvAddWeighted(iplBG, 1, iplFG, 0.5, 0, iplOut);

// cv::Mat - works
cv::Mat imgBG = cv::Mat(201, 201, CV_8UC3, cv::Scalar(255, 0, 0));
cv::Mat imgFG = cv::Mat(201, 201, CV_8UC3, cv::Scalar(0, 0, 0));
cv::circle(imgFG, cv::Point(100, 100), 50, cv::Scalar(0, 0, 255), cv::FILLED);
cv::Mat imgOut;
cv::addWeighted(imgBG, 1, imgFG, 0.5, 0, imgOut);

In fact, we create a blue 3-channel background image like this:

Background

And, we create a black foreground 3-channel image of the same size with the red circle:

Foreground

Using addWeighted with alpha = 1 and beta = 0.5, we get the expected output for both versions:

Correct output

HansHirse
  • 18,010
  • 10
  • 38
  • 67