fun chall! my first thought was to
- find the font -> do deterministic search for the bitarrays
i couldn't find the font, missed that the beginning of the b64 had the font set, and then thought:
- find a grid size that segmented all the characters into equal rectangles, then just manually label stuff and compare rectangles
As it turns out, the lines were not consistent sizes, so i considered:
- doing a flow algorithm to find all connected pixels so i could identify characters
I couldn't get this working and realized it was unnecessary so I instead settled on:
- finding the bounding boxes of each character (loosely) by finding the all-white lines that segmented the picture into a grid
import imageio
import numpy as np
import cv2
white_pixel = [255, 255, 255, 255]
image = imageio.imread('image.png')
ar = np.array(image)
cols_mask = np.all(ar == white_pixel, axis=(1, 2))
rows_mask = np.all(ar == white_pixel, axis=(0, 2))
cols = np.where(cols_mask)[0]
rows = np.where(rows_mask)[0]
#get all white lines around each line, will be run on horizontal and vertical masks
def process_lines(cols):
bounding = []
for i in range(len(cols)-1):
if cols[i+1] - cols[i] > 1:
bounding.append(cols[i])
bounding.append(cols[i+1])
i += 1
return bounding
r = process_lines(rows)
c = process_lines(cols)
all_cropped = []
# crop base image into characters
for i in range(0, len(c)-1, 2):
for j in range(0, len(r)-1, 2):
print(i, i+1)
print(j, j+1)
print()
cropped = image[c[i]:c[i+1], r[j]:r[j+1]]
all_cropped.append(cropped)
#cv2.imshow("label", cropped)
#cv2.waitKey(0)
#accidentally took in some blank squares at the end and quickly cleaned it up
new_cropped = []
for x in all_cropped:
if not np.all(x == white_pixel):
new_cropped.append(x)
# labelled all unique characters manually (there were like 100)
hashes = {}
for item in new_cropped:
h = hash(tuple(item.flatten()))
if h not in hashes:
cv2.imshow('h', item)
d = cv2.waitKey(0)
dd = input("char here: ")
cv2.destroyAllWindows()
hashes[h] = dd
print("adding " + dd)
else:
print("skipping")
# decoding by hash based on table created by manually labelling above
for x in new_cropped:
h = hash(tuple(x.flatten()))
flag.append(hashes[h])
#the end!
''.join(flag)