Skip to main content
1 of 2
Jeanot Zubler
  • 1.5k
  • 11
  • 39

Tasks

  1. Quote:

    Three may keep a secret, if two of them are dead.

  2. Objects: A key or a kite, depending on how you define "on the line".

Approach

I have done some image processing in Python before, so I chose to stick with that. I used a jupyter notebook for the interactivity. It took some experimenting (and manually converting binary) to get the right ordering of bits (LSB / MSB) for each step, but otherwise the tasks worked without major problems. In the end I cleaned up the code a little to be able to post it here without having to be too ashamed.

Code

import cv2
import matplotlib.pyplot as plt

test_b = cv2.imread("./SO-Challenge18-TestB.png") # one of the test images
img_1 = cv2.imread("./SO-Challenge18-Image1.png")
img_2 = cv2.imread("./SO-Challenge18-Image2.png")

print(f"'Test Test' should be {[c for c in "Test Test".encode("ascii")]}")
print(f"Test image shape: {test_b.shape}, total {test_b.size} bits")
print(f"Main image shape: {img_1.shape}, total {img_1.size} bits")

def get_int(bits):
    val = 0
    for i, bit in enumerate(bits[::-1]):
        val = val | (bit << i)
    return val

def get_flat_bits(img):
    return img[:, :, ::-1].flatten() % 2

def decode_text(img):
    bits = get_flat_bits(img)
    assert bits[0] == 0 and bits[1] == 0
    length = get_int(bits[2:18])
    print(length)
    chunks = bits[18:18+length].reshape((-1, 8))
    chars = [chr(get_int(chunk)) for chunk in chunks]
    return "".join(chars)

def decode_image(img):
    bits = get_flat_bits(img)
    assert bits[0] == 1 and bits[1] == 0
    width = get_int(bits[2:18])
    height = get_int(bits[18:34])
    print(f"{width} x {height}")
    image = bits[34 : 34 + width * height].reshape((width, height))
    return image

part_1 = decode_text(img_1)
print(part_1)

part_2 = decode_image(img_2)
plt.imshow(part_2, cmap="gray")
plt.show()