OpenCV对NV12进行通道分离后缩放再保存为NV12格式
1.OpenCV对NV12进行通道分离后缩放再保存为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