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

1.OpenCVNV12进行通道分离后缩放再保存为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

 

posted @   盛夏夜  阅读(500)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示