基于OpenCV 2.4.93.1的汉字显示(FreeType 2.6.2)

其实下文中的Ft2.6.2重编译为x64平台的Lib和dll也适用于freetype-2.8.1

(写的很详细,只要将 freetype-2.6.2换为freetype-2.8.1即可)


1、主要工作

(1)FreeType下载与编译;

(2)OpenCV工程demo中须添加代码资源;

(3)OpenCV中添加FreeType库及配置;

(4)遇到的问题与解决;

2、工作具体内容

2.1汉字显示准备工作

由于OpenCV自带的cvInitFont和cvPutText函数不支持向图像中写入中文,需要使用FreeType库来进行汉字显示。

FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,包括TrueType, OpenType, Type1, CID, CFF, Windows FON/FNT, X11 PCF等。

OpenCV+FreeType显示汉字的中步骤如下:

(1)VS2013+OpenCV配置;

(2)FreeType下载;

(3)FreeType重编译;

(4)OpenCV工程demo中添加代码资源等;

(5)OpenCV中添加FreeType库及配置。

(6)OpenCV工程demo编译、运行工程。

2.2 VS2013+OpenCV配置

VS + CV的配置已介绍过多次,这里不再赘述。详细见:Win7 64位+VS2013 OpenCV 2.4.9安装配置Win7 64位+VS2013 OpenCV 3.1.0安装配置

本工程中系统版本为:Win7 64位,平台为:VS2013,OpenCV采用:

OpenCV 2.4.9OpenCV 3.1.0,其中OpenCV 2.4.9在VS2013中调试平台为

Win 32(32位:x86),OpenCV 3.1.0在VS2013中调试平台为x64(64位:x64)。

2.3 FreeType下载

首先,我们下载 FreeType 的源代码。从官网(https://www.freetype.org/sourceforge:https://sourceforge.net/projects/freetype/files/freetype2上获得 FreeType 的源码工程,(这里最新版本为2.7,本工程中采用较为稳定的2.6.2)。

图 2.2.1 FreeType 下载

2.4 FreeType基于VS2013的重编译

STEP 1:

将下载下来的ft262.zip文件解压后得到freetype-2.6.2文件夹,把 freetype-2.6.2这个目录拷贝到这个目录下:D:\opencv lib\

图 2.3.1 freeyype-2.6.2 文件夹

注意:[1] 如果电脑上并不存在这个目录,需要自己创建。[2] 亦可使用电脑中的其他路径,但如果在后面的步骤中涉及到这个路径,需要自行转换成自己所用的路径。

STEP 2:

在系统变量中,增加:FreeType : D:\opencv lib\\freetype-2.6.2

图 2.3.2 freeyype-2.6.2 环境变量配置

这么做的好处是:

[1]以后当我们需要用到 D:\opencv lib\\freetype-2.6.2这个路径的时候,可以用%FreeType%或者$(FreeType)来代替它;

[2]如果我们以后更换了 FreeType的版本,只需要更新FreeType系统变量,就可以用%FreeType%或者$(FreeType)来指向最新版本的路径了。

STEP 3:

在 %FreeType%\builds\windows 这个目录下,我们能看到 visualc(这是给VC6用的)、vc2005、vc2008、vc2010,没有vs2013。这里我们直接把vs2010复制出一份重命名为vs2013。

图 2.3.3 将 vs2010 复制出一份重命名为vs2013

STEP 4:

在 %FreeType%\builds\windows\vs2013中,用Visual Studio 2013打开freetype.sln。右键freetype工程打开属性页

图 2.3.4 freetype属性页

 

[1]将配置属性→常规中的配置(C)选为所有配置,平台(P)选为所有平台

[2]将输出目录及中间目录中的vc2010字样修改为MSVC

(注意:为什么改成 MSVC 呢?是为了跟 FreeType for Windows Binary Download下载得到的文件路径保持一致。)

[3]将字符集中的使用多字节字符集(也就是 MBCS,MBCS的存在是为了兼容Windows NT、Windows 98、Windows 2000等旧操作系统,对于较新Windows系统尽量使用Unicode字符集。)修改为使用Unicode字符集

[4]将配置类型中的静态库 (.lib),其实像这种公共的库我们最好使用动态链接库。我们把它改成动态库 (.dll)

修改之后的属性页如下图所示:

图 2.3.5 修改后的属性页

[5]此时如果去编译,虽然可以得到动态链接库(DLLs),但不会得到LIB。此时程序只能显式地调用动态链接库,却无法隐式地调用动态链接库(需要LIB)。

在 %FreeType%/include/freetype/config/ftconfig.h的找到这一段(第387行):

?
1
2
3
4
5
6
7
8
9
#ifndef FT_EXPORT
 
#ifdef __cplusplus
#define FT_EXPORT( x )  extern "C"  x
# else
#define FT_EXPORT( x )  extern  x
#endif
 
#endif /* !FT_EXPORT */

 

修改为:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#ifdef DLL_EXPORT
#undef DLL_EXPORT
#define DLL_EXPORT  __declspec(dllexport)
# else
#define DLL_EXPORT  __declspec(dllimport)
#endif /* !DLL_EXPORT */
 
 
#ifndef FT_EXPORT
 
#ifdef __cplusplus
#define FT_EXPORT( x )  extern "C"  DLL_EXPORT  x
# else
#define FT_EXPORT( x )  extern  DLL_EXPORT  x
#endif
 
#endif /* !FT_EXPORT */

STEP 5:进行编译

点击 Visual Studio 2013菜单生成批生成,点击全选然后点击生成

图 2.3.6 编译菜单

编译结果如下,至此FreeType 2.6.2 VS2013下重编译完成。

图 2.3.7 编译结果

2.5 OpenCV工程demo中添加代码资源

STEP 1:

新建一个VS C++工程,配置好OpenCV(重新配置或者添加原来工程配置好的OpenCV项目属性表,本项目中采用添加现有项目属性表的方式)。

STEP 2:

项目中添加头文件CvxText.h和源文件CvxText.cpp。源代码如下。

CvxText.h:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//====================================================================
//====================================================================
//
// 文件: CvxText.h
//
// 说明: OpenCV汉字输出
//
// 时间:
//
// 作者: chaishushan#gmail.com
//
//====================================================================
//====================================================================
 
#ifndef OPENCV_CVX_TEXT_2007_08_31_H
#define OPENCV_CVX_TEXT_2007_08_31_H
 
/**
* \file CvxText.h
* \brief OpenCV汉字输出接口
*
* 实现了汉字输出功能。
*/
 
#include <ft2build.h>
#include FT_FREETYPE_H
 
#include<opencv2 opencv.hpp= "" >
 
/**
* \class CvxText
* \brief OpenCV中输出汉字
*
* OpenCV中输出汉字。字库提取采用了开源的FreeFype库。由于FreeFype是
* GPL版权发布的库,和OpenCV版权并不一致,因此目前还没有合并到OpenCV
* 扩展库中。
*
* 显示汉字的时候需要一个汉字字库文件,字库文件系统一般都自带了。
* 这里采用的是一个开源的字库:“文泉驿正黑体”。
*
* 关于"OpenCV扩展库"的细节请访问
*
* 关于FreeType的细节请访问
*/
 
 
class CvxText
{
     // 禁止copy
 
     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,
         CvScalar *size = NULL, bool *underline = NULL, float *diaphaneity = NULL);
 
     /**
     * 设置字体。目前有些参数尚不支持。
     *
     * \param font        字体类型, 目前不支持
     * \param size        字体大小/空白比例/间隔比例/旋转角度
     * \param underline   下画线
     * \param diaphaneity 透明度
     *
     * \sa getFont, restoreFont
     */
 
     void setFont( int *type,
         CvScalar *size = NULL, bool *underline = NULL, float *diaphaneity = NULL);
 
     /**
     * 恢复原始的字体设置。
     *
     * \sa getFont, setFont
     */
 
     void restoreFont();
 
     //================================================================
     //================================================================
 
     /**
     * 输出汉字(颜色默认为黑色)。遇到不能输出的字符将停止。
     *
     * \param img  输出的影象
     * \param text 文本内容
     * \param pos  文本位置
     *
     * \return 返回成功输出的字符长度,失败返回-1。
     */
 
     int putText(IplImage *img, const char    *text, CvPoint pos);
 
     /**
     * 输出汉字(颜色默认为黑色)。遇到不能输出的字符将停止。
     *
     * \param img  输出的影象
     * \param text 文本内容
     * \param pos  文本位置
     *
     * \return 返回成功输出的字符长度,失败返回-1。
     */
 
     int putText(IplImage *img, const wchar_t *text, CvPoint pos);
 
     /**
     * 输出汉字。遇到不能输出的字符将停止。
     *
     * \param img   输出的影象
     * \param text  文本内容
     * \param pos   文本位置
     * \param color 文本颜色
     *
     * \return 返回成功输出的字符长度,失败返回-1。
     */
 
     int putText(IplImage *img, const char    *text, CvPoint pos, CvScalar color);
 
     /**
     * 输出汉字。遇到不能输出的字符将停止。
     *
     * \param img   输出的影象
     * \param text  文本内容
     * \param pos   文本位置
     * \param color 文本颜色
     *
     * \return 返回成功输出的字符长度,失败返回-1。
     */
     int putText(IplImage *img, const wchar_t *text, CvPoint pos, CvScalar color);
 
     //================================================================
     //================================================================
 
private :
 
     // 输出当前字符, 更新m_pos位置
 
     void putWChar(IplImage *img, wchar_t wc, CvPoint &pos, CvScalar color);
 
     //================================================================
     //================================================================
 
private :
 
     FT_Library   m_library;   // 字库
     FT_Face      m_face;      // 字体
 
     //================================================================
     //================================================================
 
     // 默认的字体输出参数
 
     int         m_fontType;
     CvScalar   m_fontSize;
     bool      m_fontUnderline;
     float      m_fontDiaphaneity;
 
     //================================================================
     //================================================================
};
 
#endif // OPENCV_CVX_TEXT_2007_08_31_H</opencv2></ft2build.h>

CvxText.cpp:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#include <wchar.h>
#include
#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);
}
 
// 设置字体参数:
//
// font         - 字体类型, 目前不支持
// size         - 字体大小/空白比例/间隔比例/旋转角度
// underline   - 下画线
// diaphaneity   - 透明度
 
void CvxText::getFont( int *type, CvScalar *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, CvScalar *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(IplImage *img, const char    *text, CvPoint pos)
{
     return putText(img, text, pos, CV_RGB( 255 , 255 , 255 ));
}
int CvxText::putText(IplImage *img, const wchar_t *text, CvPoint pos)
{
     return putText(img, text, pos, CV_RGB( 255 , 255 , 255 ));
}
 
//
 
int CvxText::putText(IplImage *img, const char    *text, CvPoint pos, CvScalar color)
{
     if (img == 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(IplImage *img, const wchar_t *text, CvPoint pos, CvScalar color)
{
     if (img == 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(IplImage *img, wchar_t wc, CvPoint &pos, CvScalar 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 = ((img->origin == 0 ) ? i : (rows - 1 - i))
                 * slot->bitmap.pitch + j / 8 ;
 
             if (slot->bitmap.buffer[off] & ( 0xC0 >> (j % 8 )))
             {
                 int r = (img->origin == 0 ) ? pos.y - (rows - 1 - i) : pos.y + i;;
                 int c = pos.x + j;
 
                 if (r >= 0 && r < img->height
                     && c >= 0 && c < img->width)
                 {
                     CvScalar 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);
}</ctype.h></locale.h></ assert .h></wchar.h>

测试主程序main.cpp:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <opencv highgui.h= "" >
#include
#include "CvxText.h"
using namespace cv;
 
int main( int argc, char *argv[])
{
     // 打开一幅
     IplImage *img = cvLoadImage( "lena.jpg" );
     // 输出汉字
     {
         CvxText text( "C:\\Windows\\Fonts\\simhei.ttf" ); // "zenhei.ttf"为黑体常规
         //CvxText text("simhei.ttf"); // "zenhei.ttf"为黑体常规
         const char *msg = "在OpenCV中输出汉字!" ;
         float p = 0.5 ;
         text.setFont(NULL, NULL, NULL, &p);   // 透明处理
         text.putText(img, msg, cvPoint( 100 , 150 ), CV_RGB( 255 , 0 , 0 ));
     }
     // 定义窗口,并显示影象
     cvShowImage( "test" , img); cvWaitKey(- 1 );
     cvReleaseImage(&img);
     return 0 ;
}</ assert .h></opencv>

STEP 3:

添加测试源代码main.cpp。源代码见附录。

经过以上步骤,将工程所需源代码添加完成,但此时由于并没有将先前得到的FreeType库链接到工程中,工程仍无法运行,此时需要添加FreeType库。

2.6 OpenCV中添加FreeType库及配置

OpenCV中添加FreeType库时,需要对原有项目属性表进行修改。

本项目中分别测试了VS 2013+OpenCV 2.4.9及VS2013+OpenCV 3.1.0,二者分别对应两个不同的项目属性表。它们最大的不同在于2.4.9调试平台为Win 32,而3.1.0调试平台为x64,所以配置在大体一致的情况下有少许不同。具体配置步骤如下。

STEP 1:

右键所添加项目属性表打开属性页面。在通用属性→VC++目录中,在包含目录添加路径:%FreeType%\include,库目录添加路径:%FreeType%\objs\MSVC\Win32(这里的Win32对应的是OpenCV 2.4.9,对于OpenCV 3.1.0来说,由于其调试平台为x64,所以库目录应添加路径:%FreeType%\objs\MSVC\x64)。

注:这里%FreeType%是上文提到的添加的FreeType环境变量,其值为freetype 2.6.2所在目录。

图 2.5.1 项目属性表VC++目录添加

STEP 2:

添加好包含目录和库目录之后,开始添加之前重新编译好的freetype库,在项目属性表属性页→输入→附加的链接项中添加:freetype262.dll。

图 2.5.2 项目属性表附加依赖项添加

2.7 OpenCV工程demo编译、运行工程

经过以上步骤,成功完成了工程运行所需全部步骤,对工程文件进行编译、调试。

图 2.6.1 项工程编译通过

运行结果如下:

图 2.6.2 工程运行结果

2.8遇到的问题与解决

由于网上没有完整的一套完整的OpenCV显示汉字的教程,所以在自己摸索过程当中遇到了许多问题,其中许多问题也无法在网上找到答案,于是自己一步步摸索了很久最终终于解决了一个个问题,顺利完成了汉字的显示!

其中问题主要集中在OpenCV与Freetype库的链接过程。

(1)无法打开包括文件”ft2build.h”

图 2.7.1 错误:无法打开包括文件”ft2build.h”

解决办法:

检查项目属性表属性页中VC++包含目录中是否添加了%FreeType%\include路径,填写是否正确。

若正确则把路径换为文件绝对路径,如:D:\opencv lib\freetype-2.6.2\include。

若仍提示此错误,则在属性页→C/C++→常规→附加包含目录中填写路径:D:\opencv lib\freetype-2.6.2\include。

(2)无法打开文件”freetype262.lib”

图 2.7.2 错误:无法打开文件”freetype262.lib”

解决办法:

检查项目属性表属性页中VC++库目录中是否添加了%FreeType%\objs\MSVC\Win32(或者x64)路径,填写是否正确。

(3)无法在0xXXX处读取freetype262.dll及无法解析的外部符号

图 2.7.3 错误:无法在0xXXX处读取freetype262.dll

图 2.7.4 错误:无法解析的外部符号

解决办法:

检查项目属性表属性页中连接器→输入→附加依赖项中是否添加了freetype.lib,填写是否正确。

此处特别注意不要把freetype.lib填写为freetype.dll否则会出现图2.7.3所示错误,非常难发现。

(4)无法启动此程序

解决办法:

(1)将上文提及的分别与OpenCV版本对应的freetype262.dll文件放在C:\Windows\SysWOW64目录下;

(2)在环境变量中的系统变量中PATH值中添加%FreeType%\objs\MSVC\x64;%FreeType%\objs\MSVC\Win32。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值