1

Before ruby-vips 1.0, I can get the array of RGB average colors using:

im.stats[1][4].to_i, im.stats[2][4].to_i, im.stats[3][4].to_i

But after update to ruby-vips 1.0, stats method does not return a ruby array any more. I noticed there is an im.avg() method, but it returns a scalar value, not separate values for RGB channels.

How to calculate image average colors using the new API?

Nakilon
  • 34,866
  • 14
  • 107
  • 142
Wei Huang
  • 23
  • 2
  • You don't indicate which exact version of 'ruby-vips' you use, But I'll note that the GitHub page for the only one with recent publishes has the following note at the top of the page: "API break: version 1.0 of this gem is an API break, see below for some notes on why there is a break and how to update your code. The older ruby-vips is still here and still maintained in branch 0.3-stable." I suspect you'll find your answers here: https://github.com/jcupitt/ruby-vips – Derrell Durrett Jun 16 '16 at 15:10
  • Thanks for your comment. I knew the API break, and I've updated our codebase following their instructions (like change `VIPS` to `Vips`), most of them are easy. The only problem left is what I asked in the question: I can not figure out how to use the new version of `stats`. – Wei Huang Jun 17 '16 at 13:32

1 Answers1

2

For historical reasons libvips used to have its own array type. It had a whole set of functions for manipulating these arrays, all slightly different from the functions for manipulating images.

libvips8 has fixed this by removing the array type and using one-band double images instead. So the result of stats is now a small image you can just read pixels values from.

Use getpoint to read pixels from images:

http://www.rubydoc.info/gems/ruby-vips/1.0.0/Vips/Image#getpoint-instance_method

For example:

$ irb
irb(main):001:0> require 'vips'
=> true
irb(main):002:0> im = Vips::Image.new_from_file "/home/john/pics/k2.jpg"
=> #<Vips::Image:0x1c83830 ptr=0x1fb7020>
irb(main):003:0> im.getpoint(10, 10)
=> [10.0, 0.0, 3.0]
irb(main):004:0> im.stats
=> #<Vips::Image:0x20d1950 ptr=0x1fb7e30>

The layout of the image you get from stats is in the C docs (ruby-vips is a thin layer over the C API, so all those docs work):

http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/libvips-arithmetic.html#vips-stats

So you want column 4, rows 1, 2, 3 for the RGB averages. getpoint returns an array, so for a one-band image, use [0] to get the first element.

irb(main):007:0> im.stats.getpoint(4, 1)[0]
=> 110.87133688038793
irb(main):008:0> im.stats.getpoint(4, 2)[0]
=> 101.0471090382543
irb(main):009:0> im.stats.getpoint(4, 3)[0]
=> 96.45809502963363

This does seem a bit clumsy. Perhaps Image should have a to_a method? It would only make sense for very small images, of course.

jcupitt
  • 10,213
  • 2
  • 23
  • 39
  • `to_a` sound like a disaster for large images, :-). Thanks for your helpful answer! – Wei Huang Jun 24 '16 at 08:19
  • 1
    I've added `Image.to_a` to git master ruby-vips, so you can now just do `im.stats.to_a[2][4]`, almost as before. You're right, do `to_a` on a large image and your machine will die! – jcupitt Jun 25 '16 at 09:07