一、汉字编码的介绍
二、在图上加汉字和数字
(一)环境配置
(二)操作及代码
(三)操作结果
三、总结及参考文章
四、代码
一、汉字编码
区位码
在国标 GD2312—80 中规定,所有的国标汉字及符号分配在一个 94 行、94 列的方阵中,方阵的每一行称为一个“区”,编号为 01 区到 94 区,每一列称为一个“位”,编号为01 位到 94 位,方阵中的每一个汉字和符号所在的区号和位号组合在一起形成的四个阿拉伯数字就是它们的“区位码”。区位码的前两位是它的区号,后两位是它的位号。用区位码就可以唯一地确定一个汉字或符号,反过来说,任何一个汉字或符号也都对应着一个唯一的区位码。
机内码
汉字的机内码是指在计算机中表示一个汉字的编码。机内码与区位码稍有区别。如直接用区位码作为机内码,就会与基本 ASCII 码混淆。为了避免机内码与基本 ASCII 码的冲突,需要避开基本 ASCII 码中的控制码(00H~1FH),还需与基本 ASCII 码中的字符相区别。为了实现这两点,可以先在区码和位码分别加上 20H,在此基础上再加 80H(此处“H”表示前两位数字为十六进制数)。经过这些处理,用机内码表示一个汉字需要占两个字节,分别 称为高位字节和低位字节,这两位字节的机内码按如下:
高位字节 = 区码 + 20H + 80H(或区码 + A0H)
低位字节 = 位码 + 20H + 80H(或位码 + A0H)
点阵字库存储
在汉字的点阵字库中,每个字节的每个位都代表一个汉字的一个点,每个汉字都是由一个矩形的点阵组成,0 代表没有,1 代表有点,将 0 和 1 分别用不同颜色画出,就形成了一个汉字,常用的点阵矩阵有 1212, 1414, 16*16 三种字库。
汉字点阵获取
1.利用区位码获取汉字
汉字点阵字库是根据区位码的顺序进行存储的,因此,我们可以根据区位来
获取一个字库的点阵,它的计算公式如下:
*点阵起始位置 = ((区码- 1)94 + (位码 – 1)) * 汉字点阵字节数
获取点阵起始位置后,我们就可以从这个位置开始,读取出一个汉字的点阵。
2.利用汉字机内码获取汉字
我们可以根据机内码来获得区位码:
区码 = 机内码高位字节 - A0H
位码 = 机内码低位字节 - A0H
将这个公式与获取汉字点阵的公式进行合并计就可以得到汉字的点阵位置。
二、在图片上加汉字和数字
**(一)环境配置
按照下面的博客
**https://blog.csdn.net/m0_58414679/article/details/120634666?spm=1001.2014.3001.5501
**(二)操作及代码
cd进入文件目录
将图片,文字文件,字库文件添加到该目录下
输入指令添加程序
gedit test.cpp
程序代码如下
注意:文字出现的位置与图片的像素有关,自己需要进行调整
编译输入命令
g++ test.cpp -o test `pkg-config --cflags --libs opencv`
(三)操作结果**
输入指令
./name
运行效果图如下:
三、总结及参考文章
总结
本次实验了解了汉字的编写规则,知道了如何在图片上加上汉字和文字,总的来说实验还是比较简单。
参考文献
https://blog.csdn.net/m0_58892312/article/details/121220958
四、代码
#include<iostream>
#include<opencv/cv.h>
#include"opencv2/opencv.hpp"
#include<opencv/cxcore.h>
#include<opencv/highgui.h>
#include<math.h>
using namespace cv;
using namespace std;
void paint_chinese(Mat& image,int x_offset,int y_offset,unsigned long offset);
void paint_ascii(Mat& image,int x_offset,int y_offset,unsigned long offset);
void put_text_to_image(int x_offset,int y_offset,String image_path,char* logo_path);
int main()
{
String image_path="1.jpg";//图片路径
char* logo_path=(char*)"logo.txt";//学号姓名路径
put_text_to_image(100,200,image_path,logo_path);
return 0;
}
void paint_ascii(Mat& image,int x_offset,int y_offset,unsigned long offset)
{
//绘制的起点坐标
Point p;
p.x=x_offset;
p.y=y_offset;
char buff[16]; //存放ascii字模
//打开ascii字库文件
FILE *ASCII;
if((ASCII=fopen("Asci0816.zf","rb"))==NULL)
{
printf("Can't open ascii.zf,Please check the path!");
//getch();
exit(0);
}
fseek(ASCII,offset,SEEK_SET);
fread(buff,16,1,ASCII);
int i,j;
Point p1=p;
for(i=0;i<16;i++) //十六个char
{
p.x=x_offset;
for(j=0;j<8;j++) //一个char八个bit
{
p1=p;
if(buff[i]&(0x80>>j)) //测试当前位是否为1
{
//由于原本ascii字膜是8*16的,不够大,所以原本的一个像素点用4个像素点替换,替换后就有16*32个像素点
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;
}
}
void paint_chinese(Mat& image,int x_offset,int y_offset,unsigned long offset)
{
//实际在图片上绘制的像素点坐标
Point p;
p.x=x_offset;
p.y=y_offset;
//打开hzk24汉字库文件
FILE *HZK;
char buff[72];//存放汉字字模
if((HZK=fopen("HZKf2424.hz","rb"))==NULL)
{
printf("Can't open HZKf2424.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<24;i++) //24x24点阵汉字,一共有24行
{
for(j=0;j<3;j++) //横向有3个字节,循环判断每个字节的
for(k=0;k<8;k++) //每个字节有8位,循环判断每位是否为1
if(buff[i*3+j]&(0x80>>k)) //测试当前位是否为1
{
mat[j*8+k][i]=true; //为1的存入新的字模中
}
else
{
mat[j*8+k][i]=false;
}
}
for(i=0;i<24;i++)
{
p.x=x_offset;
for(j=0;j<24;j++)
{
if(mat[i][j])
circle(image,p,1,Scalar(255,0,0),-1); //写(替换)像素点
p.x++; //右移一个像素点
}
p.y++; //下移一个像素点
}
}
void put_text_to_image(int x_offset,int y_offset,String image_path,char* logo_path)
{
//通过图片路径获取图片
Mat image=imread(image_path);
int length=18;//要打印的字符长度
unsigned char qh,wh;//定义区号,位号
unsigned long offset;//偏移量
unsigned char hexcode[30];//用于存放记事本读取的十六进制
FILE* file_logo;
if ((file_logo=fopen(logo_path,"rb"))==NULL)
{
printf("Can't open txtfile,Please check the path!");
//getch();
exit(0);
}
fseek(file_logo,0,SEEK_SET);//将文件指针移动到偏移量的位置
fread(hexcode,length,1,file_logo);
int x=x_offset,y=y_offset;//x,y:在图片上绘制文字的起始坐标
for(int m=0;m<length;)
{
if(hexcode[m]==0x23)
{
break;//读到#号时结束
}
//判断高阶两个十六进制数,大于或等于b0(汉字第一个是b0a1)的都应从汉字字库找
else if(hexcode[m]>0xaf)
{
qh=hexcode[m]-0xaf;//计算区码
wh=hexcode[m+1]-0xa0;//计算位码
offset=(94*(qh-1)+(wh-1))*72L;//计算该汉字在字库中偏移量
paint_chinese(image,x,y,offset);
m=m+2;//一个汉字占两个char,所以加2
x+=24;//一个汉字在图片上占24个像素点,所以水平坐标每次+24
}
else
{
wh=hexcode[m];
offset=wh*16l;//计算英文字符的偏移量
paint_ascii(image,x,y,offset);
m++;//一个char
x+=16;//原本8*16,改为16*32,原本的一个像素点现用四个像素点绘画
}
}
cv::imshow("image",image);
cv::waitKey();
}