首页 > 其他分享 >OpenCV|FFmpeg – OpenCV cv::Mat与FFmpeg AVFrame的相互转换

OpenCV|FFmpeg – OpenCV cv::Mat与FFmpeg AVFrame的相互转换

时间:2023-08-22 16:47:36浏览次数:48  
标签:FFmpeg width image nullptr height OpenCV input cv Mat

OpenCV cv::Mat与FFmpeg AVFrame相互转换

最近在处理OpenCV采集摄像头图片然后使用ffmpeg编码为h264裸流,之后再将h264裸流转换为OpenCV cv::Mat进行显示的问题,在这个过程中,如何将OpenCV的cv::Mat转化为FFmpeg AVFrame在进行h264编码,以及如何将h264解码后的AVFrame转换为cv::Mat是两个核心的问题,下文将简单展示OpenCV cv::Mat与FFmpeg AVFrame相互转换的核心代码,主要使用了FFmpeg中主要用于视频像素格式转换和视频缩放的sws_getContext和sws_scale函数。

注意这里使用的ffmpeg的版本为4.1,使用更低版本注意API适配,使用更高版本注意丢弃API的更换。

1.1 OpenCV cv::Mat转换为FFmpeg AVFrame

void CvMatToAVFrame(const cv::Mat& input_mat, AVFrame* out_avframe)
{
    int image_width = input_mat.cols;
    int image_height = input_mat.rows;
    int cvLinesizes[1];
    cvLinesizes[0] = input_mat.step1();

    SwsContext* openCVBGRToAVFrameSwsContext = sws_getContext(
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_BGR24,
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_YUV420P,
        SWS_FAST_BILINEAR,
        nullptr, nullptr, nullptr
    );

    sws_scale(openCVBGRToAVFrameSwsContext,
        &input_mat.data,
        cvLinesizes,
        0,
        image_height,
        out_avframe->data,
        out_avframe->linesize);

    if (openCVBGRToAVFrameSwsContext != nullptr)
    {
        sws_freeContext(openCVBGRToAVFrameSwsContext);
        openCVBGRToAVFrameSwsContext = nullptr;
    }
}
C++

然后是之后用chatGPT生成的转换代码,大家看一下,哈哈哈,码农真要失业了

#include <opencv2/opencv.hpp>

extern "C" {
#include <libavcodec/avcodec.h>
#include <libavutil/frame.h>
#include <libavutil/imgutils.h>
}

void convertMatToAVPicture(const cv::Mat& mat, AVFrame* frame)
{
    int width = mat.cols;
    int height = mat.rows;
    int channels = mat.channels();

    int ret;
    frame->width = width;
    frame->height = height;
    frame->format = AV_PIX_FMT_BGR24;

    // 为AVFrame分配内存
    ret = av_image_alloc(frame->data, frame->linesize, width, height, frame->format, 32);
    if (ret < 0)
    {
        return;
    }

    // 将opencv的Mat转换成AVFrame
    int step = width * channels;
    for (int row = 0; row < height; row++) 
    {
        memcpy(frame->data[0] + row * frame->linesize[0], mat.data + row * step, step);
    }
}
C++

1.2 FFmpeg AVFrame转换为OpenCV cv::Mat

cv::Mat AVFrameToCvMat(AVFrame* input_avframe)
{
    int image_width = input_avframe->width;
    int image_height = input_avframe->height;

    cv::Mat resMat(image_height, image_width, CV_8UC3);
    int cvLinesizes[1];
    cvLinesizes[0] = resMat.step1();

    SwsContext* avFrameToOpenCVBGRSwsContext = sws_getContext(
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_YUV420P,
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_BGR24,
        SWS_FAST_BILINEAR,
        nullptr, nullptr, nullptr
    );

    sws_scale(avFrameToOpenCVBGRSwsContext,
        input_avframe->data,
        input_avframe->linesize,
        0,
        image_height,
        &resMat.data,
        cvLinesizes);

    if (avFrameToOpenCVBGRSwsContext != nullptr)
    {
        sws_freeContext(avFrameToOpenCVBGRSwsContext);
        avFrameToOpenCVBGRSwsContext = nullptr;
    }

    return resMat;
}
C++

1.3 使用示例

#include <iostream>

// ffmpeg
extern "C" {
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/avutil.h"
#include "libswscale/swscale.h"
#include <libavutil/imgutils.h>
}

// opencv
#include "opencv/cv.h"
#include "opencv2/opencv.hpp"

void CvMatToAVFrame(const cv::Mat& input_mat, AVFrame* out_avframe)
{
    int image_width = input_mat.cols;
    int image_height = input_mat.rows;
    int cvLinesizes[1];
    cvLinesizes[0] = input_mat.step1();

    SwsContext* openCVBGRToAVFrameSwsContext = sws_getContext(
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_BGR24,
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_YUV420P,
        SWS_FAST_BILINEAR,
        nullptr, nullptr, nullptr
    );

    sws_scale(openCVBGRToAVFrameSwsContext,
        &input_mat.data,
        cvLinesizes,
        0,
        image_height,
        out_avframe->data,
        out_avframe->linesize);

    if (openCVBGRToAVFrameSwsContext != nullptr)
    {
        sws_freeContext(openCVBGRToAVFrameSwsContext);
        openCVBGRToAVFrameSwsContext = nullptr;
    }
}

cv::Mat AVFrameToCvMat(AVFrame* input_avframe)
{
    int image_width = input_avframe->width;
    int image_height = input_avframe->height;

    cv::Mat resMat(image_height, image_width, CV_8UC3);
    int cvLinesizes[1];
    cvLinesizes[0] = resMat.step1();

    SwsContext* avFrameToOpenCVBGRSwsContext = sws_getContext(
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_YUV420P,
        image_width,
        image_height,
        AVPixelFormat::AV_PIX_FMT_BGR24,
        SWS_FAST_BILINEAR,
        nullptr, nullptr, nullptr
    );

    sws_scale(avFrameToOpenCVBGRSwsContext,
        input_avframe->data,
        input_avframe->linesize,
        0,
        image_height,
        &resMat.data,
        cvLinesizes);

    if (avFrameToOpenCVBGRSwsContext != nullptr)
    {
        sws_freeContext(avFrameToOpenCVBGRSwsContext);
        avFrameToOpenCVBGRSwsContext = nullptr;
    }

    return resMat;
}


int main()
{
    cv::Mat input_image = cv::imread("C:/Users/Administrator/Desktop/example.jpg");
    AVFrame* avFrame = av_frame_alloc();
    avFrame->format = AVPixelFormat::AV_PIX_FMT_YUV420P;
    avFrame->width = input_image.cols;
    avFrame->height = input_image.rows;

    // 为需要创建的YUV Frame分配内存
    if (av_frame_get_buffer(avFrame, 0) < 0)
    {
        av_frame_free(&avFrame);
        avFrame = nullptr;
        return -1;
    }


    cv::imshow("解码前", input_image);

    // OpenCV cv::Mat转换成AVFrame
    CvMatToAVFrame(input_image,avFrame);


    // 将AVFrame转换成OpenCV cv::Mat
    cv::Mat out_avFrameToMat = AVFrameToCvMat(avFrame);

    cv::imshow("解码后", out_avFrameToMat);


    cv::waitKey(0);
    cv::destroyAllWindows();

    // free memory
    if (avFrame != nullptr)
    {
        av_frame_free(&avFrame);
        avFrame = nullptr;
    }

    return 0;
}
C++

从示例程序的结果上看,上述的转换代码是正确的

OpenCV|FFmpeg – OpenCV cv::Mat与FFmpeg AVFrame的相互转换-StubbornHuang Blog End

标签:FFmpeg,width,image,nullptr,height,OpenCV,input,cv,Mat
From: https://www.cnblogs.com/lidabo/p/17648921.html

相关文章

  • FFmpeg将视频转换成一帧一帧的jpeg图片(代码实现)
      #include<iostream> usingnamespacestd; extern"C" { #include"libavcodec/avcodec.h" #include"libavformat/avformat.h" #include"libswscale/swscale.h" #include......
  • ffmpeg把读取的视频流保存为jpeg文件
    intimg_savejpeg(AVFrame*pFrame,char*out_filename){//视频流保存为jpegintwidth=pFrame->width;intheight=pFrame->height;AVCodecContext*pCodeCtx=NULL;AVFormatContext*pFormatCtx=avformat_alloc_context();//设置输出文件格式pFormatCtx->oformat=av......
  • 使用ffmpeg将MP4文件的每一帧保存为jpg图片
    #include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<fcntl.h>#include<sys/ioctl.h>#include<string.h>#include<sys/mman.h>#include<assert.h>#include<liba......
  • opencv加载内存中图片
           opencv从磁盘加载一张图片非常简单,通过cv::imread即可,代码如下:  cv::Matsrc_mat=cv::imread("1.jpg");//读取图片1.jpg,imread会将图片内容解码成yuv或rgb存放到Mat对象 cv::Matdst_mat=src_mat(cv::Rect(100,100,1600,900));//获取图......
  • OpenCV 读取内存图片
    方法一(适用于OpenCV3):     #include<opencv2/opencv.hpp> #include<opencv2/imgproc/imgproc_c.h> #include<iostream>   char*lpFileBuf=GetFileBuf("girl.bmp");   CvMatmCvm......
  • [Mac软件]Pixelmator Pro 3.3.12 专业图像编辑中文版
    PixelmatorPro是专为Mac设计的功能强大,美观且易于使用的图像编辑器。借助广泛的专业级无损图像编辑工具,PixelmatorPro可使您发挥出最佳的照片效果,创建华丽的构图和设计,绘制,绘画,应用令人惊叹的效果,设计精美的文字并仅编辑图像您可以想象的任何方式。而且,由于其直观且易于访问的......
  • Lnton羚通云算力平台OpenCV Python颜色空间转换与抠图教程
    在OpenCVPython中,颜色空间转换和图像抠图是常见的图像处理任务。下面我将为你介绍如何进行颜色空间转换和图像抠图。颜色空间转换:在OpenCVPython中,可以使用 cv2.cvtColor() 函数将图像从一个颜色空间转换为另一个颜色空间。常用的颜色空间转换包括RGB、BGR、灰度(GRAY)、HS......
  • Shopify 内容玩法之 Discounts 折扣码批量上传:matrixify
     折扣码使用的插件是:Matrixify。这个插件可以批量上传Products,Discounts等数据,可以直接使用excel模板创建数据。Discounts的excel模板,见下表:需要注意的几点:Code和Title保持一致,方便在Discounts列表查看当前折扣码的名称DiscountsValue是减掉的金额您需......
  • Windows 使用vscode 下载编译opencv
    1.下载opencv源码.下载地址:https://opencv.org/releases/2.下载mingw这里的安装版本需要注意下,需要安装posix线程版本,不然opencv编译的时候会报错x86_64-12.2.0-release-posix-seh-rt_v10-rev1解压后配置环境变量就行下载地址如下:https://github.com/niXman/mingw-builds-b......
  • Lnton羚通云算力平台如何在OpenCV-Python 中,来进行图像算术运算?
    在OpenCV-Python中,可以使用函数cv2.add()、cv2.subtract()、cv2.multiply()和cv2.divide()来进行图像算术运算。这些函数接受两个输入图像,并对其进行逐像素的运算。1.图像加法:OpenCV 是饱和运算(大于255算255),NumPy 是模运算(大于255会与256进行求模)。importnumpyasnpimpo......