dimanche 9 septembre 2018

Freeman Code Chain with redCV 1

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
]

Result







Aucun commentaire:

Enregistrer un commentaire