[Image-SIG] Removing specific range of colors from scanned image

jcupitt at gmail.com jcupitt at gmail.com
Tue Apr 28 17:31:49 CEST 2009


2009/4/28 Eduardo Ismael <eismb at hotmail.com>:
> I'm having trouble thinking out of the "for pixel in image" loop. Is it
> possible to calculate with images and not pixels with PIL?

Yes, but the range of operations is a little limited. Numpy would be
easier, if you know that.

I know vips well (I'm one of the maintainers) so I tried in that. On
my machine (2.7 GHz amd64), this runs in about 3 seconds and needs
20mb of RAM for a 5,000 x 5,000 pixel TIFF:

----------------
from vipsCC import *

filename = "bench/wtc_tiled_small.tif"

# set all pixels within threshold of blue to 255
blue = [157, 196, 230]
threshold = 10

im = VImage.VImage (filename)

# calculate (im - blue)
# b = a.lin (x, y) finds (b = a * x + y) for each pixel
# we have to invert our blue values to get subtract
diff = im.lin ([1,1,1], [x * -1 for x in blue])

# square each pixel
sq = diff.multiply (diff)

# break into three bands, then sum
# vips has a split operator, but it's not wrapped in Python,
# sadly
r = sq.extract_band (0)
g = sq.extract_band (1)
b = sq.extract_band (2)
sum = r.add (b.add(b))

# sqrt each pixel
sq = sum.pow (0.5)

# now find pixels within a certain distance of our blue point
# we get an 8-bit mono image where 255 is "within threshold"
mask = sq.less (threshold)

# make the image we get the replacement pixels from
# we need an image the same size as im, but with [255, 255, 255] for each
# pixel
# make a black image, add 255, then clip to 8-bit uchar
black = VImage.VImage.black (im.Xsize (), im.Ysize (), 3)
white = black.lin (1, 255).clip ()

# and use the mask to pick white or image pixels
result = mask.ifthenelse (replace, im)

result.write ("test.tif")
-----------------

vips has cielab, so you can try that colour space as well. This takes
about 5s/20mb.

--------------
from vipsCC import *

filename = "bench/wtc_tiled_small.tif"

# set all pixels within threshold of blue to 255
blue = [157, 196, 230]
threshold = 10

im = VImage.VImage (filename)

# make a CIELAB image of the blue colour
black = VImage.VImage.black (im.Xsize (), im.Ysize (), 3)
blue_lab_im = black.lin ([1,1,1], blue).clip ().sRGB2XYZ ().XYZ2Lab ()

# turn our image to CIELAB as well
lab_im = im.sRGB2XYZ ().XYZ2Lab ()

# find the colour difference
diff = lab_im.dE_fromLab (blue_lab_im)

# threshold to get a mask image
mask = diff.less (threshold)

# make a white rgb image
white = black.lin (1, 255).clip ()

# and use the mask to pick white or image pixels
result = mask.ifthenelse (white, im)

result.write ("test.tif")
--------------

J


More information about the Image-SIG mailing list