initial commit

This commit is contained in:
2022-09-22 13:13:15 +02:00
commit ea1fbe4e94
93 changed files with 9161 additions and 0 deletions

66
python/img_gen/hamming.py Normal file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This module provides encoding and decoding functions for Hamming codes
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
class HammingError(Exception):
pass
def encode(data, blocksize=7):
result = []
datasize = blocksize-blocksize.bit_length()
data = list(map(int, data))
if len(data) % datasize:
raise HammingError(f"Length of data is not a multiple of {datasize}")
nblocks = int(len(data)/datasize)
for b in range(nblocks):
for i in range(blocksize):
# Power of 2
if (i+1)&i == 0 or i == 0:
result.append(0)
else:
result.append(data.pop(0))
for i in range(blocksize.bit_length()):
p = 1 << i
c = sum([result[b*blocksize+j] for j in range(blocksize) if (j+1)&p])
if c%2:
result[b*blocksize+p-1] = 1
return "".join(list(map(str, result)))
def decode(data, blocksize=7):
result = []
datasize = blocksize-blocksize.bit_length()
data = list(map(int, data))
if len(data) % blocksize:
raise HammingError(f"Length of data is not a multiple of {blocksize}")
nblocks = int(len(data)/blocksize)
for b in range(nblocks):
pos = 0
for i in range(blocksize.bit_length()):
p = 1 << i
c = sum([data[b*blocksize+j] for j in range(blocksize) if (j+1)&p])
if c%2:
pos |= p
if pos != 0:
if pos > blocksize:
raise HammingError("Too many errors")
return
data[b*blocksize+pos-1] = 1-data[b*blocksize+pos-1]
for i in range(1, blocksize):
if (i+1)&i != 0:
result.append(data[b*blocksize+i])
return "".join(list(map(str, result)))

View File

@ -0,0 +1,276 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates Lycacode data layout matrix figure
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
import pygame
import numpy as np
import hamming
S = 600
class LycacodeError(Exception):
pass
class Lycacode:
RES = 3
BLOCKSIZE = 7
MODE_PERSON = 0
MODE_LOC = 1
MODE_LINK = 2
MODE_TEXT = 3
PERSON_STUDENT = 0
PERSON_TEACHER = 1
PERSON_OTHER = 2
BLACK = (158,17,26)
#BLACK = (0,0,0)
WHITE = (255,255,255)
OFFSETS = [(0,-1), (1,0), (0,1), (-1,0)]
MASKS = [
lambda x, y: x%3 == 0,
lambda x, y: y%3 == 0,
lambda x, y: (x+y)%3 == 0,
lambda x, y: (x%3)*(y%3)==0,
lambda x, y: (y//3+x//3)%2==0,
lambda x, y: (y%3-1)*(x%3-y%3-2)*(y%3-x%3-2)==0,
lambda x, y: (abs(13-x)+abs(13-y))%3==1,
lambda x, y: (1-x%2 + max(0, abs(13-y)-abs(13-x))) * (1-y%2 + max(0,abs(13-x)-abs(13-y))) == 0
]
MASK = True
def __init__(self, data, mode):
self.data = data
self.mode = mode
self.encode()
self.create_matrix()
def encode(self):
self.bits = f"{self.mode:02b}"
if self.mode == self.MODE_PERSON:
type_ = self.data["type"]
id_ = self.data["id"]
self.bits += f"{type_:02b}"
self.bits += f"{id_:020b}"
if type_ == self.PERSON_STUDENT:
year = self.data["year"]
class_ = self.data["class"]
self.bits += f"{year:03b}"
self.bits += f"{class_:04b}"
in1, in2 = self.data["initials"]
in1, in2 = ord(in1)-ord("A"), ord(in2)-ord("A")
self.bits += f"{in1:05b}"
self.bits += f"{in2:05b}"
# 83 left
elif type_ == self.PERSON_TEACHER:
# 100 left
pass
elif type_ == self.PERSON_OTHER:
# 100 left
pass
elif self.mode == self.MODE_LOC:
section = self.data["section"]
room = self.data["room"]
self.bits += f"{section:03b}"
self.bits += f"{room:08b}"
# 107 left
elif self.mode == self.MODE_LINK:
self.bits += f"{self.data:032b}"
# 86 left
elif self.mode == self.MODE_TEXT: # max 13 chars
data = self.data.encode("utf-8")
self.bits += f"{len(data):07b}"
self.bits += "".join(list(map(lambda b: f"{b:08b}", data)))
# 7 left
else:
raise LycacodeError(f"Invalid mode {self.mode}")
ds = self.BLOCKSIZE-self.BLOCKSIZE.bit_length()
total_bits = (self.RES**2 * 24 - 6)
data_bits = total_bits * ds // self.BLOCKSIZE
self.bits += "0"*(ds-len(self.bits)%ds)
s = ""
i = 0
left = data_bits-len(self.bits)
while len(s) < left:
s += f"{i:0b}"
i += 1
s = s[:left]
self.bits += s
self.bits = hamming.encode(self.bits, self.BLOCKSIZE)
def create_matrix(self):
R = self.RES
self.matrix = np.zeros([R*9, R*9])-3
self.matrix[R*4:R*5, :] = -1
self.matrix[:, R*4:R*5] = -1
self.matrix[R:R*2, R*3:R*6] = -1
self.matrix[R*3:R*6, R:R*2] = -1
self.matrix[-R*2:-R, -R*6:-R*3] = -1
self.matrix[-R*6:-R*3, -R*2:-R] = -1
self.matrix[R*4:R*5,R*4:R*5] = 0
self.matrix[0, R*4:R*5] = -2 # mask
self.matrix[-1, R*4:R*5] = -2 # mask
mask_area = np.where(self.matrix == -1, 1, 0)
self.matrix[R*4, R*4+1:R*5-1] = 1
self.matrix[R*5-1, R*4] = 1
self.matrix[R*4+1:R*5-1, R*4+1:R*5-1] = 1
bits = list(map(int, self.bits))
bits = np.reshape(bits, [-1,self.BLOCKSIZE]).T
bits = np.reshape(bits, [-1]).tolist()
for y in range(R*9):
for x in range(R*9):
if self.matrix[y,x] == -1:
self.matrix[y,x] = bits.pop(0)
if len(bits) == 0:
break
if len(bits) == 0:
break
if self.MASK:
best = [None, None, None]
for i, mask in enumerate(self.MASKS):
score, matrix = self.evaluate(mask, mask_area)
if best[0] is None or score < best[0]:
best = (score, matrix, i)
self.matrix = best[1]
id_ = list(map(int, f"{best[2]:03b}"))
self.matrix[0, R*4:R*5] = id_ # mask
self.matrix[-1, R*4:R*5] = id_ # mask
def evaluate(self, mask, mask_area):
matrix = self.matrix.copy()
for y in range(self.matrix.shape[0]):
for x in range(self.matrix.shape[1]):
if mask_area[y][x] and mask(x,y):
matrix[y][x] = 1-matrix[y][x]
score = 0
# 3 or more of the same color (horizontal)
for y in range(self.matrix.shape[0]):
c = 0
col = -1
for x in range(self.matrix.shape[1]):
if matrix[y][x] == -1: continue
if col != matrix[y][x]:
c = 0
col = matrix[y][x]
c += 1
if c == 3:
score += 4
elif c > 3:
score += 2
# 3 or more of the same color (vertical)
for x in range(self.matrix.shape[1]):
c = 0
col = -1
for y in range(self.matrix.shape[0]):
if matrix[y][x] == -1: continue
if col != matrix[y][x]:
c = 0
col = matrix[y][x]
c += 1
if c == 3:
score += 4
elif c > 3:
score += 2
# 2x2 blocks of the same color
for y in range(matrix.shape[0]-1):
for x in range(matrix.shape[1]-1):
if matrix[y][x] == -1: continue
zone = matrix[y:y+2, x:x+2]
if np.all(zone == zone[0,0]):
score += 2
# more dots/1s => higher score
total = matrix.shape[0]*matrix.shape[1]
dots = np.sum(matrix == 1)
percent = 100*dots//total
score += percent//5 * 2
return score, matrix
def display(self, surf):
R = self.RES
S = min(surf.get_size())
s = int(S/12/R)*R
O = (S-s*9)/2
surf.fill((255,255,255))
for y in range(R*9):
for x in range(R*9):
col = self.matrix[y,x]
if col == -3:
X, Y = O+x*s/R, O+y*s/R
size = s/R
pygame.draw.line(surf, (0,0,0), [X+size/2, Y], [X, Y+size/2])
pygame.draw.line(surf, (0,0,0), [X+size, Y+size/2], [X+size/2, Y+size])
else:
if col == -2:
col = (190,190,190)
elif col == -1:
col = (127,127,127)
elif col == 0:
col = (0,0,0)
elif col == 1:
col = (255,255,255)
pygame.draw.rect(surf, col, [O+x*s/R, O+y*s/R, s/R, s/R])
pts = [
(4, 4), (4, 2), (3, 2), (3, 1), (4, 1), (4, 0), (5, 0), (5, 1), (6, 1), (6, 2), (5, 2),
(5, 4), (7, 4), (7, 3), (8, 3), (8, 4), (9, 4), (9, 5), (8, 5), (8, 6), (7, 6), (7, 5),
(5, 5), (5, 7), (6, 7), (6, 8), (5, 8), (5, 9), (4, 9), (4, 8), (3, 8), (3, 7), (4, 7),
(4, 5), (2, 5), (2, 6), (1, 6), (1, 5), (0, 5), (0, 4), (1, 4), (1, 3), (2, 3), (2, 4)
]
pygame.draw.polygon(surf, (0,0,0), [(O+s*p[0], O+s*p[1]) for p in pts], 1)
if __name__ == "__main__":
pygame.init()
surf = pygame.Surface([S, S])
code = Lycacode({
"type": Lycacode.PERSON_STUDENT,
"id": 16048,
"year": 5,
"class": 3,
"initials": "LH"
}, Lycacode.MODE_PERSON)
#code = Lycacode("Embarquement", Lycacode.MODE_TEXT)
"""code = Lycacode({
"section": 4,
"room": 209
}, Lycacode.MODE_LOC)"""
#code = Lycacode(1, Lycacode.MODE_LINK)
code.display(surf)
pygame.image.save(surf, "lycacode_data_layout.png")

View File

@ -0,0 +1,92 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates lycacode frame dimensions figure
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
import pygame
import numpy as np
S = 600
class Lycacode:
RES = 3
BLACK = (158,17,26)
#BLACK = (0,0,0)
WHITE = (255,255,255)
OFFSETS = [(0,-1), (1,0), (0,1), (-1,0)]
def __init__(self):
R = self.RES
self.matrix = np.zeros([R*9, R*9])-1
self.matrix[R*4:R*5, :] = 0
self.matrix[:, R*4:R*5] = 0
self.matrix[R:R*2, R*3:R*6] = 0
self.matrix[R*3:R*6, R:R*2] = 0
self.matrix[-R*2:-R, -R*6:-R*3] = 0
self.matrix[-R*6:-R*3, -R*2:-R] = 0
self.font = pygame.font.SysFont("arial", 30, bold=True)
def display(self, surf):
R = self.RES
S = min(surf.get_size())*2
s = int(S/12/R)*R
O = (S-s*9)/2
surf.fill(self.WHITE)
# Frame
pygame.draw.rect(surf, self.BLACK, [O-s, O-s, s*11, s*11])
pygame.draw.rect(surf, self.WHITE, [O-s*0.5, O-s*0.5, s*10, s*10])
# Cross
for i in range(4):
dx, dy = self.OFFSETS[i]
X, Y = S/2 + dx*s*3, S/2 + dy*s*3
for j in range(3):
dx2, dy2 = self.OFFSETS[(i+j-1)%4]
pygame.draw.circle(surf, self.BLACK, [X+dx2*s, Y+dy2*s], 0.75*s)
pygame.draw.rect(surf, self.BLACK, [X-(1.5-abs(dx))*s, Y-(1.5-abs(dy))*s, s*(3-abs(dx)*2), s*(3-abs(dy)*2)])
pygame.draw.rect(surf, self.BLACK, [O, S/2-s/2, 9*s, s])
pygame.draw.rect(surf, self.BLACK, [S/2-s/2, O, s, 9*s])
for y in range(9):
for x in range(9):
if self.matrix[y*R, x*R] != -1:
pygame.draw.rect(surf, (0,0,0), [O+x*s, O+y*s, s+1, s+1], 2)
col = (17,158,147)
col = (0,0,0)
pygame.draw.line(surf, col, [O-s, O+s*3], [O, O+s*3], 3)
pygame.draw.line(surf, col, [O-s, O+s*3-s/6], [O-s, O+s*3+s/6], 3)
pygame.draw.line(surf, col, [O, O+s*3-s/6], [O, O+s*3+s/6], 3)
txt = self.font.render("S", True, col)
surf.blit(txt, [O-s/2-txt.get_width()/2, O+s*3-s/6-txt.get_height()])
pygame.draw.line(surf, col, [O+s, O+s*3-s/6], [O+s*2, O+s*3-s/6], 3)
pygame.draw.line(surf, col, [O+s, O+s*3-s/3], [O+s, O+s*3], 3)
pygame.draw.line(surf, col, [O+s*2, O+s*3-s/3], [O+s*2, O+s*3], 3)
txt = self.font.render("S", True, col)
surf.blit(txt, [O+3*s/2-txt.get_width()/2, O+s*3-s/3-txt.get_height()])
pygame.draw.line(surf, col, [O+s, O-s], [O+s, O-s/2], 3)
pygame.draw.line(surf, col, [O+s-s/6, O-s], [O+s+s/6, O-s], 3)
pygame.draw.line(surf, col, [O+s-s/6, O-s/2], [O+s+s/6, O-s/2], 3)
txt = self.font.render("S/2", True, col)
surf.blit(txt, [O+s-s/6-txt.get_width(), O-s*0.75-txt.get_height()/2])
if __name__ == "__main__":
pygame.init()
surf = pygame.Surface([S, S])
code = Lycacode()
code.display(surf)
pygame.image.save(surf, "lycacode_frame.png")

View File

@ -0,0 +1,71 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates Lycacode layout figure
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
import pygame
import numpy as np
S = 600
class Lycacode:
RES = 3
def __init__(self, *args):
self.create_matrix()
def create_matrix(self):
R = self.RES
self.matrix = np.zeros([R*9, R*9])-3
self.matrix[R*4:R*5, :] = -1
self.matrix[:, R*4:R*5] = -1
self.matrix[R:R*2, R*3:R*6] = -1
self.matrix[R*3:R*6, R:R*2] = -1
self.matrix[-R*2:-R, -R*6:-R*3] = -1
self.matrix[-R*6:-R*3, -R*2:-R] = -1
self.matrix[R*4:R*5,R*4:R*5] = 0
self.matrix[0, R*4:R*5] = -2 # mask
self.matrix[-1, R*4:R*5] = -2 # mask
self.matrix[R*4, R*4+1:R*5-1] = 1
self.matrix[R*5-1, R*4] = 1
self.matrix[R*4+1:R*5-1,R*4+1:R*5-1] = 1
def display(self, surf):
R = self.RES
S = min(surf.get_size())
s = int(S/12/R)*R
O = (S-s*9)/2
surf.fill((255,255,255))
for y in range(R*9):
for x in range(R*9):
col = self.matrix[y,x]
if col == -3:
X, Y = O+x*s/R, O+y*s/R
size = s/R
pygame.draw.line(surf, (0,0,0), [X+size/2, Y], [X, Y+size/2])
pygame.draw.line(surf, (0,0,0), [X+size, Y+size/2], [X+size/2, Y+size])
else:
if col == -2:
col = (190,190,190)
elif col == -1:
col = (127,127,127)
elif col == 0:
col = (0,0,0)
elif col == 1:
col = (255,255,255)
pygame.draw.rect(surf, col, [O+x*s/R, O+y*s/R, s/R, s/R])
if __name__ == "__main__":
pygame.init()
surf = pygame.Surface([S, S])
code = Lycacode()
code.display(surf)
pygame.image.save(surf, "lycacode_layout.png")

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates Lycacode mask figures
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
import numpy as np
from PIL import Image
MASKS = [
lambda x, y: x%3 == 0,
lambda x, y: y%3 == 0,
lambda x, y: (x+y)%3 == 0,
lambda x, y: (x%3)*(y%3)==0,
lambda x, y: (y//3+x//3)%2==0,
lambda x, y: (y%3-1)*(x%3-y%3-2)*(y%3-x%3-2)==0,
lambda x, y: (abs(13-x)+abs(13-y))%3==1,
lambda x, y: (1-x%2 + max(0, abs(13-y)-abs(13-x))) * (1-y%2 + max(0,abs(13-x)-abs(13-y))) == 0
]
if __name__ == '__main__':
R = 3
for i, mask in enumerate(MASKS):
a = np.ones([27, 27], dtype="uint8")
a[R*4:R*5, :] = 2
a[:, R*4:R*5] = 2
a[R:R*2, R*3:R*6] = 2
a[R*3:R*6, R:R*2] = 2
a[-R*2:-R, -R*6:-R*3] = 2
a[-R*6:-R*3, -R*2:-R] = 2
a[R*4:R*5, R*4:R*5] = 1
for y in range(a.shape[0]):
for x in range(a.shape[1]):
if mask(x, y) and a[y,x] == 2:
a[y, x] = 0
a *= 0x7f
img = Image.fromarray(a)
img.save(f"lycacode_mask_{i}.png")

View File

@ -0,0 +1,256 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates QR Code mask evaluation figures
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
import pygame
import numpy as np
matrix = np.array([[1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0], [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0], [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0], [0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0], [1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0], [1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0], [1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0], [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0], [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0], [1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0], [1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0], [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0]])
matrix = np.where(matrix == -0.5, 0, matrix)
class History:
def __init__(self):
self.widths = [0]*7
self.widths[-1] = 4
self.color = 0
def add(self, col):
a, b, w = False, False, self.widths.copy()
if col != self.color:
self.color = col
a,b,w = self.check()
self.widths.pop(0)
self.widths.append(0)
self.widths[-1] += 1
return (a, b, w)
def check(self):
n = self.widths[1]
# if 1:1:3:1:1
if n > 0 and self.widths[2] == n and self.widths[3] == n*3 and self.widths[4] == n and self.widths[5] == n:
# add 40 if 4:1:1:3:1:1 + add 40 if 1:1:3:1:1:4
return (self.widths[0] >= 4, self.widths[6] >= 4, self.widths.copy())
return (False, False, self.widths.copy())
def final(self):
for i in range(4):
self.add(0)
return self.check()
def generate_imgs():
m = ((matrix.copy()+2)%3)*127
mat = np.ones((m.shape[0]+8, m.shape[1]+8))*255
mat[4:-4, 4:-4] = m
size = 30
surf = pygame.Surface([mat.shape[0]*size, mat.shape[0]*size])
surf.fill((255,255,255))
for y in range(mat.shape[0]):
for x in range(mat.shape[1]):
col = mat[y, x]
col = (col, col, col)
pygame.draw.rect(surf, col, [x*size, y*size, size, size])
img1, img2, img3, img4 = [surf.copy() for i in range(4)]
f = pygame.font.SysFont("sans", 20)
f2 = pygame.font.SysFont("sans", 48, bold=True)
f3 = pygame.font.SysFont("sans", 32, bold=True)
#Condition 1 (horizontal)
counts = []
scores = []
for y in range(matrix.shape[0]):
col = -1
row = []
s = 0
for x in range(matrix.shape[1]):
if matrix[y,x] != col:
if len(row) > 0 and row[-1] < 5:
n = row[-1]
row = row[:-n]+[0]*n
row.append(1)
col = matrix[y,x]
else:
row.append(row[-1]+1)
if row[-1] == 5:
s += 3
elif row[-1] > 5:
s += 1
counts.append(row)
scores.append(s)
for i, c in enumerate(counts[0]):
if c:
txt = f.render(str(c), True, (255,255,255))
img1.blit(txt, [(i+4.5)*size-txt.get_width()/2, 4.5*size-txt.get_height()/2])
for i, s in enumerate(scores):
txt = f.render(str(s), True, (255,0,0))
img1.blit(txt, [size*(5+matrix.shape[1])-txt.get_width()/2, (i+4.5)*size-txt.get_height()/2])
#Condition 1 (vertical)
scores2 = []
for x in range(matrix.shape[1]):
col, count = -1, 0
s = 0
for y in range(matrix.shape[0]):
if matrix[y,x] != col:
count = 0
col = matrix[y,x]
count += 1
if count == 5:
s += 3
elif count > 5:
s += 1
scores2.append(s)
for i, s in enumerate(scores2):
txt = f.render(str(s), True, (255,0,0))
img1.blit(txt, [(i+4.5)*size-txt.get_width()/2, size*(5+matrix.shape[0])-txt.get_height()/2])
txt = f2.render(f"= {sum(scores)+sum(scores2)}", True, (255,0,0))
img1.blit(txt, [size*(5+matrix.shape[1])-txt.get_width()/2, size*(6+matrix.shape[1])-txt.get_height()/2])
pygame.image.save(img1, "qr_mask_ex_eval_1.png")
#Condition 2
score = 0
txtR = f.render("3", True, (255,0,0))
txtW = f.render("3", True, (255,255,255))
for y in range(matrix.shape[0]-1):
for x in range(matrix.shape[1]-1):
zone = matrix[y:y+2, x:x+2]
if np.all(zone == zone[0,0]):
score += 3
txt = [txtR, txtW][int(zone[0,0])]
img2.blit(txt, [(x+5)*size-txt.get_width()/2, (y+5)*size-txt.get_height()/2])
txt = f2.render(f"= {score}", True, (255,0,0))
img2.blit(txt, [size*(5+matrix.shape[1])-txt.get_width()/2, size*(6+matrix.shape[1])-txt.get_height()/2])
pygame.image.save(img2, "qr_mask_ex_eval_2.png")
i = 0
cols = [(255,0,0),(44,219,99),(26,135,240),(229,205,44)]
cols = []
for j in range(36):
c = pygame.Color(0)
hsla = [j*40%360, 60, 50, 100]
c.hsla = hsla
cols.append(c)
for y in range(matrix.shape[0]):
hist = History()
for x in range(matrix.shape[1]):
a,b,w = hist.add(matrix[y,x])
if a:
col = cols[min(len(cols)-1,i)]
X = x-sum(w[1:]) #+4-4
draw_line(img3, col, size, X, y)
i += 1
if b:
col = cols[min(len(cols)-1,i)]
X = x-sum(w[1:])+4
draw_line(img3, col, size, X, y)
i += 1
a,b,w = hist.final()
if a:
col = cols[min(len(cols)-1,i)]
X = matrix.shape[1]-sum(w[1:])
draw_line(img3, col, size, X, y)
i += 1
if b:
col = cols[min(len(cols)-1,i)]
X = matrix.shape[1]+4-sum(w[1:-1])
draw_line(img3, col, size, X, y)
i += 1
for x in range(matrix.shape[1]):
hist = History()
for y in range(matrix.shape[0]):
a,b,w = hist.add(matrix[y,x])
if a:
col = cols[min(len(cols)-1,i)]
Y = y-sum(w[1:])
draw_line(img3, col, size, x, Y, True)
i += 1
if b:
col = cols[min(len(cols)-1,i)]
Y = y-sum(w[1:])+4
draw_line(img3, col, size, x, Y, True)
i += 1
a,b,w = hist.final()
if a:
col = cols[min(len(cols)-1,i)]
Y = matrix.shape[0]-sum(w[1:])
draw_line(img3, col, size, x, Y, True)
i += 1
if b:
col = cols[min(len(cols)-1,i)]
Y = matrix.shape[0]+4-sum(w[1:-1])
draw_line(img3, col, size, x, Y, True)
i += 1
txt = f2.render(f"= {i}*40 = {i*40}", True, (255,0,0))
img3.blit(txt, [size*(4+matrix.shape[1]/2)-txt.get_width()/2, size*(6+matrix.shape[1])-txt.get_height()/2])
pygame.image.save(img3, "qr_mask_ex_eval_3.png")
#Condition 4
total = matrix.shape[0]*matrix.shape[1]
dark = np.sum(matrix == 1)
percent = 100*dark//total
p1 = percent-(percent%5)
p2 = p1+5
p1, p2 = abs(p1-50)/5, abs(p2-50)/5
score = min(p1,p2)*10
txt = f3.render(f"P = {percent}%", True, (255,0,0))
img4.blit(txt, [size, size])
txt = f3.render(f"P1 = {percent-(percent%5)}% / P2 = {percent-(percent%5)+5}%", True, (255,0,0))
img4.blit(txt, [surf.get_width() - size - txt.get_width(), size])
txt = f2.render(f"S = min({int(p1)}, {int(p2)})*10 = {int(score)}", True, (255,0,0))
img4.blit(txt, [size*(4+matrix.shape[1]/2)-txt.get_width()/2, size*(6+matrix.shape[1])-txt.get_height()/2])
pygame.image.save(img4, "qr_mask_ex_eval_4.png")
def draw_line(surf, col, size, x, y, vert=False):
a, b = [(x+0.25)*size, (4.5+y)*size], [(x+10.75)*size, (4.5+y)*size]
if vert:
a, b = [(4.5+x)*size, (y+0.25)*size], [(4.5+x)*size, (y+10.75)*size]
dx, dy = [size/3, 0] if vert else [0, size/3]
pygame.draw.line(surf, col, a, b, 6)
pygame.draw.line(surf, col, [a[0]-dx, a[1]-dy], [a[0]+dx, a[1]+dy], 6)
pygame.draw.line(surf, col, [b[0]-dx, b[1]-dy], [b[0]+dx, b[1]+dy], 6)
if __name__ == "__main__":
pygame.init()
generate_imgs()

View File

@ -0,0 +1,33 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates QR Code mask figures
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
import numpy as np
from PIL import Image
MASKS = [
lambda x, y: (x+y) % 2 == 0,
lambda x, y: y % 2 == 0,
lambda x, y: (x) % 3 == 0,
lambda x, y: (x+y) % 3 == 0,
lambda x, y: (y//2+x//3) % 2 == 0,
lambda x, y: ((x*y) % 2 + (x*y) % 3) == 0,
lambda x, y: ((x*y) % 2 + (x*y) % 3) % 2 == 0,
lambda x, y: ((x+y) % 2 + (x*y) % 3) % 2 == 0
]
if __name__ == '__main__':
for i, mask in enumerate(MASKS):
a = np.ones([21, 21], dtype="uint8")
for y in range(a.shape[0]):
for x in range(a.shape[1]):
if mask(x, y):
a[y, x] = 0
a *= 0xffffff
img = Image.fromarray(a)
img.save(f"qr_mask_{i}.png")

View File

@ -0,0 +1,101 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Generates QR Code placement path figure
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
"""
import pygame
import numpy as np
WIDTH, HEIGHT = 580, 580
matrix = np.array([
[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
[ 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
[ 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0],
[ 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0],
[ 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0],
[ 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
[ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[-0.5, -0.5, -0.5, -0.5, -0.5, -0.5, 1.0, -0.5, -0.5, -1.0, -1.0, -1.0, -1.0, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5, -0.5],
[-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 0.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[ 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[ 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[ 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[ 1.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[ 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0],
[ 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, -0.5, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0]
])
if __name__ == "__main__":
pygame.init()
surf = pygame.Surface([WIDTH, HEIGHT])
W, H = WIDTH/(matrix.shape[1]+8), HEIGHT/(matrix.shape[0]+8)
hW, hH = W/2, H/2
surf.fill((255,255,255))
m = ((matrix.copy()+2)%3)*127
mat = np.ones((m.shape[0]+8, m.shape[1]+8))*255
mat[4:-4, 4:-4] = m
for y in range(mat.shape[0]):
for x in range(mat.shape[1]):
col = mat[y, x]
col = (col, col, col)
pygame.draw.rect(surf, col, [x*W, y*H, W, H])
points = []
all_points = []
#Place data
dir_ = -1 #-1 = up | 1 = down
x, y = matrix.shape[1]-1, matrix.shape[0]-1
zigzag = 0
while x >= 0:
all_points.append([(x+4)*W+hW, (y+4)*H+hH])
if matrix[y,x] == -1:
points.append([(x+4)*W+hW, (y+4)*H+hH])
if ((dir_+1)/2 + zigzag)%2 == 0:
x -= 1
else:
y += dir_
x += 1
if y == -1 or y == matrix.shape[0]:
all_points.append([(x+4)*W+hW, (y+4)*H+hH])
dir_ = -dir_
y += dir_
x -= 2
else:
zigzag = 1-zigzag
#Vertical timing pattern
if x == 6:
x -= 1
all_points.append([(x+4)*W+hW, (y+4)*H+hH])
for p in all_points:
pygame.draw.circle(surf, (255,0,0), p, 3)
pygame.draw.lines(surf, (255,0,0), False, all_points)
for p in points:
pygame.draw.circle(surf, (255,255,255), p, 3)
pygame.draw.lines(surf, (255,255,255), False, points)
pygame.image.save(surf, "qr_plcmt_path.png")