I have a JPEG and a Mask. I want to create a PNG with the three JPEG channels and the alpha channel should be the Mask. How can I achieve this with OpenCV?
Regards
std::vector<cv::Mat> channels;
cv::split(jpgImage, channels);
channels.push_back(mask);
cv::Mat bgraImage;
cv::merge(channels, bgrAImage);
Documentation for split and merge functions
Thanks for your answer, I found a second solution:
cv::Mat transparent( height, width, CV_8UC4);
cv::Mat srcImg[] = {JPEG_img, alpha_Mask};
int from_to[] = { 0,0, 1,1, 2,2, 3,3 };
cv::mixChannels( srcImg, 2, &transparent, 1, from_to, 4 );
This works perfect, not sure which solution is better.
Related
i have searched a lot on the internet but i have only found how to convert Qimage to RGB format, i want to convert an Qimage to cv mat format CV_64FC3.
i have really bad results when i work with CV_8UC3
here is my code :
QImage myImage;
myImage.load("C://images//PolarImage300915163358.bmp");
QLabel myLabel;
myLabel.setPixmap(QPixmap::fromImage(myImage));
//myLabel.show();
cv::Mat image1 = QImage2Mat(myImage);
Mat img;
image1.convertTo(img, CV_64FC3, 1.0 / 255.0);
and here is the function that i used :
cv::Mat QImage2Mat(QImage const& src)
{
cv::Mat tmp(src.height(),src.width(),CV_8UC3,(uchar*)src.bits(),src.bytesPerLine());
cv::Mat result; // deep copy just in case (my lack of knowledge with open cv)
cvtColor(tmp, result,CV_BGR2RGB);
return result;
}
please help me i m new to both opencv and Qt
Not sure what you mean with bad results, but you are assuming that QImage also loads the image as OpenCV (BGR). In the documentation it tells you that they use ARGB.
So, knowing this you have 2 options:
Convert to QImage::Format_RGB888 the Qimage using the function convertToFormat and then this line cvtColor(tmp, result,CV_BGR2RGB); is not needed, since it will be already in RGB.
Use CV_8UC4 when creating the cv::Mat and then drop the first channel (channel alpha) using either split and join or mixchannels.
i have found what was going wrong, in fact, Qimage has a fourth channel for alpha so when you read the Qimage data you need to put it in CV_8UC4
here is the code :
Mat QImage2Mat(const QImage& src) {
cv::Mat mat = cv::Mat(src.height(), src.width(), CV_8UC4, (uchar*)src.bits(), src.bytesPerLine());
cv::Mat result = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = { 0,0, 1,1, 2,2 };
cv::mixChannels( &mat, 1, &result, 1, from_to, 3 );
return result;
}
I want to convert BGR image to ABGR/ARGB.There are conversion BGR2RGBA in opencv but not BGR2ABGR or BGR2ARGB.
It is possible with opencv or using any other method?
The required operation can be accomplished by swapping the image channels using cv::mixChannels as follows:
cv::Mat bgr, bgra;
//bgr initialization code here...
//.
//.
//.
cv::cvtColor(bgr, bgra, cv::COLOR_BGR2BGRA);
cv::Mat abgr(bgra.size(), bgra.type());
int from_to[] = { 0,3, 1,1, 2,2, 3,0 };
cv::mixChannels(&bgra,1,&abgr,1,from_to,4);
from_to array is the mapping function which specifies which channels from source will be copied to which channels of the destination image. The pairs indicate that channel number 0 of the input will be copied to channel number 3 of the output, 1 to 1, 2 to 2, and channel number 3 will be copied to channel number 0 of the output.
Alternatively, we can split the image channels, swap the required channels and merge again. It can be done as follows:
cv::cvtColor(bgr, bgra, cv::COLOR_BGR2BGRA);
std::vector<cv::Mat> channels_bgra;
cv::split(bgra, channels_bgra);
std::vector<cv::Mat> channels_abgr = { channels_bgra[3], channels_bgra[1], channels_bgra[2], channels_bgra[0] };
cv::merge(channels_abgr, abgr);
OpenCV doesn't support ARGB or ABGR formats, so you will not be able to display it or use some of the functions on it... However, it is possible to create them with split and merge functions of OpenCV. Here is some code to explain what I mean.
cv::Mat src, final_image;
// fill src as you prefer
std::vector<cv::Mat> channels;
cv::split(src, channels); // this will put each channel in a mat in the vector
// swap or add channels in the vector
cv::Mat alpha(src.rows, src.cols, CV_8U, cv::Scalar(255));
channels.push_back(alpha);
std::reverse(channels.begin(), channels.end()); //needs <algorithm>
// merge the channels in one new image
cv::merge(channels, final_image);
This can be done faster (maybe it will be just shorter) with the function mixChannels, but I will say that this one is a little bit more confusing.
So far i have managed to use masks and get the second image from the first. But what i want is the black area in second image to be transparent (i.e the output i an trying to get is the third image) Here is the code so far. Please advice me on this.
EDIT: Third one is from photoshop
//imwrite parameters
compression_params.push_back(CV_IMWRITE_JPEG_QUALITY);
compression_params.push_back(100);
//reading image to be masked
image = imread(main_img, -1);
//CV_LOAD_IMAGE_COLOR
namedWindow("output", WINDOW_NORMAL);
//imshow("output", image);
//Creating mask image with same size as original image
Mat mask(image.rows, image.cols, CV_8UC1, Scalar(0));
// Create Polygon from vertices
ROI_Vertices.push_back(Point2f(float(3112),float(58)));
ROI_Vertices.push_back(Point2f(float(3515),float(58)));
ROI_Vertices.push_back(Point2f(float(3515),float(1332)));
ROI_Vertices.push_back(Point2f(float(3112),float(958)));
approxPolyDP(ROI_Vertices, ROI_Poly, 1, true);
// Fill polygon white
fillConvexPoly(mask, &ROI_Poly[0] , ROI_Poly.size(), 255, 8, 0);
//imshow("output", mask);
// Create new image for result storage
imageDest = cvCreateMat(image.rows, image.cols, CV_8UC4);
// Cut out ROI and store it in imageDest
image.copyTo(imageDest, mask);
imwrite("masked.jpeg", imageDest, compression_params);
imshow("output", imageDest);
cvWaitKey(0);
This can be done by first setting its alpha value to 0 of the regions that you want to make them fully transparent (255 for others), and then save it to PNG.
To set the alpha value of pixel-(x,y), it can be done:
image.at<cv::Vec4b>(y, x)[3] = 0;
PS: you need to convert it to 4-channel format first if the image is not currently. For example:
cv::cvtColor(image, image, CV_BGR2BGRA);
Updated: It will be easier if you have already computed the mask for the ROI region, where you can simply merge it with the original image (assume having 3 channels) to get the final result. Like:
cv::Mat mask; // 0 for transparent regions, 255 otherwise (serve as the alpha channel)
std::vector<cv::Mat> channels;
cv::split(image, channels);
channels.push_back(mask);
cv::Mat result;
cv::merge(channels, result);
I am trying to convert a RGB image to ARGB format. Is there any way to this in openCV? As far as I know, it is possible to convert the image to RGBA, but am not sure about ARGB.
This is what I am doing currently:
cv::Mat argb(myImage.rows, myImage.cols, CV_8UC4);
cv::Mat alpha(myImage.rows, myImage.cols, CV_8UC1);
cv::Mat in[] = { myImage, alpha };
int from_to[] = { 0,1, 1,2, 2,3, 3,0 };
cv::mixChannels( in, 2, &argb, 1, from_to, 4 );
myImage is in 8uc3 format, which is my input image. But I need to change the format to ARGB for another application.
As far as i know cvtColor function doesn't provide such convertion, so you need to write it on your own - look at the source code of cvtColor function, your convertion will be quite similar to CV_BGR2RGB - you just need to switch first and last channel.
I am trying to change 3-channel image into 4-channel like this:
cv::VideoCapture video;
video.open("sample.avi");
cv::Mat source;
cv::Mat newSrc;
int from_to = { 0,0, 1,1, 2,2, 3,3 };
for ( int i = 0; i < 1000; i ++ )
{
video >> source;
cv::mixChannels ( source, 2, newSrc, 1, from_to, 4 );
}
Then I got
too many input arguments in function call
for the 'mixChannels' line. Besides, I am not sure whether I am giving the arguments correctly for my goal. Can someone help me? Thank you.
You can convert 3 channel image to 4 channel as follows:
cv::Mat source = cv::imread(path);
cv::Mat newSrc(source.size(), CV_MAKE_TYPE(source.depth(), 4));
int from_to[] = { 0,0, 1,1, 2,2, 2,3 };
cv::mixChannels(&source,1,&newSrc,1,from_to,4);
This way channel 4 will be a duplicate of channel 3. By using a negative number in the from_to list, the output channel is zero filled. eg:
int from_to[] = { 0,0, 1,1, 2,2, -1,3 };
What is the 4th channel supposed to contain?
How about:
VideoCapture cap(0);
Mat frame;
cap >> frame;
Mat RGBA(frame.size(), CV_8UC4, camData);
cv::cvtColor(frame, RGBA, CV_BGR2RGBA, 4);
I think it should be like this:
cv::Mat source = cv::imread(path);
cv::Mat newSrc = cv::Mat(source.rows,source.cols,CV_8UC4);
int from_to[] = { 0,0, 1,1, 2,2, 3,3 };
cv::mixChannels(&source,1,&newSrc,1,from_to, source.channels());
In C++11 you can use initializer lists to provide multiple matrices for batch conversion inline:
cv::mixChannels({{source}}, {{newSrc}}, from_to, source.channels());
We set 3 pairs to be copied, so this leaves the 4 channel empty in newsrc. And 1 in the second and forth parameter means that the pointers source and newSrc point to one element to be processed. The last parameter gives the length of from_to.