
一、在圖片上打印文字 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操作已經正常了。
附件列表