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.
Related
Hel lo,
I am writing an effect plug-in for Adobe After Effects in C++, and I need to create a cv::Mat using pixel data that's already in memory. However, when I initialize it using:
cv::Mat in_frame_mat(height, width, CV_8UC4, input->data);
(input->data is a pointer to the first byte), the output is all blue.
I think this is because AE stores pixel data RGBA or ARGB while OpenCV assumes BGRA or ABGR (not sure which).
I know that I could iterate through every pixel and create a new space in memory to store a BGRA representation of the image, then initialize a cv::Mat with that, but this is really performance constrained and I don't want to add unnecessary compute time.
Is there a way to create a cv::Mat using existing pixel data that is stored RGBA?
Thanks!
OpenCV assumes the channel order is BGR (or BGRA).
You can use cv::cvtColor to change your input to BGRA.
The 3rd parameter code should be one of the values from cv::ColorConversionCodes, e.g.: cv::COLOR_RGBA2BGRA (seems to be what you need).
Update:
Following the OP's comment below that his input is actually ARGB (not RGBA):
ARGB to BGRA is not supported by cv::cvtColor.
But you can use cv:mixChannels to do any arbitrary reordering of the channels (the fromTo parameter specifies the reordering).
See below how to use it to convert ARGB to BGRA:
#include <vector>
cv::Mat argb; // initialized from your input data
cv::Mat bgra(argb.size(), argb.type());
std::vector<int> fromTo{ 0,3, 1,2, 2,1, 3,0 }; // ARGB->BGRA: 0->3, 1->2, 2->1, 3->0
cv::mixChannels(argb, bgra, fromTo);
If your OpenCV version does not support this flavor of cv::mixChannels (with std::vector etc.), you can try:
cv::Mat argb; // initialized from your input data
cv::Mat bgra(argb.size(), argb.type());
int fromTo[] = { 0,3, 1,2, 2,1, 3,0 }; // ARGB->BGRA: 0->3, 1->2, 2->1, 3->0
cv::mixChannels(&argb, 1, &bgra, 1, fromTo, 4);
Update 2:
In order to convert ARGB to BGR (i.e. without the alpha channel), you can use cv::mixChannels in the following way:
#include <vector>
cv::Mat argb; // initialized from your input data
cv::Mat bgr(argb.size(), CV_8UC3); // NOTE: the type is CV_8UC3, not argb.type()
std::vector<int> fromTo{ 1,2, 2,1, 3,0 }; // ARGB->BGR: 1->2, 2->1, 3->0
cv::mixChannels(argb, bgr, fromTo);
I have a 32-bit integer array containing pixel values of a 3450x3450 image I want to create a Mat image with. Tried the following:
int *image_array;
image_array = (int *)malloc( 3450*3450*sizeof(int) );
memset( (char *)image_array, 0, sizeof(int)*3450*3450 );
image_array[0] = intensity_of_first_pixel;
...
image_array[11902499] = intensity_of_last_pixel;
Mat M(3450, 3450, CV_32FC1, image_array);
and upon displaying the image I get a black screen. I should also note the array contains a 16-bit grayscale image.
I guess you should try to convert the input image, which I assume is in RGB[A] format using:
cv::Mat m(3450, 3450, CV_8UC1, image_array) // For GRAY image
cv::Mat m(3450, 3450, CV_8UC3, image_array) // For RGB image
cv::Mat m(3450, 3450, CV_8UC4, image_array) // For RGBA image
Is there a way to convert from RGB to YUYV (YUY 4:2:2) format? I noted that OpenCV has reverse operation, but not RGB to YUYV for some reason. Maybe someone can point to code which does that (even outside of OpenCV library)?
UPDATE
I found libyuv library which may work for this purpose by doing BGR to ARGB conversion and then ARGB to YUY2 format (hopefully this is the same as YUYV 4:2:2). But it doesn't seem to work. Do you happen to know what yuyv buffer dimensions/type should look like? What its stride?
To clarify YUYV and YUY2 are the same formats if it helps.
UPDATE 2
Here is my code of using libyuv library:
Mat frame;
// Convert original image im from BGR to BGRA for further use in libyuv
cvtColor(im, frame, CVX_BGR2BGRA);
// Actually libyuv requires ARGB (i.e. reverse of BGRA), so I swap channels here
int from_to[] = { 0,3, 1,2, 2,1, 3,0 };
mixChannels(&frame, 1, &frame, 1, from_to, 4);
// This is the most confusing part. Not sure what argb_stride suppose to be - length of a row in bytes or size of single value in the array?
const uint8_t* argb_data = frame.data;
int argb_stride = 8;
// Also it is not clear what size of yuyv frame should be since we duplicate one Y
Mat yuyv(frame.rows, frame.cols, CVX_8UC2);
uint8_t* yuyv_data = yuyv.data;
int yuyv_stride = 16;
// Do actual conversion
libyuv::ARGBToYUY2(argb_data, argb_stride, yuyv_data, yuyv_stride,
frame.cols, frame.rows);
// Then I feed yuyv_data to video stream buffer and see green or purple image instead of video stream.
UPDATE 3
Mat frame;
cvtColor(im, frame, CVX_BGR2BGRA);
// ARGB
int from_to[] = { 0,3, 1,2, 2,1, 3,0 };
Mat rgba(frame.size(), frame.type());
mixChannels(&frame, 1, &rgba, 1, from_to, 4);
const uint8_t* argb_data = rgba.data;
int argb_stride = rgba.cols*4;
Mat yuyv(rgba.rows, rgba.cols, CVX_8UC2);
uint8_t* yuyv_data = yuyv.data;
int yuyv_stride = width * 2;
int res = libyuv::ARGBToYUY2(argb_data, argb_stride, yuyv_data, yuyv_stride, rgba.cols, rgba.rows);
It appears that although method is called ARGBToYUY2 it requires BGRA order of channels (not reverse).
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.
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.