【嵌入式】Opencv3.4.1绘制中文点阵

目标:利用opencv在图片上添加文字

  • 利用opencv自带的putText就可以添加数字和英文
  • 我们要求添加中文,达到以下效果
    在这里插入图片描述

(一)Windows上绘制中文点阵

环境:VS2017+opencv3.4.1

  1. 创建空项目、添加源文件Textimage.cpp、配置opencv环境(配置教程点这儿~
    在这里插入图片描述
  2. 思路:
  • 从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;
}

(二)树莓派绘制中文点阵

  1. 用teamviewer将中文点阵字库文件图片、之前在windows上创建Textimage.cpptest.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;
}

大功告成!

猜你喜欢

转载自blog.csdn.net/cungudafa/article/details/84862560