zoukankan      html  css  js  c++  java
  • OpenCV和FFMpeg图片转换对比

    最近一直在处理图片,从H264解码后得到的图片是YUV图片,而且很多都是NV12的,不是YUV420P(它们的差别是NV12格式为YYY...Y UV UV UV ... UV,而420P格式为 YYY...YY UUU..U VVV...V),一张1920x1080的图片大小为3.1M,为了节省空间,我需要存储为jpg,jpeg格式实际上就是压缩后的YUV,别的不说先上代码

        /* OpenCV */
        cv::Mat srcimg, dstimg;
        srcimg.create(height*3/2, width, CV_8UC1);
        FILE* fp = fopen(yuvf, "rb");
        fread(srcimg.data, 1, height*width*3/2, fp);
        // 需要进行一次转化
        cv::cvtColor(srcimg, dstimg, cv::COLOR_YUV2BGR_NV12);
        // 文件保存,目前已经测试jpg和png文件可行
        cv::imwrite(fout, dstimg);
    /* libavcodec */
    1
    AVCodec* codec; 2 AVCodecContext* codecCtx; 3 struct SwsContext* swsCtx; 4 FILE* fp; 5 int inSz, tmpSz; 6 uint8_t *inbuff, *tmpbuff; 7 size_t rd; 8 int got_output = 0; 9 int ret = 0; 10 AVFrame *frame = NULL; 11 AVPacket pkt; 12 if (width < 1 || height < 1 || !in || !out) 13 return -1; 14 15 // 准备转换环境 16 av_register_all(); // 必须调用,否则 avcodec_find_encoder 会失败 17 codec = avcodec_find_encoder(AV_CODEC_ID_MJPEG); 18 if (NULL == codec) { 19 return -2; 20 } 21 codecCtx = avcodec_alloc_context3(codec); 22 if (NULL == codecCtx) { 23 ret = -3; 24 goto codecctx_errout; 25 } 26 codecCtx->bit_rate = 4000000; 27 codecCtx->width =width; 28 codecCtx->height = height; 29 codecCtx->time_base = (AVRational){ 1, 25 }; 30 codecCtx->pix_fmt = AV_PIX_FMT_YUVJ420P; 31 if (avcodec_open2(codecCtx, codec, NULL) < 0) { 32 ret = -4; 33 goto codecctx_errout; 34 } 35 frame = av_frame_alloc(); 36 av_init_packet(&pkt); 37 pkt.data = NULL; 38 pkt.size = 0; 39 40 // 加载源文件 41 fp = fopen(in, "rb"); 42 if (NULL == fp) { 43 ret = -5; 44 goto out; 45 } 46 47 inSz = av_image_get_buffer_size(infmt, width, height, 1); 48 if (inSz <= 0) { 49 ret = -6; 50 goto out; 51 } 52 inbuff = (uint8_t*)malloc(inSz); 53 if (NULL == inbuff) { 54 ret = -7; 55 goto out; 56 } 57 rd = fread(inbuff, 1, inSz, fp); 58 if (rd != (size_t)inSz) { 59 fclose(fp); 60 ret = -8; 61 goto allout; 62 } 63 fclose(fp); 64 65 // 转换格式为YUV420P 66 if (infmt != AV_PIX_FMT_YUVJ420P && infmt != AV_PIX_FMT_YUV420P) { 67 swsCtx = sws_getContext(width, height, infmt, width, height, AV_PIX_FMT_YUV420P, SWS_BILINEAR, 0, 0, 0); 68 if (NULL == swsCtx) { 69 ret = -9; 70 goto allout; 71 } 72 tmpSz = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, width, height, 1); 73 tmpbuff = (uint8_t*)malloc(tmpSz); 74 if (NULL == tmpbuff) { 75 ret = -9; 76 goto allout; 77 } 78 79 AVFrame FrIn, FrOut; 80 av_image_fill_linesizes(FrIn.linesize, infmt, width); 81 av_image_fill_pointers(FrIn.data, infmt, height, inbuff, FrIn.linesize); 82 av_image_fill_linesizes(FrOut.linesize, AV_PIX_FMT_YUV420P, width); 83 av_image_fill_pointers(FrOut.data, AV_PIX_FMT_YUV420P, height, tmpbuff, FrOut.linesize); 84 85 sws_scale(swsCtx, (const uint8_t* const*)FrIn.data, FrIn.linesize, 0, height, FrOut.data, FrOut.linesize); 86 // 使用新的buffer 87 free(inbuff); 88 inbuff = tmpbuff; 89 } 90 // 填充AVFrame 91 frame->format = codecCtx->pix_fmt; 92 frame->width = width; 93 frame->height = height; 94 95 // 转换 96 av_image_fill_linesizes(frame->linesize, codecCtx->pix_fmt, width); 97 av_image_fill_pointers(frame->data, codecCtx->pix_fmt, height, inbuff, frame->linesize); 98 if (avcodec_send_frame(codecCtx, frame) < 0) { 99 ret = -10; 100 goto allout; 101 } 102 if (0 == avcodec_receive_packet(codecCtx, &pkt)) { 103 fp = fopen(out, "wb"); 104 if (fp) { 105 fwrite(pkt.data, 1, pkt.size, fp); 106 fclose(fp); 107 } 108 else { 109 ret = 12; 110 } 111 av_packet_unref(&pkt); 112 } 113 114 // 环境回收 115 allout: 116 free(inbuff); 117 out: 118 sws_freeContext(swsCtx); 119 av_frame_free(&frame); 120 codecctx_errout: 121 avcodec_close(codecCtx); 122 av_free(codecCtx); 123 errout: 124 return ret;

    我的电脑配置I7 6700HQ,内存16G,系统Ubuntu 18.04,转换1920x1080图片结果为:OpenCV耗时超过80ms(在84左右浮动),而使用libavcodec版本只需要12ms。

    OpevCV是很多做算法的喜欢的工具,可是这个效率,真的是很差 ,它的强项应该就是——代码足够短,FFMpeg使用将近100行的代码它只用了6行就完成了。

    现在库包装越来越“豪华”,执行效率却是越来越低,我们真的需要这么高的硬件配置吗?还是我们被这么多工具给忽悠了?

    近段在折腾Rockchip的RK3399,在前面被表扬的FFMepg这里就要被打脸了,解码1920x1080的H264视频流,FFMpeg也加入了硬解码,我测试了一下,CPU消耗也是100%,而我直接使用Rockchip提供的MPP借口解码CPU占用率维持在35%左右,没有细看FFMpeg代码,扫了一下,也是一样使用MPP接口,但就不知道为什么差别会这么大了。

  • 相关阅读:
    288 Node.js模块化开发:js开发弊端,模块的概念,模块成员导出的2种方式及其区别,模块成员导入
    287 Node.js快速入门:Node.js 的组成,Node.js基础语法,Node.js全局对象global
    286 Node开发概述,Node运行环境搭建以及安装失败解决办法
    285 H5 Web Workers
    使用nvm安装nodejs
    函数式 UI:Web开发终于摆脱了框架的束缚
    Vue渲染函数
    微信小程序使用canvas实现生成海报图的功能
    Vue中插槽指令
    Vue之nextTick原理
  • 原文地址:https://www.cnblogs.com/darkise/p/9945699.html
Copyright © 2011-2022 走看看