Created
March 30, 2011 17:44
-
-
Save jeffkreeftmeijer/894864 to your computer and use it in GitHub Desktop.
Counting blobs in an image in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'chunky_png' | |
image = ChunkyPNG::Image.from_file('blobs.png') | |
# First, we need to map the image to data we can use. We'll give any pixel that | |
# is (completely) black in the original image a value of 0 and the pixels that | |
# have color get a value of 1 (in the blobs_bw.png image, this is illustrated | |
# by making every colored pixel black and leaving the others transparent): | |
image.pixels.map! { |pixel| pixel == ChunkyPNG::Color::BLACK ? 0 : 1 } | |
# Now, the image's pixels are mapped to a matrix. Here's the whole thing, by | |
# row: | |
# | |
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0] | |
# [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0] | |
# [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0] | |
# [0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0] | |
# [0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0] | |
# [0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0] | |
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0] | |
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0] | |
# [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0] | |
# [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0] | |
# [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] | |
# To calculate how many blobs are in this image, we need to count the corners | |
# in the image (because the blobs are _not_ round, they're built up from square | |
# pixels, remember?): | |
corners = 0 | |
image.height.times do |row| | |
image.row(row).each_with_index do |pixel, index| | |
# For every pixel on every row, we figure out its neighborhood. In this | |
# case, we're using a 2x2 one, so we'll get the row and pixel index and | |
# add one to get the pixel on the right of the current one, the pixel below | |
# and the one right from the one below. We'll store the sum of the pixel | |
# values in `neighborhood`. | |
if image.include_x?(index + 1) && image.include_y?(row + 1) | |
neighborhood = | |
image[index, row] + | |
image[index + 1, row] + | |
image[index, row + 1] + | |
image[index + 1, row + 1] | |
# Recognising an external or internal corner is easy. An external one | |
# looks like the one on the left and an internal one looks like the one | |
# on the right: | |
# | |
# [0,0] [0,1] | |
# [0,1] [1,1] | |
# | |
# Using that, we know that a `neighborhood` with a value of 3 represents | |
# an internal corner and one with a value of 1 means it's an external | |
# corner. | |
# | |
# After counting the corners, we subtract the internal corners from the | |
# external ones: | |
corners += 1 if neighborhood == 1 | |
corners -= 1 if neighborhood == 3 | |
end | |
end | |
end | |
# The output will be a multiple of four, so dividing the result by four will | |
# give us the result we're looking for: | |
puts corners / 4 # 3 | |
# If you have any comments or know a way to improve the code, please let me | |
# know! I'm still totally new to this stuff myself but I decided to write about | |
# it while learning to better understand it myself. Why I'm not publishing this | |
# on my blog? I don't know.. Would you like to read more about this stuff? :) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment