Можно ли получить средний цвет изображения с помощью RMagick?

Мне нужно знать средний цвет изображения, когда я загружаю его в свое приложение Ruby on Rails. Можно ли получить среднее значение цвета в HEX или RGB, чтобы использовать этот цвет позже в представлении, которое будет отображать это изображение?

Что-то типа:

img =  Magick::Image.read(path).first
hexVal = img.getHexValue

person Mr_Nizzle    schedule 02.03.2011    source источник
comment
Как я спросил в вашем связанном вопрос с использованием JavaScript: вам нужен только точный цвет пикселя или в пределах определенного диапазона HSV? (Я бы предположил, что последний будет служить вам лучше.)   -  person Phrogz    schedule 02.03.2011


Ответы (6)


Изменить размер изображения на один пиксель и получить его цвет?

img =  Magick::Image.read(path).first
pix = img.scale(1, 1)
averageColor = pix.pixel_color(0,0)
person stef    schedule 02.03.2011
comment
(Очень) быстрый тест показал, что это намного быстрее, чем использование color_histogram. - person joost; 23.07.2014
comment
Действительно умное решение! +1 - person bodacious; 09.04.2015
comment
Мы получаем объект Magick::Pixel, но если нам нужен rgb в шестнадцатеричном формате, как это использует css (например, #f0a1b2), как мы можем это сделать? На него отвечает tingel2k ниже - person Aleksandrus; 15.10.2016

Я не думаю, что вы можете напрямую запросить у изображения RMagick его средний цвет, но вычислить такую ​​вещь не так уж сложно.

Я думаю, что самым простым способом было бы извлечь цветовую гистограмму, а затем использовать чтобы вычислить среднее значение. Вы, вероятно, захотите сначала квантовать изображение, вычислив гистограмму для изображения с большим количеством цветов - это недешево и, вероятно, бессмысленная работа, если вас интересует только среднее значение:

total = 0
avg   = { :r => 0.0, :g => 0.0, :b => 0.0 }
img.quantize.color_histogram.each { |c, n|
    avg[:r] += n * c.red
    avg[:g] += n * c.green
    avg[:b] += n * c.blue
    total   += n
}
[:r, :g, :b].each { |comp| avg[comp] /= total }

Это даст вам средний цвет в avg. Но цвет будет во внутреннем формате ImageMagick (то есть компоненты будут варьироваться от нуля до Magick::QuantumRange), поэтому вам придется уменьшить их до 0-255:

[:r, :g, :b].each { |comp| avg[comp] = (avg[comp] / Magick::QuantumRange * 255).to_i }

И, наконец, у вас есть компоненты RGB в avg как целые числа от нуля до 255, и получение среднего цвета в шестнадцатеричном формате должно быть тривиальным. При желании вы можете легко объединить это с шагом усреднения.

Я, вероятно, мог бы быть умнее с итераторами, но .each хорош и ясен, а ясность важнее, чем ум.

Вы также можете попробовать с шагом квантования и без него и использовать тот, который лучше всего подходит для изображений, с которыми вы работаете.

person mu is too short    schedule 02.03.2011
comment
@zarazan: Этот блог датирован 5 июля 2011 года, мой ответ был опубликован 2 марта 2011 года. - person mu is too short; 14.02.2013
comment
@muistooshort Если все, что делает функция квантования, это делает изображение менее сложным, взяв средние значения цветов пикселей (при условии) - было бы еще проще, если бы вы просто квантизировали изображение до цвета, например: - person sfkaos; 29.04.2013
comment
@sfkaos: я предполагаю, что недостающая часть вашего комментария касается квантования изображения до одного цвета. Это может сработать, и я предполагаю, что это будет иметь тот же эффект, что и stef, масштабирует его до одного пикселя. Я не уверен, что лежащие в основе алгоритмы будут делать с палитрой, однако я хотел бы запустить несколько тестов, чтобы увидеть, что происходит с реальными изображениями. Неплохая идея однако. - person mu is too short; 29.04.2013

Я нашел свое решение (здесь) после того, как протестировал все возможности, представленные здесь. .

def maincolor()
  img =  Magick::Image.read(self.url).first
  pix = img.scale(1, 1)
  avg_color_hex = pix.to_color(pix.pixel_color(0,0))
  return avg_color_hex
end

Надеюсь, это поможет. Я добавил преобразование в шестнадцатеричный цвет с помощью rmagick, потому что это лаваш с рубином (в противном случае я использовал преобразование sprintf в шестнадцатеричное)

person tingel2k    schedule 28.01.2014
comment
К сожалению, этот метод иногда возвращает неверные шестнадцатеричные цвета. Пример: #AAC5C3F1. - person Ricardo Otero; 24.03.2014
comment
Хм... Я не уверен. Откуда я могу это знать? Или как я могу преобразовать изображение? - person Ricardo Otero; 26.03.2014
comment
Привет, прочтите здесь -› github.com/rmagick/rmagick/blob /master/examples/identify.rb , вы можете получить информацию о глубине цветового канала. - person tingel2k; 28.03.2014

Рассмотрите возможность использования драгоценного камня miro, который, кажется, следует подходу «mu is too short»: https://github.com/jonbuda/miro

person Benissimo    schedule 27.02.2012

Согласно @muistooshort - если вся функция квантования делает изображение менее сложным, взяв средние значения цветов пикселей (при условии), - было бы еще проще, если бы вы просто квантизировали изображение до цвета, например:

img.quantize(1,Magick::RGBColorspace).color_histogram

И просто использовать полученный цвет?

person sfkaos    schedule 29.04.2013

Рассмотрите возможность использования гема доминирующих цветов рельсов, https://github.com/OpenGems/rails_dominant_colors

person Boris BRESCIANI    schedule 03.05.2020
comment
Пожалуйста, не просто публикуйте какой-либо инструмент или библиотеку в качестве ответа. По крайней мере, продемонстрируйте как он решает проблему в самом ответе. - person Yunnosch; 03.05.2020