По условию задачи у нас есть странная картинка и описание: «Этот лабиринт скрывает в себе флаг». Также известна категория – misc, то есть тут может быть что угодно, но сложность обозначена easy, значит, ничего сложного или глубокого искать не нужно.
Текст задачи странноват и ничего не проясняет, поэтому стоит посмотреть на саму картинку.
Тут мы видим структуру QR-кода
Если внимательно посмотреть на картинку, можно узнать структуру QR-кода, только на нём не хватает трёх квадратов по углам, которые служат маркерами для позиционирования камеры. Такие квадраты всегда расположены в одних и тех же углах – левом верхнем, левом нижнем и правом нижнем. Но наш «лабиринт» имеет пустые места в других углах, что наталкивает на мысль: картинка из задачи повёрнута.
Чтобы камера или сканер смогли прочитать данные, нужно развернуть изображение на 90 градусов по часовой стрелке и добавить три квадратика по углам, за которые «зацепится» сканер и «поймёт», как считать данные.
QR-код может быть любого цвета – это не проблема для сканеров, но привычнее для человека, когда цвета контрастные: чёрно-белые.
Теперь полностью понятно, как восстановить данные и прочитать их. Остаётся только обработать картинку из задачи. Всё это вполне реально и быстро сделать в любом графическом редакторе. Но, чтобы разбор был интереснее, часть манипуляций сделаем кодом на Python: повернём картинку на 90 градусов и сделаем цвета чёрно-белыми. Ниже код, который это выполняет:
from PIL import Image
import numpy as np
def replace_colors_flexible(image_path, output_path, tolerance=0):
img = Image.open(image_path)
# Получаем размеры картинки
width, height = img.size
# Создаем новое изображение
new_img = Image.new('RGB', (width, height))
# Обрабатываем каждый пиксель
for x in range(width):
for y in range(height):
r, g, b = img.getpixel((x, y))
# Проверяем, является ли пиксель зелным (#01AB01)
# Проверка с учетом расхождения на tolerance
if (abs(r - 1) <= tolerance and
abs(g - 171) <= tolerance and
abs(b - 1) <= tolerance):
# Меняем цвет пикселя на черный
new_img.putpixel((x, y), (0, 0, 0))
# Проверяем, является ли пиксель черным
# Проверка с учетом расхождения на tolerance
elif (abs(r - 0) <= tolerance and
abs(g - 0) <= tolerance and
abs(b - 0) <= tolerance):
# Меняем цвет пикселя на белый
new_img.putpixel((x, y), (255, 255, 255))
else:
# Оставляем без изменений непонятные цвета
new_img.putpixel((x, y), (r, g, b))
new_img.save(output_path)
def rotate_image(image_path, output_path):
img = Image.open(image_path)
rotated_img = img.transpose(Image.ROTATE_270)
rotated_img.save(output_path)
if __name__ == "__main__":
# Заменяем зелный зелный на черный, а черный на белый.
# С допуском отличая цвета в 50 едениц(от 0 до 255)
replace_colors_flexible("maze.png", "output.png", tolerance=50)
# Поворачиваем картинку на 90 градусов по часовой стрелке
rotate_image("output.png", "output-rotated.png")
Остаётся только «прилепить» три квадрата по углам – и можно считывать данные любым телефоном или онлайн-сканером.
И напоследок ещё один вариант обработки – магия от Пикси.