How-To make your own ImageProcessing code

Implemented Features


ImageProcessing supports the following features, which you can use when implementing your examples:

For detailed descriptions of all features visit Api Reference.

Processing on CPU


CPU filter kernels

Filter kernels are used to call applyFilter function. You can create 2D float32 array as new kernel or use implemented kernels such as:

Multi-threaded processing on CPU

You can use either single-threaded CPU-based image processing or multi-threaded image processing. Multithreading is performed using logger and agent functions, which is specified in this section.

Four of them are implemented:

Simple CPU Example

Open library and load image to process:

open MyImage
open CPU

let myImage = load ("Full/Path/To/Images/Folder/image_name.jpg")

Create new function which sequentially applies blur filter and clockwise rotation to images and saves the result:

let applyCustomFilterOnCPU (image: MyImage) (pathToSave : string) = 
    let blurredImage = image |> applyFilter gaussianBlurKernel
    let rotatedImage = blurredImage |> rotate true
    
    save rotatedImage pathToSave

The result:

open MyImage
open CPU

let myImage = load ("Full/Path/To/Images/Folder/image_name.jpg")

let applyCustomFilterOnCPU (image: MyImage) (pathToSave : string) = 
    let blurredImage = image |> applyFilter gaussianBlurKernel
    let rotatedImage = blurredImage |> rotate true
    
    save rotatedImage pathToSave
 
let pathToSave = "Path/To/Directory/image_name.jpg"

applyCustomFilterOnCPU myImage pathToSave

Processing on GPU


GPU filter kernels

Filter kernels are used to call applyFilter function. You can create 2D float32 array as new kernel or use implemented kernels such as:

GPU processing kernels

GPU kernels are used to call GPU-processing functions. They have specific defining style, so for more information about how they work I recommended to visit Brahma.Fsharp tutorial. But if you have no need in creating new GPU kernels just use implemented ones, such as:

All of them take clContext (which is device's environment abstraction) and localWorkSize (which shows the size of local work group) as input parameters.

Multi-threaded processing on GPU

You can use either single-threaded GPU-based image processing or multi-threaded image processing. Multithreading is performed using logger and agent functions, which specified in this section.

Four of them are implemented:

Simple GPU Example

Open library and load image to process:

open MyImage
open GPU

let myImage = load ("Full/Path/To/Images/Folder/image_name.jpg")

Before creating our function we need to do some steps for diagnosing graphical device.

Define the device value by specifying the brand of your GPU or whatever the program finds (embedded graphics cards are also suitable). And make OpenCL context of it:

let device = Brahma.FSharp.ClDevice.GetFirstAppropriateDevice()
let clContext = Brahma.FSharp.ClContext(device)

Next, define new values for filter and rotation functions. This action is necessary because of compiling kernel function once:

let applyFilterGPU = applyFilter clContext 64
let rotateGPU = rotate clContext 64

Create new function which sequentially applies blur filter and clockwise rotation to images and saves the result:

let applyCustomFilterOnGPU (image: MyImage) (pathToSave : string) = 
    let blurredImage = image |> applyFilterGPU gaussianBlurKernel
    let rotatedImage = blurredImage |> rotateGPU true
    
    save rotatedImage pathToSave

The result:

open MyImage
open GPU

let myImage = load ("Full/Path/To/Images/Folder/image_name.jpg")

let device = Brahma.FSharp.ClDevice.GetFirstAppropriateDevice()
let clContext = Brahma.FSharp.ClContext(device)

let applyFilterGPU = applyFilter clContext 64
let rotateGPU = rotate clContext 64

let applyCustomFilterOnGPU (image: MyImage) (pathToSave : string) = 
    let blurredImage = image |> applyFilterGPU gaussianBlurKernel
    let rotatedImage = blurredImage |> rotateGPU true
    
    save rotatedImage pathToSave
 
let pathToSave = "Path/To/Directory/image_name.jpg"

applyCustomFilterOnGPU myImage pathToSave

Processing of Multiple Images via Directories


Process parameters

The processImage function is designed to process directories with various configuration options. It allows you to choose the type of agent support for processing:

And define a list of transformations to apply to the image, and specify the processing unit (CPU or GPU) for the operation.

Simple Directory Processing Example

Open library and define directories:

open Process
open AgentSupport

let inputDirectory = "Full/Path/To/Input/Images/Folder/"
let outputDirectory = "Full/Path/To/Output/Images/Folder/"

Define list of transformations and filters that will be used:

let imageEditorsList = [Darken; Edges; RotationL]

Note that transformations and filters will be applied sequentially, one-by-one on each image in the specific directory. Choose and define processing unit and multithreading mode.

let processingUnit = GPU Brahma.FSharp.Platform.Nvidia
let agentsSupport = AgentSupport.Full

The result:

open Process
open AgentSupport

let inputDirectory = "Full/Path/To/Input/Images/Folder/"
let outputDirectory = "Full/Path/To/Output/Images/Folder/"

let imageEditorsList = [Darken; Edges; RotationL]

let processingUnit = GPU Brahma.FSharp.Platform.Nvidia
let agentsSupport = AgentSupport.Full

processImages inputDirectory outputDirectory processingUnit imageEditorsList agentsSupport
val myImage: obj
val applyCustomFilterOnCPU: image: 'a -> pathToSave: string -> 'b
val image: 'a
val pathToSave: string
Multiple items
val string: value: 'T -> string

--------------------
type string = System.String
val blurredImage: obj
val rotatedImage: obj
val device: obj
val clContext: obj
val applyFilterGPU: (obj -> obj -> obj)
val rotateGPU: (bool -> obj -> obj)
val applyCustomFilterOnGPU: image: obj -> pathToSave: string -> 'a
val image: obj
val inputDirectory: string
val outputDirectory: string
val imageEditorsList: obj list
val processingUnit: obj
val agentsSupport: obj