生活随笔
收集整理的這篇文章主要介紹了
Ubuntu下点阵汉字的字模读取与显示
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
文章目錄
- 一、漢字的區位碼、機內碼編碼規則
- 二、字形數據存儲格式
- 1. Unicode 字符集和編碼
- 2.字模
- 3.漢字點陣獲取
- 三、在圖片上疊加顯示學號、姓名
- 四、總結
- 五、參考資料
一、漢字的區位碼、機內碼編碼規則
1.GB2312標準
GB2312 標準把 ASCII 碼表 127 號之后的擴展字符集直接取消掉,并規定小于 127 的編碼按原來 ASCII 標準解釋字符。當 2 個大于 127 的字符連在一起時,就表示 1 個漢字,第 1 個字節使用 (0xA1-0xFE) 編碼,第 2 個字節使用(0xA1-0xFE)編碼,這樣的編碼組合起來可以表示了 7000 多個符號,其中包含 6763 個漢字。
當我們設定系統使用 GB2312 標準的時候,它遇到一個字符串時,會按字節檢測字符值的大小,檢測原理如下圖。
GB2312 兼容 ASCII 碼的原理圖
2.區位碼
所有的國標漢字及符號分配在一個 94 行、94 列的方
陣中,方陣的每一行稱為一個“區”,編號為 01 區到 94 區,每一列稱為一個“位”,編號為01 位到 94 位,方陣中的每一個漢字和符號所在的區號和位號組合在一起形成的四個阿拉伯數字就是它們的“區位碼”。區位碼的前兩位是它的區號,后兩位是它的位號。
GB2312部分區位碼圖
3.機內碼
漢字的機內碼是指在計算機中表示一個漢字的編碼。為了避免機內碼與基本 ASCII 碼的沖突,可以先在區碼和位碼分別加上 20H,在此基礎上再加 80H。經過這些處理,用機內碼表示一個漢字需要占兩個字節,分別 稱為高位字節和低位字節,這兩位字節的機內碼按如下規則表示:
高位字節 = 區碼 + 20H + 80H(或區碼 + A0H)
低位字節 = 位碼 + 20H + 80H(或位碼 + AOH)
二、字形數據存儲格式
1. Unicode 字符集和編碼
國際標準化組織(ISO)重新給全球上所有文化使用的字母和符號進行編號,對每個字符指定一個唯一的編號,ASCII 中原有的字符編號不變, 該編號集稱為Unicode。有UTF-32、UTF-16、UTF-8(兼容ASCII 碼)和BOM幾種編碼方式。
2.字模
計算機必須把字符編碼轉化成對應的字符圖形人類才能正常識別,因此我們要給計算機提供字符的圖形數據,這些數據就是字模,多個字模數據組成的文件也被稱為字庫。在漢字的點陣字庫中,每個字節的每個位都代表一個漢字的一個點,每個漢字都是由一個矩形的點陣組成,0 代表沒有,1 代表有點,將 0 和 1 分別用不同顏色畫出,就形成了一個漢字,常用的點陣矩陣有 12x12、14x14、16x16三種字庫。
16x16點陣
對于 1616 的矩陣來說,它所需要的位數共是 1616=256 個位,每個字節為 8 位,因此,每個漢字都需要用256/8=32 個字節來表示。
即每兩個字節代表一行的 16 個點,共需要 16 行,顯示漢字時,只需一次性讀取 32 個字節,并將每兩個字節為一行打印出來,即可形成一個漢字。
3.漢字點陣獲取
漢字點陣字庫是根據區位碼的順序進行存儲的,因此,我們可以根據區位來獲取一個字庫的點陣,它的計算公式如下:
點陣起始位置 = ((區碼- 1)*94 + (位碼 – 1)) * 漢字點陣字節數
獲取點陣起始位置后,我們就可以從這個位置開始,讀取出一個漢字的點陣。
三、在圖片上疊加顯示學號、姓名
打開終端,創建目錄10thweek,并在目錄下存放下圖所示文件
mkdir
10thweek
cd
10thweek
注意該文本文件的編碼格式,將默認的UTF-8改成ANSI否則漢字將出現亂碼問題。
在同一工作目錄下輸入gedit test.cpp,輸入以下代碼,每個圖片文字開始顯示的像素坐標不同,需要自行調整。先根據文本文件的字符提取出相應的字模數據 ,然后計算出字模數據的指針,將字模數據替代對應的像素點即可。
#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
="/home/xxl/10thweek/gaga.jpg";char* logo_path
=(char*)"/home/xxl/10thweek/logo.txt";put_text_to_image(80,415,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]; FILE
*ASCII
;if ((ASCII
= fopen("/home/xxl/10thweek/Asci0816.zf", "rb")) == NULL){printf("Can't open ascii.zf,Please check the path!");exit(0);}fseek(ASCII
, offset
, SEEK_SET);fread(buff
, 16, 1, ASCII
);int i
, j
;Point p1
= p
;for (i
= 0; i
<16; i
++) {p
.x
= x_offset
;for (j
= 0; j
< 8; j
++) {p1
= p
;if (buff
[i
] & (0x80 >> j
)) {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; }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];if((HZK
=fopen("/home/xxl/10thweek/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
);bool mat
[24][24];int i
,j
,k
;for (i
= 0; i
<24; i
++) {for (j
= 0; j
<3; j
++) for (k
= 0; k
<8; k
++) if (buff
[i
* 3 + j
] & (0x80 >> k
)) {mat
[j
* 8 + k
][i
] = true
; }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
=22;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!");exit(0);}fseek(file_logo
, 0, SEEK_SET);fread(hexcode
, length
, 1, file_logo
);int x
=x_offset
,y
= y_offset
;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
);m
=m
+2;x
+=24;}else{wh
=hexcode
[m
];offset
=wh
*16l;paint_ascii(image
,x
,y
,offset
);m
++;x
+=16;}}cv
::imshow("image", image
);cv
::waitKey();
}
保存后輸入g++ test.cpp -o test pkg-config --cflags --libs opencv進行編譯,然后輸入./test即可得出結果。
四、總結
在了解了漢字點陣字庫的基本原理后,其實整個實現過程的難度系數不是很大,了解以上的這些知識只是實現液晶顯示的基礎。一開始我的文本文件就是用的UTF-8編碼格式,結果圖片上的漢字是幾個很奇怪的字符,改成ANSI格式就正確了。
五、參考資料
中文點陣字庫及顯示工具程序
提取碼:spbw
總結
以上是生活随笔為你收集整理的Ubuntu下点阵汉字的字模读取与显示的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。