A 2D convolution can be thought of as replacing each pixel with the weighted sum of its neighbors. The kernel is another image, usually of smaller size, which contains the weights. Convolution is useful for blurring, sharpening, embossing, edges detection and more.
Many filters are based on 2-D convolution. The 2-D convolution operation isn't extremely fast, unless you use small (3x3 or 5x5) kernels. There are a few rules about the kernel. Its size has to be generally uneven, so that it has a center, for example 3x3, 5x5, 7x7 or 9x9 are ok. Apart from using a kernel matrix, convolution operation also has a multiplier factor and a bias. After applying the filter, the factor will be multiplied with the result, and the bias added to it. So if you have a filter with an element 0.25 in it, but the factor is set to 2, all elements of the filter are multiplied by two so that element 0.25 is actually 0.5. The bias can be used if you want to make the resulting image brighter.
rcvConvolve
In RedCV, this function is defined as follows:
rcvConvolve: function [src [image!] dst [image!] kernel [block!] factor [float!] delta [float!]]
src: source image
dst: destination image
kernel: kernel matrix as block!
factor: multiplier factor as float!
delta: bias for image brightness
Code example
In this example, some basic kernels are provided, but you can easily create your own filters or mofify the size of kernels. The code is self-explanatory and easy to understand.
Red [
Title: "Test images convolution Red VID "
Author: "Francois Jouen - Didier Cadieu"
File: %convolution.red
Needs: 'View
]
fileName: ""
isFile: false
; all we need for computer vision with red
#include %../../libs/redcv.red ; for red functions
noFilter: [0.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 0.0]
quickMask: [-1.0 0.0 -1.0
0.0 4.0 0.0
-1.0 0.0 -1.0]
emboss1: [0.0 0.0 0.0
0.0 1.0 0.0
0.0 0.0 -1.0]
emboss2: [2.0 0.0 0.0
0.0 -1.0 0.0
0.0 0.0 -1.0]
emboss3: [-1.0 -1.0 0.0
-1.0 0.0 1.0
0.0 1.0 1.0]
laplacian: [-1.0 0.0 -1.0
0.0 4.0 0.0
-1.0 0.0 -1.0]
embossH: [0.0 0.0 0.0
-1.0 2.0 -1.0
0.0 0.0 0.0]
embossV: [0.0 -1.0 0.0
0.0 0.0 0.0
0.0 1.0 0.0]
sobelH: [1.0 2.0 1.0
0.0 0.0 0.0
-1.0 -2.0 -1.0]
sobelV: [1.0 2.0 -1.0
2.0 0.0 -2.0
1.0 -2.0 -1.0]
edges1: [-1.0 -1.0 -1.0
-1.0 8.0 -1.0
-1.0 -1.0 -1.0]
edges2: [-5.0 -5.0 -5.0
-5.0 40.0 -5.0
-5.0 -5.0 -5.0]
removal: [-1.0 -1.0 -1.0
-1.0 9.0 -1.0
-1.0 -1.0 -1.0]
gaussian: [0.0 0.2 0.0
0.2 0.2 0.2
0.0 0.2 0.0]
cross: [0.0 1.0 -1.0 0.0]
motion: [1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0
0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0]
rimg: rcvCreateImage 512x512
dst: rcvCreateImage 512x512
loadImage: does [
sb1/data: ""
isFile: false
canvas/image/rgb: black
canvas/size: 0x0
tmp: request-file
if not none? tmp [
fileName: to string! to-local-file tmp
win/text: fileName
rimg: load tmp
dst: load tmp
; update faces
if rimg/size/x >= 512 [
win/size/x: rimg/size/x + 20
win/size/y: rimg/size/y + 70
]
canvas/size/x: rimg/size/x
canvas/size/y: rimg/size/y
canvas/image/size: canvas/size
canvas/offset/x: (win/size/x - rimg/size/x) / 2
canvas/image: dst
isFile: true
op/selected: 1
]
]
img-convolve: func [num [integer!]] [
switch num [
1 [rcvConvolve rimg dst noFilter 1.0 0.0]
2 [t1: now/time/precise
rcvConvolve rimg dst emboss1 1.0 128.0
sb1/data: third now/time/precise - t1
]
3 [t1: now/time/precise
rcvConvolve rimg dst emboss2 1.0 128.0
sb1/data: third now/time/precise - t1
]
4 [t1: now/time/precise
rcvConvolve rimg dst emboss3 1.0 128.0
sb1/data: third now/time/precise - t1
]
5 [t1: now/time/precise
rcvConvolve rimg dst laplacian 1.0 128.0
sb1/data: third now/time/precise - t1
]
6 [t1: now/time/precise
rcvConvolve rimg dst embossH 1.0 127.0
sb1/data: third now/time/precise - t1
]
7 [t1: now/time/precise
rcvConvolve rimg dst embossV 1.0 127.0
sb1/data: third now/time/precise - t1
]
8 [t1: now/time/precise
rcvConvolve rimg dst sobelH 1.0 127.0
t2: now/time/precise
sb1/data: third now/time/precise - t1
]
9 [t1: now/time/precise
rcvConvolve rimg dst sobelV 1.0 127.0
sb1/data: third now/time/precise - t1
]
10 [t1: now/time/precise
rcvConvolve rimg dst edges1 1.0 0.0
sb1/data: third now/time/precise - t1
]
11 [t1: now/time/precise
rcvConvolve rimg dst edges2 1.0 127.0
sb1/data: third now/time/precise - t1
]; Edges 2
12 [t1: now/time/precise
rcvConvolve rimg dst removal 1.0 0.0
sb1/data: third now/time/precise - t1
]; mean removal
13 [t1: now/time/precise
rcvConvolve rimg dst gaussian 1.0 0.0
sb1/data: third now/time/precise - t1
]; Gaussian Blur
14 [t1: now/time/precise
rcvConvolve rimg dst motion 1.0 / 9.0 0.0
sb1/data: third now/time/precise - t1
]; Motion Blur
15 [t1: now/time/precise
rcvConvolve rimg dst quickMask 1.0 0.0
sb1/data: third now/time/precise - t1
]; Quick Mask
16 [t1: now/time/precise
rcvConvolve rimg dst cross 1.0 0.0
sb1/data: third now/time/precise - t1
];
]
]
view win: layout [
title "Red view"
origin 10x10 space 10x10
style btn: button -1x22
style drop-d: drop-down 120x24 on-create [face/selected: 1]
btn "Load" [loadImage]
op: drop-d data [
"Convolution" "Emboss1" "Emboss2" "Emboss3" "Emboss Laplacian"
"Emboss Horizontal" "Emboss Vertical" "Sobel Horizontal" "Sobel Vertical"
"Edges detection" "Edges detection 2" "Mean removal" "Gaussian blur"
"Motion blur (9x9 Kernel)" "Quick Mask" "Cross"
] select 1 on-change [if isFile [img-convolve face/selected]]
text "Rendered in: " sb1: field 100x24
btn "Quit" [quit]
return
canvas: base dst
]