What does this expression’s algorithm mean?
p = ((p<<1)&0666) | ((q<<3)&0110) | (Image->scanLine(y+1)[x+1] != 0);
Algorithm “Binary Image Thinning Using Neigborhood Maps” in a book “Graphics Gems IV”:
static int masks[] = {0200, 0002, 0040, 0010};
uchar delete_[512] =
{
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,1,0,0,1,1, 0,1,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,1,1,1,0,1,1, 0,0,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 1,1,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 1,1,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,1,1,1,0,1,1, 1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,0, 1,1,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,1,1,1,0,1,1, 1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,1,1,1,0,1,1, 0,0,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0, 0,0,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,0, 1,1,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,1,1,1,0,1,1, 1,1,1,1,1,1,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,0,0,0,0,0,0, 1,1,1,1,0,0,1,1,
0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
1,0,1,1,1,0,1,1, 1,1,1,1,1,1,1,1
};
int xsize, ysize;
int x, y;
int i;
int count = 1;
int p, q;
uchar *qb;
int m;
xsize = Image->width();
ysize = Image->height();
qb = (uchar*) malloc (xsize*sizeof(uchar));
qb[xsize-1] = 0;
while(count)
{
count = 0;
for (i = 0; i < 4; ++i)
{
m = masks[i];
p = Image->scanLine(0)[0] != 0;
for (x = 0; x < xsize-1; ++x)
qb[x] = p = ((p<<1)&0006) | (Image->scanLine(0)[x+1] != 0);
// Scan image for pixel deletion candidates.
for (y = 0; y < ysize-1; ++y)
{
q = qb[0];
p = ((q<<3)&0110) | (Image->scanLine(y+1)[0] != 0);
for (x = 0; x < xsize-1; ++x)
{
q = qb[x];
p = ((p<<1)&0666) | ((q<<3)&0110) | (Image->scanLine(y+1)[x+1] != 0);
qb[x] = p;
if ((p&m)==0 && delete_[p])
{
count++;
Image->scanLine(y)[x] = 0;
}
}
(See commented source code)
The variables
m,p,q, and elements of theqbarray are 9-bit numbers that represent the 3×3-pixel “neighborhood” of a pixel.Suppose your image looks like this (each letter represents a pixel, which is either ‘on’ or ‘off’ (1 or 0, black or white):
The pixel at (x,y) location (2,1) is
j. The neighborhood of that pixel isSince each pixel has a binary value, the neighborhood can be represented in 9 bits. The neighborhood above can be written out linearly, expressed in binary as
bcd_ijk_pqr. The grouping of 3 pixels in a row makes octal a good choice, since each octal digit represents three bits.Once you have a neighborhood expressed as a 9-bit value, you can do bit-manipulation on it. An operation such as
((p << 1) & 0666)takes a neighborhood, shifts all bits to the left one position, and clears the rightmost column of bits. For example, the shift changesbcd_ijk_pqrtocdi_jkp_qr@(where@represents a ‘null’ bit, by default 0). Then the mask changes it tocd@_jk@_qr@. Expressed in 3×3 grid form:Essentially, the whole grid has been shifted to the left.
Similarly, an operation such as
((q << 3) & 0110)shifts all bits three positions (moves rows up) and clears the first two columns of bits. Sobcd_ijk_pqrbecomesijk_pqr_@@@and then after the masking, becomes@@k_@@r_@@@.The gist of the algorithm is to evaluate the neighborhood of each pixel to determine whether to turn that pixel off (delete it). This line does the evaluation:
Everything that precedes that line is done to set up the neighborhood in
p. The code is written so that each pixel value is read exactly once per pass.The
qbarray stores the neighborhood for each pixel in the previous scanline. Note that the elements ofqbare only 8-bits wide. This means the upper-left pixel of the neighborhood is omitted. That is not a problem, since any timeqbis used, it gets shifted up a row.So to answer your question about what this line does:
It creates the neighborhood of a pixel by merging the following:
For example, the neighborhood about
jis calculated as: