dimanche 9 septembre 2018

Freeman Code Chain with redCV 2

As demonstrated in the previous article, redCV Freeman code chain works perfectly for regular shapes such as square, triangle, or circle. However many shapes in image are often irregular such as illustrated here.

Using Canny Detector and Morphological Operators

The process is two-fold. First, we use a Canny convolution filter to find the edges of the shape with rcvConvolve function. Since Canny detector is rather noise-sensitive, in some cases, edges detection is incomplete and the result of the function is a discret contour with some values equal to 0. In this case, rcvMatGetChainCode function returns an error (-1). The second process is to use a morphological operator like rcvDilate which slightly dilates the contour. With this simple idea, rcvMatGetChainCode, always returns the correct direction for the next  pixel whatever the complexity of the shape.

Code Sample


Red [
    Title:   "Freeman tests "
    Author:  "Francois Jouen"
    File:    %freemanirregular.red
    Needs:   'View
]


#include %../../libs/redcv.red ; for redCV functions
iSize: 512x512
rSize: 300x300
img: rcvCreateImage iSize
edges: rcvCreateImage iSize
edges2: rcvCreateImage iSize
mat:  rcvCreateMat 'integer! 32 iSize
bMat: rcvCreateMat 'integer! 32 iSize
visited: rcvCreateMat 'integer! 32 iSize
plot: copy []
fgVal: 1
canvas: none
knlSize: 3x3
knl: rcvCreateStructuringElement/rectangle knlSize
factor: 1.0
delta: 0.0
anim: false
canny: [-1.0 -1.0 -1.0
        -1.0 8.0 -1.0 
        -1.0 -1.0 -1.0]
        
generatePolygon: does [
    canvas/image: none
    clear f0/text
    clear f1/text
    clear f2/text
    clear f3/text
    clear f4/text
    clear r/text
    p1: 128x128 + random rSize p2: 128x128 + random rSize  p3: 128x128 + random rSize 
    p4: 128x128 + random rSize  128x128 +  p5: 128x128 + random rSize
    plot: compose [pen white fill-pen white polygon (p1) (p2) (p3) (p4) (p5)]
    canvas/draw: reduce [plot]
    pgb/data: 0%
]

processImage: does [
    img: to-image canvas
    rcvConvolve img edges canny factor delta    ; edges detection with Canny
    rcvDilate edges edges2 knlSize knl          ; dilates shape to suppress 0 values if exist
    rcvImage2Mat edges2 mat                     ; make first matrix 0..255
    rcvMakeBinaryMat mat bmat                   ; make second matrix 0..1
    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 
    visited: rcvCreateMat 'integer! 32 iSize            ; for storing visited pixels    
    border: []                                          ; for neighbors
    rcvMatGetBorder bmat iSize fgVal border             ; get border
    foreach p border [rcvSetInt2D visited iSize p 1]    ; values in matrix
    perim: (length? border) / 2                         ; pre-processing multiplies number of pixels
    f0/text: form perim
    p: uPix;first border
    i: 1
    s: copy ""
    clear r/text
    append append plot 'pen 'green
    pix: 1
    ; repeat until all pixels are processed
    while [pix > 0] [
        pix: rcvGetInt2D visited iSize p
        d: rcvMatGetChainCode visited iSize p 1     ; get chain code
        rcvSetInt2D visited iSize p 0               ; pixel processed 
        append append append plot 'circle (p) 2 
        if d > -1 [append s form d]
        if anim [do-events/no-wait]; to show progression
        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
        ]
        pgb/data: to-percent (i / to-float perim)
        i: i + 1
    ]
    r/text: s
]

; ***************** Test Program ****************************
view win: layout [
    title "Chain Code with Canny Detector"
    button "Generate Polygon" [generatePolygon]
    cb: check "Show Anination" [anim: face/data]
    button "Process" [processImage]
    pgb: progress 160
    f0: field 125
    button "Quit" [
                    rcvReleaseImage img
                    rcvReleaseImage edges
                    rcvReleaseImage edges2
                    rcvReleaseMat mat
                    rcvReleaseMat bmat
                    rcvReleaseMat visited
                    Quit]
    return
    canvas: base iSize black draw plot
    r: area 200x512
    return
    pad 120x0
    f1: field 60
    f2: field 60
    f3: field 60
    f4: field 60
    return  
]


Result





Aucun commentaire:

Enregistrer un commentaire