-
We recently added support for We needed a way to extract the background color for images, as well as the most used color, because we adapt the viewing UI to those. The implementation is here: https://github.com/mastodon/mastodon/blob/main/lib/paperclip/color_extractor.rb#L76 You also have the IM implementation in the same file for reference. We based this on a comment / gist from @jcupitt but we found some small issues with edge cases. You can see the discussion here for more context: mastodon/mastodon#30090 (comment) If you are interested in the whole vips implementation, you can look at this PR: mastodon/mastodon#30090 Is there a better / more efficient way to write this code? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 13 replies
-
Hi @renchap, Yes, we've been following that PR with interest. Nice work! Would you like one of us to look through the code for possible improvements? We've added a "developer checklist" to the 8.16 docs: https://github.com/libvips/libvips/blob/master/doc/Developer-checklist.md It might be worth a quick look. I'll have a look at your background and dominant colour code.
libvips has had good GIF support since 8.13, I think. Though ffmpeg is a fine choice of course. |
Beta Was this translation helpful? Give feedback.
-
For distinguishing blues, you need to extract that (x, y) pixel as a vector and run max a second time. I'll make an example. Something else you could do to improve it would be to blur the image slightly before doing the binning. This will make the histogram less noisy and should mean a more stable result. But the improvement would probably be small in practice. You can run this in sequential mode, that would help too. What value do you typically use for |
Beta Was this translation helpful? Give feedback.
-
@ClearlyClaire I had a facepalm moment yesterday -- a very simple fix is to use
And unfolds it to a 9x3 mono image like this:
Now you can run #!/usr/bin/ruby
require "vips"
BINS = 16
def palette_from_image(image)
histogram = image.hist_find_ndim(bins: BINS).bandunfold()
_, colors = histogram.max(size: 10, out_array: true, x_array: true, y_array: true)
maxima = colors['out_array'].map.with_index do |v, i|
x = colors['x_array'][i]
y = colors['y_array'][i]
r = BINS / 2 + BINS * (x / BINS)
g = BINS / 2 + BINS * y
b = BINS / 2 + BINS * (x % BINS)
[v, r, g, b]
end.sort { |a, b| b[0] - a[0] }
end
image = Vips::Image.new_from_file(ARGV[0], access: :sequential)
hist = palette_from_image(image)
puts("hist = #{hist}") Quite a bit less crazy. |
Beta Was this translation helpful? Give feedback.
🤦 I see what you mean, we could have one pixel containing two maxima.
You could add all v, r, g, b for a pixel, then sort by v and take the top 10. Perhaps: