• Stars
    star
    607
  • Rank 73,351 (Top 2 %)
  • Language
    C
  • Created almost 8 years ago
  • Updated almost 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Image unshredding using a TSP solver

Introduction

Yesterday I saw a fun demo by Nayuki using simulated annealing to reconstruct photographs whose columns have been shuffled.

For example, the photograph Blue Hour in Paris (CC licensed by Falcon® Photography):

Blue hour in Paris

is shuffled to produce:

Blue hour in Paris, shuffled

and the simulated annealing algorithm (starting temperature 4000, 1 billion iterations) reconstructs this:

Blue hour in Paris, reconstructed using simulated annealing

Subsequently Sangaline showed that the images can be reconstructed faster and more effectively using a simple greedy algorithm to pick the most-similar column at each step. The greedy algorithm produces this:

Blue hour in Paris, reconstructed using a greedy algorithm

which is quite close to the original, though you can see some misplaced columns in the sky at the right.

Image unshredding is an instance of the Travelling Salesman Problem

Our task is to piece the columns of pixels together so that, over all, adjacent columns are as similar as possible. Think of the columns as being nodes in a weighted graph, with the edge-weight between two columns being a dissimilarity measure. Then we are looking for a Hamiltonian path of minimum weight in the graph. So it is an instance of the Travelling Salesman Problem.

(A small technical note: since we want a Hamiltonian path rather than a Hamiltonian cycle, we add a dummy node to the graph that has weight-0 edges to all the other nodes. If we can find a least-weight Hamiltonian cycle on this augmented graph, we remove the dummy node to obtain a least-weight Hamiltonian path on the original graph.)

This project

This project uses a fast approximate solver for the Travelling Salesman Problem to reconstruct the images quickly and perfectly.

Blue hour in Paris, reconstructed using LKH

You will notice that the image is flipped, but otherwise reconstructed perfectly. It is impossible in general to distinguish an image from its flipped version when the columns have been shuffled, and all the algorithms mentioned here produce flipped reconstructions half the time.

Apart from that, I believe this algorithm can correctly reconstruct all the images in Nayuki’s demo.

The dissimilarity measure matters

One interesting thing I found is that the result is sensitive to the dissimilarity measure used. I have used the same measure as the other projects mentioned here: the sum of the absolute values of the differences in the R/G/B channels, summed over all pixels in the column. If instead we use the square rather than the absolute value, the image is reconstructed incorrectly as follows:

Blue hour in Paris, reconstructed using LKH

This is not a failure of the TSP algorithm: in fact this mangled image has a better score than the original, using the sum-of-squares measure!

Running the code

  • Clone the repository
  • Run make to download and shuffle the images, and download and compile LKH.
  • Now you can run make reconstruct to reconstruct the images from their shuffled versions using LKH.

You can also run make nayuki to reconstruct the images using Nayuki’s simulated annealing code.

Prerequisites

You will need a working build environment (Make and a C compiler), and curl is used to download files from the web. You also need libpng >= 1.6 (which the Makefile assumes to be in /usr/local, but that is easy to change). The simpler bits of image manipulation are done using Python 2 and require the Python Imaging Library or a compatible fork such as Pillow.

Double-shuffling

It is perhaps not surprising, but rather striking, that if we shuffle the columns and then the rows to obtain a really scrambled-looking image like this:

Blue hour in Paris, shuffled by columns and then by rows

that it can nevertheless be reconstructed perfectly by applying the algorithm twice, first to the rows and then to the columns. Of course now the result may be flipped vertically as well as horizontally, but in this case I happened to get lucky twice and it came out in the same orientation as the original:

Blue hour in Paris, reconstructed from the double-shuffled version

The code for the double-shuffling and reconstruction is in the branch double-shuffling. Switch to that branch and run make double_reconstruct to try it.

More Repositories

1

freckle-command

freck – A friendly command-line interface for Freckle
Python
14
star
2

write-to-mp

Allow people to write to their MP about an issue, with appropriate advice on what to say
Python
11
star
3

PadWalker

Perl module for lexical variable introspection
XS
10
star
4

xbrl-extractor

Extract data from Companies House accounts
Python
9
star
5

maze-experiments

Various bits of experimental code that do things with or related to mazes
Python
8
star
6

pdftk

An unofficial fork of Pdftk
Java
8
star
7

Want

Perl module generalising the wantarray function, allowing a function to determine in some detail how its return value is going to be immediately used
Perl
6
star
8

cartograms

Code for generating area cartograms
C
6
star
9

fibonacci-float-calc

Calculating Fibonacci numbers using floating-point arithmetic
C
6
star
10

clean-sheet

http://www.clean-sheet.org/
HTML
5
star
11

wdg-html-validator

An OS X packaging of wdg-html-validator
Clean
4
star
12

AMEE-Python-interface

A simple Python interface to the AMEE API, designed to work on Google App Engine.
Python
4
star
13

doyle-spirals

Doyle spirals
JavaScript
4
star
14

newman-cart

Mark Newman’s cartogram generation code
C
3
star
15

opencorporates-bot

A simple Open Corporates bot to scrape Regulated Entities from the British Virgin Islands Financial Services Commission
Ruby
2
star
16

svgtopng

A simple script to render SVG files to PNG, using Apache Batik
Java
2
star
17

hinged-dissections

Animations of hinged dissections
Python
1
star
18

process-runner

A simple client/server for running processes, designed for handling long-running processes from a web app.
Python
1
star
19

mazify

Make anything into a maze!
Shell
1
star
20

mizzazify

Make images into mazes
Python
1
star
21

mazing

Random access to mazes
C
1
star
22

land-matrix-map

Land Matrix map
JavaScript
1
star
23

toss140

A crowdsourced summary of newspaper columnists
Python
1
star
24

linear-logic-without-units

My 2007 PhD thesis
1
star
25

HMG-Petitions-Twitterstream

Makes a tweet-stream of UK Government e-petitions (@UKPetitions)
Python
1
star
26

flow-viz

Stream visualisation of vector fields
JavaScript
1
star
27

bounding-balls

JavaScript
1
star
28

prisoners-dilemma

Interactive demo of Press-Dyson strategies
JavaScript
1
star
29

TheySpentWhat

Python
1
star
30

allrgb

Image generation à la allrgb.com
C
1
star
31

coins

Find all the ways to make a specified amount from a specified number of specified coins
HTML
1
star