Ubuntu下调用OpenCV库编程显示图片并叠加汉字

您所在的位置:网站首页 三个男叠加汉字 Ubuntu下调用OpenCV库编程显示图片并叠加汉字

Ubuntu下调用OpenCV库编程显示图片并叠加汉字

2024-05-28 23:36| 来源: 网络整理| 查看: 265

目录

一、汉字点阵库原理

1. 汉字编码

2. 点阵字库结构

3. 汉字点阵获取

二、实验内容

三、实验准备

四、实验过程 

 五、参考资料

一、汉字点阵库原理 1. 汉字编码

区位码 在国标 GD2312—80 中规定,所有的国标汉字及符号分配在一个 94 行、94 列的方 阵中,方阵的每一行称为一个“区”,编号为 01 区到 94 区,每一列称为一个“位”,编号为 01 位到 94 位,方阵中的每一个汉字和符号所在的区号和位号组合在一起形成的四个阿拉 伯数字就是它们的“区位码”。区位码的前两位是它的区号,后两位是它的位号。用区位码就 可以唯一地确定一个汉字或符号,反过来说,任何一个汉字或符号也都对应着一个唯一的 区位码。汉字“母”字的区位码是 3624,表明它在方阵的 36 区 24 位,问号“?”的区位码为 0331,则它在 03 区 3l 位。

机内码 汉字的机内码是指在计算机中表示一个汉字的编码。机内码与区位码稍有区别。如上所 述,汉字区位码的区码和位码的取值均在 1~94 之间,如直接用区位码作为机内码,就会 与基本 ASCII 码混淆。为了避免机内码与基本 ASCII 码的冲突,需要避开基本 ASCII 码 中的控制码(00H~1FH),还需与基本 ASCII 码中的字符相区别。为了实现这两点,可以 先在区码和位码分别加上 20H,在此基础上再加 80H(此处“H”表示前两位数字为十六进制 数)。经过这些处理,用机内码表示一个汉字需要占两个字节,分别 称为高位字节和低位字 节,这两位字节的机内码按如下规则表示: 高位字节 = 区码 + 20H + 80H(或区码 + A0H) 低位字节 = 位码 + 20H + 80H(或位码 + AOH) 由于汉字的区码与位码的取值范围的十六进制数均为 01H~5EH(即十进制的 01~94),所以汉字的高位字节与低位字节的取值范围则为 A1H~FEH(即十进制的 161~254)。 例如,汉字“啊”的区位码为 1601,区码和位码分别用十六进制表示即为 1001H,它 的机内码的高位字节为 B0H,低位字节为 A1H,机内码就是 B0A1H。

2. 点阵字库结构

(1)点阵字库储存 在汉字的点阵字库中,每个字节的每个位都代表一个汉字的一个点,每个汉 字都是由一个矩形的点阵组成,0 代表没有,1 代表有点,将 0 和 1 分别用不同 颜色画出,就形成了一个汉字,常用的点阵矩阵有 1212, 1414, 16*16 三 种字库。 字库根据字节所表示点的不同有分为横向矩阵和纵向矩阵,目前多数的字库 都是横向矩阵的存储方式(用得最多的应该是早期 UCDOS 字库),纵向矩阵一 般是因为有某些液晶是采用纵向扫描显示法,为了提高显示速度,于是便把字库 矩阵做成纵向,省得在显示时还要做矩阵转换。我们接下去所描述的都是指横向 矩阵字库。

(2)16*16的点阵字库

对于 1616 的矩阵来说,它所需要的位数共是 1616=256 个位,每个字 节为 8 位,因此,每个汉字都需要用 256/8=32 个字节来表示。 即每两个字节代表一行的 16 个点,共需要 16 行,显示汉字时,只需一次 性读取 32 个字节,并将每两个字节为一行打印出来,即可形成一个汉字。 点阵结构如下图所示:

(3)14×14与12×12点阵字库 对于 14×14 和 12×12 的字库,理论上计算,它们所需要的点阵分别为(14×14/8)=25, (12×12/8)=18 个字节,但是,如果按这种方式来存储,那么取 点阵和显示时,由于它们每一行都不是 8 的整位数,因此,就会涉到点阵的计 算处理问题,会增加程序的复杂度,降低程序的效率。 为了解决这个问题,有些点阵字库会将 14×14 和 12×12 的字库按 16×14 和 16×12 来存储,即,每行还是按两个字节来存储,但是 14×14 的字库,每 两个字节的最后两位是没有使用,12×12 的字节,每两字节的最后 4 位是没有 使用,这个根据不同的字库会有不同的处理方式,所以在使用字库时要注意这个 问题,特别是 14×14 的字库。

3. 汉字点阵获取

(1)利用区位码获取汉字 汉字点阵字库是根据区位码的顺序进行存储的,因此,我们可以根据区位来 获取一个字库的点阵,它的计算公式如下: 点阵起始位置 = ((区码- 1)×94 + (位码 – 1)) ×汉字点阵字节数 获取点阵起始位置后,我们就可以从这个位置开始,读取出一个汉字的点阵。 (2)利用汉字机内码获取汉字 汉字的区位码和机内码的关系如下: 机内码高位字节 = 区码 + 20H + 80H(或区码 + A0H) 机内码低位字节 = 位码 + 20H + 80H(或位码 + AOH) 反过来说,我们也可以根据机内码来获得区位码: 区码 = 机内码高位字节 - A0H 位码 = 机内码低位字节 - AOH 将这个公式与获取汉字点阵的公式进行合并计就可以得到汉字的点阵位置。  

二、实验内容

学习理解汉字的机内码、区位码编码规则和字形数据存储格式。在Ubuntu下用C/C++(或python) 调用opencv库编程显示一张图片,并打开一个名为"logo.txt"的文本文件(其中只有一行文本文件,包括你自己的名字和学号),按照名字和学号去读取汉字24*24点阵字形字库(压缩包中的文件HZKf2424.hz)中对应字符的字形数据,将名字和学号叠加显示在此图片右下位置。

三、实验准备

下载汉字点阵库及显示应用工具

下载链接:百度网盘 请输入提取码  提取码:4u3q

解压后如下所示:

 本次实验需要用到以下两个文件

 

Ubuntu下创建一个文件夹用来存放本次实验的文件,其中包括一张图片、一个txt文件和上面两个文件

 txt文件打开后中文是一串乱码,需要修改格式,把乱码修改为中文,然后点击另存为 ,修改Character Encoding为GBK,点击保存

 再次打开就没有乱码了

四、实验过程 

在该文件夹下打开终端

 编写代码,输入以下命令

gedit main.cpp

在main.cpp文件中输入以下代码 

#include #include #include"opencv2/opencv.hpp" #include #include #include using namespace cv; void PaintSChinese(Mat& image, int x_offset, int y_offset, unsigned long offset); void PaintSAscii(Mat& image,int x_offset, int y_offset, unsigned long offset); void putTextToImage(int x_offset,int y_offset,String imagePath ,char* txtPath); int main(){ String image_path="lena.jpeg"; char* logo_path=(char*)"logo.txt"; putTextToImage(20,300,image_path,logo_path); return 0; } void putTextToImage(int x_offset,int y_offset,String imagePath ,char* txtPath) { //通过图片路径获取图片 Mat img = imread(imagePath); unsigned char qh, wh; unsigned long offset; //用于存放从记事本读取的十六进制 char hexcode[30]; //打开包含名字的txt文件,转为十六进制,存入hexcode中 FILE* filetxt; if ((filetxt = fopen(txtPath, "rb")) == NULL){ printf("Can't open txtfile,Please check the path!"); //getch(); exit(0); } fseek(filetxt, 0, SEEK_SET); /*将文件指针移动到偏移量的位置*/ fread(hexcode, 19, 1, filetxt); int x = x_offset, y = y_offset;//x,y:在图片上绘文字的起始的坐标 for (int m = 0; m < 19; ) if (hexcode[m] == 0x23) /* 当读取到‘#’号时结束 */ break; //判断高阶两个十六进制数,大于或等于b0(汉字第一个是b0a1)的都应该从汉字字库中找 else if (hexcode[m] > 0xffffffaf) { qh = hexcode[m] - 0xaf; /*计算区码*/ wh = hexcode[m+1] - 0xa0; /*计算位码*/ offset = (94 * (qh - 1) + (wh - 1)) * 72L;/*计算该汉字在字库中偏移量*/ PaintSChinese(img, x , y , offset); m = m + 2; //一个汉字占两个char,所以加2 x += 24; //一个汉字在图片上占24个像素点,所以水平坐标每次+24 } else { wh = hexcode[m]; offset = wh * 16L; //计算其他英文字符的偏移量 PaintSAscii(img, x, y, offset); m++; //一个char //原本应该8*16,但是和24*24比小了点,所以改为16*32,原本的一个像素点现在用四个像素点绘画 x += 16; } cv::imshow("image", img); cv::waitKey(); } void PaintSChinese(Mat& image, int x_offset, int y_offset, unsigned long offset){ //实际在图片上绘制的像素点坐标 Point p; p.x = x_offset; p.y = y_offset; //打开DZKs1516汉字库文件 FILE *HZK; char buff[72]; //存放汉字字膜 if ((HZK = fopen("HZKs2424.hz", "rb")) == NULL){ printf("Can't openHZKf2424.hz,Please check the path!"); //getch(); exit(0); } fseek(HZK, offset, SEEK_SET); /*将文件指针移动到偏移量的位置*/ fread(buff, 72, 1, HZK); /*从偏移量的位置读取72个字节,每个汉字占72个字节*/ bool mat[24][24]; /*定义一个新的矩阵存放转置后的文字字膜 */ int i, j, k; //转置汉字字膜矩阵,因为汉字字膜存储的是装置后的数据(反的) for (i = 0; i j)) /*测试当前位是否为1*/ { /* 由于原本ascii字膜是8*16的,不够大, 所以原本的一个像素点用4个像素点替换, 替换后就有16*32个像素点 ps:感觉这样写代码多余了,但目前暂时只想到了这种方法 */ circle(image, p1, 0, Scalar(0, 0, 255), -1); p1.x++; circle(image, p1, 0, Scalar(0, 0, 255), -1); p1.y++; circle(image, p1, 0, Scalar(0, 0, 255), -1); p1.x--; circle(image, p1, 0, Scalar(0, 0, 255), -1); } p.x+=2; //原来的一个像素点变为四个像素点,所以x和y都应该+2 } p.y+=2; } }

注意:需要根据自己的情况对名称、字符长度、显示位置进行修改

修改名称

 修改字符长度

 修改显示位置

 编写完成后保存,输入以下命令编译

g++ main.cpp -o main `pkg-config --cflags --libs opencv`

 执行,输入命令  ./main ,结果如下

 五、参考资料

Linux下点阵汉字的字模读取与显示_Mouer__的博客-CSDN博客

点阵汉字的字模读取与显示:图片上显示汉字(Ubuntu+OpenCV+C++)_WOOZI9600L²的博客-CSDN博客_c++ 字模



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3