引言

如图,这是一张二维码 ( QR Code ),可以看出,除了左上,右下及左下的三个定位块,剩余部分看起来似乎是杂乱无章的,那么我们是否可以用随机点绘制一个随机二维码呢?
qrcode

设计

首先,我们需要知道,我们的二维码要有多大?为了讲解方便,这里暂定为 36 x 36 px 。随机量取生活中的一张二维码,可以测出定位块的长宽均为整张二维码长宽的六分之一。单独细看一个定位块,它的结构如下:
qrcode block
在 36 x 36 px 的二维码中,这个定位块的长宽均为6,内部小正方形的长宽为4,中间间隙宽为1。
再看二维码剩余的部分,随机点的范围应为:

6 < x < 36 - 6 = 30
6 < y < 36 - 6 = 30

满足上述条件其一者,将使随机点出现在 ①、②、③、④、⑤ 五个区域 而当 30 < x < 36 且 30 < y < 36 时,随机点将出现在 ⑥ 区域

实现

在 Casio fx-9860 GⅢ 上的实现

首先导入 casioplot 模块用于画图

1
from casioplot import *

在这个模块中,我们主要使用两个函数:

函数名 功能
set_pixel(x,y) 设置一个坐标为深色
show_screen() 显示屏幕

再导入 random 模块用于生成随机数

1
from random import *

经过测试,这台 Casio 计算器的屏幕在绘制点时分辨率为 128 x 64 px , 所以准备了一个转换函数用于将最终图像放置于居中的位置。

1
def p(x,y): set_pixel(x+50, y+18)

接着,使用直接指定的方式绘制三个定位块:

1
2
for i in range(7):p(i,0);p(i+18,0);p(i,18);p(i,6);p(i+18,6);p(i,24);p(0,i);p(18,i);p(0,i+18);p(6,i);p(24,i);p(6,i+18)
for i in range(3):p(2+i,2);p(2+i,20);p(2,20+i);p(2+i,4);p(2+i,22);p(4,20+i);p(2,2+i);p(20,2+i);p(20+i,2);p(4,2+i);p(22,2+i);p(20+i,4)

接着绘制随机点:

1
2
3
for i in range(int(input("points num:"))):
a=randint(0,24);b=randint(0,24)
if (18>a>=7 or 18>b>=7) or (a>=18 and b>=18):p(a,b)

其中, int(input(“points num:”)) 即为输入随机点数量,推荐 500 ,看起来与正常无异。
另外,由于随机函数的随机性问题,最后显示的一定不足给定的数量,可能存在重复的状况

最后显示屏幕

1
show_screen()

组合后的代码:

1
2
3
4
5
6
7
8
from casioplot import *;from random import *
def p(x,y): set_pixel(x+50, y+18)
for i in range(7):p(i,0);p(i+18,0);p(i,18);p(i,6);p(i+18,6);p(i,24);p(0,i);p(18,i);p(0,i+18);p(6,i);p(24,i);p(6,i+18)
for i in range(3):p(2+i,2);p(2+i,20);p(2,20+i);p(2+i,4);p(2+i,22);p(4,20+i);p(2,2+i);p(20,2+i);p(20+i,2);p(4,2+i);p(22,2+i);p(20+i,4)
for i in range(int(input("points num:"))):
a=randint(0,24);b=randint(0,24)
if (18>a>=7 or 18>b>=7) or (a>=18 and b>=18):p(a,b)
show_screen()

那么可能就有小伙伴会问了:“不是说 9 行吗?”,其实主要是 casio 计算器的 Python 编辑器有单行最大字符数限制,像第 4 行代码在 Casio 中是没法放在一行的。
测试一下,成功得到如下二维码,只是能不能扫就不知道了。

成功演示:

成功演示

在 Windows 上通过 Matplotlib 的实现

略。

鸣谢

感谢冯子豪同学友情提供 Casio fx-9860GⅢ 以供测试