制作 opencv4.8.0+ffmpeg5.1.3的docker镜像

文章目录

  • 前言
  • 1. 基础组件安装
    • 1.1 安装docker
    • 1.2 编写build-dep.dockerfile
    • 1.3 编译镜像
  • 2. 安装opencv 4.8.0 + ffmpeg 5.1.3
    • 2.0 下载包
    • 2.1 制作镜像
      • 2.1.1 首先要准备几个文件
      • 2.1.2 编写build-cv.dockerfile
    • 2.2 编译及保存
    • 2.3 创建容器测试
      • 2.3.1 创建容器
      • 2.3.2 opencv自带demo测试
      • 2.3.3 opencv在图片上写汉字测试
      • 2.3.4 视频播放demo测试
  • 参考博客


前言

opencv和ffmpeg是学习计算机视觉的两个功能强大的库,opencv主要是图像处理,ffmpeg主要用于处理视频,本文主要记录opencv4.8.0和ffmpeg5.1.3的编译,并制作成docker镜像,这样换了电脑直接load docker镜像就可以啦。
如果需要镜像或者安装相关文件的可以评论区留言,大概3G多。


1. 基础组件安装

1.1 安装docker

见0-1_install_os.md
创建docker_build文件夹,所有编译脚本以及相关源码包都保存在这个目录下

mkdir docker_build && cd docker_build
mkdir software

1.2 编写build-dep.dockerfile

采用centos7.9.2009的操作系统

FROM centos:7.9.2009

LABEL name="build-dep"
LABEL version="0.0.1"
LABEL description="cv build dependencies."

ARG AUTOCONF_VERSION=2.71
ARG AUTOMAKE_VERSION=1.16.5
ARG BISON_VERSION=3.8.2
ARG LIBEVENT_VERSION=2.1.12-stable
ARG BOOST_VERSION=1_77_0
ARG THRIFT_VERSION=0.15.0
ARG NINJA_VERSION=1.10.2
ARG CMAKE_VERSION=3.21.4
ARG YASM_VERSION=1.3.0
ARG X264_VERSION=5db6aa6cab1b146e07b60cc1736a01f21da01154
ARG X265_VERSION=3.5
ARG FFMPEG_VERSION=5.1.3
ARG NASM_VERSION=2.15.05

RUN yum -y install kde-l10n-Chinese
RUN yum -y reinstall glibc-common
RUN yum clean all
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8

RUN set -e; \
	yum -y update; \
	yum -y install \
	wget perl m4 libtool \
	centos-release-scl \
	rpm-build \
	flex-devel openssl-devel zlib-devel make; \
	yum -y install \
	devtoolset-7-gcc devtoolset-7-gcc-c++; \
	yum clean all

# install cmake
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
	wget https://github.com/Kitware/CMake/releases/download/v${CMAKE_VERSION}/cmake-${CMAKE_VERSION}.tar.gz; \
	tar xvf cmake-${CMAKE_VERSION}.tar.gz; \
	cd cmake-${CMAKE_VERSION}; \
	./bootstrap; \
	make; \
	make install; \
	cd /; \
	rm -rf /tmp/pkg

# install ninja
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
	wget https://github.com/ninja-build/ninja/archive/refs/tags/v${NINJA_VERSION}.tar.gz; \
	tar xvf v${NINJA_VERSION}.tar.gz; \
	cd ninja-${NINJA_VERSION}; \
	cmake .; \
	make; \
	make install; \
	cd / ; \
	rm -rf /tmp/pkg

# install autoconf
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
	wget http://ftp.gnu.org/gnu/autoconf/autoconf-${AUTOCONF_VERSION}.tar.gz; \
	tar xvf autoconf-${AUTOCONF_VERSION}.tar.gz; \
	cd autoconf-${AUTOCONF_VERSION}; \
	./configure --prefix=/usr; \
	make; \
	make install; \
	cd /; \
	rm -rf /tmp/pkg

# install automake
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
	wget http://ftp.gnu.org/gnu/automake/automake-${AUTOMAKE_VERSION}.tar.gz; \
	tar xvf automake-${AUTOMAKE_VERSION}.tar.gz; \
	cd automake-${AUTOMAKE_VERSION}; \
	./configure --prefix=/usr; \
	make; \
	make install; \
	cd /; \
	rm -rf /tmp/pkg

# install bison
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
	wget http://ftp.gnu.org/gnu/bison/bison-${BISON_VERSION}.tar.gz; \
	tar xvf bison-${BISON_VERSION}.tar.gz; \
	cd bison-${BISON_VERSION}; \
	./configure --prefix=/usr; \
	make; \
	make install; \
	cd /; \
	rm -rf /tmp/pkg

# install libevent
COPY software/libevent/libevent-${LIBEVENT_VERSION}.tar.gz /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
	set -e; \
	#mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
        ls; \
	# wget https://github.com/libevent/libevent/releases/download/release-${LIBEVENT_VERSION}/libevent-${LIBEVENT_VERSION}.tar.gz; \
	tar xvf libevent-${LIBEVENT_VERSION}.tar.gz; \
	cd libevent-${LIBEVENT_VERSION}; \
	./configure --prefix=/usr; \
	make; \
	make install; \
	cd /; \
	rm -rf /tmp/pkg

# install boost
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
	wget https://nchc.dl.sourceforge.net/project/boost/boost/1.77.0/boost_${BOOST_VERSION}.tar.gz; \
	tar xvf boost_${BOOST_VERSION}.tar.gz; \
	cd boost_${BOOST_VERSION}; \
	./bootstrap.sh --prefix=/usr --with-libraries=program_options,test,locale; \
	./b2 install; \
	cd /; \
	rm -rf /tmp/pkg

# install thrift
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
	wget http://archive.apache.org/dist/thrift/${THRIFT_VERSION}/thrift-${THRIFT_VERSION}.tar.gz; \
	tar xvf thrift-${THRIFT_VERSION}.tar.gz; \
	cd thrift-${THRIFT_VERSION}; \
	./configure --with-lua=no; \
	make; \
	make install; \
	cd /; \
	rm -rf /tmp/pkg

RUN set -e; \
	ldconfig

ENTRYPOINT scl enable devtoolset-7 bash

1.3 编译镜像

编写脚本build-dep.sh

#!/bin/bash
docker build -f build-dep.dockerfile -t build-dep .

执行./build-dep.sh
查看镜像

docker images 可以查看

保存镜像,备份用的

docker save -o build-dep-v0.0.1.tar build-dep
#docker save -o build-dep-v0.0.1.tar REPOSITORY:TAG

加载镜像

docker load -i build-dep-v0.0.1.tar

2. 安装opencv 4.8.0 + ffmpeg 5.1.3

在build-dep镜像的基础上构建,下载链接见dockerfile中的wget链接

cd docker_build/software

2.0 下载包

软件目录结构

software/
├── autoconf
│   └── autoconf-2.71.tar.gz
├── automake
│   └── automake-1.16.5.tar.gz
├── bison
│   └── bison-3.8.2.tar.gz
├── boost
│   └── boost_1_77_0.tar.gz
├── cmake
│   └── cmake-3.21.4.tar.gz
├── ffmpeg
│   └── ffmpeg-5.1.3.tar.bz2
├── freetype
│   └── freetype-2.10.0.tar.bz2
├── libevent
│   └── libevent-2.1.12-stable.tar.gz
├── nasm
│   └── nasm-2.15.05.tar.gz
├── ninja
│   └── v1.10.2.tar.gz
├── opencv
│   └── opencv-4.8.0.zip
├── SDL
│   └── SDL2-2.0.22.tar.gz
├── thrift
│   └── thrift-0.15.0.tar.gz
├── x264
│   └── x264-stable.tar.bz2
├── x265
│   └── x265_3.5.tar.gz
└── yasm
    └── yasm-1.3.0.tar.gz

2.1 制作镜像

2.1.1 首先要准备几个文件

  • cv_pkgconfig.sh 放在 docker_build下
export PKG_CONFIG_PATH=/usr/local/ffmpeg-5.1.3/lib/pkgconfig:/usr/local/opencv-4.8.0/lib64/pkgconfig:/usr/local/freetype-2.10.0/lib/pkgconfig:$PKG_CONFIG_PATH
  • x265_3.5.pc 放在software/x265下
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include

Name: @CMAKE_PROJECT_NAME@
Description: H.265/HEVC video encoder
Version: @X265_LATEST_TAG@
Libs: -L${libdir} -lx265
Libs.private: -lpthread -lm -ldl
Cflags: -I${includedir}
  • cv.conf 在 docker_build下
/usr/local/opencv-4.8.0/lib64
/usr/local/ffmpeg-5.1.3/lib
/usr/local/freetype-2.10.0/lib

2.1.2 编写build-cv.dockerfile

build-cv.dockerfile 在 docker_build下

FROM build-dep

LABEL name="build-cv"
LABEL version="0.0.1"
LABEL description="cv build dependencies."

ARG YASM_VERSION=1.3.0
ARG X264_VERSION=5db6aa6cab1b146e07b60cc1736a01f21da01154
ARG X265_VERSION=3.5
ARG FFMPEG_VERSION=5.1.3
ARG NASM_VERSION=2.15.05
ARG SDL_VERSION=2.0.22
ARG OPENCV_VERSION=4.8.0

# install yasm
# wget http://www.tortall.net/projects/yasm/releases/yasm-1.3.0.tar.gz
COPY software/yasm/yasm-${YASM_VERSION}.tar.gz /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
    tar xvf yasm-${YASM_VERSION}.tar.gz; \
    cd yasm-${YASM_VERSION}; \
    ./configure --enable-pic --prefix=/usr; \ 
    make -j4; \
    make install; \ 
    cd /;  \
    rm -rf /tmp/pkg

# install nasm
# wget https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/nasm-2.15.05.tar.gz
COPY software/nasm/nasm-${NASM_VERSION}.tar.gz /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
	set -e; \
	mkdir -p /tmp/pkg; \
	cd /tmp/pkg; \
    tar xvf nasm-${NASM_VERSION}.tar.gz; \
    cd nasm-${NASM_VERSION}; \
    ./configure;  \
    make -j4; \
    make install; \
    cd /;  \
    rm -rf /tmp/pkg 

# install x264
# wget https://code.videolan.org/videolan/x264/-/archive/stable/x264-stable.tar.bz2
COPY software/x264/x264-stable.tar.bz2 /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
	set -e; \
    mkdir -p /tmp/pkg;  \
    cd /tmp/pkg;  \
    tar xvf x264-stable.tar.bz2; \
    cd x264-stable; \
    ./configure --enable-pic --enable-shared --enable-static --prefix=/usr;  \
    make -j4; \
    make install; \
    cd /;  \
    rm -rf /tmp/pkg

# install x265
# wget https://bitbucket.org/multicoreware/x265_git/downloads/x265_3.5.tar.gz
COPY software/x265/x265_${X265_VERSION}.tar.gz /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
	set -e; \
    mkdir -p /tmp/pkg;  \
    cd /tmp/pkg; \
    tar xvf x265_${X265_VERSION}.tar.gz; \
    cd x265_${X265_VERSION}/build/linux; \
    #./make-Makefiles.bash; \ 
    cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/usr ../../source/; \
    make -j4; \
    make install; \
    cp  /tmp/pkg/x265_${X265_VERSION}/build/linux/libx265.so.199 /usr/lib; \
    cd /usr/lib; \
    ln -s /usr/lib/libx265.so.199 /usr/lib/libx265.so; \
    # cp /tmp/pkg/x265_${X265_VERSION}/source/x265.pc.in /usr/lib/pkgconfig/x265.pc; \
    cd /; \
    rm -rf /tmp/pkg
COPY software/x265/x265_${X265_VERSION}.pc /usr/lib/pkgconfig/x265.pc

# install SDL
# install SDL 用于编译ffplay,多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数
# https://blog.csdn.net/weixin_43400806/article/details/124288676
# https://zhuanlan.zhihu.com/p/579678056
# wget http://libsdl.org/release/SDL2-2.0.22.tar.gz
COPY software/SDL/SDL2-${SDL_VERSION}.tar.gz /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
    mkdir -p /tmp/pkg; \
    cd /tmp/pkg; \
    tar xvf SDL2-${SDL_VERSION}.tar.gz; \
    cd SDL2-${SDL_VERSION}; \
    ./configure --prefix=/usr; \
    make -j4; \
    make install; \
    cd /; \
    rm -rf /tmp/pkg

# install ffmpeg
# wget http://www.ffmpeg.org/releases/ffmpeg-5.1.3.tar.bz2
COPY software/ffmpeg/ffmpeg-${FFMPEG_VERSION}.tar.bz2 /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
    mkdir -p /tmp/pkg; \
    cd /tmp/pkg;  \
    tar xvf ffmpeg-${FFMPEG_VERSION}.tar.bz2; \
    cd ffmpeg-${FFMPEG_VERSION}; \
    export PKG_CONFIG_PATH=/usr/lib/pkgconfig/; \
    ./configure --pkg-config-flags="--static" --extra-cflags="-I/usr/include" --extra-ldflags="-I/usr/lib" --extra-libs="-lpthread -lm -lx264 -lx265" --enable-gpl --enable-shared --enable-static --enable-pic --enable-libx264 --enable-libx265 --enable-cross-compile --prefix=/usr/local/ffmpeg-${FFMPEG_VERSION}; \
    make -j4; \
    make install
    # ; \
    # cd /;  \
    # rm -rf /tmp/pkg

RUN source scl_source enable devtoolset-7; \
    echo 'export PKG_CONFIG_PATH=/usr/local/ffmpeg-${FFMPEG_VERSION}/lib/pkgconfig:$PKG_CONFIG_PATH' >  /etc/profile.d/pkgconfig.sh; \  
    source /etc/profile; \
    ldconfig

# install opencv
# wget https://codeload.github.com/opencv/opencv/zip/refs/tags/4.8.0 -O opencv-4.8.0.zip
COPY software/opencv/opencv-${OPENCV_VERSION}.zip /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
    mkdir -p /tmp/pkg; \
    cd /tmp/pkg;  \
    unzip opencv-${OPENCV_VERSION}.zip; \
    cd opencv-${OPENCV_VERSION}; \
    mkdir build; \
    cd build; \
    export PKG_CONFIG_PATH=/usr/lib/pkgconfig/:/usr/local/ffmpeg-${FFMPEG_VERSION}/lib/pkgconfig:$PKG_CONFIG_PATH; \
    export LD_LIBRARY_PATH=/usr/local/ffmpeg-${FFMPEG_VERSION}/lib/:$LD_LIBRARY_PATH; \
    export PATH=/usr/local/ffmpeg-${FFMPEG_VERSION}/bin:$PATH; \
    cmake -D CMAKE_BUILD_TYPE=Release -D OPENCV_GENERATE_PKGCONFIG=ON -D WITH_FFMPEG=ON   -D OPENCV_FFMPEG_USE_FIND_PACKAGE=ON -D OPENCV_FFMPEG_SKIP_BUILD_CHECK=ON -D FFMPEG_DIR=/usr/local/ffmpeg-${FFMPEG_VERSION} -D CMAKE_INSTALL_PREFIX=/usr/local/opencv-${OPENCV_VERSION} ..; \ 
    make -j8; \
    make install; \
    cd /;  \
    rm -rf /tmp/pkg

# install freetype
# wget http://download.savannah.gnu.org/releases/freetype/freetype-2.10.0.tar.bz2
COPY software/freetype/freetype-2.10.0.tar.bz2 /tmp/pkg/
RUN source scl_source enable devtoolset-7; \
    mkdir -p /tmp/pkg; \
    cd /tmp/pkg;  \
    tar -jxvf freetype-2.10.0.tar.bz2; \
    cd freetype-2.10.0; \
    ./configure --prefix=/usr/local/freetype-2.10.0; \
    make -j4; \
    make install; \
    cd /; \
    rm -rf /tmp/pkg

# 配置环境变量
COPY cv_pkgconfig.sh /etc/profile.d/pkgconfig.sh
RUN source scl_source enable devtoolset-7; \
    source /etc/profile
COPY cv.conf /etc/ld.so.conf.d/cv.conf
RUN source scl_source enable devtoolset-7; \
    ldconfig
    # #  配置pkgconfig环境
    # sudo find / -iname opencv4.pc; \
    # sudo vi /etc/profile.d/pkgconfig.sh; \
    # # 在pkgconfig.sh文件中写入(可能是空文件):
    # export PKG_CONFIG_PATH=/usr/local/lib64/pkgconfig:$PKG_CONFIG_PATH
    # # 最后:
    # source /etc/profile

    # # 配置编译环境
    # sudo vim /etc/ld.so.conf.d/opencv4.conf
    # # 在opencv4.conf文件中写入(可能是空文件):/usr/local/lib64
    # sudo ldconfig
    # # 验证
    # pkg-config --modversion opencv4

RUN yum -y install kde-l10n-Chinese
RUN yum -y reinstall glibc-common
RUN yum clean all
RUN localedef -c -f UTF-8 -i zh_CN zh_CN.utf8

RUN set -e; \
	ldconfig

ENTRYPOINT scl enable devtoolset-7 bash

2.2 编译及保存

在 docker_build下 编译镜像
build-cv.sh

#!/bin/bash

docker build -f build-cv.dockerfile -t build-cv:v1.0 .
docker tag build-cv build-cv:v1.0
docker rmi build-cv:latest
docker save -o images/build-cv-v1.0.tar build-cv:v1.0

在docker_build下执行./build-cv.sh

2.3 创建容器测试

2.3.1 创建容器

设置-e LANG=zh_CN.UTF-8 -e LC_ALL=zh_CN.UTF-8是为了用opencv在图片上写汉字demo使用

# 防止之前构建过
docker stop build-cv && docker rm build-cv
docker run  -e LANG=zh_CN.UTF-8 -e LC_ALL=zh_CN.UTF-8  -it --name build-cv -v /home/trimps/:/workspace --entrypoint bash build-cv:v1.0	

2.3.2 opencv自带demo测试

cd /usr/local/opencv-4.8.0/samples/cpp/example_cmake/

编辑makefile,vi Makefile

CXX ?= g++

CXXFLAGS += -c -std=c++11 -Wall $(shell pkg-config --cflags opencv4)
LDFLAGS += $(shell pkg-config --libs --static opencv4)

all: opencv_example

opencv_example: example.o; $(CXX) $< -o $@ $(LDFLAGS)

%.o: %.cpp; $(CXX) $< -o $@ $(CXXFLAGS)

clean: ; rm -f example.o opencv_example

编译执行

source scl_source enable devtoolset-7
make
./opencv_example

2.3.3 opencv在图片上写汉字测试

  • 下载SimHei.ttf字体
  • write_chinese.cpp
#include 
#include 
#include 
#include FT_FREETYPE_H
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

// //汉字
// int myputText(cv::Mat img, const char *text, cv::Point pos, cv::Scalar color);
// void myputWChar(cv::Mat img, wchar_t wc, cv::Point &pos, cv::Scalar color);

/*时间打印*/
char*   log_Time(void)
{
    struct  tm      *ptm;
    struct  timeb   stTimeb;
    static  char    szTime[19];

    ftime(&stTimeb);
    ptm = localtime(&stTimeb.time);
    sprintf(szTime, "%02d-%02d %02d:%02d:%02d.%03d",ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, stTimeb.millitm);
    szTime[18] = 0;
    return szTime;
}


class CvxText {
public:
    CvxText(const char* freeType);
    virtual ~CvxText();
    void getFont(int* type, cv::Scalar* size=NULL, bool* underline=NULL, float* diaphaneity=NULL);
    void setFont(int* type, cv::Scalar* size=NULL, bool* underline=NULL, float* diaphaneity=NULL);
    void restoreFont();
    int putText(cv::Mat& img, char* text, cv::Point pos);
    int putText(cv::Mat& img, const wchar_t* text, cv::Point pos);
    int putText(cv::Mat& img, const char* text, cv::Point pos, cv::Scalar color);
    int putText(cv::Mat& img, const wchar_t* text, cv::Point pos, cv::Scalar color);

private:
    CvxText& operator=(const CvxText&);
    void putWChar(cv::Mat& img, wchar_t wc, cv::Point& pos, cv::Scalar color);

    FT_Library   m_library;
    FT_Face      m_face;

    int         m_fontType;
    cv::Scalar   m_fontSize;
    bool      m_fontUnderline;
    float      m_fontDiaphaneity;
};

// 打开字库
CvxText::CvxText(const char* freeType)
{
    assert(freeType != NULL);

    // 打开字库文件, 创建一个字体
    if(FT_Init_FreeType(&m_library)) throw;
    if(FT_New_Face(m_library, freeType, 0, &m_face)) throw;

    // 设置字体输出参数
    restoreFont();

    // 设置C语言的字符集环境
    setlocale(LC_ALL, "");
}

// 释放FreeType资源
CvxText::~CvxText()
{
    FT_Done_Face(m_face);
    FT_Done_FreeType(m_library);
}

void CvxText::getFont(int* type, cv::Scalar* size, bool* underline, float* diaphaneity)
{
    if (type) *type = m_fontType;
    if (size) *size = m_fontSize;
    if (underline) *underline = m_fontUnderline;
    if (diaphaneity) *diaphaneity = m_fontDiaphaneity;
}

void CvxText::setFont(int* type, cv::Scalar* size, bool* underline, float* diaphaneity)
{
    // 参数合法性检查
    if (type) {
        if(type >= 0) m_fontType = *type;
    }
    if (size) {
        m_fontSize.val[0] = std::fabs(size->val[0]);
        m_fontSize.val[1] = std::fabs(size->val[1]);
        m_fontSize.val[2] = std::fabs(size->val[2]);
        m_fontSize.val[3] = std::fabs(size->val[3]);
    }
    if (underline) {
        m_fontUnderline   = *underline;
    }
    if (diaphaneity) {
        m_fontDiaphaneity = *diaphaneity;
    }

    FT_Set_Pixel_Sizes(m_face, (int)m_fontSize.val[0], 0);
}

// 恢复原始的字体设置
void CvxText::restoreFont()
{
    m_fontType = 0;            // 字体类型(不支持)

    m_fontSize.val[0] = 20;      // 字体大小
    m_fontSize.val[1] = 0.5;   // 空白字符大小比例
    m_fontSize.val[2] = 0.1;   // 间隔大小比例
    m_fontSize.val[3] = 0;      // 旋转角度(不支持)

    m_fontUnderline   = false;   // 下画线(不支持)

    m_fontDiaphaneity = 1.0;   // 色彩比例(可产生透明效果)

    // 设置字符大小
    FT_Set_Pixel_Sizes(m_face, (int)m_fontSize.val[0], 0);
}

// 输出函数(颜色默认为白色)
int CvxText::putText(cv::Mat& img, char* text, cv::Point pos)
{
    return putText(img, text, pos, CV_RGB(255, 255, 255));
}

int CvxText::putText(cv::Mat& img, const wchar_t* text, cv::Point pos)
{
    return putText(img, text, pos, CV_RGB(255,255,255));
}

int CvxText::putText(cv::Mat& img, const char* text, cv::Point pos, cv::Scalar color)
{
    if (img.data == NULL) return -1;
    if (text == NULL) return -1;

    int i;
    for (i = 0; text[i] != '\0'; ++i) {
        wchar_t wc = text[i];

        // 解析双字节符号
        if(!isascii(wc)) mbtowc(&wc, &text[i++], 2);

        // 输出当前的字符
        putWChar(img, wc, pos, color);
    }

    return i;
}

int CvxText::putText(cv::Mat& img, const wchar_t* text, cv::Point pos, cv::Scalar color)
{
    if (img.data == NULL) return -1;
    if (text == NULL) return -1;

    int i;
    for(i = 0; text[i] != '\0'; ++i) {
        // 输出当前的字符
        putWChar(img, text[i], pos, color);
    }

    return i;
}

// 输出当前字符, 更新m_pos位置
void CvxText::putWChar(cv::Mat& img, wchar_t wc, cv::Point& pos, cv::Scalar color)
{
    // 根据unicode生成字体的二值位图
    FT_UInt glyph_index = FT_Get_Char_Index(m_face, wc);
    FT_Load_Glyph(m_face, glyph_index, FT_LOAD_DEFAULT);
    FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_MONO);

    FT_GlyphSlot slot = m_face->glyph;

    // 行列数
    int rows = slot->bitmap.rows;
    int cols = slot->bitmap.width;

    for (int i = 0; i < rows; ++i) {
        for(int j = 0; j < cols; ++j) {
            int off  = i * slot->bitmap.pitch + j/8;

            if (slot->bitmap.buffer[off] & (0xC0 >> (j%8))) {
                int r = pos.y - (rows-1-i);
                int c = pos.x + j;

                if(r >= 0 && r < img.rows && c >= 0 && c < img.cols) {
                    cv::Vec3b pixel = img.at<cv::Vec3b>(cv::Point(c, r));
                    cv::Scalar scalar = cv::Scalar(pixel.val[0], pixel.val[1], pixel.val[2]);

                    // 进行色彩融合
                    float p = m_fontDiaphaneity;
                    for (int k = 0; k < 4; ++k) {
                        scalar.val[k] = scalar.val[k]*(1-p) + color.val[k]*p;
                    }

                    img.at<cv::Vec3b>(cv::Point(c, r))[0] = (unsigned char)(scalar.val[0]);
                    img.at<cv::Vec3b>(cv::Point(c, r))[1] = (unsigned char)(scalar.val[1]);
                    img.at<cv::Vec3b>(cv::Point(c, r))[2] = (unsigned char)(scalar.val[2]);
                }
            }
        }
    }

    // 修改下一个字的输出位置
    double space = m_fontSize.val[0]*m_fontSize.val[1];
    double sep   = m_fontSize.val[0]*m_fontSize.val[2];

    pos.x += (int)((cols? cols: space) + sep);
}

static int ToWchar(char* &src, wchar_t* &dest, const char *locale = "zh_CN.utf8")
{
    if (src == NULL) {
        dest = NULL;
        return 0;
    }

    // 根据环境变量设置locale
    setlocale(LC_CTYPE, locale);

    // 得到转化为需要的宽字符大小
    int w_size = mbstowcs(NULL, src, 0) + 1;

    // w_size = 0 说明mbstowcs返回值为-1。即在运行过程中遇到了非法字符(很有可能使locale
    // 没有设置正确)
    if (w_size == 0) {
        dest = NULL;
        return -1;
    }

    //wcout << "w_size" << w_size << endl;
    dest = new wchar_t[w_size];
    if (!dest) {
        return -1;
    }

    int ret = mbstowcs(dest, src, strlen(src)+1);
    if (ret <= 0) {
        return -1;
    }
    return 0;
}

int main() {
    CvxText text("./SimHei.ttf"); //指定字体
    cv::Scalar size1{ 40, 0.5, 0.1, 0 }; // (字体大小, 无效的, 字符间距, 无效的 }
    text.setFont(nullptr, &size1, nullptr, 0);
    vector<int> compression_params;
    compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);  //选择jpeg
    compression_params.push_back(60); //在这个填入你要的图片质量

    // open image
    cv::Mat image;
    image = cv::imread("1.png");
    if (!image.data) {
        return 0;
    }

    cv::rectangle( image,cv::Point( 155,693),cv::Point( 349,1073),cv::Scalar(0,0,255),3,1);
    std::string chr = "我爱中国!";
    wchar_t *w_str;
    char *copy = new char[strlen(chr.c_str()) + 1];
    strcpy(copy, chr.c_str());
    ToWchar(copy,w_str);
    text.putText(image, w_str, cv::Point(160, 160), cv::Scalar(0, 0, 255)); 
    cv::imwrite("output1.jpg", image,compression_params);

    return 0;
}

  • 编译执行
cd /workspace/gb_dev/
#!/bin/bash
source scl_source enable devtoolset-7
g++ write_chinese.cpp -std=c++11 `pkg-config --libs --cflags opencv4 freetype2`
./a.out

2.3.4 视频播放demo测试

  • test_video.cpp
#include
#include
using namespace std;
using namespace cv;
 
int main()
{
      VideoCapture video("001.wmv");
      if (video.isOpened()) {
          cout << "视频中图像的宽度" << video.get(CAP_PROP_FRAME_WIDTH) << endl;
          cout << "视频图像的高度" << video.get(CAP_PROP_FRAME_HEIGHT) << endl;
          cout << "视频总帧率" << video.get(CAP_PROP_FPS) << endl;
          cout << "视频总帧数" << video.get(CAP_PROP_FRAME_COUNT) << endl;
      } else {
          cout << "视频文件读取失败" << endl;
      }
    

      VideoWriter w1;
      double fps = 25.0; //设置视频帧率
      // 保存为avi格式
      // int encode_type = VideoWriter::fourcc('M', 'J', 'P', 'G');   //选择编码格式    
      // string filename = "test_save.avi";

      // 保存为mp4格式
      int encode_type = VideoWriter::fourcc('m', 'p', '4', 'v');   //选择编码格式    
      string filename = "test_save.mp4";      
      
      w1.open(filename, encode_type, fps, Size(video.get(CAP_PROP_FRAME_WIDTH),video.get(CAP_PROP_FRAME_HEIGHT)), true);   //创建保存视频文件的视频流  img.size()为保存的视频图像的尺寸

      while (1) {
          Mat frame;
          video >> frame;
          if (frame.empty()) {
            break;
          }
          w1.write(frame);
      }
      video.release();  //这两句是在退出程序后关闭视频流,不写的话系统也会自动关闭
      w1.release();
}
  • 编译测试
cd /workspace/gb_dev/
#!/bin/bash
source scl_source enable devtoolset-7
g++ test_video.cpp -std=c++11 `pkg-config --libs --cflags opencv4`


参考博客

Linux CentOS 编译安装ffmpeg Opencv
ffmpeg opencv 指定_OpenCV静态库编译与链接
Ubuntu 20.04源码编译安装OpenCV 4.7.0
opencv编译with ffmpeg

你可能感兴趣的:(运维,docker,opencv,ffmpeg)