Skip to content

Python_Examples

John Cupitt edited this page Mar 29, 2017 · 1 revision

title: Python Examples permalink: /Python_Examples/

This page shows a few examples of using VIPS from Python.

getting started in Ubuntu

make sure you have libvips15 libvips-tools and python-vipscc packages installed

Average a region of interest box on an image

#!/usr/bin/env python
import sys
from vipsCC import *

roix = 10
roiy = 10
roiw = 64
roih = 64
try:
  a = VImage.VImage (sys.argv[1])
  roi = a.extract_area(roix, roiy, roiw, roih)
  print 'average: ', roi.avg ()
except VError.VError, e:
  e.perror (sys.argv[0])

VIPS and PIL

This script moves an image between PIL and VIPS.

#!/usr/bin/python

import sys

from vipsCC import *
import Image

# try this 1,000 times and check for leaks
for i in range (0,1000):
  vim = VImage.VImage (sys.argv[1])

  # do some processing in vips ... cut out a small piece of image
  vim = vim.extract_area (500, 500, 100, 100)

  # make a PIL image
  # we use Image.frombuffer (), so PIL is using vim's memory
  # you need to be very careful not to destroy vim until you're done with pim
  # ideally you should make a proxy class that wraps this lifetime problem up
  mode = VImage.PIL_mode_from_vips (vim)
  size = (vim.Xsize (), vim.Ysize ())
  data = vim.tobuffer ()
  pim = Image.frombuffer (mode, size, data, 'raw', mode, 0, 1)

  # rotate 12 degrees with PIL
  pim = pim.rotate (12, Image.BILINEAR, 1)

  # back to vips again
  # PIL doesn't have a tobuffer method, so we have to use tostring to copy the
  # data out of PIL and then fromstring to copy back into VIPS
  str = pim.tostring ()
  bands, format, type = VImage.vips_from_PIL_mode (pim.mode)
  width, height = pim.size
  vim2 = VImage.VImage.fromstring (str, width, height, bands, format)

  # finally write from vips
  vim2.write (sys.argv[2])

Leak testing

This loads an image, does some simple processing, and saves again. Handy for leak testing.

#!/usr/bin/python

import sys

# just need this for leaktesting
import gc

from vipsCC import *

if len (sys.argv) != 3:
  print 'usage:', sys.argv[0], 'inputimage outputimage'
  sys.exit (1)

try:
  a = VImage.VImage (sys.argv[1])
  b = a.invert ()
  c = b.lin ([1,2,3],[4,5,6])
  m = VMask.VIMask (3, 3, 1, 0,
          [-1, -1, -1,
         -1,  8, -1,
         -1, -1, -1])
  d = a.conv (m)
  d.write (sys.argv[2])
except VError.VError, e:
  e.perror (sys.argv[0])

# we can get properties of VImage too
print 'inputimage is', a.Xsize (), 'pixels across'

print 'starting shutdown ...'
del b
del a
del c
del d
del m
# sometimes have to do several GCs to get them all, not sure why
for i in range(10):
  gc.collect ()
print 'shutdown!'

print 'leaked IMAGEs:'
VImage.im__print_all ()
print 'done ... hopefully you saw no leaks'

Build image mosaic

This loads a lot of images (RGB or greyscale) and pastes them at random positions in a 10,000 by 10,000 pixel output image. 8-bit only, but it'd be easy to change that.

#!/usr/bin/python

import sys
import random
from vipsCC import *

# the size of the image we build
size = 10000

try:
   if len(sys.argv) < 3:
      print 'usage:', sys.argv[0], 'outfile infile1 ...'
      sys.exit (1)

   # make the background image
   bg = VImage.VImage.black (size, size, 3)

   # paste each argument in
   for file in sys.argv[2:]:
      im = VImage.VImage (file)

      # is this a mono image? convert to RGB by joining three of them
      # together
      if im.Bands() == 1:
         im = im.bandjoin (im).bandjoin (im)

      x = random.randint (0, size - im.Xsize () - 1)
      y = random.randint (0, size - im.Ysize () - 1)
      bg = bg.insert_noexpand (im, x, y)

   # write result
   bg.write (sys.argv[1])

except VError.VError, e:
   e.perror (sys.argv[0])

Build image pyramid

This makes a tiled image pyramid, with each tile in a separate 512x512 pixel file.

#!/usr/bin/python

import sys
from vipsCC import *

tilesize = 512
maxlevel = 100

try:
   im = VImage.VImage (sys.argv[1])

   for level in range (maxlevel, -1, -1):
      print "Creating tiles for level", level

      # loop to create the tiles
      for y in range (0, im.Ysize(), tilesize):
         for x in range (0, im.Xsize(), tilesize):
            filename = '%dx%d_y%d.jpg' % (level, x / tilesize, y / tilesize)
            # clip tilesize against image size
            width = min (im.Xsize () - x, tilesize)
            height = min (im.Ysize () - y, tilesize)

            # expand edge tiles up to the full tilesize ... Google maps likes this
            # im.extract_area (x, y, width, height).embed(0, 0, 0, tilesize, tilesize).write(filename)

            # let edge tiles be smaller than the full tile size, tiff tiling prefers this
            im.extract_area (x, y, width, height).write (filename)

      # was there only a single tile? we are done
      if im.Xsize() <= tilesize and im.Ysize() <= tilesize:
         break

      # create next pyramid level in RAM
      shrink = im.rightshift_size (1, 1, im.BandFmt())
      im = shrink.write (VImage.VImage ("temp", "t"))

except VError.VError, e:
   e.perror (sys.argv[0])

Rename DICOM images using header fields

DICOM images commonly come in an awful directory hierarchy named as something like images/a/b/e/z04. There can be thousands of files and it can be very hard to find the one you want.

This utility copies files to a single flat directory, naming them using fields from the DICOM header. You can actually find stuff! Useful.

#!/usr/bin/python

import sys
import re
import os
import shutil

from vipsCC import *

if len (sys.argv) != 3:
  print 'rename DICOM files using tags from the header'
  print 'usage:'
  print '\t%s srcdir destdir' % sys.argv[0]
  print 'the directory tree below srcdir is searched, all files are'
  print 'renamed and put into destdir in a flat list'
  sys.exit (1)

srcdir = sys.argv[1]
destdir = sys.argv[2]

if not os.access (destdir, os.F_OK | os.R_OK | os.W_OK | os.X_OK):
  os.mkdir (destdir)

def get_field (vim, field):
  result = vim.meta_get_string (field)

  # remove any \n etc.
  result = re.sub ("\n", "", result)

  # remove any leading or trailing spaces
  result = re.sub (" $", "", result)
  result = re.sub ("^ ", "", result)

  return result

id_name = "magick-dcm:Patient'sID"
modality_name = "magick-dcm:Modality"
series_name = "magick-dcm:SeriesNumber"
instance_name = "magick-dcm:Instance(formerlyImage)Number"
date_name = "magick-dcm:ImageDate"

n_processed = 0

for (dirpath, dirnames, filenames) in os.walk (srcdir):
  for file in filenames:
    path = os.path.join (dirpath, file)

    try:
      vim = VImage.VImage (path)
    except VError.VError, e:
      print 'unable to open', path
      continue

    try:
      id = get_field (vim, id_name)
      modality = get_field (vim, modality_name)
      series = get_field (vim, series_name)
      instance = get_field (vim, instance_name)
      date = get_field (vim, date_name)
    except VError.VError, e:
      print 'unable to get fields from header', path
      continue

    match = re.match ("(\d\d\d\d)(\d\d)(\d\d)", date)
    date = match.group (1) + "." + match.group (2) + "." + match.group (3)
    newname = id + "." + modality + "." + series + "." + instance + "." + date + ".IMA"

    shutil.copyfile(path, os.path.join (destdir, newname))

    n_processed += 1

print '\t(%d files processed)' % n_processed
Clone this wiki locally