二维码的码字布置
一、模式标识符(Mode Indicator) QR码的模式(Mode)就是前文提到的数字、字符、8bit 字节码、多字节码等。对于不同的模式,都有对应的模式标识符(Mode Indicator)来帮助解码程序进行匹配,模式标识符是4bit的二进制数:
1、数字模式(numeric mode ): 0001
2、混合字符模式(alphanumeric mode) : 0010
3、8bit byte mode: 0100
4、日本汉字(KANJI mode) : 1000
5、中国汉字(GB2312):1101 由于示例文本串是混合字符,因此将选择alphanumeric mode,其标识码为:0010
二、文本串计数标识符(Character count indicator) 文本串计数标识符用来存储源内容字符串的长度,在版本1-9的QR码中,文本串长度标识符自身的长度被定义为:
数字 : 10bit
混合字符 : 9bit
8bit 字节码 : 8bit
多字节码 : 8bit 在本例中,源文本串的长度为8个字符,混合字符的长度用9bit表示,因此将字符个数8编码为9位二进制表示:000001000 加上混合字符模式标识码,总的编码为0010 000001000
三、数据的编码请参照网络资料。 如果编码后的字符长度不足当前版本和纠错级别所存储的容量,则在后续补"0000",如果容量已满则无需添加终止符。各个版本和纠错级别存储容量网络查表得知。
四、将以上编码数据编码成8bit码字将以上的编码再按8bit一组,形成码字(code words): 00100000 01000001 11001101 01000101 00101001 11011100 00101110 10000 如果尾部数据不足8bit,则在尾部充0。
如果编码后的数据不足版本及纠错级别的最大容量,则在尾部补充 "11101100" 和 "00010001",直到全部填满。 各个版本和纠错级别最大容量网络查表得知。
五、码字的布置: (以垂直布置为例)
码字大多数以2*4模块(2宽4高)规则分布,遇到功能图则跳过成不规则分布 :
码字从最下角依次由从右向左、从下向上或从上向下交替布局。(也就是将所有码字看成一数据流,依次从最高位开始将其放在矩阵中从右向左,向上或向下(先2宽向上,再2宽向下,依次交替))的位置,遇到功能图形跳过其区域。
读码字:
uchar data=0;
int bit_count=0,word_count=0;
int dir=-1;
int x=codes->width-1;
int y=codes->height-1;
do{
data<<=1;
bit_count++;
//x,y是否是数据元素(非边界,非功能数据?)
if(CV_IMAGE_ELEM(codes,uchar,y,x)>=128)
data|=1;
//每8个元素一个码字。
if(!(bit_count%8)){
if(this->qr->push_codedata(data))
word_count++;
data=0;
}
//当x为2宽右边一列,判断其左边的元素是否数据元素(非边界、非功能数据?)不是则判断其上边元素,当y到边界,则此2宽读完,x-2读下一个2宽。
if(x&0x1){
if(CV_IMAGE_ELEM(funcs,uchar,y,x-1)) //funcs的功能区全为黑色,其他区为白色,故非零的点x,y对应的codes
x--; //的点即为编码区。
else{
do{
y+=dir;
if(y<0||y>=codes->height){
x-=2;
dir*=-1;
y+=dir;
if(x<0)
break;
}
}while(!CV_IMAGE_ELEM(funcs,uchar,y,x));
}
}
//当x为2宽左边一列,判断其右边的上边的元素是否数据元素(非边界、非功能数据?)不是则判断其上边(右边的上边的左边)元素,当y到边界,则此2宽读完,x-2读下一个2宽。
else{
x++;
do{
y+=dir;
if(y>=0&&y<codes->height){
if(CV_IMAGE_ELEM(funcs,uchar,y,x)){
break;
}
else if(CV_IMAGE_ELEM(funcs,uchar,y,x-1)){
x--;
break;
}
else{
y+=dir;
}
}
else{
x-=2;
dir*=-1;
y+=dir;
if(x<0)
break;
}
}while(!CV_IMAGE_ELEM(funcs,uchar,y,x));
}
}while(x>=0);
if(data){
if(this->qr->push_codedata(data))
word_count++;
}
1、数字模式(numeric mode ): 0001
2、混合字符模式(alphanumeric mode) : 0010
3、8bit byte mode: 0100
4、日本汉字(KANJI mode) : 1000
5、中国汉字(GB2312):1101 由于示例文本串是混合字符,因此将选择alphanumeric mode,其标识码为:0010
二、文本串计数标识符(Character count indicator) 文本串计数标识符用来存储源内容字符串的长度,在版本1-9的QR码中,文本串长度标识符自身的长度被定义为:
数字 : 10bit
混合字符 : 9bit
8bit 字节码 : 8bit
多字节码 : 8bit 在本例中,源文本串的长度为8个字符,混合字符的长度用9bit表示,因此将字符个数8编码为9位二进制表示:000001000 加上混合字符模式标识码,总的编码为0010 000001000
三、数据的编码请参照网络资料。 如果编码后的字符长度不足当前版本和纠错级别所存储的容量,则在后续补"0000",如果容量已满则无需添加终止符。各个版本和纠错级别存储容量网络查表得知。
四、将以上编码数据编码成8bit码字将以上的编码再按8bit一组,形成码字(code words): 00100000 01000001 11001101 01000101 00101001 11011100 00101110 10000 如果尾部数据不足8bit,则在尾部充0。
如果编码后的数据不足版本及纠错级别的最大容量,则在尾部补充 "11101100" 和 "00010001",直到全部填满。 各个版本和纠错级别最大容量网络查表得知。
五、码字的布置: (以垂直布置为例)
码字大多数以2*4模块(2宽4高)规则分布,遇到功能图则跳过成不规则分布 :
码字从最下角依次由从右向左、从下向上或从上向下交替布局。(也就是将所有码字看成一数据流,依次从最高位开始将其放在矩阵中从右向左,向上或向下(先2宽向上,再2宽向下,依次交替))的位置,遇到功能图形跳过其区域。
读码字:
uchar data=0;
int bit_count=0,word_count=0;
int dir=-1;
int x=codes->width-1;
int y=codes->height-1;
do{
data<<=1;
bit_count++;
//x,y是否是数据元素(非边界,非功能数据?)
if(CV_IMAGE_ELEM(codes,uchar,y,x)>=128)
data|=1;
//每8个元素一个码字。
if(!(bit_count%8)){
if(this->qr->push_codedata(data))
word_count++;
data=0;
}
//当x为2宽右边一列,判断其左边的元素是否数据元素(非边界、非功能数据?)不是则判断其上边元素,当y到边界,则此2宽读完,x-2读下一个2宽。
if(x&0x1){
if(CV_IMAGE_ELEM(funcs,uchar,y,x-1)) //funcs的功能区全为黑色,其他区为白色,故非零的点x,y对应的codes
x--; //的点即为编码区。
else{
do{
y+=dir;
if(y<0||y>=codes->height){
x-=2;
dir*=-1;
y+=dir;
if(x<0)
break;
}
}while(!CV_IMAGE_ELEM(funcs,uchar,y,x));
}
}
//当x为2宽左边一列,判断其右边的上边的元素是否数据元素(非边界、非功能数据?)不是则判断其上边(右边的上边的左边)元素,当y到边界,则此2宽读完,x-2读下一个2宽。
else{
x++;
do{
y+=dir;
if(y>=0&&y<codes->height){
if(CV_IMAGE_ELEM(funcs,uchar,y,x)){
break;
}
else if(CV_IMAGE_ELEM(funcs,uchar,y,x-1)){
x--;
break;
}
else{
y+=dir;
}
}
else{
x-=2;
dir*=-1;
y+=dir;
if(x<0)
break;
}
}while(!CV_IMAGE_ELEM(funcs,uchar,y,x));
}
}while(x>=0);
if(data){
if(this->qr->push_codedata(data))
word_count++;
}