QRcode二维码以及其背后的数学运算

二维码

二维码在生活中随处可见。添加好友,微信扫一扫;吃饭娱乐停车费,扫码支付;活动宣传海报,扫一扫了解更多…各种各样形式的二维码布满我们的生活,而我们早已习惯了二维码带来的便利。接下来从研发的角度出发,更深入了解一下二维码的世界。

1、定义

二维码是一种由黑白像素组成,可以用于存储各种类型的信息(例如文本、URL、图像、视频等)的矩形矩阵式二维条码。

在这里插入图片描述

2、二维码的数据容量

抽象成一个盒子 里面放东西

  • 版本:是指二维码中模块(Module)数的大小及其容量大小的定义。版本号越高,模块数和数据容量越大——型号
  • 纠错等级:Error Correction Level,是指二维码中纠错码的长度和能力,通常用L、M、Q、H四个等级表示。纠错等级越高,纠错码越长,相应冗余数据增加,数据容量随之降低——隔板
  • 编码方式:二维码可以使用多种编码方式来存储数据。通常情况下采用数字、字母、特殊字符混合编码方式来获取最大的数据承载量。对于特定类型,例如URL地址、电话号码等采用相应编码方式来获得更大数据承载量——摆放方式
  • 码制:Symbol Type,常见的有QR Code,Data Matrix,PDF417等。不同码制具有不同的编码方式和数据结构,从而影响数据承载量——材质
  • 像素密度:Pixel Density,二维码像素密度越高,存储数据越多,但是二维码尺寸、复杂度也随之增加,会导致扫描、解码的速度和准确性降低——存放物品的形状

选择不同型号的盒子, 大小不一, 容量不等。

选择不同隔板,横放、竖放,占用容量不等,数据容量不等

选择不同摆放方式,平铺、叠放,占用容量不等,数据容量不等

选择不同材质的盒子,纸糊、铁铸承受不等,数据容量不等

选择不同的物品,三角形、矩形、圆形形状不等,数据容量不等

于实时生成的二维码应用:

二维码不会被破坏(扫码时生成)——> 选择L纠错级别增加数据容量

笔记本浏览器显示限制——> 选择800*800大小

考虑手机扫码、拍照场景、光线等因素——> 字符固定约2000个(手机扫码上限约2600)

3、纠错能力

  • L级——纠正7%错误
  • M级——纠正15%错误
  • Q级——纠正25%错误
  • H级——纠正30%错误

版本10的二维码,纠错等级为H时,总共包含346码字,其中224个纠错码字,可以纠正112个替代错误(如彩色颠倒)或者224个据读错误(无法读到或无法译码),112/346=32.4%

常用的是里德-所罗门码(Reed-solomon codes, RS码)。是一种前向错误更正的信道编码,对由校正过采样数据所产生的有效多项式。编码过程首先在多个点上对这些多项式求冗余,然后将其传输或存储。对多项式的这种超出必要值的采样使得多项式超过限定。当接收器正确地收到足够的点后,它就可以恢复原来的多项式,即使接收到的多项式上有很多点被噪声干扰失真。

——原理基于“任意k个确定点可表示一个阶数至少为k-1的多项式”,发送超过k个点,二维码损坏时也可以通过数学原理反推最初的多项式,获取信息

并不是所有位置都可以损坏,三个方框则会直接影响初始定位;

​ 为什么是三个?

	- 一个方框,会产生无数个固定一点、大小不同的正方形
	- 两个方框,无法区分正反
	- 三个方框,三点共面,确定一个正方形,可以以任意方向扫码
	- 四个方框,无法区分正反
GF(256)有限域

是一个有限域(finite field),也称为伽罗华域(Galois field),由256个元素组成,其中每个元素都可以表示为一个8位二进制数。

加减法规则: 模2的异或运算(XOR),即两个二进制数的每一位进行异或运算,得到的结果作为和。

eg: 在GF(256)中,83+202 ——> 01010011 XOR 11001010 (十进制转二进制——模2取余倒排) 结果为10011001

乘法规则: 将不可约多项式(irreducible polynomial)不能分解为两个次数更低的多项式的多项式作为模数,将两数相乘的结果对不可约多项式取模,得到的结果作为积。

常见的不可约多项式:

  • x8 + x4 + x3 + x + 1 —— 100011011 ——283
  • x8 + x4 + x3 + x2 + 1 —— 100011101 ——285

eg:在GF(256)中, 83 * 202 ——> (x6 + x4 + x + 1)* (x7 + x6 + x3 + x)% (x8 + x4 + x3 + x2 + 1) 结果为00000001, 即82与202互为乘法逆元(乘积为1)

在这里插入图片描述

除法规则:

  1. 选择合适的项、系数去乘除数,使得被除数与除数的第一项次数相同
  2. 采用XOR运算
  3. 重复步骤1、2

总结GF(256):

  1. 加法乘法满足交换律、结合律、分配律

  2. 加法单位元为0, 乘法单位元为1

  3. 每个非零元素都有一个乘法逆元素,即对于∀ a≠0,∃ b ∈ GF(256), 使得 a * b = 1

log以及反log乘法运算

两个数字p和q相乘 可以表示为: 2log2p+log2q

这也就意味着,所有GF(256)的值均可以被表示为2的次幂,那么域中的所有乘法都可以表示为2的指数相加

283 * 2202 = 283+202 = 2285%255 = 230

在 GF(256) 进行乘法是为了获得所有的 2 的次幂。所有值都被预先计算好,可以在 log 和 反 log 表中 查到。表中 alpha = 2,0 到 255 的数字都可以对应到 2 的 0 到 255 次幂,同时 2 的 0 到 255 次幂也都可以对应到 0到 255 的数字。

log和反log表 https://www.thonky.com/qr-code-tutorial/log-antilog-table

生成多项式

生成多项式是由 (x-α0 )…(x-α(n-1)) 相乘得到的,其中 n 为校错表中的纠错码中字节个数,alpha 值为 2。

n=2, alpha=2的生成多项式为:【α25 = 3, 可从上表查询】

(x - 20)(x - 21) = x2 + 3x1 + 2x0 = α0x2 + α25x1 + α1x0

生成多项式小工具: https://www.thonky.com/qr-code-tutorial/generator-polynomial-tool

生成纠错码
信息多项式

采用1-M二维码, 以HELLO WORLD为例

HELLO WORLD选择1-M二维码,得到的十进制数字为:32, 91, 11, 120, 209, 114, 220, 77, 67, 64, 236, 17, 236, 17, 236, 17

将其作为信息多项式的系数,得到信息多项式。

32x15 + 91x14 + …… + 17x0

生成多项式

纠错表 https://www.thonky.com/qr-code-tutorial/error-correction-table

采用1-M二维码 查询纠错表需要生成10个纠错码,通过生成多项式小工具得:

α0x10 + α251x9 + α67x8 + α46x7 + α61x6 + α118x5 + α70x4 + α64x3 + α94x2 + α32x+ α45

消息多项式XOR生成多项式

生成多项式做消息多项式的指数补齐、系数补齐

α0x10 + α251x9 + α67x8 + α46x7 + α61x6 + α118x5 + α70x4 + α64x3 + α94x2 + α32x+ α45

——> α5x25 + α256x24 + α72x23 + α51x22 + α66x21 + α123x20 + α75x19 + α69x18 + α99x17 + α37x16+ α50x15

(指数>255 取余)——>α5x25 + α1x24 + α72x23 + α51x22 + α66x21 + α123x20 + α75x19 + α69x18 + α99x17 + α37x16+ α50x15

进行除法操作

α5 = 32, α1 = 2, α72 = 101,…

(32 XOR 32)x25 + (91 XOR 2)x24 + (11 XOR 101)x24 + ……+ (17 XOR 0)x10

——> 89x24 + 110x23 + 114x22 + 176x21 + ……+ 17x10

重复【指数补齐、系数补齐, 除法操作】,最后得到:

196x9 + 35x8 + 39x7 + 119x6 + 235x5 + 215x4 + 231x3 + 226x2 + 93x1 + 23

余数多项式的系数,即10个纠错码: 196 35 39 119 235 215 231 226 93 23

package main

import (
	"fmt"
	"math"
	"testing"
)

// GetPowersOf2ForGF 获取GF(256)中指定2的num次方
func GetPowersOf2ForGF(num int) int {
	list := make([]int, num+1)
	tmp := 0
	list[0] = 1
	for i := 1; i <= num; i++ {
		tmp = list[i-1] * 2
		if tmp > 255 {
			tmp ^= 285
		}
		list[i] = tmp
	}
	return list[num]
}

// GetAllPowersOf2ForGF 获取GF(256)中2的幂
func GetAllPowersOf2ForGF() []int {
	list := make([]int, 256)
	tmp := 0
	list[0] = 1
	for i := 1; i <= 255; i++ {
		tmp = list[i-1] * 2
		if tmp > 255 {
			tmp ^= 285
		}
		list[i] = tmp
	}
	for i, v := range list {
		fmt.Println(fmt.Sprintf("%d--------%d", i, v))
	}
	return list
}

// GetAntiLog 获取反日志的逆对数(antilogarithm
func GetAntiLog() []int {

	list := GetAllPowersOf2ForGF()
	antiLogs := make([]int, 256)
	for i := 0; i <= 255; i++ {
		antiLogs[list[i]] = i
	}
	antiLogs[0] = math.MinInt32
	antiLogs[1] = 0
	return antiLogs
}

func TestGetPowersOf2ForGF(t *testing.T) {

	fmt.Println(GetPowersOf2ForGF(72)) // 获取2^72
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值