samedi 16 décembre 2017

Red and Pandore Library

I really appreciate using Pandore library (https://clouard.users.greyc.fr/Pandore/) which provides  a lot of useful image processing operators. In many case when processing images, you have to apply successive operators: An image processing application is a chain of operators and Pandore offers very efficient operators. The library is 100% pure C++ code  and can't be easily binded to Red. But we have a solution with red call instruction which can be used to execute a shell process to run another process or program.

Installing Pandore

Go to Pandore website and download the lib which is optimized for Unix, Linux, Windows and macOS. 

The complete installation needs a C++ compiler which is required and  Qt (version >= 4.0.0)  or X11 and Motif for visualization operation (www.trolltech.com).Without these API, operators 'pvisu' and 'pdraw' are not available.  However, the rest of the operators works without Qt (or X11).

Then unpack the distribution on your computer.

Installation is straightforward:   
  1. ./configure
  2. make 
  3. make install
  4. make clean

Using Pandore with Red

The idea is now to call the operators from Red program with call. This is really simple. All operators are in pandore_6.6.7/bin directory and your red code must point to this directory
panhome: "Your access to/pandore_6.6.7"
change-dir to-file panhome
Then just use call operator 
call/output "bin/pversion" status 
The pversion operator can be used to test if the pandore lib is correctly installed. Here we use wait/output in order to redirect stdout to a string and get the result of the operator: SUCCESS or FAILURE. When using other operators which process image don't forget to use call/wait  to run the operator and wait for exit.

Pandore creates a specific image format (.pan) and thus you code must convert red image to pandore image with pany2pan operator.
In the code example we call  then the pthresholding operator which  build the output image  with the pixels of the input image  that have a value greater or equal than low or lower or equal than high provided by sliders. Other values are set to 0. Lastly we call ppan2jpeg operator which transform the filtered image to  jpg image.

Code sample

Red [
    Title:   "Pandore test"
    Author:  "Francois Jouen"
    File:    %threshold2.red
    Needs:   'View
]

status: ""
isFile: false
srcImg: none
f: ""
lowT: 0
highT: 255
prog: make string! ""

dSize: 256
gsize: as-pair dSize dSize
sldSize: as-pair ((dSize * 2) - 100) 16

; update according to you OS and pandore directory
panhome: "/Libraries/pandore_6.6.7"
change-dir to-file panhome

; is pandore installed?
call/output "bin/pversion" status

; Converts red loaded image to pandore image
red2pan: func [img [file!] return: [string!]] [
    fName: ""
    fName: form second split-path img
    fileName: copy/part fName (length? fName) - 4 ;removes .ext
    append fileName ".pan"
    prog: copy "bin/pany2pan " 
    append append append prog to-string img " /tmp/" fileName
    call/wait prog
    call/output "bin/pstatus" status
    fileName ; returns filename
]

; Pandore thresholding
{pthresholding builds the output image  with the pixels of the input image 
that have a value greater or equal than low or lower or equal than high. Other values are set to 0}

thresholdPan: func [fn [string!] t1 [integer!] t2 [integer!]] [
    prog: copy "bin/pthresholding "
    append append append prog form t1 " " form t2
    append prog " /tmp/" ; default dir for storing pandore images
    append append prog fn " /tmp/result.pan"
    call/wait prog 
    call/output "bin/pstatus" status    
]

;Converts to jpg
pan2JPG: does [
    prog: copy "bin/ppan2jpeg 1.0"
    append append prog " /tmp/result.pan" " /tmp/result.jpg"
    call/wait prog
    call/output "bin/pstatus" status 
]



; Removes all pandore images in /tmp/ directory
removePanImg: does [call "rm /tmp/*.pan" 
                    call "rm /tmp/*.jpg"
                    call "rm /tmp/pand*"
                    sb2/text: "All pandore images removed"]

; Loads red image
loadImage: does [
    isFile: false
    clear sb2/text
    canvas2/image: none
    tmpFile: request-file
    if not none? tmpFile [
        srcImg: load tmpFile
        canvas/image: srcImg
        isFile: true
        sb2/text: "Red Image loaded"
    ]
]

; Processes image
process: does [
    resImg: %/tmp/result.jpg
    sb2/text: copy "Shows filtered pan image: "
    thresholdPan f lowT highT   
    pan2JPG
    append sb2/text status
    if exists? resImg [canvas2/image: load resImg]
]

; ***************** Test Program ****************************
view win: layout [
        title "Pandore Thresholding"
        button 100 "Load Image"     [loadImage f: red2pan tmpFile process]          
        button 70 "Quit"            [removePanImg Quit]
        return
        text 50 "Low" 
        sl1: slider sldSize [lowT: to-integer face/data * 255 
                            lowsb/text: form lowT 
                            if isFile [process]] 
        lowsb: field 40 "0"
        return
        text 50 "High"
        sl2: slider sldSize [highT: to-integer face/data * 255 
                            highsb/text: form highT
                            if isFile [process]]  
        highsb: field 40 "255"
        return
        text dSize "Source"
        text dSize "Result"
        return
        canvas:  base gsize black
        canvas2: base gsize black
        return
        sb1: field dSize
        sb2: field dSize
        do [sb1/text: status sl1/data: lowT / 255.0 sl2/data: highT / 255.0]    
]

Result


Red and Pandore: a great association !



Aucun commentaire:

Enregistrer un commentaire