如何获得图像平均像素的HSV值?

时间:2017-01-29 22:52:02

标签: ruby hsv vips

在此代码中

*

最后一行抛出

im = Vips::Image.new_from_file "some.jpg"
r = (im * [1,0,0]).avg
g = (im * [0,1,0]).avg
b = (im * [0,0,1]).avg

p [r,g,b]                      # => [57.1024, 53.818933333333334, 51.9258]

p Vips::Image.sRGB2HSV [r,g,b]

P.S。:临时采取并重构了ChunkyPNG实施:

/ruby-vips-1.0.3/lib/vips/argument.rb:154:in `set_property': invalid argument Array (expect #<Class:0x007fbd7c923600>) (ArgumentError)`

2 个答案:

答案 0 :(得分:2)

像素平均值应该在线性色彩空间中。 XYZ是一个简单的,但scRGB也可以很好地工作。获得1x1像素图像后,转换为HSV并读出该值。

#!/usr/bin/ruby

require 'vips'

im = Vips::Image.new_from_file ARGV[0]

# xyz colourspace is linear, ie. the value is each channel is proportional to
# the number of photons of that frequency 
im = im.colourspace "xyz"

# 'shrink' is a fast box filter, so each output pixel is the simple average of
# the corresponding input pixels ... this will shrink the whole image to a
# single pixel
im = im.shrink im.width, im.height

# now convert the one pixel image to hsv and read out the values
im = im.colourspace "hsv"
h, s, v = im.getpoint 0, 0

puts "h = #{h}"
puts "s = #{s}"
puts "v = #{v}"

我不会自己使用HSV,LCh通常要好得多。

https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC

对于LCh,只需将结尾更改为:

im = im.colourspace "lch"
l, c, h = im.getpoint 0, 0

答案 1 :(得分:0)

我意识到,将平均Hue计算为算术平均值显然是错误的,所以我通过添加长度等于饱和度的向量来解决它。但是我没有找到如何在视频中迭代像素,所以我使用了chunky_png的拐杖:

require "vips"
require "chunky_png"

def get_average_hsv_by_filename filename
  im = Vips::Image.new filename
  im.write_to_file "temp.png"
  y, x = 0, 0
  ChunkyPNG::Canvas.from_file("temp.png").to_rgba_stream.unpack("N*").each do |rgba|
    h, s, v = ChunkyPNG::Color.to_hsv(rgba)
    a = h * Math::PI / 180
    y += Math::sin(a) * s
    x += Math::cos(a) * s
  end
  h = Math::atan2(y, x) / Math::PI * 180
  _, s, v = im.colourspace("hsv").bandsplit.map(&:avg)
  [h, s, v]
end

对于使用.resize的大图像,当使用默认内核调整到10000平方像素区域时,似乎只会导致高达~2%的错误。