Тема: Як виділити найбільш вживані, але різні кольори на картинці?
Добрий вечір, я диспетчер.
Уявіть собі, шо ви бачите хмаринку, і вона складається хоч і з різних кольорів, але подібних. Вона має тіні та підсвічування, є якісь геть темні кольори, але їх може бути небагато, а інших, сірих, може бути багато.
Як можна виділити декілька кольорів, з яких потім можна намалювати цю саму хмаринку, але не такою деталізованою за рахунок меншої кількості кольорів?
Поки що мій алгоритм такий:
1. порахувати кількість пікселів кожного кольору
2. обрати 5 (для прикладу) найбільш вживаних кольорів
3. пройтись по всім пікселям і порахувати, до якого з тих п'яти кольорів цей піксель найбільш подібний, і замінити його цим кольором
Алгоритм порівняння кольорів дуже простий, це просто довжина вектору, що складається зі значення червоного, зеленого і синього кольорів пікселя.
Ось код на рубі
require 'rmagick'
include Magick
def color_length(color)
Math.sqrt(
color.red**2 +
color.green**2 +
color.blue**2
)
end
image = Image.read('./makoto_cloud123.png').first
colors = Hash.new(0)
image.each_pixel do |pixel, _c, _r|
next if pixel.alpha < 65_535
name = pixel.to_s
if colors.key? name
colors[name][:count] += 1
else
colors[name] = { count: 1, length: color_length(pixel), pixel: pixel }
end
end
top_5 = colors.sort_by { |_key, value| -value.count }.first 5
top_5_hash = top_5.to_h
puts(colors.max_by { |_color, info| info[:pixel].alpha })
colors.delete_if { |key, _value| top_5_hash.key? key }
image.each_pixel do |pixel, c, r|
next if pixel.alpha < 65_535
name = pixel.to_s
next unless colors.key? name
closest_color = top_5_hash.min_by { |_color, info| (info[:length] - colors[name][:length]).abs }
image.pixel_color(c, r, closest_color[1][:pixel])
end
# Save the modified image
image.write('./makoto_simple.png')
але воно шось не виходе.
На вхід даю таку картинку
а на виході отаке