OpenCV_YUV图片处理

该文章详细介绍了如何在OpenCV中进行YUV图像的读取、转换和保存,特别是从BGR到YUV420_NV12的转换,以及从YUV420_NV12回转到BGR的过程。提供了手动和自动转换的代码示例,还包括了将YUV转换为灰度图像并保存的函数。
摘要由CSDN通过智能技术生成

YUV图片格式

OpenCV读取图片时默认都是BGR,一般需要使用cv::cvtColor转为RGB,但有些情况下需要使用YUV格式,YUV格式比较多,OpenCV并没有提供所有的转换方法,但是可以自己实现

YUV格式详解

主要使用的还是YUV420_NV12格式

// read img and convert to different format
// bgr -> argb1555
cv::Mat GetArgb(std::string& img_path) {
    cv::Mat src_img = cv::imread(img_path);
    cv::Mat bgr_555_img;
    cv::cvtColor(src_img, bgr_555_img, cv::COLOR_BGR2BGR555);
    cv::Mat rgba_img;
    cv::cvtColor(bgr_555_img, rgba_img, cv::COLOR_BGR5552RGBA);
    cv::Mat argb_img(rgba_img.size(), rgba_img.type());
    int from_to[] = {0, 1, 1, 2, 2, 3, 3, 0};
    cv::mixChannels(&rgba_img, 1, &argb_img, 1, from_to, 4);
    return argb_img;
}

// bgr -> YUV420_NV12
cv::Mat GetYuv(std::string& img_path) {
    cv::Mat src_img = cv::imread(img_path);
    int src_h = src_img.rows;
    int src_w = src_img.cols;
    cv::Mat yuv_img(src_h * 1.5, src_w, CV_8UC1);
    cv::cvtColor(src_img, yuv_img, cv::COLOR_BGR2YUV_I420);  // YUV_I420

    int n_y  = src_h * src_w;
    int n_uv = n_y / 2;
    int n_u  = n_y / 4;

    std::vector<uint8_t> uv(n_uv);
    std::copy(yuv_img.data + n_y, yuv_img.data + n_y + n_uv, uv.data());
    for (int i = 0; i < n_u; ++i) {
        yuv_img.data[n_y + 2 * i] = uv[i];               // U
        yuv_img.data[n_y + 2 * i + 1] = uv[n_u + i];     // V
    }
    return yuv_img;
 }

// YUV420_NV12 -> bgr
cv::Mat GetBgr(cv::Mat& yuv_img) {
    cv::Mat bgr_img;
    cv::cvtColor(yuv_img, bgr_img, cv::COLOR_YUV2BGR_NV12);
    return bgr_img;
}

// YUV420_NV12 -> bgr, manual conversion
cv::Mat GetBgrManual(cv::Mat& yuv_img) {
    int src_h = yuv_img.rows;
    int src_w = yuv_img.cols;
    int yuv_h = src_h * 2 / 3;
    int yuv_w = src_w;
    int n_y  = yuv_h * yuv_w;
    int n_uv = n_y / 2;
    int n_u  = n_y / 4;

    std::vector<uint8_t> uv(n_uv);
    std::copy(yuv_img.data + n_y, yuv_img.data + n_y + n_uv, uv.data());
    for (int i = 0; i < n_u; i += 2) {
        yuv_img.data[n_y + i] = uv[i];  // U
    }

    for (int i = 1; i < n_u; i += 2) {
        yuv_img.data[n_y + i] = uv[i];  // V
    }

    cv::Mat bgr_img(yuv_h, yuv_w, CV_8UC3);
    cvtColor(yuv_img, bgr_img, cv::COLOR_YUV2BGR_I420);
    return bgr_img;
}

// YUV420 -> bgr, then save img
void SaveImg(cv::Mat& res, std::string& res_img_path) {
    // std::cout << "save img. " << std::endl;
	if (!res.empty()) {
		cv::Mat bgr_img = GetBgr(res);
		cv::imwrite(res_img_path, bgr_img);
        std::cout << "Save img success. " << std::endl;
	}else {
        std::cout << "Save img error. " << std::endl;
    }
}

// save gray img
void SaveGrayImg(cv::Mat& res, std::string& res_img_path) {
    // std::cout << "save img. " << std::endl;
	if (!res.empty()) {
		cv::imwrite(res_img_path, res);
        std::cout << "Save img success. " << std::endl;
	}else {
        std::cout << "Save img error. " << std::endl;
    }
}

// YUV420 -> gray, then save img
void saveYUVtoGrayImg(cv::Mat& yuv_img, std::string& res_img_path) {
    // std::cout << "save gray img. " << std::endl;
    if (!yuv_img.empty()) {
        int yuv_img_h = yuv_img.rows;
        int yuv_img_w = yuv_img.cols;
        int gray_img_h = yuv_img_h * 2 / 3;
        int gray_img_w = yuv_img_w;
        cv::Mat gray_img(gray_img_h, gray_img_w, CV_8UC1);
        memcpy((void *)gray_img.data, (void *)yuv_img.data, (size_t)gray_img_h * gray_img_w);
		cv::imwrite(res_img_path, gray_img);
        std::cout << "Save img success. " << std::endl;
	}else {
        std::cout << "Save img error. " << std::endl;
    }
}

// print img property
void PrintImgPro(cv::Mat &img) {
    std::cout << "img.rows: "           << img.rows             << std::endl;
	std::cout << "img.cols: "           << img.cols             << std::endl;
    std::cout << "img.empty: "          << img.empty()          << std::endl;
	std::cout << "img.dims: "           << img.dims             << std::endl;
	std::cout << "img.channels: "       << img.channels()       << std::endl;
	std::cout << "img.type: "           << img.type()           << std::endl;
	std::cout << "img isContinuous: "   << img.isContinuous()   << std::endl;
    std::cout << "img.depth: "          << img.depth()          << std::endl;
	std::cout << "img.elemSize: "       << img.elemSize()       << std::endl;
	std::cout << "img.step: "           << img.step             << std::endl;
    // if (!img.isContinuous()) {  // make img continuous
	// 	img = img.clone();
	// }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值