OpenCV对NV12进行通道分离后缩放再保存为NV12格式

1.OpenCVNV12进行通道分离后缩放再保存为NV12格式

 

#include <stdio.h>
#include <opencv2/opencv.hpp>

/**
 * @brief 
 *   把输入的NV12图像分离为YUV三个分量图像
 * @param image_yuv 输入YUV图像
 * @param image_y   输出的Y分量
 * @param image_u   输出的U分量
 * @param image_v   输出的V分量
 * @param image_h   输入图像高度
 * @param image_w   输入图像宽度
 * @return void     方法返回空值
 */
int nv12_split_yuv(cv::Mat &image_yuv, cv::Mat &image_y, cv::Mat &image_u, cv::Mat &image_v, int image_h, int image_w)
{
	// 分离Y分量数据
	void *y_src = (void *)image_yuv.data; // Y分量的起始指针
	void *y_dst = (void *)image_y.data;   // Y分量的目的指针
	size_t y_len = image_h * image_w;     // Y分量的拷贝长度
	memcpy(y_dst, y_src, y_len);          // 分离Y分量的数据

	// 分离UV分量数据
	unsigned char *uv_src = (unsigned char *)(image_yuv.data + image_h * image_w); // UV分量的起始指针
	unsigned char *u_dst = (unsigned char *)image_u.data;                          //  U分量的目的指针
	unsigned char *v_dst = (unsigned char *)image_v.data;                          //  V分量的目的指针
	int uv_len = (image_h / 2) * (image_w / 2);                                    // UV分量的拷贝长度
	for(int i = 0; i < uv_len; i++){                                               // 分量UV分量的数据
		u_dst[i] = *uv_src++;                                                      // 拷贝 U后指针后移
		v_dst[i] = *uv_src++;                                                      // 拷贝 V后指针后移
	}

	return 0;
}

/**
 * @brief 
 *   把输入的YUV三个分量图像合并为NV12图像
 * @param image_y   输入的Y分量
 * @param image_u   输入的U分量
 * @param image_v   输入的V分量
 * @param image_yuv 输出YUV图像
 * @param image_h   输入图像高度
 * @param image_w   输入图像宽度
 * @return void     方法返回空值
 */
int nv12_merge_yuv(cv::Mat &image_y, cv::Mat &image_u, cv::Mat &image_v, cv::Mat &image_yuv, int image_h, int image_w)
{
	// 合并Y分量数据
	void *y_src = (void *)image_y.data;   // Y分量的起始指针
	void *y_dst = (void *)image_yuv.data; // Y分量的目的指针
	size_t y_len = image_h * image_w;     // Y分量的拷贝长度
	memcpy(y_dst, y_src, y_len);          // 合并Y分量的数据

	// 合并UV分量数据
	unsigned char *u_src = (unsigned char *)image_u.data;                          //  U分量的起始指针
	unsigned char *v_src = (unsigned char *)image_v.data;                          //  V分量的起始指针
	unsigned char *uv_dst = (unsigned char *)(image_yuv.data + image_h * image_w); // UV分量的目的指针
	int uv_len = (image_h / 2) * (image_w / 2);                                    // UV分量的拷贝长度
	for(int i = 0; i < uv_len; i++){                                               // 分量UV分量的数据
		*uv_dst++ = u_src[i];                                                      // 拷贝 U后指针后移
		*uv_dst++ = v_src[i];                                                      // 拷贝 V后指针后移
	}

	return 0;
}

int main(int argc, char **argv)
{
	// 检查输入参数
	if(argc != 4){
		printf("Usage: %s <image_path> <image_width> <image_height>\n", argv[0]);
		return -1;
	}

	// 读取输入图像
	char *image_path = argv[1];
	int image_w = atoi(argv[2]);
	int image_h = atoi(argv[3]);
	int image_len = image_w * image_h * 3 / 2;
	unsigned char *image_buf = (unsigned char *)malloc(image_len);

	FILE *fp = fopen(image_path, "rb");
	fread(image_buf, image_len, 1, fp);
	fclose(fp);

	// 分离NV12分量
	cv::Mat image_yuv(image_h * 3 / 2, image_w, CV_8UC1, image_buf);
	cv::Mat image_y(image_h, image_w, CV_8UC1);
	cv::Mat image_u(image_h / 2, image_w / 2, CV_8UC1);
	cv::Mat image_v(image_h / 2, image_w / 2, CV_8UC1);

	nv12_split_yuv(image_yuv, image_y, image_u, image_v, image_h, image_w);

	// 缩放分离图像
	float hw_ratio = (float)image_h / image_w;
	int image2_h = int(416 * hw_ratio);
	int image2_w = 416;
	printf("image2_h:%d, image2_w:%d\n", image2_h, image2_w);

	cv::resize(image_y, image_y, cv::Size(image2_w, image2_h), cv::INTER_LINEAR);
	cv::resize(image_u, image_u, cv::Size(image2_w / 2, image2_h / 2), cv::INTER_LINEAR);
	cv::resize(image_v, image_v, cv::Size(image2_w / 2, image2_h / 2), cv::INTER_LINEAR);

	// 合并NV12分量
	cv::Mat image_yuv2(image2_h * 3 / 2, image2_w, CV_8UC1, image_buf);
	nv12_merge_yuv(image_y, image_u, image_v, image_yuv2, image2_h, image2_w);

	// 显示分离图像
	cv::imshow("image_y", image_y);
	cv::waitKey();

	cv::imshow("image u", image_u);
	cv::waitKey();

	cv::imshow("image v", image_v);
	cv::waitKey();

	cv::Mat image_bgr;
	cv::cvtColor(image_yuv2, image_bgr, cv::COLOR_YUV2BGR_NV12);
	cv::imshow("image bgr", image_bgr);
	cv::waitKey();

	// 保存转换图像
	fp = fopen("output/result.yuv", "wb");
	int image2_len = image2_w * image2_h * 3 / 2;
	fwrite(image_yuv2.data, image2_len, 1, fp);
	fclose(fp);

	// 读取转换图像
	fp = fopen("output/result.yuv", "rb");
	unsigned char *image2_buf = (unsigned char *)malloc(image_len);
	fread(image2_buf, image2_len, 1, fp);
	fclose(fp);

	// 显示转换图像
	cv::Mat image2_yuv(image2_h * 3 / 2, image2_w, CV_8UC1, image2_buf);
	cv::Mat image2_bgr;
	cv::cvtColor(image2_yuv, image2_bgr, cv::COLOR_YUV2BGR_NV12);
	cv::imshow("image2 bgr", image2_bgr);
	cv::waitKey();

	// 释放图像缓存
	free(image_buf);
	free(image2_buf);

	return 0;
}

 

 

参考地址:

https://www.shuzhiduo.com/A/Ae5Rw1W3dQ/

https://blog.51cto.com/u_12204415/3804362

https://blog.csdn.net/sinat_36684217/article/details/75117920

https://www.cnblogs.com/peifx/p/16360976.html

https://cloud.tencent.com/developer/article/2048327

https://blog.csdn.net/sadsfdsvf/article/details/124291194

https://blog.csdn.net/chengkeke366/article/details/119616735

https://blog.csdn.net/m0_37862025/article/details/100727652

https://blog.csdn.net/weixin_43817380/article/details/111578757

 

posted @ 2023-02-17 11:18  盛夏夜  阅读(415)  评论(0编辑  收藏  举报