本文主要就是讲解利用Opencv3.2+freetype生成汉字字符图像的过程.  目前只做了原图, 加背景噪声(椒盐) ,文字倾斜, 膨胀, 腐蚀, 几种汉字字体等几种情况下的字符图像.

在Opencv的官网下载3.x或者4.0的版本, freetype用官网最新. 开发环境是VS2015, 设置为Unicode, 文中涉及中文字体都应该复制到工程目录下.Opencv的配置或编译这一块不用说了,网上很多, 部分代码源自网络.懒的解释,直接看代码.

// CvxText.h
//====================================================================
//
// 文件: CvxText.h
//
// 说明: OpenCV汉字输出
//
//====================================================================#ifndef OPENCV_CVX_TEXT_2016_NEW_H
#define OPENCV_CVX_TEXT_2016_NEW_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, Scalar *size = NULL, bool *underline = NULL, float *diaphaneity = NULL);/*** 设置字体。目前有些参数尚不支持。** \param font        字体类型, 目前不支持* \param size        字体大小/空白比例/间隔比例/旋转角度* \param underline   下画线* \param diaphaneity 透明度** \sa getFont, restoreFont*/void setFont(int *type, Scalar *size = NULL, bool *underline = NULL, float *diaphaneity = NULL);/*** 恢复原始的字体设置。** \sa getFont, setFont*/void restoreFont();/*** 输出汉字(颜色默认为黑色)。遇到不能输出的字符将停止。** \param img  输出的影象* \param text 文本内容* \param pos  文本位置** \return 返回成功输出的字符长度,失败返回-1。*/int putText(Mat img, const char *text, Point pos);/*** 输出汉字(颜色默认为黑色)。遇到不能输出的字符将停止。** \param img  输出的影象* \param text 文本内容* \param pos  文本位置** \return 返回成功输出的字符长度,失败返回-1。*/int putText(Mat img, const wchar_t *text, Point pos);/*** 输出汉字。遇到不能输出的字符将停止。** \param img   输出的影象* \param text  文本内容* \param pos   文本位置* \param color 文本颜色** \return 返回成功输出的字符长度,失败返回-1。*/int putText(Mat img, const char *text, Point pos, Scalar color);/*** 输出汉字。遇到不能输出的字符将停止。** \param img   输出的影象* \param text  文本内容* \param pos   文本位置* \param color 文本颜色** \return 返回成功输出的字符长度,失败返回-1。*/int putText(Mat img, const wchar_t *text, Point pos, Scalar color);private:// 输出当前字符, 更新m_pos位置void putWChar(Mat img, wchar_t wc, Point &pos, Scalar color);private:FT_Library   m_library;   // 字库FT_Face      m_face;      // 字体// 默认的字体输出参数int          m_fontType;Scalar       m_fontSize;bool         m_fontUnderline;float        m_fontDiaphaneity;
};#endif // OPENCV_CVX_TEXT_2007_08_31_H</ft2build.h>
//CvxText.cpp
#include "stdafx.h"
#include <wchar.h>
#include <assert.h>
#include <locale.h>
#include <ctype.h>#include "CvxText.h"
using namespace cv;//====================================================================
//====================================================================// 打开字库
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(Mat img, const char *text, 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(Mat img, const wchar_t *text, Point pos)
{return putText(img, text, pos, CV_RGB(255, 255, 255));
}//int CvxText::putText(Mat img, const char *text, 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(Mat img, const wchar_t *text, 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(Mat img, wchar_t wc, 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:{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;}}//                  Scalar scalar = cvGet2D(img, r, c); ////                  // 进行色彩融合//                  float p = m_fontDiaphaneity;//                  for(int k = 0; k < 4; ++k)//                  {//                      scalar.val[k] = scalar.val[k]*(1-p) + color.val[k]*p;//                  }// //                  cvSet2D(img, r, c, scalar);}}} // 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);
}

主源文件:

#include "freetype/include/ft2build.h"
#include "CvxText.h"
#include "direct.h"
#include "io.h"
#ifdef _DEBUG
#pragma  comment(lib, "opencv_world320d.lib")
#pragma  comment(lib, "freetype.lib")
#else
#pragma  comment(lib, "opencv_world320.lib")
#endifint GetROIImage(const cv::Mat& src, cv::Mat& dst);
void SPNoise(Mat& img, int n);
///下面有隐性依赖, 有点不妥
int g_iStartRows = 0;
int g_iEndRows   = 0;
int g_iStartCols = 0;
int g_iEndCols   = 0;
////参考http://blog.51cto.com/green906/2158027
int main(int argc, char *argv[])
{//多种字体std::vector<const char*> vecFont{ "msyh.ttc",  "msyhl.ttc", "simfang.ttf", "simhei.ttf", "simkai.ttf", "SIMLI.TTF" , "simsun.ttc", "SIMYOU.TTF", "STCAIYUN.TTF", "STFANGSO.TTF", "STHUPO.TTF", "STKAITI.TTF",\"STLITI.TTF", "STSONG.TTF", "STXIHEI.TTF", "STXINGKA.TTF", "STXINWEI.TTF", "STZHONGS.TTF" };//abcdefghijklmnopqrstuvwxyzconst wchar_t  char_set[] = L"0123456789QWERTYUIOPASDFGHJKLZXCVBNM一乙二十丁厂七卜人入八九几儿了力乃刀又三于干亏士工土才寸下大丈与万上小口巾山千乞川亿个勺久凡及夕丸么广亡门义之尸弓己已子卫也女飞刃习叉马乡丰王井开夫天无元专云扎艺木五支厅不太犬区历尤友匹车巨牙屯比互切瓦止少日中冈贝内水见午牛手毛气升长仁什片仆化仇币仍仅斤爪反介父从今凶分乏公仓月氏勿欠风丹匀乌凤勾文六方火为斗忆订计户认心尺引丑巴孔队办以允予劝双书幻玉刊示末未击打巧正扑扒功扔去甘世古节本术可丙左厉右石布龙平灭轧东卡北占业旧帅归且旦目叶甲申叮电号田由史只央兄叼叫另叨叹四生失禾丘付仗代仙们仪白仔他斥瓜乎丛令用甩印乐句匆册犯外处冬鸟务包饥主市立闪兰半汁汇头汉宁穴它讨写让礼训必议讯记永司尼民出辽奶奴加召皮边发孕圣对台矛纠母幼丝式刑动扛寺吉扣考托老执巩圾扩扫地扬场耳共芒亚芝朽朴机权过臣再协西压厌在有百存而页匠夸夺灰达列死成夹轨邪划迈毕至此贞师尘尖劣光当早吐吓虫曲团同吊吃因吸吗屿帆岁回岂刚则肉网年朱先丢舌竹迁乔伟传乒乓休伍伏优伐延件任伤价份华仰仿伙伪自血向似后行舟全会杀合兆企众爷伞创肌朵杂危旬旨负各名多争色壮冲冰庄庆亦刘齐交次衣产决充妄闭问闯羊并关米灯州汗污江池汤忙兴宇守宅字安讲军许论农讽设访寻那迅尽导异孙阵阳收阶阴防奸如妇好她妈戏羽观欢买红纤级约纪驰巡寿弄麦形进戒吞远违运扶抚坛技坏扰拒找批扯址走抄坝贡攻赤折抓扮抢孝均抛投坟抗坑坊抖护壳志扭块声把报却劫芽花芹芬苍芳严芦劳克苏杆杠杜材村杏极李杨求更束豆两丽医辰励否还歼来连步坚旱盯呈时吴助县里呆园旷围呀吨足邮男困吵串员听吩吹呜吧吼别岗帐财针钉告我乱利秃秀私每兵估体何但伸作伯伶佣低你住位伴身皂佛近彻役返余希坐谷妥含邻岔肝肚肠龟免狂犹角删条卵岛迎饭饮系言冻状亩况床库疗应冷这序辛弃冶忘闲间闷判灶灿弟汪沙汽沃泛沟没沈沉怀忧快完宋宏牢究穷灾良证启评补初社识诉诊词译君灵即层尿尾迟局改张忌际陆阿陈阻附妙妖妨努忍劲鸡驱纯纱纳纲驳纵纷纸纹纺驴纽奉玩环武青责现表规抹拢拔拣担坦押抽拐拖拍者顶拆拥抵拘势抱垃拉拦拌幸招坡披拨择抬其取苦若茂苹苗英范直茄茎茅林枝杯柜析板松枪构杰述枕丧或画卧事刺枣雨卖矿码厕奔奇奋态欧垄妻轰顷转斩轮软到非叔肯齿些虎虏肾贤尚旺具果味昆国昌畅明易昂典固忠咐呼鸣咏呢岸岩帖罗帜岭凯败贩购图钓制知垂牧物乖刮秆和季委佳侍供使例版侄侦侧凭侨佩货依的迫质欣征往爬彼径所舍金命斧爸采受乳贪念贫肤肺肢肿胀朋股肥服胁周昏鱼兔狐忽狗备饰饱饲变京享店夜庙府底剂郊废净盲放刻育闸闹郑券卷单炒炊炕炎炉沫浅法泄河沾泪油泊沿泡注泻泳泥沸波泼泽治怖性怕怜怪学宝宗定宜审宙官空帘实试郎诗肩房诚衬衫视话诞询该详建肃录隶居届刷屈弦承孟孤陕降限妹姑姐姓始驾参艰线练组细驶织终驻驼绍经贯奏春帮珍玻毒型挂封持项垮挎城挠政赴赵挡挺括拴拾挑指垫挣挤拼挖按挥挪某甚革荐巷带草茧茶荒茫荡荣故胡南药标枯柄栋相查柏柳柱柿栏树要咸威歪研砖厘厚砌砍面耐耍牵残殃轻鸦皆背战点临览竖省削尝是盼眨哄显哑冒映星昨畏趴胃贵界虹虾蚁思蚂虽品咽骂哗咱响哈咬咳哪炭峡罚贱贴骨钞钟钢钥钩卸缸拜看矩怎牲选适秒香种秋科重复竿段便俩贷顺修保促侮俭俗俘信皇泉鬼侵追俊盾待律很须叙剑逃食盆胆胜胞胖脉勉狭狮独狡狱狠贸怨急饶蚀饺饼弯将奖哀亭亮度迹庭疮疯疫疤姿亲音帝施闻阀阁差养美姜叛送类迷前首逆总炼炸炮烂剃洁洪洒浇浊洞测洗活派洽染济洋洲浑浓津恒恢恰恼恨举觉宣室宫宪突穿窃客冠语扁袄祖神祝误诱说诵垦退既屋昼费陡眉孩除险院娃姥姨姻娇怒架贺盈勇怠柔垒绑绒结绕骄绘给络骆绝绞统耕耗艳泰珠班素蚕顽盏匪捞栽捕振载赶起盐捎捏埋捉捆捐损都哲逝捡换挽热恐壶挨耻耽恭莲莫荷获晋恶真框桂档桐株桥桃格校核样根索哥速逗栗配翅辱唇夏础破原套逐烈殊顾轿较顿毙致柴桌虑监紧党晒眠晓鸭晃晌晕蚊哨哭恩唤啊唉罢峰圆贼贿钱钳钻铁铃铅缺氧特牺造乘敌秤租积秧秩称秘透笔笑笋债借值倚倾倒倘俱倡候俯倍倦健臭射躬息徒徐舰舱般航途拿爹爱颂翁脆脂胸胳脏胶脑狸狼逢留皱饿恋桨浆衰高席准座脊症病疾疼疲效离唐资凉站剖竞部旁旅畜阅羞瓶拳粉料益兼烤烘烦烧烛烟递涛浙涝酒涉消浩海涂浴浮流润浪浸涨烫涌悟悄悔悦害宽家宵宴宾窄容宰案请朗诸读扇袜袖袍被祥课谁调冤谅谈谊剥恳展剧屑弱陵陶陷陪娱娘通能难预桑绢绣验继球理捧堵描域掩捷排掉堆推掀授教掏掠培接控探据掘职基著勒黄萌萝菌菜萄菊萍菠营械梦梢梅检梳梯桶救副票戚爽聋袭盛雪辅辆虚雀堂常匙晨睁眯眼悬野啦晚啄距跃略蛇累唱患唯崖崭崇圈铜铲银甜梨犁移笨笼笛符第敏做袋悠偿偶偷您售停偏假得衔盘船斜盒鸽悉欲彩领脚脖脸脱象够猜猪猎猫猛馅馆凑减毫麻痒痕廊康庸鹿盗章竟商族旋望率着盖粘粗粒断剪兽清添淋淹渠渐混渔淘液淡深婆梁渗情惜惭悼惧惕惊惨惯寇寄宿窑密谋谎祸谜逮敢屠弹随蛋隆隐婚婶颈绩绪续骑绳维绵绸绿琴斑替款堪搭塔越趁趋超提堤博揭喜插揪搜煮援裁搁搂搅握揉斯期欺联散惹葬葛董葡敬葱落朝辜葵棒棋植森椅椒棵棍棉棚棕惠惑逼厨厦硬确雁殖裂雄暂雅辈悲紫辉敞赏掌晴暑最量喷晶喇遇喊景践跌跑遗蛙蛛蜓喝喂喘喉幅帽赌赔黑铸铺链销锁锄锅锈锋锐短智毯鹅剩稍程稀税筐等筑策筛筒答筋筝傲傅牌堡集焦傍储奥街惩御循艇舒番释禽腊脾腔鲁猾猴然馋装蛮就痛童阔善羡普粪尊道曾焰港湖渣湿温渴滑湾渡游滋溉愤慌惰愧愉慨割寒富窜窝窗遍裕裤裙谢谣谦属屡强粥疏隔隙絮嫂登缎缓编骗缘瑞魂肆摄摸填搏塌鼓摆携搬摇搞塘摊蒜勤鹊蓝墓幕蓬蓄蒙蒸献禁楚想槐榆楼概赖酬感碍碑碎碰碗碌雷零雾雹输督龄鉴睛睡睬鄙愚暖盟歇暗照跨跳跪路跟遣蛾蜂嗓置罪罩错锡锣锤锦键锯矮辞稠愁筹签简毁舅鼠催傻像躲微愈遥腰腥腹腾腿触解酱痰廉新韵意粮数煎塑慈煤煌满漠源滤滥滔溪溜滚滨粱滩慎誉塞谨福群殿辟障嫌嫁叠缝缠静碧璃墙撇嘉摧截誓境摘摔聚蔽慕暮蔑模榴榜榨歌遭酷酿酸磁愿需弊裳颗嗽蜻蜡蝇蜘赚锹锻舞稳算箩管僚鼻魄貌膜膊膀鲜疑馒裹敲豪膏遮腐瘦辣竭端旗精歉熄熔漆漂漫滴演漏慢寨赛察蜜谱嫩翠熊凳骡缩慧撕撒趣趟撑播撞撤增聪鞋蕉蔬横槽樱橡飘醋醉震霉瞒题暴瞎影踢踏踩踪蝶蝴嘱墨镇靠稻黎稿稼箱箭篇僵躺僻德艘膝膛熟摩颜毅糊遵潜潮懂额慰劈操燕薯薪薄颠橘整融醒餐嘴蹄器赠默镜赞篮邀衡膨雕磨凝辨辩糖糕燃澡激懒壁避缴戴擦鞠藏霜霞瞧蹈螺穗繁辫赢糟糠燥臂翼骤鞭覆蹦镰翻鹰警攀蹲颤瓣爆疆壤耀躁嚼嚷籍魔灌蠢霸露囊罐匕刁丐歹戈夭仑讥冗邓艾夯凸卢叭叽皿凹囚矢乍尔冯玄邦迂邢芋芍吏夷吁吕吆屹廷迄臼仲伦伊肋旭匈凫妆亥汛讳讶讹讼诀弛阱驮驯纫玖玛韧抠扼汞扳抡坎坞抑拟抒芙芜苇芥芯芭杖杉巫杈甫匣轩卤肖吱吠呕呐吟呛吻吭邑囤吮岖牡佑佃伺囱肛肘甸狈鸠彤灸刨庇吝庐闰兑灼沐沛汰沥沦汹沧沪忱诅诈罕屁坠妓姊妒纬玫卦坷坯拓坪坤拄拧拂拙拇拗茉昔苛苫苟苞茁苔枉枢枚枫杭郁矾奈奄殴歧卓昙哎咕呵咙呻咒咆咖帕账贬贮氛秉岳侠侥侣侈卑刽刹肴觅忿瓮肮肪狞庞疟疙疚卒氓炬沽沮泣泞泌沼怔怯宠宛衩祈诡帚屉弧弥陋陌函姆虱叁绅驹绊绎契贰玷玲珊拭拷拱挟垢垛拯荆茸茬荚茵茴荞荠荤荧荔栈柑栅柠枷勃柬砂泵砚鸥轴韭虐昧盹咧昵昭盅勋哆咪哟幽钙钝钠钦钧钮毡氢秕俏俄俐侯徊衍胚胧胎狰饵峦奕咨飒闺闽籽娄烁炫洼柒涎洛恃恍恬恤宦诫诬祠诲屏屎逊陨姚娜蚤骇耘耙秦匿埂捂捍袁捌挫挚捣捅埃耿聂荸莽莱莉莹莺梆栖桦栓桅桩贾酌砸砰砾殉逞哮唠哺剔蚌蚜畔蚣蚪蚓哩圃鸯唁哼唆峭唧峻赂赃钾铆氨秫笆俺赁倔殷耸舀豺豹颁胯胰脐脓逛卿鸵鸳馁凌凄衷郭斋疹紊瓷羔烙浦涡涣涤涧涕涩悍悯窍诺诽袒谆祟恕娩骏琐麸琉琅措捺捶赦埠捻掐掂掖掷掸掺勘聊娶菱菲萎菩萤乾萧萨菇彬梗梧梭曹酝酗厢硅硕奢盔匾颅彪眶晤曼晦冕啡畦趾啃蛆蚯蛉蛀唬啰唾啤啥啸崎逻崔崩婴赊铐铛铝铡铣铭矫秸秽笙笤偎傀躯兜衅徘徙舶舷舵敛翎脯逸凰猖祭烹庶庵痊阎阐眷焊焕鸿涯淑淌淮淆渊淫淳淤淀涮涵惦悴惋寂窒谍谐裆袱祷谒谓谚尉堕隅婉颇绰绷综绽缀巢琳琢琼揍堰揩揽揖彭揣搀搓壹搔葫募蒋蒂韩棱椰焚椎棺榔椭粟棘酣酥硝硫颊雳翘凿棠晰鼎喳遏晾畴跋跛蛔蜒蛤鹃喻啼喧嵌赋赎赐锉锌甥掰氮氯黍筏牍粤逾腌腋腕猩猬惫敦痘痢痪竣翔奠遂焙滞湘渤渺溃溅湃愕惶寓窖窘雇谤犀隘媒媚婿缅缆缔缕骚瑟鹉瑰搪聘斟靴靶蓖蒿蒲蓉楔椿楷榄楞楣酪碘硼碉辐辑频睹睦瞄嗜嗦暇畸跷跺蜈蜗蜕蛹嗅嗡嗤署蜀幌锚锥锨锭锰稚颓筷魁衙腻腮腺鹏肄猿颖煞雏馍馏禀痹廓痴靖誊漓溢溯溶滓溺寞窥窟寝褂裸谬媳嫉缚缤剿赘熬赫蔫摹蔓蔗蔼熙蔚兢榛榕酵碟碴碱碳辕辖雌墅嘁踊蝉嘀幔镀舔熏箍箕箫舆僧孵瘩瘟彰粹漱漩漾慷寡寥谭褐褪隧嫡缨撵撩撮撬擒墩撰鞍蕊蕴樊樟橄敷豌醇磕磅碾憋嘶嘲嘹蝠蝎蝌蝗蝙嘿幢镊镐稽篓膘鲤鲫褒瘪瘤瘫凛澎潭潦澳潘澈澜澄憔懊憎翩褥谴鹤憨履嬉豫缭撼擂擅蕾薛薇擎翰噩橱橙瓢蟥霍霎辙冀踱蹂蟆螃螟噪鹦黔穆篡篷篙篱儒膳鲸瘾瘸糙燎濒憾懈窿缰壕藐檬檐檩檀礁磷瞭瞬瞳瞪曙蹋蟋蟀嚎赡镣魏簇儡徽爵朦臊鳄糜癌懦豁臀藕藤瞻嚣鳍癞瀑襟璧戳攒孽蘑藻鳖蹭蹬簸簿蟹靡癣羹鬓攘蠕巍鳞糯譬霹躏髓蘸镶瓤矗";int iFontIndex = 0;for (auto it = vecFont.begin(); it != vecFont.end(); ++it, ++iFontIndex){CvxText text((*it));int  iAngle = 45;
//          for (int i = 0; i < 6; ++i, iAngle += 10)//这里设置倾斜不管用??{Scalar size(24, 0.5, 0.1, iAngle);       //字体大小/空白比例/间隔比例/旋转角度text.setFont(NULL, &size, NULL);//, &p);int iCharSetSize = sizeof(char_set) / sizeof(char_set[0]);for (int j = 0; j < iCharSetSize; ++j){std::string sPath = ".\\result\\" + std::to_string(j) + "\\";if (_access(sPath.c_str(), 0) == -1) //0只判断是否存在, 2判断写入权限_mkdir(sPath.c_str());String strFileName(sPath.c_str());cv::Mat image(28, 28, CV_8UC1, Scalar(255));wchar_t  msg[4]={0};msg[0] = char_set[j];if (msg[0] == 0)continue;text.putText(image, &msg[0], Point(2, 26), Scalar(0));//原图保存{cv::Mat imageROI;if (GetROIImage(image, imageROI) == 0)imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_0°_0_0.bmp").c_str(), imageROI);elseimwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_0°_0_0.bmp").c_str(), image);}//文字扭曲, 背景噪声(椒盐) ,文字倾斜{//加背景噪声{cv::Mat imageNoise2(image.clone());cv::Mat imageNoise1(image.clone());SPNoise(imageNoise2, 200);SPNoise(imageNoise1, 100);cv::Mat imageROI2 = imageNoise2(cv::Rect(g_iStartCols, g_iStartRows, g_iEndCols - g_iStartCols, g_iEndRows - g_iStartRows));cv::Mat imageROI1 = imageNoise1(cv::Rect(g_iStartCols, g_iStartRows, g_iEndCols - g_iStartCols, g_iEndRows - g_iStartRows));imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_0°_200_0.bmp").c_str(), imageROI2);imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_0°_100_0.bmp").c_str(), imageROI1);}//膨胀{cv::Mat imageDilate(image.clone());//获取自定义核Mat element = getStructuringElement(MORPH_RECT, Size(2, 2)); //第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的//膨胀操作dilate(imageDilate, imageDilate, element);cv::Mat imageROI1 = imageDilate(cv::Rect(g_iStartCols, g_iStartRows, g_iEndCols - g_iStartCols, g_iEndRows - g_iStartRows));imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_0°_0_P.bmp").c_str(), imageROI1);}//腐蚀{cv::Mat imageErode(image.clone());//获取自定义核Mat element = getStructuringElement(MORPH_RECT, Size(2, 2)); //第一个参数MORPH_RECT表示矩形的卷积核,当然还可以选择椭圆形的、交叉型的//腐蚀操作erode(imageErode, imageErode, element);
//                      cv::Mat imageROI1 = imageErode(cv::Rect(g_iStartCols, g_iStartRows, g_iEndCols - g_iStartCols, g_iEndRows - g_iStartRows));
//                      imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_0°_0_F.bmp").c_str(), imageROI1);cv::Mat imageROI1;if (GetROIImage(imageErode, imageROI1) == 0)imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_0°_0_F.bmp").c_str(), imageROI1);elseimwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_0°_0_F.bmp").c_str(), imageErode);}//旋转//指定旋转中心cv::Point2f center(image.cols/2., image.rows/2.);iAngle = -45; //-45°开始到45°for (int i = 0; i < 16; ++i, iAngle += 5){//获取旋转矩阵(2x3矩阵)cv::Mat rot_mat = cv::getRotationMatrix2D(center, iAngle, 1.0);cv::Mat imageRotate;//根据旋转矩阵进行仿射变换cv::Size dst_sz(image.size().height, image.size().width);cv::warpAffine(image, imageRotate, rot_mat, dst_sz, INTER_LINEAR,  BORDER_CONSTANT, Scalar(255));cv::Mat imageROI;if (GetROIImage(imageRotate, imageROI) == 0)imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_" + std::to_string(iAngle) + "°_0_0.bmp").c_str(), imageROI);elseimwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_" + std::to_string(iAngle) + "°_0_0.bmp").c_str(), image);}//扭曲}//裁剪至最小边框{
//                  if (GetROIImage(image, imageROI) == 0)
//                      imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_" + std::to_string(iAngle) + ".bmp").c_str(), imageROI);
//                  else
//                      imwrite(strFileName + (std::to_string(j) + "_" + std::to_string(iFontIndex) + "_" + std::to_string(iAngle) + ".bmp").c_str(), image);}}}}return 0;
}int  GetROIImage(const cv::Mat& image, cv::Mat& imageROI)
{g_iStartRows = image.rows;g_iEndRows = 0;g_iStartCols = image.cols;g_iEndCols = 0;if (image.isContinuous()){for (int iRow = 0; iRow < image.rows; ++iRow){for (int iCol = 0; iCol < image.cols; ++iCol){if (image.data[iRow*image.cols + iCol] < 200){if (g_iStartRows > iRow) g_iStartRows = iRow;if (g_iEndRows < iRow)   g_iEndRows = iRow;if (g_iStartCols > iCol) g_iStartCols = iCol;if (g_iEndCols < iCol)   g_iEndCols = iCol;}}}assert(g_iEndCols != g_iStartCols);
//      assert(g_iEndRows != g_iStartRows);if (g_iEndCols <= g_iStartCols || g_iEndRows <= g_iStartRows)return 1;imageROI = image(cv::Rect(g_iStartCols, g_iStartRows, g_iEndCols - g_iStartCols, g_iEndRows - g_iStartRows));return 0;}else{std::wcout << L"此图不连续" << std::endl;return 1;}
}
//椒盐噪声产生函数
void SPNoise(Mat& img, int n) {//  椒盐噪声需要循环进行反复赋值,循环次数一般人工输入确定//  循环变量仅用于循环,不用于赋值的移位等功用int typeOfNoice = 0; //  定义噪声种类变量,默认为0(椒噪声),1表示盐噪声int Crow = 0;int Ccol = 0;while (n > 0) {//  第一个随机数产生函数用于确定椒盐噪声种类typeOfNoice = rand() % 2;   //  确定输出仅有1和0两个结果  //  使用两个随机数产生函数获取被修改的图像矩阵对应位置Crow = rand() % img.rows;Ccol = rand() % img.cols;//  使用at模板函数进入图像矩阵,修改矩阵参数,即加入噪声//  加入判断,如果图像的类别为单通道(灰度图),仅处理一个通道的数据即可if (img.type() == CV_8UC1) {if (typeOfNoice == 0)img.at<uchar>(Crow, Ccol) = 0;else if (typeOfNoice == 1)img.at<uchar>(Crow, Ccol) = 255;}//  如果是3通道图,则处理像素的三元数据(BGR)else if (img.type() == CV_8UC3) {if (typeOfNoice == 0) {img.at<Vec3b>(Crow, Ccol)[0] = 0;img.at<Vec3b>(Crow, Ccol)[1] = 0;img.at<Vec3b>(Crow, Ccol)[2] = 0;}else if (typeOfNoice == 1){img.at<Vec3b>(Crow, Ccol)[0] = 255;img.at<Vec3b>(Crow, Ccol)[1] = 255;img.at<Vec3b>(Crow, Ccol)[2] = 255;}}n--;}
}

OCR中文简体汉字字符材料制作相关推荐

  1. oracle10中文排序规则,【NLSSORT】改变Oralce 对简体汉字的排序规则(拼音、部首、笔画)...

    如果数据库字符集选用的是ZH16GBK,那么使用order by默认是按照汉字的"二进制编码"顺序进行排序的.有方法改变这个默认规则么?答案是肯定的,Oracle针对简体中文提供三 ...

  2. oracle10中文排序规则,【转】 【NLSSORT】改变Oralce 对简体汉字的排序规则(拼音、部首、笔画)...

    如果数据库字符集选用的是ZH16GBK,那么使用order by默认是按照汉字的拼音顺序进行排序的.有方法改变这个默认规则么?答案是肯定的,Oracle针对简体中文提供三种排序方法,主要是围绕&quo ...

  3. 正整数的中文表示python_【python3】将小于亿的正整数转为汉字字符

    项目需要,将一些整数转为汉字字符串,搜索了一下大家基本都是自己写一下函数转换,参考了帖子:https://blog.csdn.net/PlusCha...:在其中速度最快的第三种程序的基础上,自己做了 ...

  4. 中文标点符号占用几个字节_英文字符占几个字节?汉字字符、还有标点呢?????...

    展开全部 一个英文字符等于1个字节,一个中文(含繁体)字符等于3个字节:中文标点占3个字节,英32313133353236313431303231363533e59b9ee7ad94313334313 ...

  5. ocr中文 java_java 中文ocr

    文字识别OCR 文字识别(Optical Character Recognition),就是将图片或扫描件中的文字识别成可编辑的文本.可代替人工录入,提升业务效率. 多种套餐包灵活组合,单价低至¥0/ ...

  6. [转] 汉字字符编码的科普笔记

    一 GB2312与cp936 1. GB2312简介 GB2312即GB2312-80,诞生于1981年,共收录6763个汉字,其中一级汉字3755个,二级汉字3008个:同时收录了包括拉丁字母.希腊 ...

  7. PostgreSQL 中文(汉字)数字转阿拉伯数字

    PostgreSQL 中文(简体.繁体)数字转阿拉伯数字 函数代码 --中文汉字转阿拉伯数字 CREATE OR REPLACE FUNCTION udf_hanzi2digits(input_chi ...

  8. C#支持中文的格式化字符长度方法

    支持中文的格式化字符长度,自动添加...符号 #region 格式化字符串长度/// <summary>/// 格式化字符串长度/// </summary>/// <pa ...

  9. php 简转繁体,PHP将简体汉字转为繁体的方法

    近来一项目中涉及到将简体汉字转换为繁体汉字,网上搜了搜,找了半天,发现没个能用的,不过最终也算是对这个过程有所了解了.网上大多数文章提供的思想就是在一个简体,繁体对应的表中查找相对应的汉字,然后进行替 ...

  10. C语言输出单个汉字字符

    1 #include "stdio.h" 2 #include "windows.h" 3 4 int main() 5 { 6 char sText[20] ...

最新文章

  1. shell编程:实现shell字符串连接功能
  2. Java中synchronized和Lock的区别
  3. java 获取mp4 缩略图_java获取视频缩略图
  4. Java 语法 索引 ----- 泛型(Generics)
  5. 使用ActiveMQ和HornetQ通过WebSocket通过STOMP轻松进行消息传递
  6. Python(13)-函数,lambda语句
  7. C语言中的转义字符【转ce123的技术博客】
  8. android 高度上分权重,Android LinearLayout weight权重使用
  9. 物联网项目开发工作笔记0001---物联网项目的开发周期,项目管理,厂家合作
  10. php168 的采集规则的改动
  11. html文档元素两部分,html元素
  12. React项目以及降级兼容IE低版本
  13. Linux下Libtorch运行出现free(): invalid pointer报错
  14. Python文件转换为exe文件,可执行文件方法
  15. 软件测试面试必问问题
  16. 高可用PgSQL集群架构设计与落地
  17. app封装源码|­app分发源码免签H5一键封装
  18. 细说API - 认证、授权和凭证
  19. Qt编写的项目作品30-录音播放控件(雨田哥作品)
  20. Create和OnCreate的关系

热门文章

  1. android客户端同php服务端进行XML/JSON通信
  2. hdoj2154跳舞毯
  3. 国产操作系统有哪些,你知道吗?
  4. 正弦余弦定理,求圆弧度或度数
  5. wps office 2013 利用wps文字制作一张漂亮的座位表
  6. updating homebrew
  7. 【已解决】ubuntu无法进入启动页面,全屏出现【ok】并且不停闪烁
  8. 用c/c++和Java语言实现庞加莱回归
  9. c语言一个整数犯二的程度编程,2016天梯初赛上篇(部分题目)
  10. mysql水仙花数,水仙花数_水仙花数c语言程序