【嵌入式】点阵汉字的字模读取与显示

汉字点阵原理
点阵的介绍
点阵是一种将图像或字符分解为由点组成的矩阵的显示方式。每个点被视为一个像素,可以通过控制每个像素的状态(亮或暗)来显示出图像或字符。
在点阵显示中,通常使用一个二维矩阵来表示图像或字符,每个元素代表一个像素。矩阵的行和列分别对应于显示屏的行和列。通过设置每个像素的状态,可以在显示屏上呈现出各种图像和字符。
例如,一个8x8的点阵矩阵可以表示一个由64个像素组成的图像或字符。图像或字符的每个像素通过设置为亮(通常用1表示)或暗(通常用0表示)来决定其显示状态。按照特定的排列方式,将每个像素的状态传输到显示屏上,就可以呈现出对应的图像或字符。
点阵显示广泛应用于各种设备和场景,如LED显示屏、LCD显示屏、OLED显示屏等。它们被用于显示文本、图标、图像等内容。通过控制每个像素的状态,点阵显示可以实现丰富的图形和字符显示效果。
在嵌入式系统中,点阵显示经常用于显示汉字、图标、进度条等信息,以及提供用户界面的交互元素。通过使用适当的字模数据和控制算法,可以实现高质量、高效率的点阵显示效果,为用户提供更好的视觉体验。

我们也可以利用取模软件,将我们需要的文字,以点阵的方式呈现出来:ASCII编码
ASCII(American Standard Code for Information Interchange)是一种最常用的字符编码标准,用于将字符映射为数字,在计算机中表示和存储文本信息。ASCII编码使用一个字节(8个比特)来表示一个字符,最初是为了表示英文字符而设计。
以下是ASCII编码的表格示例:
 

十进制字符描述
65大写字母A
97a小写字母a
480数字0
32 空格
33感叹号
126~波浪号

ASCII编码共定义了128个字符,包括大写字母、小写字母、数字、标点符号和控制字符等。其中,前32个字符(0-31)是控制字符,用于控制打印机和通信设备的行为。后面的95个字符(32-126)是可显示字符,用于显示文本内容。
ASCII编码只能表示有限的字符范围,无法表示其他语言的字符。随着计算机的发展和国际化的需求,后来出现了更加完善的字符编码方式,如Unicode和UTF-8,可以表示几乎所有的字符。
需要注意的是,ASCII编码只使用了一个字节来表示一个字符,因此它只能表示256个不同的字符。在使用ASCII编码的环境中,如果遇到非ASCII字符,可能会出现乱码或无法识别的情况。
ASCII编码在计算机系统中广泛使用,尤其在早期的系统和英文环境中。虽然现代计算机系统更多地使用Unicode和UTF-8等编码方式,但ASCII编码仍然具有重要的历史和概念意义。

汉字编码
汉字是中文的基本文字单位,而计算机是一种以数字为基础的设备,因此需要将汉字转换为计算机能够理解和处理的数字编码。计算机汉字编码的发展背景是为了在计算机系统中能够准确地表示和处理汉字,实现中文信息的输入、存储和显示。
在计算机汉字编码的发展过程中,出现了多种编码方式。以下是一些常见的计算机汉字编码方式及其特点的表格:
 

编码方式特点
GB2312由中国国家标准委员会于1980年制定,包含了6763个常用汉字和682个非汉字字符,是最早的汉字编码标准。
GBK在GB2312的基础上扩展,包含了21003个汉字和图形字符,支持繁体字和少数民族文字。
GB18030在GBK的基础上扩展,包含了27533个汉字和图形字符,支持Unicode字符集,是目前最完备的中文字符集编码。
Unicode包含了世界上几乎所有的字符,每个字符都有唯一的编码,可以表示多种语言文字,包括汉字。常用的汉字编码方式是UTF-8和UTF-16。
Big5主要用于繁体中文的编码,是台湾地区最常用的汉字编码方式。
HZGB2312用于在ASCII字符集中表示汉字,是一种特殊的汉字编码方式。

这些编码方式都有各自的特点和适用范围。随着计算机技术的发展和国际化的需求,Unicode成为了广泛使用的汉字编码方式,它能够表示几乎所有的字符,并且被大多数操作系统和应用程序所支持。

一个常见的计算机汉字编码的示例是使用UTF-8编码方式表示汉字。
UTF-8(Unicode Transformation Format - 8-bit)是一种可变长度的Unicode编码方式,它可以表示世界上几乎所有的字符,包括汉字。
下面是几个常见汉字的UTF-8编码示例:

汉字 “中” 的UTF-8编码是:E4 B8 AD
汉字 “文” 的UTF-8编码是:E6 96 87
汉字 “字” 的UTF-8编码是:E5 AD 97
UTF-8编码使用1到4个字节来表示不同的字符,其中汉字通常使用3个字节表示。每个字节的高位用于标识该字节是单字节编码还是多字节编码,低7位用于存储字符的编码值。
通过使用UTF-8编码,计算机可以准确地表示和处理汉字,无论是在文本输入、存储还是显示方面,都能够保证汉字的正确性和完整性。
需要注意的是,UTF-8编码是一种变长编码方式,不同字符的编码长度可能不同。因此,在处理UTF-8编码的字符串时,需要根据具体情况进行适当的解析和处理,以确保对汉字的操作是准确和完整的。
计算机汉字编码的发展使得汉字能够在计算机系统中得到准确的表示和处理,为中文信息的输入、存储、传输和显示提供了基础。同时,各种编码方式的存在也带来了编码转换的需求,以确保不同编码方式的汉字能够正确地互相转换和处理。

区位码和机内码
区位码和机内码是计算机中用于表示汉字的两种编码方式。

区位码(Quwei Code):
区位码是一种早期的汉字编码方式,用于将汉字转换为计算机能够理解的数字编码。区位码将每个汉字分为区和位两个部分进行编码。其中,区码表示汉字所在的区,取值范围为0xA1至0xFE;位码表示汉字在区内的位置,取值范围为0xA1至0xFE。通过区位码,可以将汉字转换为一个两字节的编码。
区位码的缺点是无法表示所有的汉字,因为汉字的数量远远超过了区位码的编码范围。为了解决这个问题,后来出现了更加完备的汉字编码方式,如GB2312、GBK和GB18030。

机内码(Internal Code):
机内码是一种在计算机内部使用的汉字编码方式,用于在计算机内部表示和处理汉字。机内码通常采用固定长度的编码,每个汉字对应一个特定的编码,这样可以保证在计算机内部统一处理汉字。
机内码的常见编码方式包括Unicode和GBK。Unicode是一种国际标准的字符编码方案,包含了世界上几乎所有的字符,每个字符都有唯一的编码。GBK是一种国家标准的中文字符集编码,扩展了GB2312的编码范围,支持更多的汉字和符号。
机内码的优点是能够准确地表示和处理汉字,确保在计算机内部的字符处理过程中不会出现乱码或信息丢失的问题。
区位码和机内码是汉字编码的两种不同方式,区位码主要适用于早期的汉字编码需求,而机内码则是现代计算机系统中普遍使用的汉字编码方式。随着计算机技术的发展和国际化的需求,机内码已经成为了广泛使用的汉字编码方式,保证了汉字在计算机系统中的准确表示和处理。

点阵字库存储
点阵字库是一种用于存储和表示字形的数据结构,广泛应用于计算机、打印机、显示屏等设备中。它将每个字符的字形表示为一个由二进制位组成的矩阵,其中每个位表示一个像素的状态(如黑或白)。点阵字库的存储方式可以有多种形式,如位图、字节序列或字节流等。
点阵字库的存储方式主要有两种:固定宽度和变宽度。

固定宽度点阵字库:
固定宽度点阵字库将每个字符的字形表示为一个固定宽度的矩阵。例如,一个8x8的固定宽度点阵字库可以表示每个字符为一个8行8列的矩阵。每个像素位可以用一个二进制位表示,0代表空白像素,1代表实心像素。这种存储方式简单直观,适用于具有相同宽度的等宽字体。
变宽度点阵字库:
变宽度点阵字库将每个字符的字形表示为一个变宽度的矩阵。由于不同字符的宽度可能不同,所以在存储时需要考虑字符的实际宽度。一种常见的存储方式是使用位图,每个字符的字形被编码为一个位图图像。在位图中,每个像素位表示一个像素的状态(如黑或白)。字符的宽度可以通过位图的宽度进行确定。
点阵字库的存储方式决定了字库的占用空间和字形的显示效果。固定宽度点阵字库通常占用的空间相对较小,但在显示时可能会出现字符间距不均匀的问题。变宽度点阵字库可以更准确地表示字符的字形,但相应地需要更多的存储空间。
点阵字库的存储方式对于字形的渲染和显示有着重要的影响。设备在使用点阵字库时,可以根据存储的字形数据来绘制字符的轮廓或像素点阵,以实现字符的显示和输出。

利用汉字机内码获取汉字
利用汉字的机内码获取汉字的原理是通过查找对应的字形数据来获取字符的具体形态。计算机中使用的汉字编码方式(如GBK、Unicode)将每个汉字映射到一个唯一的机内码,这个机内码可以作为索引来查找相应的字形数据。通过读取和解析字库或字形数据,计算机可以获取汉字的点阵或轮廓信息,从而实现对汉字的显示和处理。

在Linux(Ubuntu)下使用C++调用OpenCV显示图片及文字
实验要求
打开一个名为"logo.txt"的文本文件(其中只有一行文本文件,包括你自己的名字和学号),按照名字和学号去读取汉字24*24点阵字形字库(压缩包中的文件HZKf2424.hz)中对应字符的字形数据,将名字和学号叠加显示在此图片右下位置。

实验准备
Ubuntu的安装
Ubuntu安装步骤见以下链接(注意查看自己电脑的类型来决定安装方式)
链接: https://www.bilibili.com/video/BV1554y1n7zv/?spm_id_from=333.337.search-card.all.click

Ubuntu换源步骤见以下链接
链接: https://blog.csdn.net/weixin_63019977/article/details/132911498

OpenCV的简介
OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习软件库。它提供了丰富的图像处理和计算机视觉算法,可以用于开发各种视觉应用。

主要特点
跨平台性:OpenCV可以在多个操作系统上运行,包括Windows、Linux、macOS等。
广泛的功能:OpenCV提供了大量的图像处理和计算机视觉算法,涵盖了对象检测、图像分割、特征提取等多个领域。
高性能:OpenCV是基于优化的C/C++编写的,具有较高的执行效率。
易于使用:OpenCV提供了简单易懂的API和丰富的文档,使开发者能够快速上手和开发应用。
开源社区支持:OpenCV拥有庞大的开源社区,提供了丰富的示例代码、教程和支持。
主要功能模块
图像处理:包括图像读写、图像滤波、图像变换、颜色空间转换等。
计算机视觉:包括特征检测、目标跟踪、姿态估计、人脸识别等。
机器学习:提供了多种机器学习算法和工具,用于训练和分类图像数据。
视频处理:包括视频读写、实时视频处理、光流估计等。
深度学习:支持常见的深度学习框架,如TensorFlow、PyTorch等。
示例代码
下面是使用OpenCV库进行图像读取和显示的示例代码:
 

#include <opencv2/opencv.hpp>
int main() {
    // 读取图像文件
    cv::Mat image = cv::imread("image.jpg");
    // 检查图像是否读取成功
    if (image.empty())
     {
        std::cout << "无法读取图像文件" << std::endl;
        return -1;
    }
    // 创建窗口并显示图像
    cv::namedWindow("Image", cv::WINDOW_NORMAL);
    cv::imshow("Image", image);
    // 等待按键,按下任意键后关闭窗口
    cv::waitKey(0);
    cv::destroyAllWindows();
    return 0;
}

以上示例代码演示了如何使用OpenCV读取图像文件,并在窗口中显示图像。通过OpenCV提供的函数和类,我们可以方便地进行图像处理和显示操作。
通过OpenCV的强大功能和丰富的资源,我们可以轻松实现各种视觉应用,包括图像处理、计算机视觉和深度学习等领域。

安装过程
sudo apt install -y g++   
sudo apt install -y cmake   
sudo apt install -y make   
sudo apt install -y wget   
sudo apt install -y unzip 
//安装依赖项目
sudo apt-get install build-essential libgtk2.0-dev libgtk-3-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev  
//安装OpenCV依赖的基本库

下载OpenCV的源文件:
链接: Releases - OpenCV
点击Source进行下载:

下载完成后,解压到主目录下,重命名为opencv
按Ctrl+Alt+T打开终端,进入到opencv目录中,新建并进入目录build:

cd opencv  
mkdir build  
cd build  
cmake -D CMAKE_BUILD_TYPE=Release -D OPENCV_GENERATE_PKGCONFIG=YES ..  
make -j4  
sudo make install  

安装完成后,使用locate命令查看结果:

#include<opencv2/opencv.hpp>
#include "opencv2/core/core_c.h"

//#include "opencv2/core/core_c.h"
//#include "opencv2/imgproc/imgproc_c.h"
//#include "opencv2/photo/photo_c.h"
//#include "opencv2/video/tracking_c.h"
//#include "opencv2/objdetect/objdetect_c.h"
//#include<opencv4/opencv2/cxcore.h>
#include<opencv4/opencv2/highgui.hpp>
#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="plan.jpg";//图片的名字
    char* logo_path="logo.txt";//汉字文件的名字
    put_text_to_image(200,350,image_path,logo_path);//change txt place
    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;
	 //存放ascii字膜
	char buff[16];           
	//打开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个像素点
					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;
	}
}
void paint_chinese(Mat& image,int x_offset,int y_offset,unsigned long offset){//在图片上画汉字
    Point p;
    p.x=x_offset;
    p.y=y_offset;
    FILE *HZK;
    char buff[72];//72个字节,用来存放汉字的

    if((HZK=fopen("HZKf2424.hz","rb"))==NULL){
        printf("Can't open HZKf2424.hz,Please check the path!");
        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){//将汉字弄上图片
//x和y就是第一个字在图片上的起始坐标
    //通过图片路径获取图片
    Mat image=imread(image_path);
    int length=19;//要打印的字符长度(打印多少字节长度就为多少,根据自己的情况调整)
    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;//读到#号时结束
        }
        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);
            /*
            计算在汉字库中的偏移量
            对于每个汉字,使用24*24的点阵来表示的
            一行有三个字节,一共24行,所以需要72个字节来表示
            */

            m=m+2;//一个汉字的机内码占两个字节,
            x+=24;//一个汉字为24*24个像素点,由于是水平放置,所以是向右移动24个像素点
        }

        else{
        //当读取的字符为ASCII码时
        wh=hexcode[m];
        offset=wh*16l;//计算英文字符的偏移量
        paint_ascii(image,x,y,offset);
        m++;//英文字符在文件里表示只占一个字节,所以往后移一位就行了
        x+=16;
        }

    }

    cv::imshow("image", image);
    cv::waitKey();
}

运行可执行文件:

总结
根据实验内容,我进行了点阵汉字的字模读取和在Linux(Ubuntu)下使用C++调用OpenCV显示图片及文字的实验。
在实验中,我首先学习了如何读取点阵汉字的字模数据。通过编写C++函数,我能够从字库文件中读取字模数据,并将其保存到内存中供后续使用。这让我能够获取每个汉字的点阵或轮廓信息,以便后续的处理和显示。
接下来,我使用OpenCV库提供的函数和类来加载和显示图片。通过调用cv::imread()函数,我能够读取图片文件,并使用cv::imshow()函数将图片显示在屏幕上。此外,我还可以使用cv::putText()函数在图片上添加文字,并指定字体、大小、位置等参数。
通过在Linux(Ubuntu)下使用C++调用OpenCV,我能够实现图像的处理和显示。这为我们提供了广泛的应用领域,包括图像处理、计算机视觉和人机交互等。我可以通过读取点阵汉字的字模数据,并结合OpenCV的图像处理功能,实现汉字的显示、识别和处理。
总结来说,通过这个实验,我学会了如何读取点阵汉字的字模数据,并在Linux(Ubuntu)下使用C++调用OpenCV显示图片和文字。这种技术的应用前景广阔,有助于丰富我们的图像处理和显示能力,并为各种应用场景提供了更多的可能性。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值