Skip to content
gingerlime edited this page Feb 1, 2013 · 27 revisions

Examples

Color given jpg file to green (this is my favourite example).

You never iterate yourself through pixels one by one, it'd be much too slow.

Instead, imagine images are huge arrays of numbers and you have a library which can efficiently apply operations to those large matrices. Imagine what calculation the thing you want to do might correspond to, and just type it.

For example, to set the red and blue channels to zero and just leave a green image you might multiply r and b by zero and g by 1. A handy vips operation for this is "lin", meaning "linear transform").

out = in.lin(a, b)

sets every pixel in out to be

out = in * a + b

It lets you give an array of numbers for a and b and will use one array element per image channel. So therefore:

#!/usr/bin/ruby
require 'rubygems'
require 'vips'
include VIPS

im = Image.new 'mypic.jpg'
im = im.lin [0, 1, 0], [0, 0, 0]

im.write 'output.jpg'

Constant image

To make a constant image (where all pixels have the same constant value), make a 1x1 pixel zero image with Image::black, add some amount to it with .lin(), and expand it up to the size you need with .embed().

#!/usr/bin/ruby

require 'rubygems'
require 'vips'
include VIPS

im = Image.black 1, 1, 1
im = im.lin [0, 0, 1], [0, 0, 0]
im = im.embed :extend, 0, 0, 400, 400
im.write 'constant_blue.jpg'

You can speed this up a slightly. lin() makes a floating-point image (since the parameters can be floats), and jpeg-save is automatically casting this back down to 8 bits before writing. If you cast to 8 bits yourself before expanding the image you can avoid a lot of upcasting and downcasting.

im = Image.black 1, 1, 1
im = im.lin([0, 0, 1], [0, 0, 0]).clip2fmt(:UCHAR)
im = im.embed :extend, 0, 0, 400, 400
im.write 'constant_blue.jpg'

Gamma

To change image gamma you might try something like:

im = im.pow(0.5).lin(255 / 255 ** 0.5, 0)

Though that'll be a bit slow (it'll call pow() three times for each pixel), it'd be much faster to make a lookup table (see Basic concepts), run the pow() on that, then map the image through the table:

lut = Image.identity(1)
lut = lut.pow(0.5).lin(255 / 255 ** 0.5, 0)
im = im.maplut(lut)

Finally:

#!/usr/bin/ruby

require 'rubygems'
require 'vips'
include VIPS

im = Image.new 'mypic.jpg'

lut = Image.identity 1 

gamma = 0.8

lut = lut.pow(gamma).lin(255 / 255 ** gamma, 0).clip2fmt(:UCHAR)
im = im.maplut lut 

im.write 'output.jpg' 

Daltonize

Implementation of the daltonize algorithm for correcting images for colour-blind people.

#!/usr/bin/ruby

# daltonize.rb - example implementation of the daltonize algorithm using ruby-vips
# 
# This example only implements Deuternope, but can easily be adapted to include Protanope and Tritanope
#
# Usage: ruby daltonize.rb <source.jpeg> <output.jpeg>
#
# requires: ruby-vips
#
# credits:
#   Written by John Cupitt - the maintainer of ruby-vips library
#   Yoav Aner - applied small fixes and tweaks
#
# Resources and other implementations:
#   javascript - http://www.daltonize.org/search/label/Javascript
#   python - http://moinmo.in/AccessibleMoin?action=AttachFile&do=view&target=daltonize.py
#   Daltonize.org - http://www.daltonize.org/
#   
#   "Analysis of Color Blindness" by Onur Fidaner, Poliang Lin and Nevran Ozguven.
#   http://scien.stanford.edu/class/psych221/projects/05/ofidaner/project_report.pdf
#           
#   "Digital Video Colourmaps for Checking the Legibility of Displays by Dichromats" by Françoise Viénot,
#   Hans Brettel and John D. Mollon
#   http://vision.psychol.cam.ac.uk/jdmollon/papers/colourmaps.pdf

require 'rubygems'
require 'vips'

im = VIPS::Image.jpeg(ARGV[0], :sequential => true)

begin
    # import to CIELAB with lcms
    # if there's no profile there, we'll fall back to the thing below
    cielab = im.icc_import_embedded(:relative)
rescue VIPS::Error
    # nope .. use the built-in converter instead
    cielab = im.srgb_to_xyz().xyz_to_lab()
end

# turn to XYZ, a linear light space
xyz = cielab.lab_to_xyz()

# convert rgb to lms
lms = xyz.recomb([[17.8824,43.5161,4.11935],
                  [3.45565,27.1554,3.86714],
                  [0.0299566,0.184309,1.46709]])                    

# through the Deuteranope matrix
deut = lms.recomb([[1, 0, 0],
                    [0.494207, 0, 1.24827],
                    [0, 0, 1]])

# back to xyz (this is the inverse of the lms matrix above)
xyz = deut.recomb([[0.0809444479, -0.130504409, 0.116721066],
                   [-0.0102485335, 0.0540193266, -0.113614708],
                   [-0.000365296938, -0.00412161469, 0.693511405]])

# .. and export to sRGB for saving
rgb = xyz.xyz_to_srgb()

rgb.write(ARGV[1])
Clone this wiki locally