worked on the chall
This commit is contained in:
90
solve.py
90
solve.py
@@ -1,13 +1,13 @@
|
||||
from logging import disable
|
||||
from PIL import Image
|
||||
from pyzbar.pyzbar import decode
|
||||
import itertools
|
||||
from math import perm
|
||||
from tqdm import tqdm
|
||||
import numpy as np
|
||||
from multiprocessing import Pool
|
||||
from math import perm
|
||||
import sys
|
||||
|
||||
NUM_PIECES_WIDTH = 4
|
||||
NUM_PIECES_HEIGHT = 3
|
||||
BOX_SIZE = 2
|
||||
TILE = 78
|
||||
# 7x7 finder, upscaled to 14x14 (black=1, white=0)
|
||||
@@ -40,23 +40,17 @@ def cut_pieces(image):
|
||||
# Get the size of the image
|
||||
width, height = image.size
|
||||
|
||||
# Calculate the size of each grid cell
|
||||
cell_width = width // NUM_PIECES_WIDTH
|
||||
cell_height = height // NUM_PIECES_HEIGHT
|
||||
if width == height:
|
||||
NUM_PIECES_WIDTH = 3
|
||||
else:
|
||||
NUM_PIECES_WIDTH = 4
|
||||
|
||||
NUM_PIECES_HEIGHT = 3
|
||||
|
||||
pieces = []
|
||||
|
||||
# Split the original image into 12 pieces
|
||||
for i in range(NUM_PIECES_WIDTH * NUM_PIECES_HEIGHT):
|
||||
# Calculate the coordinates of the current grid cell
|
||||
x1 = (i % NUM_PIECES_WIDTH) * cell_width
|
||||
y1 = (i // NUM_PIECES_WIDTH) * cell_height
|
||||
x2 = x1 + cell_width
|
||||
y2 = y1 + cell_height
|
||||
|
||||
# Crop the corresponding part of the original image
|
||||
cropped_piece = image.crop((x1, y1, x2, y2))
|
||||
pieces.append(cropped_piece)
|
||||
for x, y in [(x, y) for x in range(NUM_PIECES_WIDTH) for y in range(NUM_PIECES_HEIGHT)]:
|
||||
pieces.append(image.crop((x * TILE, y * TILE, x * TILE + TILE, y * TILE + TILE)))
|
||||
|
||||
return pieces
|
||||
|
||||
@@ -72,7 +66,6 @@ def finder_corner_exact(tile_bw):
|
||||
'TL': tile_bw[0:H, 0:W ],
|
||||
'TR': tile_bw[0:H, TILE-W:TILE ],
|
||||
'BL': tile_bw[TILE-H:TILE, 0:W ],
|
||||
'BR': tile_bw[TILE-H:TILE, TILE-W:TILE ],
|
||||
}
|
||||
for corner, crop in crops.items():
|
||||
if np.array_equal(crop, TEMPLATE):
|
||||
@@ -90,11 +83,33 @@ def three_tiles_with_finders(tiles):
|
||||
break
|
||||
return hits
|
||||
|
||||
def solve_combo(combo):
|
||||
"""
|
||||
Function to be executed by each process in the pool.
|
||||
"""
|
||||
a, b, c, d, e, f = combo
|
||||
# Assuming `new_image` is a base image you can copy or an in-memory image object.
|
||||
# You may need to pass `new_image` to the function or have it loaded by each process.
|
||||
local_image = new_image.copy() # Make a copy to avoid race conditions
|
||||
local_image.paste(a, (78, 0))
|
||||
local_image.paste(b, (0, 78))
|
||||
local_image.paste(c, (78, 78))
|
||||
local_image.paste(d, (156, 78))
|
||||
local_image.paste(e, (78, 156))
|
||||
local_image.paste(f, (156, 156))
|
||||
|
||||
output = decodeQRCode(local_image)
|
||||
if output:
|
||||
return output
|
||||
return None
|
||||
|
||||
if __name__ == "__main__":
|
||||
img = Image.open("./scrambled_test_qr_code.png")
|
||||
|
||||
def main(img_path="student_fair/secret_message.png", verbose=True):
|
||||
img = Image.open(img_path)
|
||||
global new_image
|
||||
new_image = Image.new("RGB", (img.height, img.height))
|
||||
|
||||
|
||||
pieces = cut_pieces(img)
|
||||
corners = three_tiles_with_finders(pieces)
|
||||
|
||||
@@ -110,22 +125,27 @@ if __name__ == "__main__":
|
||||
|
||||
|
||||
pieces = [piece for piece in pieces if piece not in [tile for tile, _ in corners]]
|
||||
assert len(pieces) == 9
|
||||
new_image.show()
|
||||
possible_combos = itertools.permutations(pieces, 6)
|
||||
num_possible_combos = perm(len(pieces), 6)
|
||||
print(f"Testing {num_possible_combos} combinations")
|
||||
|
||||
for a,b,c,d,e,f in tqdm(possible_combos, total=num_possible_combos):
|
||||
new_image.paste(a, (78, 0))
|
||||
new_image.paste(b, (0, 78))
|
||||
new_image.paste(c, (78, 78))
|
||||
new_image.paste(d, (156, 78))
|
||||
new_image.paste(e, (78, 156))
|
||||
new_image.paste(f, (156, 156))
|
||||
output = decodeQRCode(new_image)
|
||||
if output:
|
||||
print(output)
|
||||
result = None
|
||||
|
||||
MAX_WORKER = 6
|
||||
|
||||
print(decodeQRCode(img))
|
||||
# Use `multiprocessing.Pool` with the number of available cores
|
||||
with Pool(MAX_WORKER) as pool:
|
||||
# `imap_unordered` returns results as they are completed.
|
||||
# This is a lazy iterator, so it doesn't create all combos at once.
|
||||
# `tqdm` can still be used to show progress.
|
||||
for result in tqdm(pool.imap_unordered(solve_combo, possible_combos), total=perm(len(pieces), 6), disable=(not verbose)):
|
||||
if result:
|
||||
if verbose:
|
||||
print(f"QR Code decoded: {result}")
|
||||
pool.terminate() # Stop all worker processes
|
||||
break
|
||||
|
||||
return result
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user