OpenCV在图片中添加汉字

本文介绍如何在OpenCV中利用Freetype库实现中文文本的绘制功能。主要内容包括配置OpenCV和Freetype环境、创建CvxText类以支持不同类型的图像上添加中文、英文及自定义字体文本,并提供了一个简单的测试示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.创建一个VS控制台工程,配置OpenCV(保证OpenCV可用);

2.为该工程配置freetype:下载freetype源码包。编译相应的版本得到对应lib文件(debug、release;win32、X64),并配置(这里我用的是freetype28),其配置过程和OpenCV配置类似。(使用freetype时,要将C:\WINDOWS\Fonts下的某一中文字符库拷贝到工程目录中!!我用的是simhei.ttf

3.将CvxText.h、CvxText.cpp文件复制到工程文件夹下。该类可以成功在单通道图像、3通道图像中添加中文、英文、字符等文本,也可以使用不同的字体库;

CvxText.h内容:

#ifndef CVXTEXT_H
#define CVXTEXT_H
 
/**
* \file CvxText.h
* \brief OpenCV汉字输出接口
*
* 实现了汉字输出功能。
*/
 
#include <ft2build.h>
#include FT_FREETYPE_H
 
#include <opencv2/opencv.hpp>
 
using namespace cv;
 
class CvxText
{
    CvxText& operator=(const CvxText&);
 
public:
    CvxText(const char *freeType);
    virtual ~CvxText();
 
    /**
    * 获取字体。目前有些参数尚不支持。
    *
    * \param font        字体类型, 目前不支持
    * \param size        字体大小/空白比例/间隔比例/旋转角度
    * \param underline   下画线
    * \param diaphaneity 透明度
    *
    * \sa setFont, restoreFont
    */
    void getFont(int *type, cv::Scalar *size=NULL, bool *underline=NULL, float *diaphaneity=NULL);
 
    /**
    * 设置字体。目前有些参数尚不支持。
    *
    * \param font        字体类型, 目前不支持
    * \param size        字体大小/空白比例/间隔比例/旋转角度
    * \param underline   下画线
    * \param diaphaneity 透明度
    *
    * \sa getFont, restoreFont
    */
    void setFont(int *type, cv::Scalar *size=NULL, bool *underline=NULL, float *diaphaneity=NULL);
 
    /**
    * 恢复原始的字体设置。
    *
    * \sa getFont, setFont
    */
    void restoreFont();
 
 
    /**
    * 输出汉字(颜色默认为黑色)。遇到不能输出的字符将停止。
    *
    * \param img  输出的影象
    * \param text 文本内容
    * \param pos  文本位置
    *
    * \return 返回成功输出的字符长度,失败返回-1。
    */
    int putText(cv::Mat img, const char *text, cv::Point pos);
 
    /**
    * 输出汉字(颜色默认为黑色)。遇到不能输出的字符将停止。
    *
    * \param img  输出的影象
    * \param text 文本内容
    * \param pos  文本位置
    *
    * \return 返回成功输出的字符长度,失败返回-1。
    */
    int putText(cv::Mat img, const wchar_t *text, cv::Point pos);
 
    /**
    * 输出汉字。遇到不能输出的字符将停止。
    *
    * \param img   输出的影象
    * \param text  文本内容
    * \param pos   文本位置
    * \param color 文本颜色
    *
    * \return 返回成功输出的字符长度,失败返回-1。
    */
    int putText(cv::Mat img, const char *text, cv::Point pos, cv::Scalar color);
 
    /**
    * 输出汉字。遇到不能输出的字符将停止。
    *
    * \param img   输出的影象
    * \param text  文本内容
    * \param pos   文本位置
    * \param color 文本颜色
    *
    * \return 返回成功输出的字符长度,失败返回-1。
    */
    int putText(cv::Mat img, const wchar_t *text, cv::Point pos, cv::Scalar color);
 
 
private:
    // 输出当前字符, 更新m_pos位置
    void putWChar(cv::Mat img, wchar_t wc, cv::Point &pos, cv::Scalar color);
 
 
private:
    FT_Library   m_library;   // 字库
    FT_Face      m_face;      // 字体
 
    // 默认的字体输出参数
    int          m_fontType;
    cv::Scalar       m_fontSize;
    bool         m_fontUnderline;
    float        m_fontDiaphaneity;
};
 
#endif // CVXTEXT_H
 

CvxText.cpp内容:

#pragma once
#include <wchar.h>
#include <assert.h>
#include <locale.h>
#include <ctype.h>
 
#include "CvxText.h"
 
//====================================================================
//====================================================================
 
// 打开字库
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, Scalar *size, bool *underline, float *diaphaneity)
{
    *type = m_fontType;
    *size = m_fontSize;
    *underline = m_fontUnderline;
    *diaphaneity = m_fontDiaphaneity;
}
 
void CvxText::setFont(int *type, Scalar *size, bool *underline, float *diaphaneity)
{
    // 参数合法性检查
 
    if(type)
    {
        if(type >= 0) m_fontType = *type;
    }
    if(size)
    {
        m_fontSize.val[0] = fabs(size->val[0]);
        m_fontSize.val[1] = fabs(size->val[1]);
        m_fontSize.val[2] = fabs(size->val[2]);
        m_fontSize.val[3] = 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, const char *text, cv::Point pos)
{
    if (3==img.channels())
    {
        return putText(img, text, pos, CV_RGB(255,255,255));
    }
    else
    {
        return putText(img, text, pos, Scalar(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, Scalar color)
{
    if(img.data == NULL) return -1;
    if(text == NULL)     return -1;
 
    int i(0);
    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, 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, 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;
 
    // 图像的高度、宽度
    int nImgHeight = img.rows;
    int nImgWidth  = img.cols;
 
    const int nOrigin = 0;
 
    for(int i = 0; i < rows; ++i)
    {
        for(int j = 0; j < cols; ++j)
        {
            int off  = ((nOrigin==0)? i: (rows-1-i)) * slot->bitmap.pitch + j/8;
 
            if(slot->bitmap.buffer[off] & (0xC0 >> (j%8)))
            {
                int r = (nOrigin==0)? pos.y - (rows-1-i): pos.y + i;;
                int c = pos.x + j;
 
                if(r >= 0 && r < nImgHeight  && c >= 0 && c < nImgWidth)
                {
                    switch(img.channels())
                    {
                    case 1:
                    {
                        img.ptr<uchar>(r)[c] = uchar(img.ptr<uchar>(r)[c]*(1-m_fontDiaphaneity)
                             + color.val[0]*m_fontDiaphaneity);
                        break;
                    }
                    case 3:
                    {
                        cv::Mat_<Vec3b> _I = img;
                        _I(r, c)[0] = uchar(_I(r, c)[0]*(1-m_fontDiaphaneity) + color.val[0]*m_fontDiaphaneity);
                        _I(r, c)[1] = uchar(_I(r, c)[1]*(1-m_fontDiaphaneity) + color.val[1]*m_fontDiaphaneity);
                        _I(r, c)[2] = uchar(_I(r, c)[2]*(1-m_fontDiaphaneity) + color.val[2]*m_fontDiaphaneity);
                        break;
                    }
                    }
                }
            }
        } // end for
    } // end for
 
    // 修改下一个字的输出位置
    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);
}
 

4.创建main.cpp测试文件;

内容如下:

#include "opencv2/opencv.hpp"
#include "CvxText.h"
using namespace cv;
int main(int argc, char *argv[])
{
Mat img = imread("true.jpg", 0);
CvxText text("simhei.ttf");
Scalar size(15, 0.5, 0.1, 0);
float p = 1.f;
const char *msg = "就是这么easy!";
text.setFont(NULL, &size, NULL, &p);
text.putText(img, msg, Point(100, 100), CV_RGB(0, 0, 0));
imwrite("test.bmp", img);
return 0;

}

结果:


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值