在 http://www.opencv.org.cn/forum.php?mod=viewthread&tid=2083&extra=&page=1 中,作者给出了原始的在OpenCV中 支持中文字符的输入,原始的实现使用的是OpenCV的C接口,使用起来不怎么方便,这里对原作者的实现进行调整,通过OpenCV的C++接口实现中文的输出,调整后的code如下:

CvxText.hpp:

#ifndef OPENCV_CVX_TEXT_HPP_
#define OPENCV_CVX_TEXT_HPP_// source from: http://www.opencv.org.cn/forum.php?mod=viewthread&tid=2083&extra=&page=1
// 支持OpenCV中文汉字输入#include <ft2build.h>
#include FT_FREETYPE_H#include <opencv2/opencv.hpp>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, 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:// 禁止copyCvxText& 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;
};#endif // OPENCV_CVX_TEXT_HPP_

CvxText.cpp:

#include <wchar.h>
#include <assert.h>
#include <locale.h>
#include <ctype.h>
#include <cmath>#include "CvxText.hpp"// 打开字库
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, const 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);
}

测试代码如下:

#include "funset.hpp"
#include <iostream>//It contains various macro declarations that are later used to #include the
//appropriate public FreeType 2 header files.
#include <ft2build.h>
//FT_FREETYPE_H is a special macro defined in file ftheader.h. It contains some
//installation-specific macros to name other public header files of the FreeType 2 API.
#include FT_FREETYPE_H
#include <ftglyph.h>#include <opencv2/opencv.hpp>#include "CvxText.hpp"int test_opencv_support_chinese_text()
{cv::Mat mat = cv::imread("E:/GitCode/OCR_Test/test_data/lena.png", 1);if (!mat.data || mat.channels() != 3) {fprintf(stderr, "read image fail\n");return -1;}CvxText text("E:/GitCode/OCR_Test/test_data/simhei.ttf"); //指定字体cv::Scalar size1{ 100, 0.5, 0.1, 0 }, size2{ 100, 0, 0.1, 0 }, size3{ 50, 0, 1, 0 }, size4{50, 0, 0.1, 0}; // (字体大小, 无效的, 字符间距, 无效的 }text.setFont(nullptr, &size1, nullptr, 0);text.putText(mat, "中国", cv::Point(50, 100));text.setFont(nullptr, &size2, nullptr, 0);text.putText(mat, "北京", cv::Point(50, 200), cv::Scalar(255, 0, 0));text.setFont(nullptr, &size3, nullptr, 0);text.putText(mat, "China", cv::Point(50, 250), cv::Scalar(0, 255, 0));text.setFont(nullptr, &size4, nullptr, 0);text.putText(mat, "BeiJing", cv::Point(50, 300), cv::Scalar(0, 0, 255));cv::imwrite("E:/GitCode/OCR_Test/test_data/result_lena.png", mat);return 0;
}

测试结果如下:

GitHub: https://github.com/fengbingchun/OCR_Test

OpenCV支持中文字符输出实现相关推荐

  1. python语言支持中文字符作为量变_尔雅尔雅汉语揭秘章节考试答案

    运营是让产品持续产生产品价值和商业价值目的. [多选题]作为现代战略营销的核心,STP营销是企业制定有效营销组合策略的基础和前提,其内容包括 ( ) A. 市场进入 B. 细分市场 C. 目标营销 D ...

  2. android 4.4.3上面,联系人的头像默认显示首字母,但是不支持中文字符,修改支持中文

    在android 4.4.3上面,联系人的头像默认显示首字母,但是不支持中文字符,如下图: 如果联系人名字的第一位是英文字符(a-z || A-Z),则默认头像将显示该首字母. 如果支持中文时显示第一 ...

  3. Dicom文件支持中文字符

    Dicom文件的默认字符集编码为ISO-IR6,这种字符集是不支持中文的,当使用Dicom工具修改病人姓名后,名字会成乱码而无法正常显示,如下图: 知道了原因就知道解决办法了,修改Dicom的字符集( ...

  4. moviepy音视频剪辑:TextClip不支持中文字符以及OSError: magick.exe: unable to read font 仿宋_GB2312.ttf的解决办法

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 moviepy对中文和多语言环境的支持做得并不好,包括中文文件名以及用于显示文字的TextClip就是典型的中文支持方面存在问题的.对于编解码的问题 ...

  5. 又重新让aspspider.net支持中文PDF输出了

    经过一番努力,再次看到中文PDF的输出: aspspider.net经过这次更新后,不知道什么原因,使用 BaseFont.AddToResourceSearch(MapPath(@".\i ...

  6. lua 不支持中文字符_英雄联盟跳票?不支持中文?别急看这里!界面最强翻译!...

    大家期待英雄联盟手游已经很久了,16 号放出消息苦苦等待 28 号.老范跟大家的心情是一样的,注册拳头账号遇到种种问题,半天注册不成功等,要么就是卡在最后一步. 注册麻烦就不用说了,约定好的日子就跳票 ...

  7. C语言读入txt文件中的中文字符输出乱码

    **记录下自己在文件操作上遇到的常见问题** 输出乱码的情况 fopen函数读写的相关操作 输出乱码的情况 在使用C语言时我们一般用fopen函数打开文件,如下 #include<stdio.h ...

  8. SciTE: 中文字符支持问题

    SciTE: 中文字符支持问题   SciTE(Scintilla Text Editor)是一个体积小巧的文本编辑器. 但是它默认的设置对中文字符处理不好,其实只要对它进行相应的配置,就可以了. 1 ...

  9. C++fstream文件流处理对中文字符不支持的解决办法

    转载一篇C++文件流处理中文路径问题的方法. http://www.cnblogs.com/upendi/archive/2013/05/10/3072195.html [以下内容转自:我住包子山 让 ...

最新文章

  1. [译]如何在C#中调试LINQ查询
  2. 判断整数序列是不是二元查找树的后序遍历结果
  3. www.android ind.com,Android
  4. TDSQL 安装部署(多图预警)
  5. 系统集成的系统架构图的相关的vsd素材_信息系统集成专业技术知识:软件架构...
  6. 数据结构 3-2-1 队列的链式存储实现
  7. Javascript 操作二进制数据
  8. Access SqLDbHelper
  9. ASP.NET之ScriptManager和ClientScriptManager
  10. 携程中转机票竟然相差23小时
  11. 如何利用迅雷下载百度云?
  12. stm32 SSI读编码器
  13. 【开发日常】手动安装fastboot驱动(开发板连不上minitool)
  14. 一级导航,二级导航,三级导航介绍
  15. 分时操作系统与分布式操作系统
  16. asp.net大文件分块上传视频教程
  17. tp-link无线路由与android手机无线连接设置指南,手机设置tplink无线路由器_tplink路由器手机设置步骤-192路由网...
  18. 100行Python代码,做一个打地鼠小游戏!
  19. Max 文件制作三维场景
  20. 清华大学计算机专业的cpu,我们研制成功进入世界500强的超级计算机

热门文章

  1. 用代码优雅的终止springboot服务
  2. opencv学习笔记(二)
  3. 第二章:3、BP神经网络
  4. 【camera】3.相机成像颜色及其组成
  5. 通信系统未编码、卷积码与格雷码的仿真性能比较
  6. Linux那些事儿 之 戏说USB(3)我是一棵树
  7. 学习《Linux设备模型浅析之驱动篇》笔记(一)
  8. 剑指offer:面试题24. 反转链表
  9. div自己移除自己/移除div下面的所有子元素
  10. 【进阶玩法】Angular用emit()实现类似Vue.js的v-model双向绑定[(ngModel)]功能