Ask Your Question
1

How to obtain Alpha from cv::mat (For wxWidgets::wxImage)

asked 2015-11-17 12:25:08 -0500

Rival gravatar image

updated 2015-11-18 11:31:13 -0500

The following code is not the entire block of code , instead it is the important pieces needed to get my question across. In short: I am asking how to receive the Alpha data from CV::Mat so that I may pass it into a parameter requesting an unsigned char* as Alpha.

in a scaling function, I have a cv::mat(Destination) that is built as so:

cvImage = convertWxToMatWithAlpha(image); //(cvImage is a CV::Mat)
wxData = (byte*) malloc(width * height * 4);
dst = cv::Mat(height, width, CV_8UC4, wxData);

I then re-size the image and save the results in dst which is a CV::Mat

cv::resize(cvImage,dst, cv::Size(width,height), 0, 0, CV_INTER_LINEAR);

I now need to create a wxImage with alpha using the dst(Be sure this is created using convertWxToMatWithAlpha, this is a function that is defined below in one of the answers.) mat. (Thanks pklab !)

    CV_Assert(dst.type() == CV_8UC4); //Throw an error if this is false.
   //Create a matrix which we will store the data in RBG format.
    cv::mat RGBMatrix; 
    //Convert the dst(BGRA) to RBG and store it in RBGMatrix.
    cv::cvtColor( dst,RGBMatrix, CV_BGRA2RGB ); 
    //Create an alpha matrix which we will mix into the RBGMatrix.
    cv::Mat alpha = cv::Mat::zeros(dst.size(),CV_8UC1); 
    int from_to[] = {3,0};
    cv::mixChannels(&dst,1,&alpha,1,from_to,1);
    if(dst.channels() == 4) //if we have four channels then build the wximage.
    {
        image->Create(dst.cols,dst.rows,RGBMatrix.data,alpha.data,false);
        return true;
    }

The constructor for wxImage I am using is specified as:

 wxImage(int width, int height, unsigned char *data, unsigned char *alpha, bool static_data=false)

EDIT: The above is the correct way of doing this. This is no longer a question, but now just a "how to". I hope this helps people in the future on the internet find a solution to this problem. Also take note of the answers given below this question.

edit retag flag offensive close merge delete

Comments

1

You can have an example here After for alpha channel you can use addWeighted function

LBerger gravatar imageLBerger ( 2015-11-17 15:32:05 -0500 )edit

I'm sorry but I don't really follow (Or understand the language.) I tried to re-read that function as much as possible to attempt and understand it, and I can see the case CV_32F: containing an if/else condition with the else case containing code being done on four pointers instead of three like all the others. So I assume that one specifically is dealing with Alpha? Even so, I have no clue really what's going on in this function.

Rival gravatar imageRival ( 2015-11-17 15:45:54 -0500 )edit
1

In png color image with alpha channels have got 4 plane. (0 to 3) Alpha channels is in 3. You can split your Mat im like this

vector<Mat> plane;
split(im,plane);

in plane[3] you have got alpha channel. After in wxwidgets constructor you can use this plane. You can forget my code because there is many case.

In your line

image->Create(dst.cols,dst.rows,dst.data,matrixChannels[3].data,false);

you can have memory management problem. Second you should check if matrixChannels[3].isContinuous is true. After if you want to use alpha channel you can read this post. In wxWidgets you can use alpha channels with wxBufferedPaintDC

LBerger gravatar imageLBerger ( 2015-11-17 16:15:31 -0500 )edit

You're still not getting through to me. You just did exactly as I have already done. But I did get new information out of that such as calling .isContinuous on matrixChannels[3]. The result is true. Is this a problem if it is true?

Rival gravatar imageRival ( 2015-11-17 16:36:27 -0500 )edit
1

What is your problem? Is it but I don't know how to get to it and use it where I want to use it Have you try save data using wxWidgets and retrieve alpha with an another software like in this post and this one ?

LBerger gravatar imageLBerger ( 2015-11-18 00:53:09 -0500 )edit

Well, It appears the output from this function goes into a different object named wxMemoryDC which does not play well with alpha at all, causing me to indirectly assume my code that builds an alpha channel into a new image was broken, when in actuality, that was not the case. Sorry! haha.

Rival gravatar imageRival ( 2015-11-18 10:07:41 -0500 )edit

1 answer

Sort by ยป oldest newest most voted
3

answered 2015-11-18 04:15:42 -0500

pklab gravatar image

updated 2015-11-18 04:21:21 -0500

In OpenCV multichannel images the columns contain as many sub columns as the number of channels. For example in case of an BGRA color system, memory is BGRABGRABGRA... planes are mixed together.

wxImage uses a buffer of RGB bytes with an optional buffer for the alpha bytes. So to create a wxImage from external buffer, two buffers are required like *data->RGBRGBRGB and *alpha->AAA

below is the code, I hope it helps... take care of channels order BGR vs RGB

From OpenCV BGRA Mat to wxWidget RGB+A image

void convertMatWithAlphaToWx(const cv::Mat &matBGRA, wxImage &wxRGBA)
{
    CV_Assert(matBGRA.type() == CV_8UC4);
    cv::Mat RGB;
    cvtColor(matBGRA, RGB, CV_BGRA2RGB);
    cv::Mat alpha = cv::Mat::zeros(matBGRA.size(), CV_8UC1);
    int from_to[] = { 3, 0 };
    cv::mixChannels(&matBGRA, 1, &alpha, 1, from_to, 1);
    // !!! Use non static memory because buffers refer to local Mats
    wxRGBA = wx::wxImage(matBGRA.cols, matBGRA.rows, RGB.data, alpha.data, false);
}

From wxWidget RGB+A image to OpenCV BGRA Mat

void convertWxToMatWithAlpha(const wxImage &wxRGBA, cv::Mat &matBGRA)
{
    CV_Assert(wxRGBA.HasAlpha());
    cv::Size sz(wxRGBA.GetWidth(), wxRGBA.GetHeight());
    unsigned char *wxData = wxRGBA.GetData();  //an array of characters in RGBRGBRGB
    unsigned char *wxAlpha = wxRGBA.GetAlpha();

    cv::Mat alpha(sz, CV_8UC1, wxAlpha);  //create a Mat over the wx alpha buf
    cv::Mat RGB(sz, CV_8UC3, wxData);     //create a RGB Mat over the wx data buf
    matBGRA = cv::Mat::zeros(sz, CV_8UC4);  //prepare a BGRA Mat
    // mix input channels RGB+Alpha to create BGRA 
    cv::Mat in[] = { RGB, alpha };
    //  rgb[0] -> bgra[2] , rgb[1] -> bgra[1] ,
    //  rgb[2] -> bgra[0] , alpha[0]-> bgra[3]
    int from_to[] = { 0, 2, 1, 1, 2, 0, 3, 3 };
    cv::mixChannels(in, 2, &matBGRA, 1, from_to, 4);
    // (i) matBGRA will have its own memory
}
edit flag offensive delete link more

Comments

1

Thanks! I figured this out yesterday before seeing this post, but the internet needed this type of documentation out there anyways, so thank you kind stranger! You've made solving this issue a little easier for anyone else in the future.

Rival gravatar imageRival ( 2015-11-18 10:09:16 -0500 )edit

@Rival you are welcome !

pklab gravatar imagepklab ( 2015-11-18 10:44:23 -0500 )edit
Login/Signup to Answer

Question Tools

1 follower

Stats

Asked: 2015-11-17 12:25:08 -0500

Seen: 1,018 times

Last updated: Nov 18 '15