ruijiege

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

 

 工程目录

cvxtext.cc

#include "cvxtext.h"

#include <assert.h>
#include <ctype.h>
#include <locale.h>
#include <wchar.h>

#include <cmath>

namespace hrj
{

  // 打开字库
  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);
  }

  // 设置字体参数:
  //
  // font         - 字体类型, 目前不支持
  // size         - 字体大小/空白比例/间隔比例/旋转角度
  // underline   - 下画线
  // diaphaneity   - 透明度
  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 == nullptr)
      return -1;
    if (text == nullptr)
      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 == nullptr)
      return -1;
    if (text == nullptr)
      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);
  }

  int CvxText::toWchar(char *src, wchar_t *&dest, const char *locale)
  {
    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;
  }
} // namespace cvxtext
View Code

cvxtext.h

#ifndef OPENCV_CVX_TEXT_HPP_
#define OPENCV_CVX_TEXT_HPP_

#include <freetype2/ft2build.h>
#include FT_FREETYPE_H

#include <opencv2/opencv.hpp>

namespace hrj
{

  class 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 = nullptr, bool *underline = nullptr, float *diaphaneity = nullptr);

    /**
     * 设置字体.目前有些参数尚不支持.
     *
     * \param font        字体类型, 目前不支持
     * \param size        字体大小/空白比例/间隔比例/旋转角度
     * \param underline   下画线
     * \param diaphaneity 透明度
     *
     * \sa getFont, restoreFont
     */
    void setFont(int *type, cv::Scalar *size = nullptr, bool *underline = nullptr, float *diaphaneity = nullptr);

    /**
     * 恢复原始的字体设置.
     *
     * \sa getFont, setFont
     */
    void restoreFont();

    /**
     * 输出汉字(颜色默认为黑色).遇到不能输出的字符将停止.
     *
     * \param img  输出的影象
     * \param text 文本内容
     * \param pos  文本位置
     *
     * \return 返回成功输出的字符长度,失败返回-1.
     */
    int putText(cv::Mat &img, 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);
    int toWchar(char *src, wchar_t *&dest, const char *locale = "zh_CN.utf8");

  private:
    // 禁止copy
    CvxText &operator=(const CvxText &);
    // 输出当前字符, 更新m_pos位置
    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;
  };
} // namespace cvxtext

#endif // OPENCV_CVX_TEXT_HPP_
View Code

cmakelist.txt

cmake_minimum_required(VERSION 3.10)
project(MyOpenCVProject)

# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

# 查找 OpenCV 包
find_package(OpenCV REQUIRED)


# 打印 OpenCV 版本
message(STATUS "OpenCV version: ${OpenCV_VERSION}")
include_directories(/usr/include/freetype2)
aux_source_directory(${PROJECT_SOURCE_DIR}/cvxtext          CVXTEXT_SRC_FILES)

# 添加可执行文件
add_executable(MyOpenCVProject main.cpp ${CVXTEXT_SRC_FILES})

# 链接 OpenCV 库
target_link_libraries(MyOpenCVProject freetype ${OpenCV_LIBS})
View Code

main.cpp

#include "cvxtext/cvxtext.h"
// using namespace cvx;
int main(int argc, char *argv[])
{
    std::string s = "/home/admin/workspace/hrj/c++test/simhei.ttf";
    cv::Mat img(400, 800, CV_8UC3, cv::Scalar(255, 255, 255)); // create a black background
    cv::String msg6 = "文字:[主要功能】:可紧致头发磷层,从而达到";
    // be careful to use the font that support Chinese
    hrj::CvxText *text_ = new hrj::CvxText(s.c_str());
    cv::Scalar size1{30, 0.5, 0.1, 0}; // (字体大小, 无效的, 字符间距, 无效的 }
    text_->setFont(nullptr, &size1, nullptr, 0);
    wchar_t *w_str;
    text_->toWchar((char *)msg6.c_str(), w_str);
    text_->putText(img, w_str, cv::Point(10, 40), cv::Scalar(0, 0, 255));
    // putText(img, msg6, cv::Point(10, 40), text_, 18, cv::Scalar(255, 0, 0));

    // 保存图像到文件
    std::string output_path = "/home/admin/workspace/hrj/c++test/output_image.jpg";
    if (cv::imwrite(output_path, img))
    {
        std::cout << "Image saved successfully at: " << output_path << std::endl;
    }
    else
    {
        std::cerr << "Failed to save the image." << std::endl;
    }
    return 0;
}
View Code

 执行

mkdir bulid

cd bulid

cmake ..

make -j8

./MyOpenCVProject

posted on 2024-09-04 15:12  哦哟这个怎么搞  阅读(12)  评论(0编辑  收藏  举报