## Information along contours

Attneave (1954) argued that information along contours is concentrated along points of locally maximal curvature. In a recent paper, we provide a formal proof of this, based on Shannon's definition of information (Feldman & Singh, Psychological Review, in press). This paper also extends Attneave's original claim by demonstrating the asymmetry in information content that arises from the sign of curvature. Whereas Attneave's analysis treated positive and negative curvature—i.e., convex and concave contour segments—symmetrically, we show that for closed contours, regions of negative curvature carry greater information than corresponding segments of positive curvature. MATLAB code for computing and plotting information along contours (i.e., the surprisal) is included below.

The option `signed = 0` treats positive and negative curvature symmetrically (consistent with Attneave), whereas the option `signed = 1`takes into account (for closed contours) the sign of curvature as well, yielding a different distribution of information. The two figures below demonstrate this difference; the left one is produced from the unsigned version, the right one from the signed version.

The code assumes that the contour is sampled uniformly, in counter-clockwise direction, and is defined by a pair of vectors of equal length (`x` and `y`). `resolution` alters the number of neighboring points the code takes into account in computing the tangent direction at any given point.

`function surprisal = contourinfoplot(x, y, signed, resolution)`

`x = x(:); y = y(:);`

`if length(x) ~= length(y)error('the x and y vectors defining the contour must have equal lengths!');end;`

`N = length(x);b = 1; % spread term for the Von Mises distribution`

`if (x(1) == x(N) & y(1) == y(N))N = N-1;open = 0;elseopen = 1;end`

`normalmap = [];surprisalmap = [];`

`for j = 1:N`

`% define the previous and next points relative to the current onexprev = 0;yprev = 0;xnext = 0;ynext = 0;`

`for k = 1:resolutionprev(k) = j-k;next(k) = j+k;if(prev(k) < 1) prev(k) = prev(k) + N; endif(next(k) > N) next(k) = next(k) - N; end`

`xprev = xprev + x(prev(k));yprev = yprev + y(prev(k));xnext = xnext + x(next(k));ynext = ynext + y(next(k));end`

`xprev = xprev/k;yprev = yprev/k;xnext = xnext/k;ynext = ynext/k;`

% vector _from_ the previous point; vector _to_ the next point

vecprev = [x(j), y(j)] - [xprev, yprev];

vecnext = [xnext, ynext] - [x(j), y(j)];

`% compute the magnitude of the turning angle using dot productalpha = acos( dot(vecprev, vecnext) / (norm(vecprev)*norm(vecnext)) ); `

`% compute the sign of turning using cross product% (assumes a counterclockwise sampling of the contour)cp = cross( [vecprev, 0], [vecnext,0] );alpha = sign(cp(3))*alpha;`

`% compute the surprisal using -log von misesif(signed)surprisal = -log( exp(b*cos(alpha - (2*pi/(N/resolution))) )/( 2*pi*besseli(0,b) ) );elsesurprisal = -log( exp(b*cos(alpha) )/( 2*pi*besseli(0,b) ) );end;`

`% turning angles not defined near the end points of an open curveif(open & (j - resolution < 1 | j + resolution > N)) surprisal = 0; end`

`% compute the tangent and normal vectorstangvec = vecprev + vecnext;tangvec = tangvec/norm(tangvec);normvec = [[0 1; -1 0]*tangvec']';`

`normalmap = [normalmap; normvec];surprisalmap = [surprisalmap; surprisal];`

`end;`

`% scale the size of histogram barssurprisalmap = (1/range(surprisalmap))*(surprisalmap(:) - min(surprisalmap));needlesize = max(range(x), range(y))/10;`

`% define the histogram normal to the shapenormalmap(:,1) = surprisalmap.*normalmap(:,1);normalmap(:,2) = surprisalmap.*normalmap(:,2);xnormals = [x(1:N), x(1:N) + needlesize*normalmap(:,1)];ynormals = [y(1:N), y(1:N) + needlesize*normalmap(:,2)];`

`% plotfigure, plot(x,y,'r'), axis equal;hold `

`on, plot(xnormals', ynormals', 'k-');`