Image unshredding using a TSP solver
github.com
github.com
The LKH solver used here has rather impressive performance. From http://webhotel4.ruc.dk/~keld/research/LKH/: "LKH has produced optimal solutions for all solved problems we have been able to obtain," and the studies linked there show that it really does find optimal solutions "with an impressively high frequency."
While the point here is to use an off-the-shelf solver, it can be nice to have visibility into what's actually happening:
- This is a reasonable example for explaining some of the local search TSP heuristics. For instance a "2-opt" move corresponds to picking a contiguous range of columns and flipping them.
- The previous HN post used simulated annealing, which would not be an outright terrible approach to TSP itself -- were it not for the better Lin-Kernighan-based approaches (like LKH).
- If we want, we can tell LKH to start from Sangaline's "nearest-neighbor" approach ("INITIAL_TOUR_ALGORITHM = NEAREST-NEIGHBOR"). This does not make a difference here though.
LKH is a lovely piece of work. I used it a couple of years ago to find a counterexample to an unimportant but fairly long-standing conjecture in combinatorics[0], and the list of scientific applications[1] is impressively diverse.
The best SMT solvers are also hugely impressive. Z3 has an excellent interactive tutorial and online solver.[2]
[0] https://arxiv.org/abs/1408.5108 [1] http://webhotel4.ruc.dk/~keld/research/LKH/ScientificApplica... [2] http://rise4fun.com/z3/tutorial
Not to mention the often impressive performance of "general" MIP solvers. It is only a shame that the best ones there are commercial (Gurobi followed by Cplex). That said, Cbc is lovely in a wide range of cases, and is open-source.
It's really basic taxonomy: what sort of problem are we dealing with? If you don't know that, how could you even begin to design a reasonable algorithm for it?
Angr is a very popular framework which allows for symbolic execution of binaries using Z3 as a backend. It's made a whole class of common CTF challenges almost trivial:
For instance, if I assign each pixel a random color and call that my "image", and then scramble all of the pixels, it is easy to see that recovery of the original image is mathematically impossible. However, if I use a photograph of a person standing in front of a car, information gleaned from similar types of photos could be sufficient to allow complete recovery given only the exact distribution of pixel colors. I don't know whether this is true, but I wouldn't be surprised if it is. (Actually, this seems like a fun hobby project. I may give it a shot.)
If enhancing a low-resolution image to regain lost information is basically impossible, getting back a picture from a color histogram would surely be much more impossible.
Here's a more explicit breakdown:
(0,0) (1,0) (2,0)
(0,1) (1,1) (2,1)
(0,2) (1,2) (2,2)
Column scrambling: swap 1&2: (0,0) (2,0) (1,0)
(0,1) (2,1) (1,1)
(0,2) (2,2) (1,2)
Now row scrambling: swap 0&1: (0,1) (2,1) (1,1)
(0,0) (2,0) (1,0)
(0,2) (2,2) (1,2)
Notice how the x coordinates still all match along the vertical, and y coordinates still all match
along the horizontal.Let's try it in the other order, row first:
(0,1) (1,1) (2,1)
(0,0) (1,0) (2,0)
(0,2) (1,2) (2,2)
And columns: (0,1) (2,1) (1,1)
(0,0) (2,0) (1,0)
(0,2) (2,2) (1,2)
It's the same result irrespective of the order.You can try it yourself, if you’ve cloned the repo. Here are the commands to reconstruct first by columns and then by rows:
git checkout double-shuffling
make images/double_shuffled/blue-hour-paris.png bin/compute_scores
mkdir tmp
bin/compute_scores --cols images/double_shuffled/blue-hour-paris.png > tmp/cols.tsp
bin/lkh.sh tmp/cols.tsp tmp/cols.tour
bin/reconstruct_image.py --cols tmp/cols.tour images/double_shuffled/blue-hour-paris.png > tmp/cols-unshuffled.png
bin/compute_scores --rows tmp/cols-unshuffled.png > tmp/rows.tsp
bin/lkh.sh tmp/rows.tsp tmp/rows.tour
bin/reconstruct_image.py --rows tmp/rows.tour tmp/cols-unshuffled.png > tmp/reverse-unshuffled.pngit shows that naturally occurring images are organized by having similar rows and columns close to each other, which is - by default - good for most compression algorithms that prefer regularities/similarities to be as local as possible.
edit: but it can be good for other cases, where there are no good-enough default orders. For example "customer - product bought" matrix (binary matrix, customer rows, product columns: X customer bought Y product = 1, otherwise =0 ).
Here the order of rows/columns are not predefined, and ordering by similar customers and products the compression of the matrix could be improved. Finding these similarities also can be a good starting point for some recommendation/collaborative filtering engine.
1.6 seconds to make the TSPLIB2 file representing the dissimilarity graph. (time make tsp/instances/blue-hour-paris.tsp)
0.3 seconds to run the solver and produce the optimal tour. (time make tsp/tours/blue-hour-paris.tour)
0.4 seconds to reconstruct the image from the shuffled version using the tour. (time make images/reconstructed/blue-hour-paris.png)
I'd be inclined to believe that with some assumptions on the problem itself (e.g. the images satisfy some smoothness assumptions and of course, assumptions on the objective, itself), we can always come up with a PTAS for this particular instance for any accuracy, ε>0.
I have a disk image of jpegs and other data I'd like recovered. It was Windows formatted a few different ways but any blocks that format didn't touch are still there.
There's other data there of course as well, so there would be lot of blocks that aren't part of images so would need to be ignored when reassembling the images.
That said, I'm sure I could be surprised by what is possible.
In cases where there is a version that compresses better, unshuffling might not work. If you had an "pinstripe" image consisting of alternating black and white columns of pixels, obviously it could compress better after being "shuffled" with all the similarly colored columns together. But then this algorithm would be unable to get the original image back.