2017-01-29 11 views
0

이미지의 평균 픽셀의 HSV 값을 얻으려면 어떻게해야합니까? 이 코드에서

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] 

마지막 줄

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

PS를 던졌습니다 : 일시적으로는 가져다가 ChunkyPNG 구현 리팩토링 :

def to_hsv r, g, b 
    r, g, b = [r, g, b].map{ |component| component.fdiv 255 } 
    min, max = [r, g, b].minmax 
    chroma = max - min 
    [ 
    60.0 * (chroma.zero? ? 0 : case max 
     when r ; (g - b)/chroma 
     when g ; (b - r)/chroma + 2 
     when b ; (r - g)/chroma + 4 
     else 0 
    end % 6), 
    chroma/max, 
    max, 
    ] 
end 

답변

1

픽셀의 평균 정말에 있어야를 선형 색상 공간. 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는 일반적으로 훨씬 좋습니다. 은 평균 색조 등의 산술 평균을 계산 분명히 잘못이다, 내가 실현

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

차가움. 아마도 이것을 'im.bandsplit.map (& : avg)'이라고 쓸 수 있습니다. – Nakilon

+0

오늘과 내일의 결과를 비교해 보겠습니다. – Nakilon

+0

아, 맵의 좋은 점 (& : avg). 정확히 같은 결과를 줄 가능성은 거의 없습니다. – user894763

0

, 그래서 길이의 벡터를 추가하여 그것을 해결 :

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

는하여 LCh를 들어, 단지에 끝을 변경 채도와 같습니다. 10000 아래로 크기를 조정하는 경우에만 ~ 2 %의 오차까지 입힐 것으로 보인다 내가 .resize를 사용 큰 이미지

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 

:하지만 내가 chunky_png의 목발을 사용하므로 VIP를 픽셀을 반복하는 방법을 찾을 수 없습니다 정사각형 픽셀 영역과 기본 커널.

+0

@ user894763, 제발, 이것 좀보세요. – Nakilon

+0

알파 채널이있는 이미지에서는 테스트되지 않았습니다. – Nakilon

+0

맞습니다. 평균적인 색조는 0/360 경계의 양쪽 값에 대해서는 작동하지 않습니다. 이미지가 자연스러운 장면이라면, 당신은 정말로 광자 (또는 광자 수에 비례하는)를 평균하고 싶습니다. 그래서 XYZ가 끝나고 HSV로 변환하십시오. 내 대답을 업데이트 할게. – user894763