Skip to content

Instantly share code, notes, and snippets.

@sausheong
Created November 15, 2011 05:50
Show Gist options
  • Save sausheong/1366279 to your computer and use it in GitHub Desktop.
Save sausheong/1366279 to your computer and use it in GitHub Desktop.
For the Instagram Challenge - Unshredder
require 'rmagick'
include Magick
shredded = ImageList.new "TokyoPanoramaShredded.png" # the original source
ROWS = shredded.rows # number of lines of pixes
working = [] # a working array of images
def strip_width
32
end
# pixel distance is calculated using the Euclidean distance of the 2 pixels
# assuming the RGB is xyz
def dist(p1,p2)
red, green, blue = p1.red - p2.red, p1.green - p2.green, p1.blue - p2.blue
Math.sqrt((red*red) + (green*green) + (blue*blue))
end
# compare pixel distances between the right-most pixel column of shred1 with
# the left-most pixel column of shred2
def compare_shreds(shred1, shred2)
distances = []
ROWS.times do |n| # for every pixel in a narrow strip
pixel1 = shred1.pixel_color(strip_width-1,n)
pixel2 = shred2.pixel_color(0,n)
distances << dist(pixel1, pixel2)
end
distances.inject{|sum,x| sum + x }/ROWS # find the mean
end
# crop individual shreds into a temporary working image list
(shredded.columns/strip_width).times do |n|
working << shredded.excerpt(n*strip_width,0,strip_width,shredded.rows)
end
sequence = [0] # working sequence, starting at 0 but can start at any number
pic_break = 0 # to store the place where the sequence breaks
# iterate through every shred to find correct sequence
working.size.times do
averages = []
working.size.times do |n| # compare this shred with every other shred
averages << compare_shreds(working[sequence.last], working[n])
end
# the next shred should be the one with the left-most pixel column the
# closest pixel distance from the right-most pixel column of the current shred
next_number = averages.index(averages.min)
if next_number == sequence.last # if the next shred is the same as this shred
pic_break = sequence.count # this is where the image break is
sequence << averages.find_index(averages.sort[1]) # use the next closest
else
sequence << next_number
end
end
final_sequence = sequence[pic_break..sequence.count] + sequence[1..pic_break-1]
final_imagelist = ImageList.new
final_sequence.each do |seq|
final_imagelist << working[seq]
end
final_imagelist.append(false).display # display the image
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment