imagepython-imaging-libraryimage-rotationscramblectf

Unscrambling rotation of jpeg concentric pixel blocks


As part of a 'Capture The Flag' challenge the attached jpg was scrambled to obscure the content. The image ("flagpoles.jpg") is 1600 pixels by 1600 pixels. The concentric lines appear to have a blocksize of 10 pixels wide. (It resembles a Frank Stella painting). It appears the original image has been split into four portions which are arranged symmetrically around the center. I have been trying to write a python script to work through the pixels and unscramble the concentric squares. My efforts have resulted in two useless recurring conditions, either no change or increased scrambling. I think this might be because I am working on the entire image and it might be better to try and unscramble part of it. Here is the code I have. At the moment it only processes half of the pixels because I am trying to match up portions of the picture with each other. I tried sending the blocks to the other side of the image to try and match them up, but there is no improvement. Any assistance in getting a clear picture would be gratefully received.

from PIL import Image
import math

im = Image.open("flagpoles.jpg", "r")
pic = im.load() 

def rot(A, r, x1, y1): 
    myArray = []
    for i in range(r):
        myArray.append([])
        for j in range(r):
            myArray[i].append(pic[x1+i, y1+j])
    for i in range(r):
        for j in range(r):
            pic[x1+i,y1+j] = myArray[r-1-i][r-1-j]

xres = 800
yres = 800
blocksize = 10 
for i in range(blocksize, blocksize+1):
    for j in range(int(math.floor(float(xres)/float(blocksize+2+i)))):
        for k in range(int(math.floor(float(yres)/float(blocksize+2+i)))):
            rot(pic, blocksize+2+i, j*(blocksize+2+i), k*(blocksize+2+i))

im.save("hopeful.png")

print("Finished!")

enter image description here


Solution

  • The image seems to consist of concentric square boxes of width 10 pixels, each rotated by 90° relative to the previous one. After every four rotations, the pixels are once again oriented in the same direction.

    You can easily undo this by making a copy of the image and repeatedly rotating by 270° while cropping away a 10 px border. Paste these rotated images back into the corresponding locations to retrieve the original image.

    from PIL import Image
    
    step_size = 10
    angle_step = 270
    img = Image.open("flagpoles.jpg", "r")
    img.load() 
    w = img.width
    assert img.height == w
    img_tmp = img.copy()        # Copy of the image that we're going to rotate
    offset = 0                  # Coordinate where the rotated images should be pasted
    cropmax = w - step_size     # Maximum coordinate of cropping region
    
    while cropmax > step_size:
        # Rotate the copy of the image
        img_tmp = img_tmp.rotate(angle_step)
        # Paste it into the original image
        img.paste(img_tmp, (offset,offset))
        # Crop a 10 px border away from the copy
        img_tmp = img_tmp.crop((step_size, step_size, cropmax, cropmax))
        # Update the crop position and width for the next iteration
        cropmax -= step_size * 2
        offset += step_size
    
    img.save("fixed.jpg")