要使用 cv::cvtColor,您必须将单独的组件复制到连续的图像缓冲区中,如 Christoph Rackwitz 所述。
我不认为复制组件是微不足道的,我认为你应该得到答案。
连续的 YV12 图像采用以下结构:
- Y(列 x 行)- 顶部图像。
- V(列/2 x 行/2)- 低于 Y
- U (cols/2 x rows/2) - 低于 V
我们可以分配一个连续的缓冲区,并将组件复制到分配的缓冲区中。
由于 OpenCV “隐藏”了 data 成员中的缓冲区,我认为使用 new 分配缓冲区并创建一个“包装”缓冲区的 cv:Mat 会更简单。
例子:
unsigned char *YV12 = new unsigned char[cols*rows*3/2]; //Allocate continuous memory buffer for storing YV12 in as single buffer.
cv::Mat inYV12 = cv::Mat(rows*3/2, cols, CV_8UC1, YV12); //cv::Mat wrapper of YV12 buffer.
将 cv:Mat 包装器定义为 Y、U 和 V,共享连续缓冲区:
cv::Mat inY0 = cv::Mat(rows, cols, CV_8UC1, YV12); //Copy Y color channel.
cv::Mat inU0 = cv::Mat(rows/2, cols/2, CV_8UC1, YV12 + cols*rows); //U color channel (after Y).
cv::Mat inV0 = cv::Mat(rows/2, cols/2, CV_8UC1, YV12 + cols*rows + cols*rows/4); //V color channel (after U).
将三个单独的图像复制到连续图像:
inY.copyTo(inY0);
inU.copyTo(inU0);
inV.copyTo(inV0);
完整的代码示例:
#include "opencv2/opencv.hpp"
int main()
{
const int cols = 192;
const int rows = 108;
//Read Y, U and V into 3 separate buffers for testing.
////////////////////////////////////////////////////////////////////////////
unsigned char *Y = new unsigned char[cols*rows];
unsigned char *U = new unsigned char[cols*rows / 4];
unsigned char *V = new unsigned char[cols*rows / 4];
FILE *f;
f = fopen("test.yv12", "rb"); //Note: In Visual Studio, you may have to use fopen_s or define _CRT_SECURE_NO_WARNINGS
fread(Y, 1, cols*rows, f); //Read Y
fread(U, 1, cols*rows/4, f); //Read U
fread(V, 1, cols*rows/4, f); //Read V
fclose(f);
//Define cv::Mat "wrappers".
cv::Mat inY = cv::Mat(rows, cols, CV_8UC1, Y);
cv::Mat inU = cv::Mat(rows/2, cols/2, CV_8UC1, U);
cv::Mat inV = cv::Mat(rows/2, cols/2, CV_8UC1, V);
////////////////////////////////////////////////////////////////////////////
unsigned char *YV12 = new unsigned char[cols*rows*3/2]; //Allocate continuous memory buffer for storing YV12 in as single buffer.
cv::Mat inYV12 = cv::Mat(rows*3/2, cols, CV_8UC1, YV12); //cv::Mat wrapper of YV12 buffer.
//Define cv::Mat "wrappers" to the continuous memory buffer.
cv::Mat inY0 = cv::Mat(rows, cols, CV_8UC1, YV12); //Copy Y color channel.
cv::Mat inU0 = cv::Mat(rows/2, cols/2, CV_8UC1, YV12 + cols*rows); //U color channel (after Y).
cv::Mat inV0 = cv::Mat(rows/2, cols/2, CV_8UC1, YV12 + cols*rows + cols*rows/4); //V color channel (after U).
//Copy the three separate images to the continuous image.
inY.copyTo(inY0);
inU.copyTo(inU0);
inV.copyTo(inV0);
//Convert YV12 to BGRA:
cv::Mat dstBGRA;
//cv::cvtColor(inYV12, dstBGRA, cv::CV_YUV2BGRA_YV12);
cv::cvtColor(inYV12, dstBGRA, cv::COLOR_YUV2BGRA_YV12);
//Release memory
delete[] Y;
delete[] U;
delete[] V;
delete[] YV12;
cv::imwrite("dstBGRA.png", dstBGRA); //Save output for testing
//Show result (for testing):
cv::imshow("dstBGRA", dstBGRA);
cv::waitKey();
cv::destroyAllWindows();
return 0;
}
输入(转换为连续灰度图):
输出: