OpenCV对NV12进行通道分离后缩放再保存为NV12格式
1.OpenCV对NV12进行通道分离后缩放再保存为NV12格式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | #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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)