Opencv3.4.1绘制中文点阵
目标:利用opencv在图片上添加文字
- 利用opencv自带的putText就可以添加数字和英文
- 我们要求添加中文,达到以下效果
![]()
(一)Windows上绘制中文点阵
环境:VS2017+opencv3.4.1
- 创建空项目、添加源文件Textimage.cpp、配置opencv环境(配置教程点这儿~)
- 思路:
- 从test.txt文件夹获取将要录入的姓名和学号,从txt文件夹获取将要录入的姓名和学号(test.txt内容如下图)
- 从lena.jpg获取将要显示的背景图片作为画布
- 将中文和学号转换为中文点阵字库中的点阵格式
(图片为数字点阵asc-48x48的“0”、asci-15x16格式“0”、hzkf16x16格式“0”和汉字点阵格式倒置的“啊”)
- 利用opencv画图将汉字画在画布上
- 完成,运行结果:
源码
#pragma warning(disable:4786)
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <cxcore.h>
#include <highgui.h>
#include <direct.h>//_getcwd直接读取
//#include <unistd.h>//派上要加上这句
using namespace cv;
class ShowName {
public:
ShowName(char *filename);
ShowName(char *name, char* code);
~ShowName();
void openfile();//打开字库
void get_name_code();//获取汉字的区码和位码
void get_mat(unsigned char qh, unsigned char wh);//获取通过区码位码来确定mat
void draw_name(int num);
void getasi(char incode[]);//获取数字的ASCII码
void draw_code(int num);
void file_Runtodraw();
protected:
FILE* CONTERNER;//内容提供者即文件logo.txt
FILE* HZK24;//24字库
FILE* ASI816;//ASCII字库
unsigned char mat[72];
unsigned char num_mat[16];
char name_code_box[30];
IplImage* img;//图片
const int MAPSIZE = 24;//字的size
const int INTERSIZE = 5;//插入间隔
unsigned char name_code[3][2];
private:
char *Name;
char *code;
char *Name_code;
int sum_word;//字体数目
int current_num;
};
//函数名称: ~ShowName
//函数功能: 释放空间
ShowName::~ShowName() {
cvReleaseImage(&img);
fclose(HZK24);
fclose(ASI816);
if (CONTERNER != NULL)
fclose(CONTERNER);
img = NULL;
HZK24 = NULL;
ASI816 = NULL;
CONTERNER = NULL;
}
//函数名称: ShowName
//函数功能: 初始化文件
ShowName::ShowName(char *filename) {
if ((CONTERNER = fopen(filename, "rb")) == NULL)exit(1);
fseek(CONTERNER, 0, SEEK_SET);
fread(name_code_box, 30, 1, CONTERNER);
char *a = name_code_box;
Name_code = a;
sum_word = strlen(Name_code) - 2;
current_num = 0;
openfile();
}
//函数名称: ShowName
//函数功能: 初始化
ShowName::ShowName(char *name, char* code) {
this->Name = name;
this->code = code;
this->current_num = 0;
this->sum_word = strlen(Name) / 2 + strlen(this->code);
openfile();
}
//函数名称: openfile
//函数功能: 打开字库和图片
void ShowName::openfile() {
char pbuf[100];
_getcwd(pbuf, 100);
strcat(pbuf, "/HZKf2424.hz");
char pbufASC[100];
_getcwd(pbufASC, 100);
strcat(pbufASC, "/Asci0816.zf");
// 读取图片
if ((img = cvLoadImage("lena.jpg")) == NULL)exit(1);
// 打开字体文件
if ((HZK24 = fopen(pbuf, "rb")) == NULL)exit(1);
//打开asci8*16文件
if ((ASI816 = fopen(pbufASC, "rb")) == NULL)exit(1);
}
//函数名称: get_name_code
//函数功能: 获取汉字的区码和位码
void ShowName::get_name_code() {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j)
name_code[i][j] = Name[i * 2 + j] - 0xa0;
}
//函数名称: get_mat
//函数功能: 通过汉字的区码和位码进行写到mat中
void ShowName::get_mat(unsigned char qh, unsigned char wh) {
long offset;
offset = (94 * (qh - 1) + (wh - 1)) * 72L;
// 读取数据存入数组
fseek(HZK24, offset, SEEK_SET);
fread(mat, 72, 1, HZK24);
}
//函数名称: draw_name
//函数功能: 通过汉字的区码和位码进行写到mat中
void ShowName::draw_name(int num) {
// 图片的像素值
int width, height;
width = img->width;
height = img->height;
// 开始的x y像素点
int start_x, start_y, size, current_start_x, current_start_y;
size = MAPSIZE;// +INTERSIZE;
start_x = width - sum_word * size;
start_y = height - MAPSIZE - INTERSIZE;
// 开始绘制
CvScalar cs;
for (int i = 0; i < 24; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 8; k++)
if (((mat[i * 3 + j] >> (7 - k)) & 0x1) != NULL)
{
// 绘点
current_start_x = start_x + i + size * num;//24*24的是纵向排列的i对应的是x
current_start_y = start_y + j * 8 + k;
cs = cvGet2D(img, current_start_y, current_start_x);
cs.val[0] = 0;
cs.val[1] = 255;//rgb控制的姓名颜色,可更改
cs.val[2] = 255;
cvSet2D(img, current_start_y, current_start_x, cs);
}
}
//函数名称: getasi
//函数功能: 获取asci码
void ShowName::getasi(char incode[]) {
unsigned char qh, wh;
unsigned long offset;
offset = incode[0] * 16L;
fseek(ASI816, offset, SEEK_SET);
fread(num_mat, 16, 1, ASI816);
}
//函数名称: draw_code
//函数功能: 绘制学号
void ShowName::draw_code(int num) {
int width, height;
width = img->width;
height = img->height;
// 开始的x y像素点
int start_x, start_y, size, current_start_x, current_start_y;
size = MAPSIZE; //+INTERSIZE;
//int numsize = 8;
start_x = width - sum_word * size;
start_y = height - 16 - INTERSIZE;
// 开始绘制
CvScalar cs;
for (int i = 0; i < 16; ++i)
for (int k = 0; k < 8; k++)
if ((num_mat[i] & (0x80 >> k)) != NULL)
{
current_start_x = k + start_x + size * num;
current_start_y = start_y + i;
cs = cvGet2D(img, current_start_y, current_start_x);//获取图像相对位置的RGB的值
cs.val[0] = 255;
cs.val[1] = 255;//这里可以改成你喜欢的颜色,rgb控制学号的颜色
cs.val[2] = 0;
cvSet2D(img, current_start_y, current_start_x, cs);//重新设值
}
}
//函数名称: file_Runtodraw
//函数功能: 启动绘制
void ShowName::file_Runtodraw() {
unsigned char mask = 0x80;
char tmpcode[3] = { 0 };
int x = 0;
while (*Name_code != NULL)
{
tmpcode[0] = *Name_code;
tmpcode[1] = *(Name_code + 1);
if (tmpcode[0] & mask) {
unsigned char qh, wh;
qh = tmpcode[0] - 0xaf;
wh = tmpcode[1] - 0xa0;
get_mat(qh, wh);
draw_name(current_num++);
Name_code += 2;
}
else if (tmpcode[0]) {
getasi(Name_code);
draw_code(current_num++);
Name_code++;
}
}
cvShowImage("Textimage", img);
cvWaitKey();
}
int main() {
char *filename = (char*) "test.txt";
ShowName *newname = new ShowName(filename);
newname->file_Runtodraw();
delete newname;
return 0;
}
(二)树莓派绘制中文点阵
- 用teamviewer将
中文点阵字库文件
和图片
、之前在windows上创建Textimage.cpp
和test.txt文件
打包传到树莓派上,如图:
- 双击.cpp文件进入修改代码文件
- 添加目录:#include <unistd.h>
- 修改2处 _getcwd(pbuf, 100); 把前面_删掉
- 命令行模式进入当前目录:
//.cpp目录
cd /home/pi/test_wy/opencv_test/test4_Add_Chinese_Front
- G++编译:
g++ Textimage.cpp -o Test `pkg-config --cflags --libs opencv`
- 得到Test可执行文件
ls
./Test
源码
#pragma warning(disable:4786)
#pragma warning(disable:4996)
#include <stdio.h>
#include <stdlib.h>
#include <cxcore.h>
#include <highgui.h>
#include <unistd.h>
using namespace cv;
class ShowName {
public:
ShowName(char *filename);
ShowName(char *name, char* code);
~ShowName();
void openfile();//´ò¿ª×Ö¿â
void get_name_code();//»ñÈ¡ºº×ÖµÄÇøÂëºÍλÂë
void get_mat(unsigned char qh, unsigned char wh);//»ñȡͨ¹ýÇøÂëλÂëÀ´È·¶¨mat
void draw_name(int num);
void getasi(char incode[]);//»ñÈ¡Êý×ÖµÄASCIIÂë
void draw_code(int num);
void file_Runtodraw();
protected:
FILE* CONTERNER;//ÄÚÈÝÌṩÕß¼´Îļþlogo.txt
FILE* HZK24;//24×Ö¿â
FILE* ASI816;//ASCII×Ö¿â
unsigned char mat[72];
unsigned char num_mat[16];
char name_code_box[30];
IplImage* img;//ͼƬ
const int MAPSIZE = 24;//×ÖµÄsize
const int INTERSIZE = 5;//²åÈë¼ä¸ô
unsigned char name_code[3][2];
private:
char *Name;
char *code;
char *Name_code;
int sum_word;//×ÖÌåÊýÄ¿
int current_num;
};
//º¯ÊýÃû³Æ£º ~ShowName
//º¯Êý¹¦ÄÜ£º Êͷſռä
ShowName::~ShowName() {
cvReleaseImage(&img);
fclose(HZK24);
fclose(ASI816);
if (CONTERNER != NULL)
fclose(CONTERNER);
img = NULL;
HZK24 = NULL;
ASI816 = NULL;
CONTERNER = NULL;
}
//º¯ÊýÃû³Æ£º ShowName
//º¯Êý¹¦ÄÜ£º ³õʼ»¯Îļþ
ShowName::ShowName(char *filename) {
if ((CONTERNER = fopen(filename, "rb")) == NULL)exit(1);
fseek(CONTERNER, 0, SEEK_SET);
fread(name_code_box, 30, 1, CONTERNER);
char *a = name_code_box;
Name_code = a;
sum_word = strlen(Name_code) - 2;
current_num = 0;
openfile();
}
//º¯ÊýÃû³Æ£º ShowName
//º¯Êý¹¦ÄÜ£º ³õʼ»¯
ShowName::ShowName(char *name, char* code) {
this->Name = name;
this->code = code;
this->current_num = 0;
this->sum_word = strlen(Name) / 2 + strlen(this->code);
openfile();
}
//º¯ÊýÃû³Æ£º openfile
//º¯Êý¹¦ÄÜ£º ´ò¿ª×Ö¿âºÍͼƬ
void ShowName::openfile() {
char pbuf[100];
getcwd(pbuf, 100);
strcat(pbuf, "/HZKf2424.hz");
char pbufASC[100];
getcwd(pbufASC, 100);
strcat(pbufASC, "/Asci0816.zf");
// ¶ÁȡͼƬ
if ((img = cvLoadImage("lena.jpg")) == NULL)exit(1);
// ´ò¿ª×ÖÌåÎļþ
if ((HZK24 = fopen(pbuf, "rb")) == NULL)exit(1);
//´ò¿ªasci8*16Îļþ
if ((ASI816 = fopen(pbufASC, "rb")) == NULL)exit(1);
}
//º¯ÊýÃû³Æ£º get_name_code
//º¯Êý¹¦ÄÜ£º »ñÈ¡ºº×ÖµÄÇøÂëºÍλÂë
void ShowName::get_name_code() {
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 2; ++j)
name_code[i][j] = Name[i * 2 + j] - 0xa0;
}
//º¯ÊýÃû³Æ£º get_mat
//º¯Êý¹¦ÄÜ£º ͨ¹ýºº×ÖµÄÇøÂëºÍλÂë½øÐÐдµ½matÖÐ
void ShowName::get_mat(unsigned char qh, unsigned char wh) {
long offset;
offset = (94 * (qh - 1) + (wh - 1)) * 72L;
// ¶ÁÈ¡Êý¾Ý´æÈëÊý×é
fseek(HZK24, offset, SEEK_SET);
fread(mat, 72, 1, HZK24);
}
//º¯ÊýÃû³Æ£º draw_name
//º¯Êý¹¦ÄÜ£º ͨ¹ýºº×ÖµÄÇøÂëºÍλÂë½øÐÐдµ½matÖÐ
void ShowName::draw_name(int num) {
// ͼƬµÄÏñËØÖµ
int width, height;
width = img->width;
height = img->height;
// ¿ªÊ¼µÄx yÏñËØµã
int start_x, start_y, size, current_start_x, current_start_y;
size = MAPSIZE;// +INTERSIZE;
start_x = width - sum_word * size;
start_y = height - MAPSIZE - INTERSIZE;
// ¿ªÊ¼»æÖÆ
CvScalar cs;
for (int i = 0; i < 24; ++i)
for (int j = 0; j < 3; ++j)
for (int k = 0; k < 8; k++)
if (((mat[i * 3 + j] >> (7 - k)) & 0x1) != NULL)
{
// »æµã
current_start_x = start_x + i + size * num;//24*24µÄÊÇ×ÝÏòÅÅÁеÄi¶ÔÓ¦µÄÊÇx
current_start_y = start_y + j * 8 + k;
cs = cvGet2D(img, current_start_y, current_start_x);
cs.val[0] = 255;
cs.val[1] = 255;
cs.val[2] = 0;
cvSet2D(img, current_start_y, current_start_x, cs);
}
}
//º¯ÊýÃû³Æ£º getasi
//º¯Êý¹¦ÄÜ£º »ñÈ¡asciÂë
void ShowName::getasi(char incode[]) {
unsigned char qh, wh;
unsigned long offset;
offset = incode[0] * 16L;
fseek(ASI816, offset, SEEK_SET);
fread(num_mat, 16, 1, ASI816);
}
//º¯ÊýÃû³Æ£º draw_code
//º¯Êý¹¦ÄÜ£º »æÖÆÑ§ºÅ
void ShowName::draw_code(int num) {
int width, height;
width = img->width;
height = img->height;
// ¿ªÊ¼µÄx yÏñËØµã
int start_x, start_y, size, current_start_x, current_start_y;
size = MAPSIZE; //+INTERSIZE;
//int numsize = 8;
start_x = width - sum_word * size;
start_y = height - 16 - INTERSIZE;
// ¿ªÊ¼»æÖÆ
CvScalar cs;
for (int i = 0; i < 16; ++i)
for (int k = 0; k < 8; k++)
if ((num_mat[i] & (0x80 >> k)) != NULL)
{
current_start_x = k + start_x + size * num;
current_start_y = start_y + i;
cs = cvGet2D(img, current_start_y, current_start_x);//»ñȡͼÏñÏà¶ÔλÖõÄRGBµÄÖµ
cs.val[0] = 255;
cs.val[1] = 255;//ÕâÀï¿ÉÒԸijÉÄãϲ»¶µÄÑÕÉ«
cs.val[2] = 0;
cvSet2D(img, current_start_y, current_start_x, cs);//ÖØÐÂÉèÖµ
}
}
//º¯ÊýÃû³Æ£º file_Runtodraw
//º¯Êý¹¦ÄÜ£º Æô¶¯»æÖÆ
void ShowName::file_Runtodraw() {
unsigned char mask = 0x80;
char tmpcode[3] = { 0 };
int x = 0;
while (*Name_code != NULL)
{
tmpcode[0] = *Name_code;
tmpcode[1] = *(Name_code + 1);
if (tmpcode[0] & mask) {
unsigned char qh, wh;
qh = tmpcode[0] - 0xaf;
wh = tmpcode[1] - 0xa0;
get_mat(qh, wh);
draw_name(current_num++);
Name_code += 2;
}
else if (tmpcode[0]) {
getasi(Name_code);
draw_code(current_num++);
Name_code++;
}
}
cvShowImage("Textimage", img);
cvWaitKey();
}
int main() {
char *filename = "test.txt";
ShowName *newname = new ShowName(filename);
newname->file_Runtodraw();
delete newname;
return 0;
}
大功告成!