Freeman code chain
A chain code is a way to represent shapes in a binary image. The basic idea is very simple: One spot on the outer boundary of a shape is selected as the starting point, we then move along the boundary of the shape and describe each movement with a directional code that describes the movement. We continue tracing the boundary of the shape until we return to the starting point.
The Freeman code encodes the movement as an integer number between 0 and 7.
0: east
1: southeast
2: south
3: southwest
4: west
5: northwest
6: north
7: northeast
The simple idea is to look for the neighbors of the current pixel and get the direction according to the neighbor value.
Freeman Code Chain in redCV
We do implement basic Freeman code chain in redCV which requires some image preprocessing.
First of all we need a binary image. This is easy done with 2 redCV functions:
rcvImage2Mat which transforms any red image to a binary matrix [0..255] and
rcvMakeBinaryMat which makes a binary [0..1] matrix.
Then we have to get all points that belong to the shape. Just call rcvMatGetBorder function that looks for all value (0 or 1) that are part of shape boundary. Found pixels in binary matrix are stored in a block such as border. When found you have to copy pixel in another matrix which will be used then to store visited pixel (foreach p border [rcvSetInt2D visited iSize p 1]).
Then redCV uses the rcvMatGetChainCode to get the successive movement direction such as in the code sample:
p: first border
i: 1
while [i < perim] [
d: rcvMatGetChainCode visited iSize p fgVal
idx: (p/y * iSize/x + p/x) + 1
visited/:idx: 0; pixel is visited
append s form d
switch d [
0 [p/x: p/x + 1] ; east
1 [p/x: p/x + 1 p/y: p/y + 1] ; southeast
2 [p/y: p/y + 1] ; south
3 [p/x: p/x - 1 p/y: p/y + 1] ; southwest
4 [p/x: p/x - 1] ; west
5 [p/x: p/x - 1 p/y: p/y - 1] ; northwest
6 [p/y: p/y - 1] ; north
7 [p/x: p/x + 1 p/y: p/y - 1] ; northeast
]
i: i + 1
]
It is very important to ensure that the current pixel was processed; if not the pixel can be again processed and the chain code could be invalid. This is why we set to 0 visited pixel in shape matrix (visited/:idx: 0; pixel is visited).
Then according to the direction value returned by the rcvMatGetChainCode function we move to the new pixel to be analyzed.
Code Sample
Red [
Title: "Matrix tests "
Author: "Francois Jouen"
File: %freeman.red
Needs: 'View
]
#include %../../libs/redcv.red ; for redCV functions
plot: []
iSize: 512x512
img: rcvCreateImage iSize
mat: rcvCreateMat 'integer! 32 iSize
bMat: rcvCreateMat 'integer! 32 iSize
visited: rcvCreateMat 'integer! 32 iSize
fgVal: 1
canvas: none
generateImage: does [
canvas/image: none
p1: random 400x400
p2: random 400x400
color: 255.255.255
plot: compose [fill-pen (color) box (p1) (p2)]
processImage
]
processImage: does [
canvas/draw: reduce [plot]
img: to-image canvas
rcvImage2Mat img mat
rcvMakeBinaryMat mat bmat
lPix: rcvMatleftPixel bmat iSize fgVal
rPix: rcvMatRightPixel bmat iSize fgVal
uPix: rcvMatUpPixel bmat iSize fgVal
dPix: rcvMatDownPixel bmat iSize fgVal
f1/text: form as-pair lPix/x uPix/y
f2/text: form as-pair rPix/x uPix/y
f3/text: form as-pair rPix/x dPix/y
f4/text: form as-pair lPix/x dPix/y
clear r/text
visited: rcvCreateMat 'integer! 32 iSize
border: copy []
rcvMatGetBorder bmat iSize fgVal border
foreach p border [rcvSetInt2D visited iSize p 1]
perim: length? border
p: first border
i: 1
s: copy ""
while [i < perim] [
d: rcvMatGetChainCode visited iSize p fgVal
idx: (p/y * iSize/x + p/x) + 1
visited/:idx: 0; pixel is visited
append s form d
switch d [
0 [p/x: p/x + 1] ; east
1 [p/x: p/x + 1 p/y: p/y + 1] ; southeast
2 [p/y: p/y + 1] ; south
3 [p/x: p/x - 1 p/y: p/y + 1] ; southwest
4 [p/x: p/x - 1] ; west
5 [p/x: p/x - 1 p/y: p/y - 1] ; northwest
6 [p/y: p/y - 1] ; north
7 [p/x: p/x + 1 p/y: p/y - 1] ; northeast
]
i: i + 1
]
r/text: s
]
; ***************** Test Program ****************************
view win: layout [
title "Chain Code"
button "Generate Shape" [generateImage]
pad 580x0
button "Quit" [rcvReleaseImage img
rcvReleaseMat mat
rcvReleaseMat bmat
rcvReleaseMat visited
Quit]
return
canvas: base iSize black draw plot
r: area 256x512
return
pad 100x0
f1: field 60
f2: field 60
f3: field 60
f4: field 60
]
Aucun commentaire:
Enregistrer un commentaire