相机字符叠加原理2

相机字符叠加原理

这里我介绍一下在国内某数一数二的监控设备制造厂商(抱歉知识产权不能说明--你懂的)他们是怎么在图像上叠加字符的(以GB2312为例)

一、点阵字库

  GB2312又称国标码,由国家标准总局发布,1981年5月1日实施,通行于大陆。新加坡等地也使用此编码。它是一个简化字的编码规范,当然也包括其他的符号、字母、日文假名等,共7445个图形字符,其中汉字占6763个。我们平时说6768个汉字,实际上里边有5个编码为空白,所以总共有6763个汉字。

      GB2312规定“对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示”,习惯上称第一个字节为“高字节”,第二个字节为“低字节”。GB2312中汉字的编码范围为,第一字节0xB0-0xF7(对应十进制为176-247),第二个字节0xA0-0xFE(对应十进制为160-254)。

    GB2312将代码表分为94个区,对应第一字节(0xa1-0xfe);每个区94个位(0xa1-0xfe),对应第二字节,两个字节的值分别为区号值和位号值加32(2OH),因此也称为区位码。01-09区为符号、数字区,16-87区为汉字区(0xb0-0xf7),10-15区、88-94区是有待进一步标准化的空白区。

二、中英文字的区分

汉字占两个字节,英文和阿拉伯数字等占一个字节。例如,需要叠加字符串char *szTime="当前2015",则其内存为:

szTime0x0f5dc50c "当前时间:2015-03"
[0x00000000] 0xb5 '?' char
[0x00000001] 0xb1 '?' char
[0x00000002] 0xc7 '?' char
[0x00000003] 0xb0 '?' char
[0x00000009] 0x32 '2' char 2
[0x0000000a] 0x30 '0' char 0
[0x0000000b] 0x31 '1' char 1
[0x0000000c] 0x35 '5' char 5


0B1011 0101 1011 0001--------当
0B1100 0111 1011 0000--------前 
0B0011 0010-----------------------2
0B0011 0000-----------------------0
0B0011 0001-----------------------1
0B0011 0005-----------------------5


我们可以看出汉字的“当”字由两个字节组成:0xb5=0B1011 01010xb1=0B1011 0001

判断汉字的规则为:第一个字节&0x80 成立 否则则为英文

三、字与字库之间的关系

下面是我画的16x16的点阵示意图
相机字符叠加原理2_第1张图片

从这个示意图我们可以看出汉字是怎么由一个个点构成的,下面这幅图又详细阐述了比特与点阵之间的关系
相机字符叠加原理2_第2张图片

一个字节为8bit,可以标识8个信息量,当汉字中的关键笔画点需要贴出来的时候,我们就为其标记该bit为1 否则为0.
特别需要注意的是:内存上排布是一个字符点阵排列完毕后再排列第二个字符
在内存上排布示意图如下:
相机字符叠加原理2_第3张图片
通过以上分析,我们可以知道点阵宽度为W的字体:
1、一个汉字所占用的内存大小为w*w/8
2、一个英文所占用的内存大小为w*w/8/2
3、英文字符在GB2312点阵字库中的存储位置为0x0起始
4、中文字符在点阵中的存储位置为0xa1起始
5、每个汉字有一个区,内存起始地址为((c[0]-0xa1)*94+c[1])
最后得出结论:
1、一个英文C点阵的内存长度L=w/16*w 拷贝起始地址为L*C
2、一个汉字c[2]的点阵长度L=w/8*w 拷贝内存起始地址为 (94 * c[0] + c[1]) * L

四、点阵与YUV图像

如果我需要叠加"当"这个字符,并且叠加为红色。
1、将当字在加载在内存中的第一行点阵偏移量找到,然后根据将"当"字的二进制数据排开
2、遍历所有的bit位如果比特位为1,则将像中的该像素点设置为红色
3、进入下一行点阵叠加,同时图像也下平移一个像素点。
汉字叠加的伪代码贴出来 英文的自己去推导
typedef struct YUV_IMAGE
{
	YUV_IMAGE(){ y = NULL; u = NULL; v = NULL; w = 0; h = 0; }
	~YUV_IMAGE(){ y = NULL; u = NULL; v = NULL; w = 0; h = 0; }
	UCHAR *y;
	UCHAR *u;
	UCHAR *v;
	UINT		w;
	UINT		h;
	IMAGE_TYPE t;
};


//pLib--点阵字库
//szHZ[2] --汉字
//pImage 图像
// col --叠加的颜色
void  OSD(TUchar *pLib, char szHZ[2], YUV_IMAGE *pImage, COLORREF col, UINT nFontW)
{
	TUchar szDZ[1000] = { 0 };
	UINT h = nFontW, w = nFontW / 8;
	UINT wImg = pImage->w;
	//计算点阵字节量
	UINT nLen = nFontW*nFontW / 8;
	//计算点阵在字库中的偏移量
	UINT nOff = (94 * szHZ[0] + szHZ[1])*nLen;
	memcpy(szDZ, pLib + nOff, nLen);
	
	
	//垂直遍历
	for (int i = 0; i < h; i++)
	{
		//水平遍历
		for (int j = 0; j < w; j++)
		{
			//按字节中的位遍历
			for (int k = 0; k < 8; i++)
			{	
				TUchar szByte = szDZ[i*w + j];
				//如果这一位是需要显示出来的
				if ((szByte >> k) & 0x01)
				{
					//叠加Y
					TUchar y, u, v;
					RGB2YUV(col.r, col.g, col.b, &y, &u, &v);
					pImage->y[wImg*h + j*nFontW + k] = y;
					//针对YUV420UV分开存储的图像格式 下面需要稍微修改一下 因为UV是垂直1/2采样
					if (i% 2)
					{
						pImage->y[wImg*h + j*nFontW + k] = u;
						pImage->y[wImg*h + j*nFontW + k] = v;
					}
					
				}

			}
		}
	}
}



你可能感兴趣的:(流媒体)