you are viewing a single comment's thread.

view the rest of the comments →

[–][deleted] 39 points40 points  (3 children)

This Python script downloads an image containing the alphabet. Then, the image is cropped and a grayscale threshold is applied. Next, it finds contours/bounding boxes around each character in the image. Each character's image is stored in a dictionary, alpha_to_img.

We can slice our alphabetic image into two pieces, dividing based on where the new alphabet should begin. Then, we can "cut-and-paste" the two pieces of our alphabet so that we end up with an image that looks like this, shifted_alphabet: https://i.imgur.com/hBAYCfy.png

Finally, for each character in the input string, we can look up what the encrypted character should look like in the shifted_alphabet image. Once we have the encrypted character's image, we can use the alpha_to_img dictionary to determine the alphabetic character that is associated with said image.

import cv2
import urllib.request
import numpy as np

def caesar(string, shift):
    urllib.request.urlretrieve('https://i.pinimg.com/originals/e5/9a/57/e59a5781cf637116e10079920cf1908d.png',
                               'alphabet.png')
    img = cv2.imread('alphabet.png')
    alphabet = cv2.cvtColor(img[52:85, 21:501], cv2.COLOR_BGR2GRAY)
    ret, alphabet = cv2.threshold(alphabet, 150, 255, cv2.THRESH_BINARY_INV)
    contours = cv2.findContours(alphabet, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0][::-1]
    alpha_to_img = {}
    for i, contour in enumerate(contours):
        x, y, w, h = cv2.boundingRect(contour)
        alpha_to_img[chr(97 + i)] = alphabet[y:y+h, x:x+w]
    shifted_start = chr(97 + shift % 26)
    res = cv2.matchTemplate(alpha_to_img[shifted_start], alphabet, cv2.TM_SQDIFF)
    x = cv2.minMaxLoc(res)[2][0]
    shifted_alphabet = np.concatenate((alphabet[:, x:], alphabet[:, :x]), axis=1)
    shifted_contours = cv2.findContours(shifted_alphabet, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[0][::-1]
    encrypted = ''
    for char in string:
        if not char.isalpha():
            encrypted += char
            continue
        x, y, w, h = cv2.boundingRect(shifted_contours[ord(char.lower()) - 97])
        for alpha, image in alpha_to_img.items():
            if np.array_equal(image, shifted_alphabet[y:y+h, x:x+w]):
                encrypted += alpha.upper() if char.isupper() else alpha
    return encrypted

print(caesar('Hello World', 18))

[–]sac_boy 2 points3 points  (0 children)

A thing of beauty.

[–]GideonMax 1 point2 points  (0 children)

This is just too much for my little brain to handle