2

I want to draw a transparent polygon (triangle in this case). But I'm unable to find any examples by searching the web.

// Create image
Mat image = Mat::zeros( 400, 400, CV_8UC3 );

// Draw a circle 
/** Create some points */
Point Treangle_points[1][20];
Treangle_points[0][0] = Point( 150, 100 );
Treangle_points[0][1] = Point( 275, 350 );
Treangle_points[0][2] = Point( 50, 20 );

const Point* ppt[1] = { Treangle_points[0] };
int npt[] = { 3 };

fillPoly( image, ppt, npt, 1, Scalar( 255, 255, 255 ), 8 );
imshow("Image",image);
halfer
  • 19,824
  • 17
  • 99
  • 186
Funktiona
  • 113
  • 2
  • 11

3 Answers3

3

To use transparency, you need to work with alpha channel, in BGRA color space. alpha = 0 means fully transparent, while alpha = 255 means opaque colors.

You need to create a CV_8UC4 image (aka Mat4b), or convert a 3 channel image to 4 channel with cvtColor(src, dst, COLOR_BGR2BGRA), and draw a transparent filled shape, with alpha channel equals to 0.

If you load a 4 channel image, remember to use imread("path_to_image", IMREAD_UNCHANGED);

Transparent triangle (the transparency is rendered as white here, you can see that the image is in fact transparent opening it with your preferred image viewer):

enter image description here

Code:

#include <opencv2/opencv.hpp>
#include <vector>
using namespace std;
using namespace cv;

int main()
{
    // Create a BGRA green image 
    Mat4b image(300, 300, Vec4b(0,255,0,255));

    vector<Point> vertices{Point(100, 100), Point(200, 200), Point(200, 100)};

    vector<vector<Point>> pts{vertices};
    fillPoly(image, pts, Scalar(0,0,0,0));
    //                                ^ this is the alpha channel                              

    imwrite("alpha.png", image);
    return 0;
}

NOTE

imshow won't show transparency correctly, since it just ignores the alpha channel.


C++98 version

#include <opencv2/opencv.hpp>
using namespace cv;

int main()
{
    // Create a BGRA green image 
    Mat4b image(300, 300, Vec4b(0, 255, 0, 255));

    Point vertices[3];
    vertices[0] = Point(100, 100);
    vertices[1] = Point(200, 200);
    vertices[2] = Point(200, 100);

    const Point* ppt[1] = { &vertices[0] };
    int npt[] = { 3 };

    fillPoly(image, ppt, npt, 1, Scalar(0, 0, 0, 0), 8);

    imwrite("alpha.png", image);

    imshow("a", image);
    waitKey();

    return 0;
}
Miki
  • 40,887
  • 13
  • 123
  • 202
  • Getting tons of errors. main.cpp: In function ‘int main()’: main.cpp:11:27: warning: extended initializer lists only available with -std=c++11 or -std=gnu++11 vector vertices{Point(100, 100), Point(200, 200), Point(200, 100)}; ^ main.cpp:11:77: error: in C++98 ‘vertices’ must be initialized by constructor, not by ‘{...}’ vector vertices{Point(100, 100), Point(200, 200), Point(200, 100)}; – Funktiona Nov 19 '15 at 01:00
  • Oh, it seems you don't have C++11. Let me refactor the code to C++98 – Miki Nov 19 '15 at 01:01
  • can't you just add `-std=c++11` to your compiler line? – Miki Nov 19 '15 at 01:13
  • This is what I type to make it g++ -o test main.cpp `pkg-config opencv --cflags --libs` – Funktiona Nov 19 '15 at 01:14
  • I really can't tell you how to configure that. Try the second snippet, it should work for C++98 @Funktiona – Miki Nov 19 '15 at 01:26
  • hello. Can u help my topic. same with your drawing function : https://stackoverflow.com/questions/51872759/ios-opencv-can-not-fillconvexpoly-with-alpha – famfamfam Aug 16 '18 at 08:41
2

This question has been really an old one. And I find some answers but they are not what I want. I want set a polygon roi transparent which overlaps that areas without help of alpha channel, ie. we can still observe the background through that transparent area without a 4 channels image: a quadrangle transparent area

Here is the code:

// img: input 3 channels image
// roi : polygon represents by points
// color: transparent base color
// alpha: transparent ratio
// out:   out image with transparent area
void SetTransparentColor(cv::Mat &img, vector<vector<cv::Point> > &roi, cv::Scalar color, double alpha, cv::Mat &out)
{
  cv::Mat layer = cv::Mat::zeros(img.size(), CV_8UC3);

  cv::fillPoly(layer, roi, color);

  cv::addWeighted(img, alpha, layer, 1-alpha, 0, out);
}

I have also tried some other ways, and the core idea is the same, by merging two area pixels with alpha value which stands for transparent ratio. But they are time consuming. So I will not put these codes here.

0

as an addition to Miki's answer the sample code below maybe useful.

for more information see http://answers.opencv.org/question/73114

see also sample code of OpenCV documentation

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"

using namespace cv;

int main( int, char** argv )
{
    Mat image(400, 400, CV_8UC4, Scalar(0, 0, 200,0));
    Mat bgra[4];
    split(image,bgra);

    rectangle(bgra[3],Rect(100,100,200,200),Scalar(255),-1);

    merge(bgra,4,image);
    imwrite("transparent1.png",image);

    rectangle(bgra[3],Rect(150,150,100,100),Scalar(127),-1);
    merge(bgra,4,image);
    imwrite("transparent2.png",image);

    bgra[3] = bgra[3] * 0.5; // here you can change transparency %50
    // bgra[3] = bgra[3] + 50 // you can add some value
    // bgra[3] = bgra[3] - 50 // you can subtract some value

    merge(bgra,4,image);
    imwrite("transparent3.png",image);

    waitKey(0);
    return(0);
}
sturkmen
  • 3,495
  • 4
  • 27
  • 63