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?
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);