go-board-code/build_image.rb

102 lines
2.5 KiB
Ruby
Executable File

#!/usr/bin/env ruby
require 'rmagick'
class GoBoardPixel
GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL = 65_536 / 8
attr_reader :red, :green, :blue
def self.from_magick(red:, green:, blue:)
new(
red: red / GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL,
green: green / GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL,
blue: blue / GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL
)
end
def initialize(red:, green:, blue:)
@red = red
@green = green
@blue = blue
end
def distance_from_real_pixel(red:, green:, blue:)
(red - @red * GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL)**2 +
(green - @green * GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL)**2 +
(blue - @blue * GO_BOARD_CHANNEL_TO_RMAGICK_CHANNEL)**2
end
def distance_from_go_pixel(red:, green:, blue:)
(red - @red)**2 +
(green - @green)**2 +
(blue - @blue)**2
end
def eql?(other)
red == other.red && green == other.green && blue == other.blue
end
def hash
[red, green, blue].hash
end
end
ImagePixel = Data.define(:red, :green, :blue)
image = Magick::Image.read(ARGV[0]).first
image.change_geometry!('80x60^') do |cols, rows, img|
img.resize!(cols, rows)
end
image.crop!(Magick::CenterGravity, 80, 60, true)
possible_colors = {}
image.each_pixel do |px|
go_px = GoBoardPixel.from_magick(red: px.red, green: px.green, blue: px.blue)
possible_colors[go_px] ||= 0
possible_colors[go_px] += 1
end
pixels_by_usage = possible_colors.sort_by(&:last).reverse
go_board_palette = pixels_by_usage[0..31].map(&:first)
color_mapping = go_board_palette.each_with_index.each_with_object({}) do |(go_px, index), obj|
obj[go_px] = index
end
pixels_by_usage[32..].map(&:first).each do |go_px|
best_match = go_board_palette.each_with_index.map do |target_go_px, index|
[
target_go_px.distance_from_go_pixel(
red: go_px.red,
green: go_px.green,
blue: go_px.blue,
), index
]
end.sort_by(&:first).first
color_mapping[go_px] = best_match.last
end
File.open('image_data.txt', 'w') do |fh|
image.each_pixel do |px|
magick_px = GoBoardPixel.from_magick(
red: px.red, green: px.green, blue: px.blue
)
fh.puts format('%05b', color_mapping[magick_px])
end
end
File.open('palette_data.txt', 'w') do |fh|
go_board_palette.each do |color|
fh.puts format('%09b', ((color.red << 6) + (color.green << 3) + color.blue))
end
end
# [ ] load image
# [ ] downsample to 40x30
# [ ] change to indexed image with go board palette
# [ ] save out body data
# [ ] save out palette data