把YUV转化成opencv中的Mat格式的两行代码备份

本文介绍了使用OpenCV将YUV灰度图和彩色图转换为Mat格式的方法,并提供了将JPG图片转换为NV12格式YUV图像的示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果是把YUV灰度图(只有Y分量)转化为Mat
cv::Mat cv_img;
cv::Mat cv_yuv(height, width, CV_8UC1, pFrame);//pFrame为YUV数据地址
cv_img = cv::Mat(height, width, CV_LOAD_IMAGE_COLOR); 
cv::cvtColor(cv_yuv, cv_img, COLOR_GRAY2BGR); 

 如果是把YUV彩色图转化为Mat

cv::Mat cv_img;
cv::Mat cv_yuv(height + height/2, width, CV_8UC1, pFrame);//pFrame为YUV数据地址,另外这里就是用 CV_8UC1非 CV_8UC3.
cv_img = cv::Mat(height, width, CV_8UC3); 
cv::cvtColor(cv_yuv, cv_img, COLOR_YUV2BGR_I420);

另外,如果想jpg转成yuv nv12没有opencv直接可以实现,要用下面的代码

您好!我很抱歉给您带来困扰。我之前的回答中提到的 cv::COLOR_BGR2YUV_NV12 常量在 OpenCV 库中并不存在。正确的常量应该是 cv::COLOR_YUV2BGR_NV12 或 cv::COLOR_YUV2RGB_NV12,它们分别用于将 NV12 格式的 YUV 图像转换为 BGR 或 RGB 图像。

如果您想将 JPG 图片转换为 NV12 格式的 YUV 图像,您可以先使用 cv::cvtColor 函数将 JPG 图片转换为 YUV 图像,然后再手动将其转换为 NV12 格式。下面是一个简单的示例代码,它演示了如何读取 JPG 图片并将其转换为 NV12 格式的 YUV 图像:

    这个代码是错误的,不要用了。
    //读取jpg图片,模拟一个yuv输入数据。
    cv::Mat cv_img = cv::imread(argv[2], 3);
    // 获取图像的宽度和高度
    int width = cv_img.cols;
    int height = cv_img.rows;

    cv::Mat yuvImage;
    //cv::cvtColor(cv_img, yuvImage, cv::COLOR_BGR2YUV_I420); 
    cv::cvtColor(cv_img, yuvImage, cv::COLOR_BGR2YUV);

    // 将 YUV 图像分离成 Y、U 和 V 三个通道
    std::vector<cv::Mat> yuvChannels(3);
    cv::split(yuvImage, yuvChannels);
    cv::Mat yChannel = yuvChannels[0];
    cv::Mat uChannel = yuvChannels[1];
    cv::Mat vChannel = yuvChannels[2];

    // 缩小 U 和 V 通道的图像
    cv::resize(uChannel, uChannel, cv::Size(), 0.5, 0.5);
    cv::resize(vChannel, vChannel, cv::Size(), 0.5, 0.5);

    // 创建 NV12 图像
    cv::Mat nv12Image(height * 3 / 2, width, CV_8UC1);
    yChannel.copyTo(nv12Image(cv::Rect(0, 0, width, height)));

    for (int i = 0; i < height / 2; i++) {
        uchar* uvRow = nv12Image.ptr<uchar>(height + i);
        uchar* uRow = uChannel.ptr<uchar>(i);
        uchar* vRow = vChannel.ptr<uchar>(i);
        for (int j = 0; j < width / 2; j++) {
            uvRow[j * 2] = uRow[j];
            uvRow[j * 2 + 1] = vRow[j];
        }
    }
这个代码是错误的,不要用了。

下面的代码是正确的将Mat转成nv12的代码

int main(int argc, char** argv) {
    if (argc != 3) {
        cout << "Usage: " << argv[0] << " <input_video> <output_yuv>" << endl;
        return -1;
    }

    string input_video = argv[1];
    string output_yuv = argv[2];

    std::cout<<"input_video  "<<input_video<<std::endl;

    VideoCapture cap(input_video);
    if (!cap.isOpened()) {
        cerr << "Error opening video file" << endl;
        return -1;
    }

    int image_w = 640;
    int image_h = 360;
    int frame_count = static_cast<int>(cap.get(CAP_PROP_FRAME_COUNT));
    int frame_width = static_cast<int>(cap.get(CAP_PROP_FRAME_WIDTH));
    int frame_height = static_cast<int>(cap.get(CAP_PROP_FRAME_HEIGHT));
    double fps = cap.get(CAP_PROP_FPS);

    cout << "Input video resolution: " << frame_width << "x" << frame_height << endl;
    cout << "Output video resolution: " << image_w << "x" << image_h << endl;
    cout << "Frame count: " << frame_count << endl;
    cout << "FPS: " << fps << endl;

    ofstream yuv_file(output_yuv, ios::out | ios::binary);
    if (!yuv_file.is_open()) {
        cerr << "Error opening output YUV file" << endl;
        return -1;
    }

    Mat frame, resized_frame, yuv_frame;
    while (cap.read(frame)) {
        resize(frame, resized_frame, Size(image_w, image_h)); 
        
    // 转换到I420
	cv::Mat I420;                                      // I420格式图像
	cv::cvtColor(resized_frame, I420, cv::COLOR_BGR2YUV_I420); // 转换I420格式
 
	uint8_t* pI420 = I420.ptr<uint8_t>();              // I420数据指针
	int32_t I420_y_s = image_h * image_w;              // I420中 Y长度
	int I420_uv_h = image_h / 2;                       // I420中UV高度
	int I420_uv_w = image_w / 2;                       // I420中UV宽度
 
	// 转换到NV12
	cv::Mat NV12 = cv::Mat(image_h * 3 / 2, image_w, CV_8UC1); // NV12格式图像
	uint8_t* pNV12 = NV12.ptr<uint8_t>();                      // NV12数据指针
	memcpy(pNV12, pI420, I420_y_s); // 拷贝I420中的Y数据到NV12中
 
	uint8_t* pI420_U = pI420 + I420_y_s;                // 移动I420中U分量指针到U数据头部
	uint8_t* pI420_V = pI420_U + I420_uv_h * I420_uv_w; // 移动I420中V分量指针到V数据头部
	pNV12 = pNV12 + I420_y_s;                           // 移动NV12指针到U数据头部
	for (int i = 0; i < I420_uv_h * I420_uv_w; i++)
    { 
        // 遍历I420中UV分量数据,复制到NV12中
		// 把I420中U数据复制到NV12中U数据对应位置
	    *pNV12 = *pI420_U;
	    pNV12++;
	    pI420_U++;
 
		// 把I420中V数据复制到NV12中V数据对应位置
	    *pNV12 = *pI420_V;
	    pNV12++;
	    pI420_V++;
	}
	int image_len = image_w * image_h * 3 / 2;
    yuv_file.write(reinterpret_cast<const char*>(NV12.data), image_len);
    }

    cap.release();
    yuv_file.close();

    cout << "Video processing completed successfully." << endl;
    return 0;
}

以下代码是把yuv转成RGB的代码备份

//将输入的nv12图像转为rgba图像
void nv12_to_rgba(uint8_t* src_nv12, uint8_t* dst_rgba, int width, int height) {
    if (width < 1 || height < 1 || src_nv12 == nullptr || dst_rgba == nullptr) {
        return;
    }

    int frame_size = width * height;
    uint8_t* y_plane = src_nv12;
    uint8_t* uv_plane = src_nv12 + frame_size;

    for (int j = 0; j < height; ++j) {
        for (int i = 0; i < width; ++i) {
            int y_index = j * width + i;
            int uv_index = (j / 2) * width + (i & ~1);

            uint8_t y = y_plane[y_index];
            uint8_t u = uv_plane[uv_index];
            uint8_t v = uv_plane[uv_index + 1];

            int c = y - 16;
            int d = u - 128;
            int e = v - 128;

            int r = (298 * c + 409 * e + 128) >> 8;
            int g = (298 * c - 100 * d - 208 * e + 128) >> 8;
            int b = (298 * c + 516 * d + 128) >> 8;

            r = clamp(r, 0, 255);
            g = clamp(g, 0, 255);
            b = clamp(b, 0, 255);

            int rgba_index = y_index * 4;
            dst_rgba[rgba_index] = static_cast<uint8_t>(r);
            dst_rgba[rgba_index + 1] = static_cast<uint8_t>(g);
            dst_rgba[rgba_index + 2] = static_cast<uint8_t>(b);
            dst_rgba[rgba_index + 3] = 255; // Alpha channel
        }
    }
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈 洪 伟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值