Last active
September 26, 2021 06:34
-
-
Save ryukinix/0ade7bf523713b5bc1b0723755ef4ead to your computer and use it in GitHub Desktop.
Fauux Mystery Decoder for 2021 puzzle
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
# -*- coding: utf-8 -*- | |
# | |
# Copyright © 2021 Manoel Vilela | |
# | |
# @project: Fauux Mystery Decoder for 2021 puzzle | |
# @author: Manoel Vilela | |
# @email: [email protected] | |
# | |
"""Ensure you have installed: | |
pip install numpy av Pillow | |
Execute this script after download blue.mov, green.mov and red.mov files from | |
fauux.neocities.org website. | |
This is only a part of the puzzle. | |
Good luck. | |
""" | |
import typing as T | |
import av | |
import numpy as np | |
from av.video.frame import VideoFrame | |
from PIL import Image | |
files_by_window_size = { | |
"blue.mov": 8, | |
"green.mov": 16, | |
"red.mov": 32 | |
} | |
def address_windowed(idx, x_shape, y_shape, window): | |
x = window * (idx // (x_shape // window)) | |
y = window * (idx % (y_shape // window)) | |
return x, y | |
def video_to_array_frames(video: str) -> T.List[np.array]: | |
video = av.open(video) | |
frames = [] | |
for packet in video.demux(): | |
for frame in packet.decode(): | |
if isinstance(frame, VideoFrame): | |
img = frame.to_image() # PIL/Pillow image | |
arr = np.asarray(img) # numpy array | |
frames.append(arr) | |
return frames | |
def blend_arrays(arrays: T.List[np.array], window: int) -> np.array: | |
array_shape = arrays[0].shape | |
x_shape, y_shape, _ = array_shape | |
array_base = np.zeros(array_shape) | |
for idx, array in enumerate(arrays): | |
x, y = address_windowed(idx, x_shape, y_shape, window) | |
x_w = x + window | |
y_w = y + window | |
array_base[x:x_w, y:y_w, :] = array[x:x_w, y:y_w, :] | |
return array_base | |
def red_blend_arrays(arrays: T.List[np.array]) -> np.array: | |
array_shape = (512, 512, 3) | |
x_shape, y_shape, _ = array_shape | |
array_base = np.zeros(array_shape) | |
window = 32 | |
for idx, array in enumerate(arrays): | |
x, y = address_windowed(idx, x_shape, y_shape, window) | |
x_w = x + window | |
y_w = y + window | |
array_base[x:x_w, y:y_w, :] = array | |
return array_base | |
def convert_array_into_image(array: np.array) -> Image: | |
x = array / array.max() | |
return Image.fromarray((x * 255).astype(np.uint8)) | |
def blend_windowed_video(video_file: str) -> np.array: | |
print(f"Decoding... {video_file}") | |
frames = video_to_array_frames(video_file) | |
if video_file.startswith("red"): | |
return red_blend_arrays(reversed(frames)) | |
else: | |
return blend_arrays(frames, window=files_by_window_size[video_file]) | |
def save_image(image: Image) -> None: | |
image.save("blend.png", format="png") | |
print("Saved blend.png file.") | |
def main(): | |
r = blend_windowed_video("red.mov") | |
g = blend_windowed_video("green.mov") | |
b = blend_windowed_video("blue.mov") | |
blended_array = np.zeros((512, 512, 3)) | |
blended_array[:, :, 0] = r[:, :, 0] | |
blended_array[:, :, 1] = g[:, :, 1] | |
blended_array[:, :, 2] = b[:, :, 2] | |
image = convert_array_into_image(blended_array) | |
save_image(image) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment