imagegradient
Image gradients are a fundamental transformation used in image processing, search indexing, and computer vision. Like a weather map showing the direction and strength of the wind, an image gradient depicts the strength and direction of changes in intensity over the surface of the image.
Through a fluke in my interpretation / understanding of the technique the gradients shown here on of images of objects from the Guttormsgaard archive, follow not the direction of the change but rather its perpendicular. As a result, the arrows chase around the edges of objects rather than piercing straight into them. Indeed, the image gradients shares a close affiliation between with the operation of edge-detection (where the movements are further segmented into discrete segments).
01_40_IMG_6294WEB.jpg01_40_IMG_6294WEB.jpg
12_IMG_2406WEB.jpg12_IMG_2406WEB.jpg
12c_IMG_5525WEB.jpg12c_IMG_5525WEB.jpg
13a_MG_8326WEB.jpg13a_MG_8326WEB.jpg
15_IMG_2418WEB.jpg15_IMG_2418WEB.jpg
18_IMG_2430WEB.jpg18_IMG_2430WEB.jpg
19a_IMG_0424Web.jpg19a_IMG_0424Web.jpg
Following the description of Image derivatives in the book Programming Computer Vision with Python (p. 18), the following python code uses gaussian filters to approximate the derivative (rate of change) in first the x and the the y directions, and then uses a square root function to find the magnitude of change, and an arc tangent function to find the direction (or its perpendicular) at each point. The results are used to construct a second “gradient image” where the pixels color (hue in degrees on the HSL color wheel) represent the direction, and the value (or lightness) the magnitude of change.
On this page, clicking on the image switches between 3 views: (1) drawing the gradient at the mouse location, (2) drawing a grid of equally spaced gradients, and (3) showing the underlying (and pre-calated) “hsl” gradient image, which is the source of data used to perform the first two views.
#!/usr/bin/python from PIL import Image from numpy import * from scipy.ndimage import filters import sys, json, os, math from hsl import hsl_to_rgb import argparse # Based on Programming Computer Vision, chapter 1, Image Derivatives parser = argparse.ArgumentParser(description='Calculate an image gradient.') parser.add_argument('input', help='an image path as input') parser.add_argument('--format', default="hslimage", help='save output format, default hslimage (direction is hue, magnitude is lightness). Other options: magimage (magnitude image), json.') parser.add_argument('--output', help='save to output path') args = parser.parse_args() p = args.input path, base = os.path.split(p) base, ext = os.path.splitext(base) out = args.output or os.path.join(path, base + ".gradient.png") im = array(Image.open(p).convert('L')) sigma = 5 # standard deviation imx = zeros(im.shape) filters.gaussian_filter(im, (sigma,sigma), (0,1), imx) imy = zeros(im.shape) filters.gaussian_filter(im, (sigma,sigma), (1,0), imy) magnitude = sqrt(imx**2+imy**2) dirs = arctan2(imy, imx) if args.format == "hslimage": # Map direction to Hue, Magnitude to value from math import pi maxmag = amax(magnitude) height, width = magnitude.shape im = Image.new("RGBA", (width, height)) for y in range(height): p = int(math.ceil(float(y)/height*100)) sys.stderr.write("\rCreating gradient HSL image... [{0}%]".format(p)) sys.stderr.flush() for x in range(width): d = dirs[y][x] hue = ((d+pi) / (2 * pi)) * 360 value = (magnitude[y][x]/maxmag) r, g, b = hsl_to_rgb(hue, 1.0, value) im.putpixel((x, y), (r, g, b, 255)) sys.stderr.write("\n") im.save(out) elif args.format == "magimage": pil_im = Image.fromarray(magnitude) pil_im.convert("LA").save(out) elif args.format == "json": with open(out, "w") as f: json.dump({ 'dirs': dirs.tolist(), 'magnitudes': magnitude.tolist() }, f)
The code is published here.