
一、在图片上打印文字 windows+GDI+TrueType字体

//====================================================================
//
// 文件: textTrueType.h
//
// 说明: OpenCV汉字输出
//
//====================================================================
#
ifndef PUTTEXT_H_
#
define PUTTEXT_H_
#
include
<windows.h
>
#
include
<string
>
#
include
<opencv2
/opencv.hpp
>
using
namespace cv;
void GetStringSize(HDC hDC,
const
char
* str,
int
* w,
int
* h);
void putTextZH(Mat
&dst,
const
char
* str, Point org, Scalar color,
int fontSize,
const
char
*fn
=
"Arial",
bool italic
=
false,
bool underline
=
false);
#
endif
// PUTTEXT_H_
//====================================================================
//
// 文件: textTrueType.cpp
//
// 说明: OpenCV汉字输出
//
//====================================================================
#
include
"textTrueType.h"
void GetStringSize(HDC hDC,
const
char
* str,
int
* w,
int
* h)
{
SIZE size;
GetTextExtentPoint32A(hDC, str, strlen(str),
&size);
if (w
!=
0)
*w
= size.cx;
if (h
!=
0)
*h
= size.cy;
}
void putTextZH(Mat
&dst,
const
char
* str, Point org, Scalar color,
int fontSize,
const
char
* fn,
bool italic,
bool underline)
{
CV_Assert(dst.data
!=
0
&& (dst.channels()
==
1
|| dst.channels()
==
3));
int x, y, r, b;
if (org.x
> dst.cols
|| org.y
> dst.rows)
return;
x
= org.x
<
0
?
-org.x
:
0;
y
= org.y
<
0
?
-org.y
:
0;
LOGFONTA lf;
lf.lfHeight
=
-fontSize;
lf.lfWidth
=
0;
lf.lfEscapement
=
0;
lf.lfOrientation
=
0;
lf.lfWeight
=
5;
lf.lfItalic
= italic;
//斜体
lf.lfUnderline
= underline;
//下划线
lf.lfStrikeOut
=
0;
lf.lfCharSet
= DEFAULT_CHARSET;
lf.lfOutPrecision
=
0;
lf.lfClipPrecision
=
0;
lf.lfQuality
= PROOF_QUALITY;
lf.lfPitchAndFamily
=
0;
strcpy_s(lf.lfFaceName, fn);
HFONT hf
= CreateFontIndirectA(
&lf);
HDC hDC
= CreateCompatibleDC(
0);
HFONT hOldFont
= (HFONT)SelectObject(hDC, hf);
int strBaseW
=
0, strBaseH
=
0;
int singleRow
=
0;
char buf[
1
<<
12];
strcpy_s(buf, str);
char
*bufT[
1
<<
12];
// 这个用于分隔字符串后剩余的字符,可能会超出。
//处理多行
{
int nnh
=
0;
int cw, ch;
const
char
* ln
= strtok_s(buf,
"\n",bufT);
while (ln
!=
0)
{
GetStringSize(hDC, ln,
&cw,
&ch);
strBaseW
= max(strBaseW, cw);
strBaseH
= max(strBaseH, ch);
ln
= strtok_s(
0,
"\n",bufT);
nnh
++;
}
singleRow
= strBaseH;
strBaseH
*= nnh;
}
if (org.x
+ strBaseW
<
0
|| org.y
+ strBaseH
<
0)
{
SelectObject(hDC, hOldFont);
DeleteObject(hf);
DeleteObject(hDC);
return;
}
r
= org.x
+ strBaseW
> dst.cols
? dst.cols
- org.x
-
1
: strBaseW
-
1;
b
= org.y
+ strBaseH
> dst.rows
? dst.rows
- org.y
-
1
: strBaseH
-
1;
org.x
= org.x
<
0
?
0
: org.x;
org.y
= org.y
<
0
?
0
: org.y;
BITMAPINFO bmp
= {
0 };
BITMAPINFOHEADER
& bih
= bmp.bmiHeader;
int strDrawLineStep
= strBaseW
*
3
%
4
==
0
? strBaseW
*
3
: (strBaseW
*
3
+
4
- ((strBaseW
*
3)
%
4));
bih.biSize
=
sizeof(BITMAPINFOHEADER);
bih.biWidth
= strBaseW;
bih.biHeight
= strBaseH;
bih.biPlanes
=
1;
bih.biBitCount
=
24;
bih.biCompression
= BI_RGB;
bih.biSizeImage
= strBaseH
* strDrawLineStep;
bih.biClrUsed
=
0;
bih.biClrImportant
=
0;
void
* pDibData
=
0;
HBITMAP hBmp
= CreateDIBSection(hDC,
&bmp, DIB_RGB_COLORS,
&pDibData,
0,
0);
CV_Assert(pDibData
!=
0);
HBITMAP hOldBmp
= (HBITMAP)SelectObject(hDC, hBmp);
//color.val[2], color.val[1], color.val[0]
SetTextColor(hDC, RGB(
255,
255,
255));
SetBkColor(hDC,
0);
//SetStretchBltMode(hDC, COLORONCOLOR);
strcpy_s(buf, str);
const
char
* ln
= strtok_s(buf,
"\n",bufT);
int outTextY
=
0;
while (ln
!=
0)
{
TextOutA(hDC,
0, outTextY, ln, strlen(ln));
outTextY
+= singleRow;
ln
= strtok_s(
0,
"\n",bufT);
}
uchar
* dstData
= (uchar
*)dst.data;
int dstStep
= dst.step
/
sizeof(dstData[
0]);
unsigned
char
* pImg
= (
unsigned
char
*)dst.data
+ org.x
* dst.channels()
+ org.y
* dstStep;
unsigned
char
* pStr
= (
unsigned
char
*)pDibData
+ x
*
3;
for (
int tty
= y; tty
<
= b;
++tty)
{
unsigned
char
* subImg
= pImg
+ (tty
- y)
* dstStep;
unsigned
char
* subStr
= pStr
+ (strBaseH
- tty
-
1)
* strDrawLineStep;
for (
int ttx
= x; ttx
<
= r;
++ttx)
{
for (
int n
=
0; n
< dst.channels();
++n){
double vtxt
= subStr[n]
/
255.
0;
int cvv
= vtxt
* color.val[n]
+ (
1
- vtxt)
* subImg[n];
subImg[n]
= cvv
>
255
?
255
: (cvv
<
0
?
0
: cvv);
}
subStr
+=
3;
subImg
+= dst.channels();
}
}
SelectObject(hDC, hOldBmp);
SelectObject(hDC, hOldFont);
DeleteObject(hf);
DeleteObject(hBmp);
DeleteDC(hDC);
}
//====================================================================
//
// 文件: test_main.cpp
//
// 说明: OpenCV汉字输出,测试主函数
//
//====================================================================
#
include
"opencv2/opencv.hpp"
#
include
"textTrueType.h"
using
namespace std;
using
namespace cv;
void main()
{
//Mat img(150,600,CV_8UC3,Scalar(255,255,255));//初始化图像
Mat img
= imread(
"D:\\005_test_4\\testImg\\road_6.png");
putTextZH(img,
"打印汉字,汉字,汉字!", Point(
30,
30), Scalar(
255,
0,
0),
45,
"华文行楷");
imwrite(
"1.png", img);
imshow(
"", img);
waitKey(
0);
}
二、在图片上打印文字 FreeType库
//====================================================================
//====================================================================
//
// 文件: CvxText.h
//
// 说明: OpenCV汉字输出
//
//====================================================================
//====================================================================
#
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
>
//modified
//将CvxText.h中的#include<cv.h> #include <highgui.h>用#include<opnecv2/opencv.hpp>替代;
/**
* \class CvxText
* \brief OpenCV中输出汉字
*
* OpenCV中输出汉字。字库提取采用了开源的FreeFype库。由于FreeFype是
* GPL版权发布的库,和OpenCV版权并不一致,因此目前还没有合并到OpenCV
* 扩展库中。
*
* 显示汉字的时候需要一个汉字字库文件,字库文件系统一般都自带了。
* 这里采用的是一个开源的字库:“文泉驿正黑体”。
*
* 关于"OpenCV扩展库"的细节请访问
* http://code.google.com/p/opencv-extension-library/
*
* 关于FreeType的细节请访问
* http://www.freetype.org/
*
* 例子:
*
* \code
int main(int argc, char *argv[])
{
// 定义CvxApplication对象
CvxApplication app(argc, argv);
// 打开一个影象
IplImage *img = cvLoadImage("test.jpg", 1);
// 输出汉字
{
// "wqy-zenhei.ttf"为文泉驿正黑体
CvText text("wqy-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));
}
// 定义窗口,并显示影象
CvxWindow myWin("myWin");
myWin.showImage(img);
// 进入消息循环
return app.exec();
}
* \endcode
*/
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
//====================================================================
//====================================================================
//
// 文件: text_in_image.cpp
//
// 说明: OpenCV汉字输出
//
//====================================================================
//====================================================================
#
include
<iostream
>
#
include
"opencv2/opencv.hpp"
#
include
"CvxText.h"
using
namespace std;
using
namespace cv;
//--------------------------------IPLImage格式的图像, 使用FreeType库---------------------------------------
int main(
int argc,
char
*argv[])
{
IplImage
*img
= cvLoadImage(
"D:\\005_test_4\\testImg\\road_6.png");
{
CvxText text(
"simfang.ttf");
const
char
*msg
=
"汉字!汉字!汉字!";
float p
=
1.
5;
text.setFont(NULL, NULL, NULL,
&p);
text.putText(img, msg, cvPoint(
100,
150), CV_RGB(
0,
255,
0));
}
cvShowImage(
"test", img ); cvWaitKey(
-
1);
cvReleaseImage(
&img);
return
0;
}

三、在图片上打印文字 putText()
/*
作者:WP @20190626
功能:opencv在图片中写入文字
说明:
(1)只在图像上打印 数字、字母的话:
1.Mat格式的图像,可以使用opencv自带的putText。
2.IPLImage格式的图像,可以使用自带的cvInitFont和cvPutText函数。
(2)在图像上打印 汉字的话,可以使用FreeType库。
FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件。
*/
#
include
<iostream
>
#
include
"opencv2/opencv.hpp"
using
namespace std;
using
namespace cv;
//--------------------------------Mat格式的图像,可以使用opencv自带的putText()函数---------------------------------------
int main( )
{
//Mat image = Mat::zeros(Size(640, 480), CV_8UC3); // 创建空白图用于绘制文字
//image.setTo(Scalar(100, 0, 0)); //设置蓝色背景
Mat image
= imread(
"D:\\005_test_4\\testImg\\road_6.png",
1);
// 最后显示,1---原图,0---灰度图
//设置绘制文本的相关参数
string text
=
"JILIN UNIVERSITY";
int font_face
= FONT_HERSHEY_COMPLEX;
double font_scale
=
2;
int thickness
=
2;
int baseline;
//获取文本框的长宽
Size text_size
= getTextSize(text, font_face, font_scale, thickness,
&baseline);
//将文本框居中绘制
Point origin;
origin.x
= image.cols
/
2
- text_size.width
/
2;
origin.y
= image.rows
/
2
+ text_size.height
/
2;
putText(image, text, origin, font_face, font_scale, Scalar(
0,
255,
255), thickness,
8,
0);
putText(image,
"This image is clear.", Point(
50,
100), FONT_HERSHEY_SIMPLEX,
1, Scalar(
0,
0,
255),
4,
8);
//显示绘制结果
imshow(
"image", image);
waitKey(
0);
return
0;
}

小结:第一种方法,基于现有的环境,一个函数解决“中文书写”问题,简单直接;但是其它方法 也需要了解掌握,以方便应对不同的情况和要求。
P.S方法1使用过程中,容易出现的错误和解决方法:来源: <
https://www.cnblogs.com/rainbow70626/p/9073017.html>
std::max、std::min error C2589: “(”:“::”右边的非法标记,error C2059: 语法错误:“::”
在VC++种同时包含头文件#include <windows.h>和#include <algorithm>后就会出现无法正常使用std标准库中的min和max模板函数,经过查阅发现这是因为在Windows.h种也有min和max的定义,这样就导致了algorithm中的min和max无法正常使用,这里给出两种解决方案,来解决std命名空间无法使用min和max的问题。
解决方案一
使用std::min或者std::max的时候加上括号,避免与Windows.h中的min、max宏定义冲突。
#include <windows.h>
#include <algorithm>
(std::min)(
100,
2000
);
(std::max)(
10,
500);
解决方案二
禁用Windows.h中的min、max宏定义。
在Windows.h中可以查阅到min、max的定义为:
#ifndef NOMINMAX
#ifndef max
#define max(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef min
#define min(a,b) (((a) < (b)) ? (a) : (b))
#endif
#endif /* NOMINMAX */
看懂了定义就很简单了,在包含Windows.h文件之前直接定义一个NOMINMAX宏定义就OK了,如下代码所示:
#define NOMINMAX
#include <windows.h>
#include <algorithm>
std::max(
100,
200);
解决方案三:
这个解决办法与第二个本质是一样的。具体方法为:打开工程属性->C/C++->预处理器->预处理器定义->加入NOMINMAX
OK,经过上面的操作,min,max操作已经正常了。
附件列表