Image convolution: Difference between revisions

m
m (→‎{{header|Perl}}: change test image)
m (→‎{{header|Wren}}: Minor tidy)
 
(13 intermediate revisions by 8 users not shown)
Line 1:
{{task|Image processing}}
 
One class of image digital filters is described by a rectangular matrix of real coefficients called [https://en.wikipedia.org/wiki/Kernel_(image_processing) '''kernel'''] convoluted in a sliding window of image pixels. Usually the kernel is square <math>K_{kl}</math>, where <i>k</i>, <i>l</i> are in the range -<i>R</i>,-<i>R</i>+1,..,<i>R</i>-1,<i>R</i>. <i>W</i>=2<i>R</i>+1 is the kernel width. The filter determines the new value of a monochromatic image pixel P<sub><i>ij</i></sub> as a convolution of the image pixels in the window centered in <i>i</i>, <i>j</i> and the kernel values:
 
The filter determines the new value of a '''grayscale image''' pixel P<sub><i>ij</i></sub> as a convolution of the image pixels in the window centered in <i>i</i>, <i>j</i> and the kernel values:
 
<blockquote>
Line 7 ⟶ 9:
</blockquote>
 
'''Color images''' are usually split into the channels which are filtered independently. A color model can be changed as well, i.e. filtration is performed not necessarily in RGB. Common kernels sizes are 3x3 and 5x5. The complexity of filtrating grows quadratically ([[O]](<i>n</i><sup>2</sup>)) with the kernel width.
 
'''Task''': Write a generic convolution 3x3 kernel filter. Optionally show some end user filters that use this generic one.
 
''(You can use, to test the functions below, these [[Read_ppm_file|input]] and [[Write_ppm_file|output]] solutions.)''
 
=={{header|Action!}}==
{{libheader|Action! Bitmap tools}}
<syntaxhighlight lang="action!">INCLUDE "H6:LOADPPM5.ACT"
 
DEFINE HISTSIZE="256"
 
PROC PutBigPixel(INT x,y BYTE col)
IF x>=0 AND x<=79 AND y>=0 AND y<=47 THEN
y==LSH 2
col==RSH 4
IF col<0 THEN col=0
ELSEIF col>15 THEN col=15 FI
Color=col
Plot(x,y)
DrawTo(x,y+3)
FI
RETURN
 
PROC DrawImage(GrayImage POINTER image INT x,y)
INT i,j
BYTE c
 
FOR j=0 TO image.gh-1
DO
FOR i=0 TO image.gw-1
DO
c=GetGrayPixel(image,i,j)
PutBigPixel(x+i,y+j,c)
OD
OD
RETURN
 
INT FUNC Clamp(INT x,min,max)
IF x<min THEN
RETURN (min)
ELSEIF x>max THEN
RETURN (max)
FI
RETURN (x)
 
PROC Convolution3x3(GrayImage POINTER src,dst
INT ARRAY kernel INT divisor)
INT x,y,i,j,ii,jj,index,sum
BYTE c
 
FOR j=0 TO src.gh-1
DO
FOR i=0 TO src.gw-1
DO
sum=0 index=0
FOR jj=-1 TO 1
DO
y=Clamp(j+jj,0,src.gh-1)
FOR ii=-1 TO 1
DO
x=Clamp(i+ii,0,src.gw-1)
c=GetGrayPixel(src,x,y)
sum==+c*kernel(index)
index==+1
OD
OD
c=Clamp(sum/divisor,0,255)
SetGrayPixel(dst,i,j,c)
OD
OD
RETURN
 
PROC Main()
BYTE CH=$02FC ;Internal hardware value for last key pressed
BYTE ARRAY dataIn(900),dataOut(900)
GrayImage in,out
INT ARRAY sharpenKernel=[
65535 65535 65535
65535 9 65535
65535 65535 65535]
INT size=[30],x,y,sharpenDivisor=[1]
 
Put(125) PutE() ;clear the screen
 
InitGrayImage(in,size,size,dataIn)
InitGrayImage(out,size,size,dataOut)
PrintE("Loading source image...")
LoadPPM5(in,"H6:LENA30G.PPM")
PrintE("Convolution...")
Convolution3x3(in,out,sharpenKernel,sharpenDivisor)
 
Graphics(9)
x=(40-size)/2
y=(48-size)/2
DrawImage(in,x,y)
DrawImage(out,x+40,y)
 
DO UNTIL CH#$FF OD
CH=$FF
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/Image_convolution.png Screenshot from Atari 8-bit computer]
 
=={{header|Ada}}==
First we define floating-point stimulus and color pixels which will be then used for filtration:
<langsyntaxhighlight lang="ada">type Float_Luminance is new Float;
 
type Float_Pixel is record
Line 49 ⟶ 149:
begin
return (To_Luminance (X.R), To_Luminance (X.G), To_Luminance (X.B));
end To_Pixel;</langsyntaxhighlight>
Float_Luminance is an unconstrained equivalent of Luminance. Float_Pixel is one to Pixel. Conversion operations To_Luminance and To_Pixel saturate the corresponding values. The operation + is defined per channels. The operation * is defined as multiplying by a scalar. (I.e. Float_Pixel is a vector space.)
 
Now we are ready to implement the filter. The operation is performed in memory. The access to the image array is minimized using a slid window. The filter is in fact a triplet of filters handling each image channel independently. It can be used with other color models as well.
<langsyntaxhighlight lang="ada">type Kernel_3x3 is array (-1..1, -1..1) of Float_Luminance;
 
procedure Filter (Picture : in out Image; K : Kernel_3x3) is
Line 98 ⟶ 198:
Above (Picture'Last (2)) := W21;
end loop;
end Filter;</langsyntaxhighlight>
Example of use:
<langsyntaxhighlight lang="ada"> F1, F2 : File_Type;
begin
Open (F1, In_File, "city.ppm");
Line 111 ⟶ 211:
Put_PPM (F2, X);
end;
Close (F2);</langsyntaxhighlight>
 
=={{header|BBC BASIC}}==
Line 117 ⟶ 217:
[[Image:original_bbc.jpg|right]]
[[Image:sharpened_bbc.jpg|right]]
<langsyntaxhighlight lang="bbcbasic"> Width% = 200
Height% = 200
Line 162 ⟶ 262:
REPEAT
WAIT 1
UNTIL FALSE</langsyntaxhighlight>
 
=={{header|C}}==
Line 168 ⟶ 268:
Interface:
 
<langsyntaxhighlight lang="c">image filter(image img, double *K, int Ks, double, double);</langsyntaxhighlight>
 
The implementation (the <tt>Ks</tt> argument is so that 1 specifies a 3&times;3 matrix, 2 a 5&times;5 matrix ...
N a (2N+1)&times;(2N+1) matrix).
 
<langsyntaxhighlight lang="c">#include "imglib.h"
 
inline static color_component GET_PIXEL_CHECK(image img, int x, int y, int l) {
Line 211 ⟶ 311:
}
return NULL;
}</langsyntaxhighlight>
 
Usage example:
Line 217 ⟶ 317:
The <tt>read_image</tt> function is from [[Read image file through a pipe|here]].
 
<langsyntaxhighlight lang="c">#include <stdio.h>
#include "imglib.h"
 
Line 277 ⟶ 377:
free_img(ii);
} else { fprintf(stderr, "err reading %s\n", input); }
}</langsyntaxhighlight>
 
=={{header|Common Lisp}}==
Uses the RGB pixel buffer package defined here [[Basic bitmap storage#Common Lisp]]. Also the PPM file IO functions defined in
[[Bitmap/Read a PPM file#Common_Lisp]] and [[Bitmap/Write a PPM file#Common_Lisp]] merged into one package.
<langsyntaxhighlight lang="lisp">(load "rgb-pixel-buffer")
(load "ppm-file-io")
 
Line 349 ⟶ 450:
(loop for pars being the hash-values of convolve::*cnv-lib*
do (princ (convolve::convolve "lena_color.ppm" pars)) (terpri)))
</syntaxhighlight>
</lang>
 
=={{header|D}}==
This requires the module from the Grayscale Image Task.
<langsyntaxhighlight lang="d">import std.string, std.math, std.algorithm, grayscale_image;
 
struct ConvolutionFilter {
Line 468 ⟶ 569:
img.convolve(filter)
.savePGM(format("lenna_gray_%s.ppm", filter.name));
}</langsyntaxhighlight>
 
=={{header|Go}}==
Using standard image library:
<langsyntaxhighlight lang="go">package main
 
import (
Line 562 ⟶ 663:
fmt.Println(err)
}
}</langsyntaxhighlight>
Alternative version, building on code from bitmap task.
 
New function for raster package:
<langsyntaxhighlight lang="go">package raster
 
import "math"
Line 637 ⟶ 738:
}
return r
}</langsyntaxhighlight>
Demonstration program:
<langsyntaxhighlight lang="go">package main
 
// Files required to build supporting package raster are found in:
Line 678 ⟶ 779:
fmt.Println(err)
}
}</langsyntaxhighlight>
 
=={{header|J}}==
 
<langsyntaxhighlight Jlang="j">NB. pad the edges of an array with border pixels
NB. (increasing the first two dimensions by 1 less than the kernel size)
pad=: adverb define{{
rank=.#$m
'a b'=. (<. ,. >.) 0.5 0.5 p. $m
'first second'=. (<.,:>.)-:$m
a"_`(0 , ] - 1:)`(# 1:)}~&# # b"_`(0 , ] - 1:)`(# 1:)}~&(1 { $) #"1 ]
-@(second+rank{.$) {. (first+rank{.$){.]
)
}}
 
kernel_filter=: adverb define{{
[: (0 >. 255 <. <.@:+&0.5) (1,:$m)+/ .*&(,m)~&(,/)&m;._3 m pad
}}</syntaxhighlight>
)</lang>
 
 
Line 698 ⟶ 800:
Example use:
 
<syntaxhighlight lang J="j"> NB. kernels borrowed from C and TCL implementations
sharpen_kernelid_kernel=: _1+10*4(=&i.-)3 3
sharpen_kernel=: ({ _1,#@,)id_kernel
blur_kernel=: 3 3$%9
blur_kernel=: ($ *&%/)3 3
emboss_kernel=: _2 _1 0,_1 1 1,:0 1 2
emboss_kernel=: id_kernel+(+/~ - >./)i.3
sobel_emboss_kernel=: _1 _2 _1,0,:1 2 1
sobel_emboss_kernel=: (i:-:<:3)*/1+(<.|.)i.3
 
'blurred.ppm' writeppm~ blur_kernel kernel_filter readppm 'original.ppm'</langsyntaxhighlight>
 
=={{header|Java}}==
 
'''Code:'''
<langsyntaxhighlight Javalang="java">import java.awt.image.*;
import java.io.File;
import java.io.IOException;
Line 849 ⟶ 952:
return;
}
}</langsyntaxhighlight>
 
 
Line 864 ⟶ 967:
 
'''Code:'''
<langsyntaxhighlight lang="javascript">// Image imageIn, Array kernel, function (Error error, Image imageOut)
// precondition: Image is loaded
// returns loaded Image to asynchronous callback function
Line 939 ⟶ 1,042:
imageOut.src = can.toDataURL('image/png');
}</langsyntaxhighlight>
 
'''Example Usage:'''
Line 967 ⟶ 1,070:
 
=={{header|Julia}}==
<langsyntaxhighlight lang="julia">
using FileIO, Images
 
Line 977 ⟶ 1,080:
 
save("imagesharper.png", imfilt)
</syntaxhighlight>
</lang>
 
=={{header|Kotlin}}==
{{trans|Java}}
<langsyntaxhighlight lang="scala">// version 1.2.10
 
import kotlin.math.round
Line 1,096 ⟶ 1,199:
}
writeOutputImage(args[1], dataArrays)
}</langsyntaxhighlight>
 
{{out}}
Line 1,109 ⟶ 1,212:
<br>
NB Things like convolution would be best done by combining LB with ImageMagick, which is easily called from LB.
<syntaxhighlight lang="lb">
<lang lb>
dim result( 300, 300), image( 300, 300), mask( 100, 100)
w =128
Line 1,205 ⟶ 1,308:
CallDLL #user32, "ReleaseDC", hw as ulong, hdc as ulong
end
</syntaxhighlight>
</lang>
Screenview is available at [[http://www.diga.me.uk/convolved.gif]]
 
=={{header|Maple}}==
Builtin command ImageTools:-Convolution()
<langsyntaxhighlight Maplelang="maple">pic:=Import("smiling_dog.jpg"):
mask := Matrix([[1,2,3],[4,5,6],[7,8,9]]);
pic := ImageTools:-Convolution(pic, mask);</langsyntaxhighlight>
 
 
=={{header|Mathematica}} / {{header|Wolfram Language}}==
Most image processing functions introduced in Mathematica 7
<langsyntaxhighlight lang="mathematica">img = Import[NotebookDirectory[] <> "Lenna50.jpg"];
kernel = {{0, -1, 0}, {-1, 4, -1}, {0, -1, 0}};
ImageConvolve[img, kernel]
ImageConvolve[img, GaussianMatrix[35] ]
ImageConvolve[img, BoxMatrix[1] ]</langsyntaxhighlight>
 
=={{header|MATLAB}}==
The built-in function [http://www.mathworks.com/help/matlab/ref/conv2.html conv2] handles the basic convolution. Below is a program that has several more options that may be useful in different image processing applications (see comments under convImage for specifics).
<langsyntaxhighlight MATLABlang="matlab">function testConvImage
Im = [1 2 1 5 5 ; ...
1 2 7 9 9 ; ...
Line 1,392 ⟶ 1,494:
% Convert back to former image data type
ImOut = cast(ImOut, classIm);
end</langsyntaxhighlight>
{{out}}
<pre>Original image:
Line 1,440 ⟶ 1,542:
5 46 40 40 2
1 1 1 1 1</pre>
 
=={{header|Nim}}==
{{trans|D}}
{{libheader|nimPNG}}
As in the D version, we use the modules built for the "bitmap" and "grayscale image" tasks. But we have chosen to read and write PNG files rather than PPM files, using for this purpose the "nimPNG" third party module.
 
<syntaxhighlight lang="nim">import math, lenientops, strutils
import nimPNG, bitmap, grayscale_image
 
type ConvolutionFilter = object
kernel: seq[seq[float]]
divisor: float
offset: float
name: string
 
func convolve[T: Image|GrayImage](img: T; filter: ConvolutionFilter): T =
 
assert not img.isNil
assert filter.divisor.classify != fcNan and filter.offset.classify != fcNan
assert filter.divisor != 0
assert filter.kernel.len > 0 and filter.kernel[0].len > 0
for row in filter.kernel:
assert row.len == filter.kernel[0].len
assert filter.kernel.len mod 2 == 1
assert filter.kernel[0].len mod 2 == 1
assert img.h >= filter.kernel.len
assert img.w >= filter.kernel[0].len
 
let knx2 = filter.kernel[0].len div 2
let kny2 = filter.kernel.len div 2
 
when T is Image:
result = newImage(img.w, img.h)
else:
result = newGrayImage(img.w, img.h)
 
for y in kny2..<(img.h - kny2):
for x in knx2..<(img.w - knx2):
when T is Image:
var total: array[3, float]
else:
var total: float
for sy, kRow in filter.kernel:
for sx, k in kRow:
let p = img[x + sx - knx2, y + sy - kny2]
when T is Image:
total[0] += p.r * k
total[1] += p.g * k
total[2] += p.b * k
else:
total += p * k
 
let d = filter.divisor
let off = filter.offset * Luminance.high
when T is Image:
result[x, y] = color(min(max(total[0] / d + off, Luminance.low.float),
Luminance.high.float).toInt,
min(max(total[1] / d + off, Luminance.low.float),
Luminance.high.float).toInt,
min(max(total[2] / d + off, Luminance.low.float),
Luminance.high.float).toInt)
else:
result[x, y] = Luminance(min(max(total / d + off, Luminance.low.float),
Luminance.high.float).toInt)
 
const
Input = "lena.png"
Output1 = "lena_$1.png"
Output2 = "lena_gray_$1.png"
 
const Filters = [ConvolutionFilter(kernel: @[@[-2.0, -1.0, 0.0],
@[-1.0, 1.0, 1.0],
@[ 0.0, 1.0, 2.0]],
divisor: 1.0, offset: 0.0, name: "Emboss"),
 
ConvolutionFilter(kernel: @[@[-1.0, -1.0, -1.0],
@[-1.0, 9.0, -1.0],
@[-1.0, -1.0, -1.0]],
divisor: 1.0, offset: 0.0, name: "Sharpen"),
 
ConvolutionFilter(kernel: @[@[-1.0, -2.0, -1.0],
@[ 0.0, 0.0, 0.0],
@[ 1.0, 2.0, 1.0]],
divisor: 1.0, offset: 0.5, name: "Sobel_emboss"),
 
ConvolutionFilter(kernel: @[@[1.0, 1.0, 1.0],
@[1.0, 1.0, 1.0],
@[1.0, 1.0, 1.0]],
divisor: 9.0, offset: 0.0, name: "Box_blur"),
 
ConvolutionFilter(kernel: @[@[1.0, 4.0, 7.0, 4.0, 1.0],
@[4.0, 16.0, 26.0, 16.0, 4.0],
@[7.0, 26.0, 41.0, 26.0, 7.0],
@[4.0, 16.0, 26.0, 16.0, 4.0],
@[1.0, 4.0, 7.0, 4.0, 1.0]],
divisor: 273.0, offset: 0.0, name: "Gaussian_blur")]
 
let pngImage = loadPNG24(seq[byte], Input).get()
 
# Convert to an image managed by the "bitmap" module.
let img = newImage(pngImage.width, pngImage.height)
for i in 0..img.pixels.high:
img.pixels[i] = color(pngImage.data[3 * i],
pngImage.data[3 * i + 1],
pngImage.data[3 * i + 2])
 
for filter in Filters:
let result = img.convolve(filter)
var data = newSeqOfCap[byte](result.pixels.len * 3)
for color in result.pixels:
data.add([color.r, color.g, color.b])
let output = Output1.format(filter.name)
if savePNG24(output, data, result.w, result.h).isOk:
echo "Saved: ", output
 
let grayImg = img.toGrayImage()
for filter in Filters:
let result = grayImg.convolve(filter).toImage()
var data = newSeqOfCap[byte](result.pixels.len * 3)
for color in result.pixels:
data.add([color.r, color.g, color.b])
let output = Output2.format(filter.name)
if savePNG24(output, data, result.w, result.h).isOk:
echo "Saved: ", output</syntaxhighlight>
 
=={{header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">let get_rgb img x y =
let _, r_channel,_,_ = img in
let width = Bigarray.Array2.dim1 r_channel
Line 1,497 ⟶ 1,723:
done;
done;
(res)</langsyntaxhighlight>
 
<langsyntaxhighlight lang="ocaml">let emboss img =
let kernel = [|
[| -2.; -1.; 0. |];
Line 1,533 ⟶ 1,759:
|] in
convolve_value ~img ~kernel ~divisor:9.0 ~offset:0.0;
;;</langsyntaxhighlight>
 
=={{header|Octave}}==
Line 1,539 ⟶ 1,765:
'''Use package''' [http://octave.sourceforge.net/image/index.html Image]
 
<langsyntaxhighlight lang="octave">function [r, g, b] = rgbconv2(a, c)
r = im2uint8(mat2gray(conv2(a(:,:,1), c)));
g = im2uint8(mat2gray(conv2(a(:,:,2), c)));
Line 1,561 ⟶ 1,787:
jpgwrite("LennaSobel.jpg", r, g, b, 100);
[r, g, b] = rgbconv2(im, sharpen);
jpgwrite("LennaSharpen.jpg", r, g, b, 100);</langsyntaxhighlight>
 
=={{header|Perl}}==
<langsyntaxhighlight lang="perl">use strict;
use warnings;
 
Line 1,574 ⟶ 1,800:
my $image = rpic 'pythagoras_tree.png';
my $smoothed = conv2d $image, $kernel, {Boundary => 'Truncate'};
wpic $smoothed, 'pythagoras_convolution.png';</langsyntaxhighlight>
Compare offsite images: [https://github.com/SqrtNegInf/Rosettacode-Perl5-Smoke/blob/master/ref/frog.png frog.png] vs.
[https://github.com/SqrtNegInf/Rosettacode-Perl5-Smoke/blob/master/ref/frog_convolution.png frog_convolution.png]
 
=={{header|Perl 6}}==
<lang perl6>#!/usr/bin/env perl6
 
# Reference:
# https://github.com/azawawi/perl6-magickwand
# http://www.imagemagick.org/Usage/convolve/
 
use v6;
 
use MagickWand;
 
# A new magic wand
my $original = MagickWand.new;
 
# Read an image
$original.read("./Lenna100.jpg") or die;
 
my $o = $original.clone;
 
# using coefficients from kernel "Sobel"
# http://www.imagemagick.org/Usage/convolve/#sobel
$o.convolve( [ 1, 0, -1,
2, 0, -2,
1, 0, -1] );
 
$o.write("Lenna100-convoluted.jpg") or die;
 
# And cleanup on exit
LEAVE {
$original.cleanup if $original.defined;
$o.cleanup if $o.defined;
}</lang>
 
=={{header|Phix}}==
{{libheader|Phix/pGUI}}
<!--<syntaxhighlight lang="phix">(notonline)-->
<lang Phix>-- demo\rosetta\Image_convolution.exw
<span style="color: #000080;font-style:italic;">--
include pGUI.e
-- demo\rosetta\Image_convolution.exw
 
-- ==================================
constant filters = {-- Emboss
--</span>
{{-2.0, -1.0, 0.0},
<span style="color: #008080;">without</span> <span style="color: #008080;">js</span> <span style="color: #000080;font-style:italic;">-- imImage, im_width, im_height, im_pixel, IupImageRGB, allocate,
{-1.0, 1.0, 1.0},
-- imFileImageLoadBitmap, { 0.0peekNS, 1.0wait_key, 2.0}},IupImageFromImImage</span>
<span style="color: #008080;">include</span> <span style="color: #000000;">pGUI</span><span style="color: #0000FF;">.</span><span style="color: #000000;">e</span>
-- Sharpen
{{-1.0, -1.0, -1.0},
<span style="color: #008080;">constant</span> <span style="color: #000000;">filters</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000080;font-style:italic;">-- Emboss</span>
{-1.0, 9.0, -1.0},
<span style="color: #0000FF;">{{-</span><span style="color: #000000;">2.0</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0</span><span style="color: #0000FF;">},</span>
{-1.0, -1.0, -1.0}},
<span style="color: #0000FF;">{-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">},</span>
-- Sobel_emboss
<span style="color: #0000FF;">{</span> <span style="color: #000000;">0.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.0</span><span style="color: #0000FF;">}},</span>
{{-1.0, -2.0, -1.0},
{<span 0.0,style="color: #000080;font-style:italic;">-- 0.0, 0.0},Sharpen</span>
<span style="color: #0000FF;">{{-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">},</span>
{ 1.0, 2.0, 1.0}},
<span style="color: #0000FF;">{-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9.0</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">},</span>
-- Box_blur
<span style="color: #0000FF;">{-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">}},</span>
{{ 1.0, 1.0, 1.0},
{<span 1.0,style="color: 1.0,#000080;font-style:italic;">-- 1.0},Sobel_emboss</span>
<span style="color: #0000FF;">{{-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">2.0</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1.0</span><span style="color: #0000FF;">},</span>
{ 1.0, 1.0, 1.0}},
<span style="color: #0000FF;">{</span> <span style="color: #000000;">0.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.0</span><span style="color: #0000FF;">},</span>
-- Gaussian_blur
<span style="color: #0000FF;">{</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">2.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">}},</span>
{{1, 4, 7, 4, 1},
{4,<span 16,style="color: 26,#000080;font-style:italic;">-- 16, 4},Box_blur</span>
<span style="color: #0000FF;">{{</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">},</span>
{7, 26, 41, 26, 7},
<span style="color: #0000FF;">{</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">},</span>
{4, 16, 26, 16, 4},
<span style="color: #0000FF;">{</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1.0</span><span style="color: #0000FF;">}},</span>
{1, 4, 7, 4, 1}}}
<span style="color: #000080;font-style:italic;">-- Gaussian_blur</span>
 
<span style="color: #0000FF;">{{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">},</span>
function convolute(imImage img, integer fdx)
<span style="color: #0000FF;">{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">16</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">26</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">16</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">},</span>
integer width = im_width(img),
<span style="color: #0000FF;">{</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">26</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">41</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">26</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">},</span>
height = im_height(img)
<span style="color: #0000FF;">{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">16</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">26</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">16</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">},</span>
sequence original = repeat(repeat(0,width),height),
<span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">}}}</span>
new_image,
filter = filters[fdx]
<span style="color: #008080;">function</span> <span style="color: #000000;">convolute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">imImage</span> <span style="color: #000000;">img</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">fdx</span><span style="color: #0000FF;">)</span>
integer fh = length(filter), hh=(fh-1)/2,
<span style="color: #004080;">integer</span> <span style="color: #000000;">width</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">im_width</span><span style="color: #0000FF;">(</span><span style="color: #000000;">img</span><span style="color: #0000FF;">),</span>
fw = length(filter[1]), hw=(fw-1)/2,
<span style="color: #000000;">height</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">im_height</span><span style="color: #0000FF;">(</span><span style="color: #000000;">img</span><span style="color: #0000FF;">)</span>
divisor = max(sum(filter),1)
<span style="color: #004080;">sequence</span> <span style="color: #000000;">original</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">width</span><span style="color: #0000FF;">),</span><span style="color: #000000;">height</span><span style="color: #0000FF;">),</span>
 
<span style="color: #000000;">new_image</span><span style="color: #0000FF;">,</span>
for y=height-1 to 0 by -1 do
<span style="color: #000000;">filterfdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">filters</span><span style="color: #0000FF;">[</span><span style="color: #000000;">fdx</span><span style="color: #0000FF;">]</span>
for x=0 to width-1 do
<span style="color: #004080;">integer</span> <span style="color: #000000;">fh</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filterfdx</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">hh</span><span style="color: #0000FF;">=(</span><span style="color: #000000;">fh</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span>
original[height-y,x+1] = im_pixel(img, x, y)
<span style="color: #000000;">fw</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filterfdx</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]),</span> <span style="color: #000000;">hw</span><span style="color: #0000FF;">=(</span><span style="color: #000000;">fw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span>
end for
<span style="color: #000000;">divisor</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sum</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filterfdx</span><span style="color: #0000FF;">),</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
end for
new_image = original
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">height</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">0</span> <span style="color: #008080;">by</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
 
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">0</span> <span style="color: #008080;">to</span> <span style="color: #000000;">width</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
for y=hh+1 to height-hh-1 do
<span style="color: #000000;">original</span><span style="color: #0000FF;">[</span><span style="color: #000000;">height</span><span style="color: #0000FF;">-</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">im_pixel</span><span style="color: #0000FF;">(</span><span style="color: #000000;">img</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">)</span>
for x=hw+1 to width-hw-1 do
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
sequence newrgb = {0,0,0}
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
for i=-hh to +hh do
<span style="color: #000000;">new_image</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">original</span>
for j=-hw to +hw do
newrgb = sq_add(newrgb,sq_mul(filter[i+hh+1,j+hw+1],original[y+i,x+j]))
<span style="color: #008080;">for</span> <span style="color: #000000;">y</span><span style="color: #0000FF;">=</span><span style="color: #000000;">hh</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">-</span><span style="color: #000000;">hh</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
end for
<span style="color: #008080;">for</span> <span style="color: #000000;">x</span><span style="color: #0000FF;">=</span><span style="color: #000000;">hw</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">width</span><span style="color: #0000FF;">-</span><span style="color: #000000;">hw</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #008080;">do</span>
end for
<span style="color: #004080;">sequence</span> <span style="color: #000000;">newrgb</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">}</span>
new_image[y,x] = sq_max(sq_min(sq_floor_div(newrgb,divisor),255),0)
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">hh</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">hh</span> <span style="color: #008080;">do</span>
end for
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=-</span><span style="color: #000000;">hw</span> <span style="color: #008080;">to</span> <span style="color: #0000FF;">+</span><span style="color: #000000;">hw</span> <span style="color: #008080;">do</span>
end for
<span style="color: #000000;">newrgb</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">newrgb</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">sq_mul</span><span style="color: #0000FF;">(</span><span style="color: #000000;">filterfdx</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">hh</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">j</span><span style="color: #0000FF;">+</span><span style="color: #000000;">hw</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span><span style="color: #000000;">original</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">+</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">+</span><span style="color: #000000;">j</span><span style="color: #0000FF;">]))</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
new_image = flatten(new_image) -- (as needed by IupImageRGB)
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
Ihandle new_img = IupImageRGB(width, height, new_image)
<span style="color: #000000;">new_image</span><span style="color: #0000FF;">[</span><span style="color: #000000;">y</span><span style="color: #0000FF;">,</span><span style="color: #000000;">x</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_max</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_min</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_floor_div</span><span style="color: #0000FF;">(</span><span style="color: #000000;">newrgb</span><span style="color: #0000FF;">,</span><span style="color: #000000;">divisor</span><span style="color: #0000FF;">),</span><span style="color: #000000;">255</span><span style="color: #0000FF;">),</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
return new_img
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
end function
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
 
IupOpen()
<span style="color: #000000;">new_image</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">flatten</span><span style="color: #0000FF;">(</span><span style="color: #000000;">new_image</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (as needed by IupImageRGB)</span>
 
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">new_img</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">IupImageRGB</span><span style="color: #0000FF;">(</span><span style="color: #000000;">width</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">height</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">new_image</span><span style="color: #0000FF;">)</span>
constant w = machine_word(),
<span style="color: #008080;">return</span> <span style="color: #000000;">new_img</span>
TITLE = "Image convolution"
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
atom pError = allocate(w)
imImage im1 = imFileImageLoadBitmap("Quantum_frog.512.png",0,pError)
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
 
if im1=NULL then
<span style="color: #008080;">constant</span> <span style="color: #000000;">w</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">machine_word</span><span style="color: #0000FF;">(),</span>
?{"error opening image",peekNS(pError,w,1)}
<span style="color: #000000;">TITLE</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Image convolution"</span>
{} = wait_key()
<span style="color: #004080;">atom</span> <span style="color: #000000;">pError</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">allocate</span><span style="color: #0000FF;">(</span><span style="color: #000000;">w</span><span style="color: #0000FF;">)</span>
abort(0)
<span style="color: #000080;font-style:italic;">--imImage im1 = imFileImageLoadBitmap("Lenna50.jpg",0,pError)
end if
--imImage im1 = imFileImageLoadBitmap("Lenna100.jpg",0,pError)
 
--imImage im1 = imFileImageLoadBitmap("Lena.ppm",0,pError)</span>
Ihandle dlg,
<span style="color: #000000;">imImage</span> <span style="color: #000000;">im1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">imFileImageLoadBitmap</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"Quantum_frog.png"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">pError</span><span style="color: #0000FF;">)</span>
filter = IupList("DROPDOWN=YES, VALUE=1")
<span style="color: #000080;font-style:italic;">--imImage im1 = imFileImageLoadBitmap("Quantum_frog.512.png",0,pError)</span>
 
Ihandln image1 = IupImageFromImImage(im1),
<span style="color: #008080;">if</span> <span style="color: #000000;">im1</span><span style="color: #0000FF;">=</span><span style="color: #004600;">NULL</span> <span style="color: #008080;">then</span>
image2 = convolute(im1,1),
<span style="color: #0000FF;">?{</span><span style="color: #008000;">"error opening image"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">peekNS</span><span style="color: #0000FF;">(</span><span style="color: #000000;">pError</span><span style="color: #0000FF;">,</span><span style="color: #000000;">w</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)}</span>
label1 = IupLabel(),
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
label2 = IupLabel()
<span style="color: #7060A8;">abort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
IupSetAttributeHandle(label1, "IMAGE", image1)
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
IupSetAttributeHandle(label2, "IMAGE", image2)
<span style="color: #000080;font-style:italic;">--(see also Color_quantization.exw if not an IM_RGB image)</span>
 
function valuechanged_cb(Ihandle /*filter*/)
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span>
IupSetAttribute(dlg,"TITLE","Working...")
<span style="color: #000000;">flt</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupList</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"DROPDOWN=YES, VALUE=1"</span><span style="color: #0000FF;">)</span>
IupSetAttributeHandle(label2, "IMAGE", NULL)
IupDestroy(image2)
<span style="color: #004080;">Ihandln</span> <span style="color: #000000;">image1</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">IupImageFromImImage</span><span style="color: #0000FF;">(</span><span style="color: #000000;">im1</span><span style="color: #0000FF;">),</span>
image2 = convolute(im1,IupGetInt(filter,"VALUE"))
<span style="color: #000000;">image2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">convolute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">im1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">),</span>
IupSetAttributeHandle(label2, "IMAGE", image2)
<span style="color: #000000;">label1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(),</span>
IupSetAttribute(dlg,"TITLE",TITLE)
<span style="color: #000000;">label2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">()</span>
IupRefresh(dlg)
<span style="color: #7060A8;">IupSetAttributeHandle</span><span style="color: #0000FF;">(</span><span style="color: #000000;">label1</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"IMAGE"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">image1</span><span style="color: #0000FF;">)</span>
return IUP_DEFAULT
<span style="color: #7060A8;">IupSetAttributeHandle</span><span style="color: #0000FF;">(</span><span style="color: #000000;">label2</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"IMAGE"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">image2</span><span style="color: #0000FF;">)</span>
end function
IupSetCallback(filter,"VALUECHANGED_CB",Icallback("valuechanged_cb"))
<span style="color: #008080;">function</span> <span style="color: #000000;">valuechanged_cb</span><span style="color: #0000FF;">(</span><span style="color: #004080;">Ihandle</span> <span style="color: #000080;font-style:italic;">/*flt*/</span><span style="color: #0000FF;">)</span>
 
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"Working..."</span><span style="color: #0000FF;">)</span>
IupSetAttributes(filter,"1=Emboss, 2=Sharpen, 3=\"Sobel emboss\", 4=\"Box_blur\", 5=Gaussian_blur")
<span style="color: #000080;font-style:italic;">-- IupSetAttributeHandle(label2, "IMAGE", NULL)</span>
IupSetAttributes(filter,"VISIBLEITEMS=6") -- (still dunno why this trick works)
<span style="color: #000000;">image2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDestroy</span><span style="color: #0000FF;">(</span><span style="color: #000000;">image2</span><span style="color: #0000FF;">)</span>
dlg = IupDialog(IupVbox({filter,
<span style="color: #000000;">image2</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">convolute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">im1</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">IupGetInt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">flt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUE"</span><span style="color: #0000FF;">))</span>
IupFill(),
<span style="color: #7060A8;">IupSetAttributeHandle</span><span style="color: #0000FF;">(</span><span style="color: #000000;">label2</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"IMAGE"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">image2</span><span style="color: #0000FF;">)</span>
IupHbox({IupFill(),label1, label2,IupFill()}),
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">TITLE</span><span style="color: #0000FF;">)</span>
IupFill()}))
<span style="color: #7060A8;">IupRefresh</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
IupSetAttribute(dlg, "TITLE", TITLE)
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
IupCloseOnEscape(dlg)
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
IupShow(dlg)
<span style="color: #7060A8;">IupSetCallback</span><span style="color: #0000FF;">(</span><span style="color: #000000;">flt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VALUECHANGED_CB"</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">Icallback</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"valuechanged_cb"</span><span style="color: #0000FF;">))</span>
 
IupMainLoop()
<span style="color: #7060A8;">IupSetAttributes</span><span style="color: #0000FF;">(</span><span style="color: #000000;">flt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">`1=Emboss, 2=Sharpen, 3="Sobel emboss", 4="Box_blur", 5=Gaussian_blur`</span><span style="color: #0000FF;">)</span>
IupClose()</lang>
<span style="color: #7060A8;">IupSetAttributes</span><span style="color: #0000FF;">(</span><span style="color: #000000;">flt</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"VISIBLEITEMS=6"</span><span style="color: #0000FF;">)</span> <span style="color: #000080;font-style:italic;">-- (still dunno why this trick works)</span>
<span style="color: #000000;">dlg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupDialog</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">IupVbox</span><span style="color: #0000FF;">({</span><span style="color: #000000;">flt</span><span style="color: #0000FF;">,</span>
<span style="color: #7060A8;">IupFill</span><span style="color: #0000FF;">(),</span>
<span style="color: #7060A8;">IupHbox</span><span style="color: #0000FF;">({</span><span style="color: #7060A8;">IupFill</span><span style="color: #0000FF;">(),</span><span style="color: #000000;">label1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">label2</span><span style="color: #0000FF;">,</span><span style="color: #7060A8;">IupFill</span><span style="color: #0000FF;">()}),</span>
<span style="color: #7060A8;">IupFill</span><span style="color: #0000FF;">()}))</span>
<span style="color: #7060A8;">IupSetAttribute</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span> <span style="color: #008000;">"TITLE"</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">TITLE</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">IupShow</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">platform</span><span style="color: #0000FF;">()!=</span><span style="color: #004600;">JS</span> <span style="color: #008080;">then</span> <span style="color: #000080;font-style:italic;">-- (no chance...)</span>
<span style="color: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<!--</syntaxhighlight>-->
 
=={{header|PicoLisp}}==
<langsyntaxhighlight PicoLisplang="picolisp">(scl 3)
 
(de ppmConvolution (Ppm Kernel)
Line 1,746 ⟶ 1,951:
(* (get X K L C) (get Kernel K L)) ) ) )
(link (min 255 (max 0 (*/ Val 1.0)))) ) ) ) )
(map pop X) ) ) ) ) ) ) )</langsyntaxhighlight>
Test using 'ppmRead' from [[Bitmap/Read a PPM file#PicoLisp]] and 'ppmWrite'
from [[Bitmap/Write a PPM file#PicoLisp]]:
Line 1,766 ⟶ 1,971:
Image manipulation is normally done using an image processing library. For PIL/Pillow do:
 
<langsyntaxhighlight lang="python">#!/bin/python
from PIL import Image, ImageFilter
 
Line 1,777 ⟶ 1,982:
im2 = im.filter(kernel)
 
im2.show()</langsyntaxhighlight>
 
Alternatively, SciPy can be used but programmers need to be careful about the colors being clipped since they are normally limited to the 0-255 range:
 
<langsyntaxhighlight lang="python">#!/bin/python
import numpy as np
from scipy.ndimage.filters import convolve
Line 1,797 ⟶ 2,002:
im3 = np.array(np.clip(im2, 0, 255), dtype=np.uint8) #Apply color clipping
imshow(im3)</langsyntaxhighlight>
 
=={{header|Racket}}==
Line 1,807 ⟶ 2,012:
 
 
<langsyntaxhighlight lang="racket">#lang typed/racket
(require images/flomap racket/flonum)
 
Line 1,856 ⟶ 2,061:
(save-image
(flomap->bitmap (flomap-convolve flmp (flvector -1. -1. -1. -1. 4. -1. -1. -1. -1.)))
"out/convolve-etch-3x3.png"))</langsyntaxhighlight>
 
=={{header|Raku}}==
(formerly Perl 6)
===Perl 5 PDL library===
 
<syntaxhighlight lang="raku" line>use PDL:from<Perl5>;
use PDL::Image2D:from<Perl5>;
 
my $kernel = pdl [[-2, -1, 0],[-1, 1, 1], [0, 1, 2]]; # emboss
 
my $image = rpic 'frog.png';
my $smoothed = conv2d $image, $kernel, {Boundary => 'Truncate'};
wpic $smoothed, 'frog_convolution.png';</syntaxhighlight>
Compare offsite images: [https://github.com/SqrtNegInf/Rosettacode-Perl6-Smoke/blob/master/ref/frog.png frog.png] vs.
[https://github.com/SqrtNegInf/Rosettacode-Perl6-Smoke/blob/master/ref/frog_convolution.png frog_convolution.png]
 
===Imagemagick library===
<syntaxhighlight lang="raku" line>
# Note: must install version from github NOT version from CPAN which needs to be updated.
# Reference:
# https://github.com/azawawi/perl6-magickwand
# http://www.imagemagick.org/Usage/convolve/
use v6;
use MagickWand;
# A new magic wand
my $original = MagickWand.new;
# Read an image
$original.read("./Lenna100.jpg") or die;
my $o = $original.clone;
# using coefficients from kernel "Sobel"
# http://www.imagemagick.org/Usage/convolve/#sobel
$o.convolve( [ 1, 0, -1,
2, 0, -2,
1, 0, -1] );
$o.write("Lenna100-convoluted.jpg") or die;
# And cleanup on exit
LEAVE {
$original.cleanup if $original.defined;
$o.cleanup if $o.defined;
}</syntaxhighlight>
 
=={{header|Ruby}}==
{{trans|Tcl}}
<langsyntaxhighlight lang="ruby">class Pixmap
# Apply a convolution kernel to a whole image
def convolute(kernel)
Line 1,916 ⟶ 2,169:
savefile = 'teapot_' + label.downcase + '.ppm'
teapot.convolute(kernel).save(savefile)
end</langsyntaxhighlight>
 
=={{header|Tcl}}==
{{works with|Tcl|8.6}}
{{libheader|Tk}}
<langsyntaxhighlight lang="tcl">package require Tk
 
# Function for clamping values to those that we can use with colors
Line 1,997 ⟶ 2,250:
pack [labelframe .$name -text $label] -side left
pack [label .$name.l -image [convolve teapot $kernel]]
}</langsyntaxhighlight>
 
=={{header|Wren}}==
{{libheader|DOME}}
Based on the Java/Kotlin solutions, though input details are hard-coded rather than read in as command line arguments and the input and output images are displayed side by side with the latter also being saved to a file.
<syntaxhighlight lang="wren">import "graphics" for Canvas, Color, ImageData
import "dome" for Window
 
class ArrayData {
construct new(width, height) {
_width = width
_height = height
_dataArray = List.filled(width * height, 0)
}
 
width { _width }
height { _height }
 
[x, y] { _dataArray[y * _width + x] }
 
[x, y]=(v) { _dataArray[y * _width + x] = v }
}
 
class ImageConvolution {
construct new(width, height, image1, image2, kernel, divisor) {
Window.title = "Image Convolution"
Window.resize(width, height)
Canvas.resize(width, height)
_width = width
_height = height
_image1 = image1
_image2 = image2
_kernel = kernel
_divisor = divisor
}
 
init() {
var dataArrays = getArrayDatasFromImage(_image1)
for (i in 0...dataArrays.count) {
dataArrays[i] = convolve(dataArrays[i], _kernel, _divisor)
}
writeOutputImage(_image2, dataArrays)
}
 
bound(value, endIndex) {
if (value < 0) return 0
if (value < endIndex) return value
return endIndex - 1
}
 
convolve(inputData, kernel, kernelDivisor) {
var inputWidth = inputData.width
var inputHeight = inputData.height
var kernelWidth = kernel.width
var kernelHeight = kernel.height
if (kernelWidth <= 0 || (kernelWidth & 1) != 1) {
Fiber.abort("Kernel must have odd width")
}
if (kernelHeight <= 0 || (kernelHeight & 1) != 1) {
Fiber.abort("Kernel must have odd height")
}
var kernelWidthRadius = kernelWidth >> 1
var kernelHeightRadius = kernelHeight >> 1
var outputData = ArrayData.new(inputWidth, inputHeight)
for (i in inputWidth - 1..0) {
for (j in inputHeight - 1..0) {
var newValue = 0
for (kw in kernelWidth - 1..0) {
for (kh in kernelHeight - 1..0) {
newValue = newValue + kernel[kw, kh] * inputData[
bound(i + kw - kernelWidthRadius, inputWidth),
bound(j + kh - kernelHeightRadius, inputHeight)
]
outputData[i, j] = (newValue / kernelDivisor).round
}
}
}
}
return outputData
}
 
getArrayDatasFromImage(filename) {
var inputImage = ImageData.load(filename)
inputImage.draw(0, 0)
Canvas.print(filename, _width * 1/6, _height * 5/6, Color.white)
var width = inputImage.width
var height = inputImage.height
var rgbData = []
for (y in 0...height) {
for (x in 0...width) rgbData.add(inputImage.pget(x, y))
}
var reds = ArrayData.new(width, height)
var greens = ArrayData.new(width, height)
var blues = ArrayData.new(width, height)
for (y in 0...height) {
for (x in 0...width) {
var rgbValue = rgbData[y * width + x]
reds[x, y] = rgbValue.r
greens[x,y] = rgbValue.g
blues[x, y] = rgbValue.b
}
}
return [reds, greens, blues]
}
 
writeOutputImage(filename, redGreenBlue) {
var reds = redGreenBlue[0]
var greens = redGreenBlue[1]
var blues = redGreenBlue[2]
var outputImage = ImageData.create(filename, reds.width, reds.height)
for (y in 0...reds.height) {
for (x in 0...reds.width) {
var red = bound(reds[x, y], 256)
var green = bound(greens[x, y], 256)
var blue = bound(blues[x, y], 256)
var c = Color.new(red, green, blue)
outputImage.pset(x, y, c)
}
}
outputImage.draw(_width/2, 0)
Canvas.print(filename, _width * 2/3, _height * 5/6, Color.white)
outputImage.saveToFile(filename)
}
 
update() {}
 
draw(alpha) {}
}
 
var k = [
[1, 4, 7, 4, 1],
[4, 16, 26, 16, 4],
[7, 26, 41, 26, 7],
[4, 16, 26, 16, 4],
[1, 4, 7, 4, 1]
]
 
var divisor = 273
 
var image1 = "Pentagon.png"
var image2 = "Pentagon2.png"
 
System.print("Input file %(image1), output file %(image2).")
System.print("Kernel size: %(k.count) x %(k[0].count), divisor %(divisor)")
System.print(k.join("\n"))
 
var kernel = ArrayData.new(k.count, k[0].count)
for (y in 0...k[0].count) {
for (x in 0...k.count) kernel[x, y] = k[x][y]
}
var Game = ImageConvolution.new(700, 300, image1, image2, kernel, divisor)</syntaxhighlight>
 
{{out}}
<pre>
Input file Pentagon.png, output file Pentagon2.png.
Kernel size: 5 x 5, divisor 273
[1, 4, 7, 4, 1]
[4, 16, 26, 16, 4]
[7, 26, 41, 26, 7]
[4, 16, 26, 16, 4]
[1, 4, 7, 4, 1]
</pre>
 
{{omit from|ML/I}}
9,476

edits