Skip to content

Instantly share code, notes, and snippets.

@carl-ellis
Created June 27, 2011 15:49
Show Gist options
  • Select an option

  • Save carl-ellis/1049124 to your computer and use it in GitHub Desktop.

Select an option

Save carl-ellis/1049124 to your computer and use it in GitHub Desktop.
Code Brawl #2
Pixelise!
=========
This has two pixelising function, a straight average of the colour channels in a given block, or a weighted mean based
upon a two dimensional normal distribution.
The code uses the weighted version, but the other is kept on for display purposes.
Name your image "input.png" and run the program.
require 'chunky_png'
# 2d gaussian
#
# @params x x coord
# @params y y coord
# @params w width of sample
# @params h height of sample
def twodguass(x,y,w,h)
#distro constants
big_a = 1
a = 0.5
b = 0
c = 0.5
x_0 = w/2
y_0 = h/2
p1 = a*((x-x_0)**2)
p2 = 2*b*((x-x_0)*(y-y_0))
p3 = c*((y-y_0)**2)
p = (p1+p2+p3)*-1
return big_a*(Math.exp(p))
end
# Pixelise functions
# Return the average colour of a given area
#
# @params image image to manipulate
# @params x x coord
# @params y y coord
# @params w width of area
# @params h height of area
def av_area(image, x, y, w, h)
# image meta for error checking
i_w = image.width
i_h = image.height
# Total area
tot = w*h
# average bins
av_r = 0
av_g = 0
av_b = 0
# fill bins
(0...w).each do |i|
(0...h).each do |j|
if(x+i >= i_w || y+j >= i_h)
tot -=1
else
raw = image[x+i,y+j]
av_r += ChunkyPNG::Color.r(raw)
av_g += ChunkyPNG::Color.g(raw)
av_b += ChunkyPNG::Color.b(raw)
end
end
end
# divide bins
av_r /= tot
av_g /= tot
av_b /= tot
return ChunkyPNG::Color.rgb(av_r, av_g, av_b)
end
# Return the weighted average colour of a given area
#
# @params image image to manipulate
# @params x x coord
# @params y y coord
# @params w width of area
# @params h height of area
def w_av_area(image, x, y, w, h)
# image meta for error checking
i_w = image.width
i_h = image.height
# Total weight
tot = 0
# average bins
av_r = 0
av_g = 0
av_b = 0
# fill bins
(0...w).each do |i|
(0...h).each do |j|
if(x+i >= i_w || y+j >= i_h)
else
weight = twodguass(i,j,w,h)
tot += weight
raw = image[x+i,y+j]
av_r += ChunkyPNG::Color.r(raw) * weight
av_g += ChunkyPNG::Color.g(raw) * weight
av_b += ChunkyPNG::Color.b(raw) * weight
end
end
end
# divide bins
av_r /= tot
av_g /= tot
av_b /= tot
return ChunkyPNG::Color.rgb(av_r.to_i, av_g.to_i, av_b.to_i)
end
# Pixelise function
#
# @params image image to pixelise
# @params b_w block width
# @params b_h block height
#
# @return pixelised image
def pixelise(image, b_w, b_h)
# Get image size
w = image.width
h = image.height
# Number of blocks
nbx = (w/b_w.to_f).ceil
nby = (h/b_h.to_f).ceil
# Go through each "block" in the image
(0...nbx).each do |p_x|
(0...nby).each do |p_y|
# Top left coord
x = p_x * b_w
y = p_y * b_h
# Get the average colour of the block
p_colour = w_av_area(image, x, y, b_w, b_h);
# Fill in block
(0...b_w).each do |x1|
(0...b_h).each do |y1|
# Fill in up to edges
image[x+x1,y+y1] = p_colour if !(x+x1 >= w || y+y1 >= h)
end
end
end
end
return image
end
### Script
# Grab image
image = ChunkyPNG::Image.from_file('input.png')
# Size of pixeled area
b_w = 10
b_h = 10
# Run the pixelisation
image = pixelise(image, b_w, b_h)
# save
image.save('output.png')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment