Data commit
This commit is contained in:
parent
7387c8f97b
commit
cb5bb5e222
199093 changed files with 3378972 additions and 0 deletions
3
Task/Image-convolution/00-META.yaml
Normal file
3
Task/Image-convolution/00-META.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
from: http://rosettacode.org/wiki/Image_convolution
|
||||
note: Image processing
|
||||
14
Task/Image-convolution/00-TASK.txt
Normal file
14
Task/Image-convolution/00-TASK.txt
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
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 '''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>
|
||||
<math>P_{ij}=\displaystyle\sum_{k=-R}^R \sum_{l=-R}^R P_{i+k\ j+l} K_{k l}</math>
|
||||
</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.)''
|
||||
|
||||
93
Task/Image-convolution/Action-/image-convolution.action
Normal file
93
Task/Image-convolution/Action-/image-convolution.action
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
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
|
||||
35
Task/Image-convolution/Ada/image-convolution-1.ada
Normal file
35
Task/Image-convolution/Ada/image-convolution-1.ada
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
type Float_Luminance is new Float;
|
||||
|
||||
type Float_Pixel is record
|
||||
R, G, B : Float_Luminance := 0.0;
|
||||
end record;
|
||||
|
||||
function "*" (Left : Float_Pixel; Right : Float_Luminance) return Float_Pixel is
|
||||
pragma Inline ("*");
|
||||
begin
|
||||
return (Left.R * Right, Left.G * Right, Left.B * Right);
|
||||
end "*";
|
||||
|
||||
function "+" (Left, Right : Float_Pixel) return Float_Pixel is
|
||||
pragma Inline ("+");
|
||||
begin
|
||||
return (Left.R + Right.R, Left.G + Right.G, Left.B + Right.B);
|
||||
end "+";
|
||||
|
||||
function To_Luminance (X : Float_Luminance) return Luminance is
|
||||
pragma Inline (To_Luminance);
|
||||
begin
|
||||
if X <= 0.0 then
|
||||
return 0;
|
||||
elsif X >= 255.0 then
|
||||
return 255;
|
||||
else
|
||||
return Luminance (X);
|
||||
end if;
|
||||
end To_Luminance;
|
||||
|
||||
function To_Pixel (X : Float_Pixel) return Pixel is
|
||||
pragma Inline (To_Pixel);
|
||||
begin
|
||||
return (To_Luminance (X.R), To_Luminance (X.G), To_Luminance (X.B));
|
||||
end To_Pixel;
|
||||
46
Task/Image-convolution/Ada/image-convolution-2.ada
Normal file
46
Task/Image-convolution/Ada/image-convolution-2.ada
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
type Kernel_3x3 is array (-1..1, -1..1) of Float_Luminance;
|
||||
|
||||
procedure Filter (Picture : in out Image; K : Kernel_3x3) is
|
||||
function Get (I, J : Integer) return Float_Pixel is
|
||||
pragma Inline (Get);
|
||||
begin
|
||||
if I in Picture'Range (1) and then J in Picture'Range (2) then
|
||||
declare
|
||||
Color : Pixel := Picture (I, J);
|
||||
begin
|
||||
return (Float_Luminance (Color.R), Float_Luminance (Color.G), Float_Luminance (Color.B));
|
||||
end;
|
||||
else
|
||||
return (others => 0.0);
|
||||
end if;
|
||||
end Get;
|
||||
W11, W12, W13 : Float_Pixel; -- The image window
|
||||
W21, W22, W23 : Float_Pixel;
|
||||
W31, W32, W33 : Float_Pixel;
|
||||
Above : array (Picture'First (2) - 1..Picture'Last (2) + 1) of Float_Pixel;
|
||||
This : Float_Pixel;
|
||||
begin
|
||||
for I in Picture'Range (1) loop
|
||||
W11 := Above (Picture'First (2) - 1); -- The upper row is taken from the cache
|
||||
W12 := Above (Picture'First (2) );
|
||||
W13 := Above (Picture'First (2) + 1);
|
||||
W21 := (others => 0.0); -- The middle row
|
||||
W22 := Get (I, Picture'First (2) );
|
||||
W23 := Get (I, Picture'First (2) + 1);
|
||||
W31 := (others => 0.0); -- The bottom row
|
||||
W32 := Get (I+1, Picture'First (2) );
|
||||
W33 := Get (I+1, Picture'First (2) + 1);
|
||||
for J in Picture'Range (2) loop
|
||||
This :=
|
||||
W11 * K (-1, -1) + W12 * K (-1, 0) + W13 * K (-1, 1) +
|
||||
W21 * K ( 0, -1) + W22 * K ( 0, 0) + W23 * K ( 0, 1) +
|
||||
W31 * K ( 1, -1) + W32 * K ( 1, 0) + W33 * K ( 1, 1);
|
||||
Above (J-1) := W21;
|
||||
W11 := W12; W12 := W13; W13 := Above (J+1); -- Shift the window
|
||||
W21 := W22; W22 := W23; W23 := Get (I, J+1);
|
||||
W31 := W32; W32 := W23; W33 := Get (I+1, J+1);
|
||||
Picture (I, J) := To_Pixel (This);
|
||||
end loop;
|
||||
Above (Picture'Last (2)) := W21;
|
||||
end loop;
|
||||
end Filter;
|
||||
12
Task/Image-convolution/Ada/image-convolution-3.ada
Normal file
12
Task/Image-convolution/Ada/image-convolution-3.ada
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
F1, F2 : File_Type;
|
||||
begin
|
||||
Open (F1, In_File, "city.ppm");
|
||||
declare
|
||||
X : Image := Get_PPM (F1);
|
||||
begin
|
||||
Close (F1);
|
||||
Create (F2, Out_File, "city_sharpen.ppm");
|
||||
Filter (X, ((-1.0, -1.0, -1.0), (-1.0, 9.0, -1.0), (-1.0, -1.0, -1.0)));
|
||||
Put_PPM (F2, X);
|
||||
end;
|
||||
Close (F2);
|
||||
46
Task/Image-convolution/BBC-BASIC/image-convolution.basic
Normal file
46
Task/Image-convolution/BBC-BASIC/image-convolution.basic
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
Width% = 200
|
||||
Height% = 200
|
||||
|
||||
DIM out&(Width%-1, Height%-1, 2)
|
||||
|
||||
VDU 23,22,Width%;Height%;8,16,16,128
|
||||
*DISPLAY Lena
|
||||
OFF
|
||||
|
||||
DIM filter%(2, 2)
|
||||
filter%() = -1, -1, -1, -1, 12, -1, -1, -1, -1
|
||||
|
||||
REM Do the convolution:
|
||||
FOR Y% = 1 TO Height%-2
|
||||
FOR X% = 1 TO Width%-2
|
||||
R% = 0 : G% = 0 : B% = 0
|
||||
FOR I% = -1 TO 1
|
||||
FOR J% = -1 TO 1
|
||||
C% = TINT((X%+I%)*2, (Y%+J%)*2)
|
||||
F% = filter%(I%+1,J%+1)
|
||||
R% += F% * (C% AND &FF)
|
||||
G% += F% * (C% >> 8 AND &FF)
|
||||
B% += F% * (C% >> 16)
|
||||
NEXT
|
||||
NEXT
|
||||
IF R% < 0 R% = 0 ELSE IF R% > 1020 R% = 1020
|
||||
IF G% < 0 G% = 0 ELSE IF G% > 1020 G% = 1020
|
||||
IF B% < 0 B% = 0 ELSE IF B% > 1020 B% = 1020
|
||||
out&(X%, Y%, 0) = R% / 4 + 0.5
|
||||
out&(X%, Y%, 1) = G% / 4 + 0.5
|
||||
out&(X%, Y%, 2) = B% / 4 + 0.5
|
||||
NEXT
|
||||
NEXT Y%
|
||||
|
||||
REM Display:
|
||||
GCOL 1
|
||||
FOR Y% = 0 TO Height%-1
|
||||
FOR X% = 0 TO Width%-1
|
||||
COLOUR 1, out&(X%,Y%,0), out&(X%,Y%,1), out&(X%,Y%,2)
|
||||
LINE X%*2,Y%*2,X%*2,Y%*2
|
||||
NEXT
|
||||
NEXT Y%
|
||||
|
||||
REPEAT
|
||||
WAIT 1
|
||||
UNTIL FALSE
|
||||
1
Task/Image-convolution/C/image-convolution-1.c
Normal file
1
Task/Image-convolution/C/image-convolution-1.c
Normal file
|
|
@ -0,0 +1 @@
|
|||
image filter(image img, double *K, int Ks, double, double);
|
||||
39
Task/Image-convolution/C/image-convolution-2.c
Normal file
39
Task/Image-convolution/C/image-convolution-2.c
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
#include "imglib.h"
|
||||
|
||||
inline static color_component GET_PIXEL_CHECK(image img, int x, int y, int l) {
|
||||
if ( (x<0) || (x >= img->width) || (y<0) || (y >= img->height) ) return 0;
|
||||
return GET_PIXEL(img, x, y)[l];
|
||||
}
|
||||
|
||||
image filter(image im, double *K, int Ks, double divisor, double offset)
|
||||
{
|
||||
image oi;
|
||||
unsigned int ix, iy, l;
|
||||
int kx, ky;
|
||||
double cp[3];
|
||||
|
||||
oi = alloc_img(im->width, im->height);
|
||||
if ( oi != NULL ) {
|
||||
for(ix=0; ix < im->width; ix++) {
|
||||
for(iy=0; iy < im->height; iy++) {
|
||||
cp[0] = cp[1] = cp[2] = 0.0;
|
||||
for(kx=-Ks; kx <= Ks; kx++) {
|
||||
for(ky=-Ks; ky <= Ks; ky++) {
|
||||
for(l=0; l<3; l++)
|
||||
cp[l] += (K[(kx+Ks) +
|
||||
(ky+Ks)*(2*Ks+1)]/divisor) *
|
||||
((double)GET_PIXEL_CHECK(im, ix+kx, iy+ky, l)) + offset;
|
||||
}
|
||||
}
|
||||
for(l=0; l<3; l++)
|
||||
cp[l] = (cp[l]>255.0) ? 255.0 : ((cp[l]<0.0) ? 0.0 : cp[l]) ;
|
||||
put_pixel_unsafe(oi, ix, iy,
|
||||
(color_component)cp[0],
|
||||
(color_component)cp[1],
|
||||
(color_component)cp[2]);
|
||||
}
|
||||
}
|
||||
return oi;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
61
Task/Image-convolution/C/image-convolution-3.c
Normal file
61
Task/Image-convolution/C/image-convolution-3.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include <stdio.h>
|
||||
#include "imglib.h"
|
||||
|
||||
const char *input = "Lenna100.jpg";
|
||||
const char *output = "filtered_lenna%d.ppm";
|
||||
|
||||
double emboss_kernel[3*3] = {
|
||||
-2., -1., 0.,
|
||||
-1., 1., 1.,
|
||||
0., 1., 2.,
|
||||
};
|
||||
|
||||
double sharpen_kernel[3*3] = {
|
||||
-1.0, -1.0, -1.0,
|
||||
-1.0, 9.0, -1.0,
|
||||
-1.0, -1.0, -1.0
|
||||
};
|
||||
double sobel_emboss_kernel[3*3] = {
|
||||
-1., -2., -1.,
|
||||
0., 0., 0.,
|
||||
1., 2., 1.,
|
||||
};
|
||||
double box_blur_kernel[3*3] = {
|
||||
1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0,
|
||||
};
|
||||
|
||||
double *filters[4] = {
|
||||
emboss_kernel, sharpen_kernel, sobel_emboss_kernel, box_blur_kernel
|
||||
};
|
||||
const double filter_params[2*4] = {
|
||||
1.0, 0.0,
|
||||
1.0, 0.0,
|
||||
1.0, 0.5,
|
||||
9.0, 0.0
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
image ii, oi;
|
||||
int i;
|
||||
char lennanames[30];
|
||||
|
||||
ii = read_image(input);
|
||||
if ( ii != NULL ) {
|
||||
for(i=0; i<4; i++) {
|
||||
sprintf(lennanames, output, i);
|
||||
oi = filter(ii, filters[i], 1, filter_params[2*i], filter_params[2*i+1]);
|
||||
if ( oi != NULL ) {
|
||||
FILE *outfh = fopen(lennanames, "w");
|
||||
if ( outfh != NULL ) {
|
||||
output_ppm(outfh, oi);
|
||||
fclose(outfh);
|
||||
} else { fprintf(stderr, "out err %s\n", output); }
|
||||
free_img(oi);
|
||||
} else { fprintf(stderr, "err creating img filters %d\n", i); }
|
||||
}
|
||||
free_img(ii);
|
||||
} else { fprintf(stderr, "err reading %s\n", input); }
|
||||
}
|
||||
68
Task/Image-convolution/Common-Lisp/image-convolution.lisp
Normal file
68
Task/Image-convolution/Common-Lisp/image-convolution.lisp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
(load "rgb-pixel-buffer")
|
||||
(load "ppm-file-io")
|
||||
|
||||
(defpackage #:convolve
|
||||
(:use #:common-lisp #:rgb-pixel-buffer #:ppm-file-io))
|
||||
|
||||
(in-package #:convolve)
|
||||
(defconstant +row-offsets+ '(-1 -1 -1 0 0 0 1 1 1))
|
||||
(defconstant +col-offsets+ '(-1 0 1 -1 0 1 -1 0 1))
|
||||
(defstruct cnv-record descr width kernel divisor offset)
|
||||
(defparameter *cnv-lib* (make-hash-table))
|
||||
(setf (gethash 'emboss *cnv-lib*)
|
||||
(make-cnv-record :descr "emboss-filter" :width 3
|
||||
:kernel '(-2.0 -1.0 0.0 -1.0 1.0 1.0 0.0 1.0 2.0) :divisor 1.0))
|
||||
(setf (gethash 'sharpen *cnv-lib*)
|
||||
(make-cnv-record :descr "sharpen-filter" :width 3
|
||||
:kernel '(-1.0 -1.0 -1.0 -1.0 9.0 -1.0 -1.0 -1.0 -1.0) :divisor 1.0))
|
||||
(setf (gethash 'sobel-emboss *cnv-lib*)
|
||||
(make-cnv-record :descr "sobel-emboss-filter" :width 3
|
||||
: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)))
|
||||
(setf (gethash 'box-blur *cnv-lib*)
|
||||
(make-cnv-record :descr "box-blur-filter" :width 3
|
||||
:kernel '(1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0) :divisor 9.0))
|
||||
|
||||
(defun convolve (filename params)
|
||||
(let* ((buf (read-ppm-file-to-rgb-pixel-buffer filename))
|
||||
(width (first (array-dimensions buf)))
|
||||
(height (second (array-dimensions buf)))
|
||||
(obuf (make-rgb-pixel-buffer width height)))
|
||||
|
||||
;;; constrain a value to some range
|
||||
;;; (int,int,int)->int
|
||||
(defun constrain (val minv maxv)
|
||||
(declare (type integer val minv maxv))
|
||||
(min maxv (max minv val)))
|
||||
|
||||
;;; convolve a single channel
|
||||
;;; list ubyte8->ubyte8
|
||||
(defun convolve-channel (band)
|
||||
(constrain (round (apply #'+ (mapcar #'* band (cnv-record-kernel params)))) 0 255))
|
||||
|
||||
;;; return the rgb convolution of a list of pixels
|
||||
;;; list uint24->uint24
|
||||
(defun convolve-pixels (pixels)
|
||||
(let ((reds (list)) (greens (list)) (blues (list)))
|
||||
(dolist (pel (reverse pixels))
|
||||
(push (rgb-pixel-red pel) reds)
|
||||
(push (rgb-pixel-green pel) greens)
|
||||
(push (rgb-pixel-blue pel) blues))
|
||||
(make-rgb-pixel (convolve-channel reds) (convolve-channel greens) (convolve-channel blues))))
|
||||
|
||||
;;; return the list of pixels to which the kernel will be applied
|
||||
;;; (int,int)->list uint24
|
||||
(defun kernel-pixels (c r)
|
||||
(mapcar (lambda (coff roff) (rgb-pixel buf (constrain (+ c coff) 0 (1- width)) (constrain (+ r roff) 0 (1- height))))
|
||||
+col-offsets+ +row-offsets+))
|
||||
|
||||
;;; body of function
|
||||
(dotimes (r height)
|
||||
(dotimes (c width)
|
||||
(setf (rgb-pixel obuf c r) (convolve-pixels (kernel-pixels c r)))))
|
||||
|
||||
(write-rgb-pixel-buffer-to-ppm-file (concatenate 'string (format nil "convolve-~A-" (cnv-record-descr params)) filename) obuf)))
|
||||
|
||||
(in-package #:cl-user)
|
||||
(defun main ()
|
||||
(loop for pars being the hash-values of convolve::*cnv-lib*
|
||||
do (princ (convolve::convolve "lena_color.ppm" pars)) (terpri)))
|
||||
116
Task/Image-convolution/D/image-convolution.d
Normal file
116
Task/Image-convolution/D/image-convolution.d
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import std.string, std.math, std.algorithm, grayscale_image;
|
||||
|
||||
struct ConvolutionFilter {
|
||||
double[][] kernel;
|
||||
double divisor, offset_;
|
||||
string name;
|
||||
}
|
||||
|
||||
|
||||
Image!Color convolve(Color)(in Image!Color im,
|
||||
in ConvolutionFilter filter)
|
||||
pure nothrow in {
|
||||
assert(im !is null);
|
||||
assert(!filter.divisor.isNaN && !filter.offset_.isNaN);
|
||||
assert(filter.divisor != 0);
|
||||
assert(filter.kernel.length > 0 && filter.kernel[0].length > 0);
|
||||
foreach (const row; filter.kernel) // Is rectangular.
|
||||
assert(row.length == filter.kernel[0].length);
|
||||
assert(filter.kernel.length % 2 == 1); // Odd sized kernel.
|
||||
assert(filter.kernel[0].length % 2 == 1);
|
||||
assert(im.ny >= filter.kernel.length);
|
||||
assert(im.nx >= filter.kernel[0].length);
|
||||
} out(result) {
|
||||
assert(result !is null);
|
||||
assert(result.nx == im.nx && result.ny == im.ny);
|
||||
} body {
|
||||
immutable knx2 = filter.kernel[0].length / 2;
|
||||
immutable kny2 = filter.kernel.length / 2;
|
||||
auto io = new Image!Color(im.nx, im.ny);
|
||||
|
||||
static if (is(Color == RGB))
|
||||
alias CT = typeof(Color.r); // Component type.
|
||||
else static if (is(typeof(Color.c)))
|
||||
alias CT = typeof(Color.c);
|
||||
else
|
||||
alias CT = Color;
|
||||
|
||||
foreach (immutable y; kny2 .. im.ny - kny2) {
|
||||
foreach (immutable x; knx2 .. im.nx - knx2) {
|
||||
static if (is(Color == RGB))
|
||||
double[3] total = 0.0;
|
||||
else
|
||||
double total = 0.0;
|
||||
|
||||
foreach (immutable sy, const kRow; filter.kernel) {
|
||||
foreach (immutable sx, immutable k; kRow) {
|
||||
immutable p = im[x + sx - knx2, y + sy - kny2];
|
||||
static if (is(Color == RGB)) {
|
||||
total[0] += p.r * k;
|
||||
total[1] += p.g * k;
|
||||
total[2] += p.b * k;
|
||||
} else {
|
||||
total += p * k;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
immutable D = filter.divisor;
|
||||
immutable O = filter.offset_ * CT.max;
|
||||
static if (is(Color == RGB)) {
|
||||
io[x, y] = Color(
|
||||
cast(CT)min(max(total[0]/ D + O, CT.min), CT.max),
|
||||
cast(CT)min(max(total[1]/ D + O, CT.min), CT.max),
|
||||
cast(CT)min(max(total[2]/ D + O, CT.min), CT.max));
|
||||
} else static if (is(typeof(Color.c))) {
|
||||
io[x, y] = Color(
|
||||
cast(CT)min(max(total / D + O, CT.min), CT.max));
|
||||
} else {
|
||||
// If Color doesn't have a 'c' field, then Color is
|
||||
// assumed to be a built-in type.
|
||||
io[x, y] =
|
||||
cast(CT)min(max(total / D + O, CT.min), CT.max);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return io;
|
||||
}
|
||||
|
||||
|
||||
void main() {
|
||||
immutable ConvolutionFilter[] filters = [
|
||||
{[[-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"},
|
||||
|
||||
{[[-1.0, -1.0, -1.0],
|
||||
[-1.0, 9.0, -1.0],
|
||||
[-1.0, -1.0, -1.0]], divisor:1.0, 0.0, "Sharpen"},
|
||||
|
||||
{[[-1.0, -2.0, -1.0],
|
||||
[ 0.0, 0.0, 0.0],
|
||||
[ 1.0, 2.0, 1.0]], divisor:1.0, 0.5, "Sobel_emboss"},
|
||||
|
||||
{[[1.0, 1.0, 1.0],
|
||||
[1.0, 1.0, 1.0],
|
||||
[1.0, 1.0, 1.0]], divisor:9.0, 0.0, "Box_blur"},
|
||||
|
||||
{[[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]], divisor:273, 0.0, "Gaussian_blur"}];
|
||||
|
||||
Image!RGB im;
|
||||
im.loadPPM6("Lenna100.ppm");
|
||||
|
||||
foreach (immutable filter; filters)
|
||||
im.convolve(filter)
|
||||
.savePPM6(format("lenna_%s.ppm", filter.name));
|
||||
|
||||
const img = im.rgb2grayImage();
|
||||
foreach (immutable filter; filters)
|
||||
img.convolve(filter)
|
||||
.savePGM(format("lenna_gray_%s.ppm", filter.name));
|
||||
}
|
||||
91
Task/Image-convolution/Go/image-convolution-1.go
Normal file
91
Task/Image-convolution/Go/image-convolution-1.go
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/jpeg"
|
||||
"math"
|
||||
"os"
|
||||
)
|
||||
|
||||
// kf3 is a generic convolution 3x3 kernel filter that operatates on
|
||||
// images of type image.Gray from the Go standard image library.
|
||||
func kf3(k *[9]float64, src, dst *image.Gray) {
|
||||
for y := src.Rect.Min.Y; y < src.Rect.Max.Y; y++ {
|
||||
for x := src.Rect.Min.X; x < src.Rect.Max.X; x++ {
|
||||
var sum float64
|
||||
var i int
|
||||
for yo := y - 1; yo <= y+1; yo++ {
|
||||
for xo := x - 1; xo <= x+1; xo++ {
|
||||
if (image.Point{xo, yo}).In(src.Rect) {
|
||||
sum += k[i] * float64(src.At(xo, yo).(color.Gray).Y)
|
||||
} else {
|
||||
sum += k[i] * float64(src.At(x, y).(color.Gray).Y)
|
||||
}
|
||||
i++
|
||||
}
|
||||
}
|
||||
dst.SetGray(x, y,
|
||||
color.Gray{uint8(math.Min(255, math.Max(0, sum)))})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var blur = [9]float64{
|
||||
1. / 9, 1. / 9, 1. / 9,
|
||||
1. / 9, 1. / 9, 1. / 9,
|
||||
1. / 9, 1. / 9, 1. / 9}
|
||||
|
||||
// blurY example function applies blur kernel to Y channel
|
||||
// of YCbCr image using generic kernel filter function kf3
|
||||
func blurY(src *image.YCbCr) *image.YCbCr {
|
||||
dst := *src
|
||||
|
||||
// catch zero-size image here
|
||||
if src.Rect.Max.X == src.Rect.Min.X || src.Rect.Max.Y == src.Rect.Min.Y {
|
||||
return &dst
|
||||
}
|
||||
|
||||
// pass Y channels as gray images
|
||||
srcGray := image.Gray{src.Y, src.YStride, src.Rect}
|
||||
dstGray := srcGray
|
||||
dstGray.Pix = make([]uint8, len(src.Y))
|
||||
kf3(&blur, &srcGray, &dstGray) // call generic convolution function
|
||||
|
||||
// complete result
|
||||
dst.Y = dstGray.Pix // convolution result
|
||||
dst.Cb = append([]uint8{}, src.Cb...) // Cb, Cr are just copied
|
||||
dst.Cr = append([]uint8{}, src.Cr...)
|
||||
return &dst
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Example file used here is Lenna100.jpg from the task "Percentage
|
||||
// difference between images"
|
||||
f, err := os.Open("Lenna100.jpg")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
img, err := jpeg.Decode(f)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
f.Close()
|
||||
y, ok := img.(*image.YCbCr)
|
||||
if !ok {
|
||||
fmt.Println("expected color jpeg")
|
||||
return
|
||||
}
|
||||
f, err = os.Create("blur.jpg")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
err = jpeg.Encode(f, blurY(y), &jpeg.Options{90})
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
72
Task/Image-convolution/Go/image-convolution-2.go
Normal file
72
Task/Image-convolution/Go/image-convolution-2.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package raster
|
||||
|
||||
import "math"
|
||||
|
||||
func (g *Grmap) KernelFilter3(k []float64) *Grmap {
|
||||
if len(k) != 9 {
|
||||
return nil
|
||||
}
|
||||
r := NewGrmap(g.cols, g.rows)
|
||||
r.Comments = append([]string{}, g.Comments...)
|
||||
// Filter edge pixels with minimal code.
|
||||
// Execution time per pixel is high but there are few edge pixels
|
||||
// relative to the interior.
|
||||
o3 := [][]int{
|
||||
{-1, -1}, {0, -1}, {1, -1},
|
||||
{-1, 0}, {0, 0}, {1, 0},
|
||||
{-1, 1}, {0, 1}, {1, 1}}
|
||||
edge := func(x, y int) uint16 {
|
||||
var sum float64
|
||||
for i, o := range o3 {
|
||||
c, ok := g.GetPx(x+o[0], y+o[1])
|
||||
if !ok {
|
||||
c = g.pxRow[y][x]
|
||||
}
|
||||
sum += float64(c) * k[i]
|
||||
}
|
||||
return uint16(math.Min(math.MaxUint16, math.Max(0,sum)))
|
||||
}
|
||||
for x := 0; x < r.cols; x++ {
|
||||
r.pxRow[0][x] = edge(x, 0)
|
||||
r.pxRow[r.rows-1][x] = edge(x, r.rows-1)
|
||||
}
|
||||
for y := 1; y < r.rows-1; y++ {
|
||||
r.pxRow[y][0] = edge(0, y)
|
||||
r.pxRow[y][r.cols-1] = edge(r.cols-1, y)
|
||||
}
|
||||
if r.rows < 3 || r.cols < 3 {
|
||||
return r
|
||||
}
|
||||
|
||||
// Interior pixels can be filtered much more efficiently.
|
||||
otr := -g.cols + 1
|
||||
obr := g.cols + 1
|
||||
z := g.cols + 1
|
||||
c2 := g.cols - 2
|
||||
for y := 1; y < r.rows-1; y++ {
|
||||
tl := float64(g.pxRow[y-1][0])
|
||||
tc := float64(g.pxRow[y-1][1])
|
||||
tr := float64(g.pxRow[y-1][2])
|
||||
ml := float64(g.pxRow[y][0])
|
||||
mc := float64(g.pxRow[y][1])
|
||||
mr := float64(g.pxRow[y][2])
|
||||
bl := float64(g.pxRow[y+1][0])
|
||||
bc := float64(g.pxRow[y+1][1])
|
||||
br := float64(g.pxRow[y+1][2])
|
||||
for x := 1; ; x++ {
|
||||
r.px[z] = uint16(math.Min(math.MaxUint16, math.Max(0,
|
||||
tl*k[0] + tc*k[1] + tr*k[2] +
|
||||
ml*k[3] + mc*k[4] + mr*k[5] +
|
||||
bl*k[6] + bc*k[7] + br*k[8])))
|
||||
if x == c2 {
|
||||
break
|
||||
}
|
||||
z++
|
||||
tl, tc, tr = tc, tr, float64(g.px[z+otr])
|
||||
ml, mc, mr = mc, mr, float64(g.px[z+1])
|
||||
bl, bc, br = bc, br, float64(g.px[z+obr])
|
||||
}
|
||||
z += 3
|
||||
}
|
||||
return r
|
||||
}
|
||||
40
Task/Image-convolution/Go/image-convolution-3.go
Normal file
40
Task/Image-convolution/Go/image-convolution-3.go
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
package main
|
||||
|
||||
// Files required to build supporting package raster are found in:
|
||||
// * This task (immediately above)
|
||||
// * Bitmap
|
||||
// * Grayscale image
|
||||
// * Read a PPM file
|
||||
// * Write a PPM file
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"raster"
|
||||
)
|
||||
|
||||
var blur = []float64{
|
||||
1./9, 1./9, 1./9,
|
||||
1./9, 1./9, 1./9,
|
||||
1./9, 1./9, 1./9}
|
||||
|
||||
var sharpen = []float64{
|
||||
-1, -1, -1,
|
||||
-1, 9, -1,
|
||||
-1, -1, -1}
|
||||
|
||||
func main() {
|
||||
// Example file used here is Lenna100.jpg from the task "Percentage
|
||||
// difference between images" converted with with the command
|
||||
// convert Lenna100.jpg -colorspace gray Lenna100.ppm
|
||||
b, err := raster.ReadPpmFile("Lenna100.ppm")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
g0 := b.Grmap()
|
||||
g1 := g0.KernelFilter3(blur)
|
||||
err = g1.Bitmap().WritePpmFile("blur.ppm")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
11
Task/Image-convolution/J/image-convolution-1.j
Normal file
11
Task/Image-convolution/J/image-convolution-1.j
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
NB. pad the edges of an array with border pixels
|
||||
NB. (increasing the first two dimensions by 1 less than the kernel size)
|
||||
pad=: {{
|
||||
rank=.#$m
|
||||
'first second'=. (<.,:>.)-:$m
|
||||
-@(second+rank{.$) {. (first+rank{.$){.]
|
||||
}}
|
||||
|
||||
kernel_filter=: {{
|
||||
[: (0 >. 255 <. <.@:+&0.5) (1,:$m)+/ .*~&(,/)&m;._3 m pad
|
||||
}}
|
||||
8
Task/Image-convolution/J/image-convolution-2.j
Normal file
8
Task/Image-convolution/J/image-convolution-2.j
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
NB. kernels borrowed from C and TCL implementations
|
||||
id_kernel=: (=&i.-)3 3
|
||||
sharpen_kernel=: ({ _1,#@,)id_kernel
|
||||
blur_kernel=: ($ *&%/)3 3
|
||||
emboss_kernel=: id_kernel+(+/~ - >./)i.3
|
||||
sobel_emboss_kernel=: (i:-:<:3)*/1+(<.|.)i.3
|
||||
|
||||
'blurred.ppm' writeppm~ blur_kernel kernel_filter readppm 'original.ppm'
|
||||
141
Task/Image-convolution/Java/image-convolution.java
Normal file
141
Task/Image-convolution/Java/image-convolution.java
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
import java.awt.image.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import javax.imageio.*;
|
||||
|
||||
public class ImageConvolution
|
||||
{
|
||||
public static class ArrayData
|
||||
{
|
||||
public final int[] dataArray;
|
||||
public final int width;
|
||||
public final int height;
|
||||
|
||||
public ArrayData(int width, int height)
|
||||
{
|
||||
this(new int[width * height], width, height);
|
||||
}
|
||||
|
||||
public ArrayData(int[] dataArray, int width, int height)
|
||||
{
|
||||
this.dataArray = dataArray;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public int get(int x, int y)
|
||||
{ return dataArray[y * width + x]; }
|
||||
|
||||
public void set(int x, int y, int value)
|
||||
{ dataArray[y * width + x] = value; }
|
||||
}
|
||||
|
||||
private static int bound(int value, int endIndex)
|
||||
{
|
||||
if (value < 0)
|
||||
return 0;
|
||||
if (value < endIndex)
|
||||
return value;
|
||||
return endIndex - 1;
|
||||
}
|
||||
|
||||
public static ArrayData convolute(ArrayData inputData, ArrayData kernel, int kernelDivisor)
|
||||
{
|
||||
int inputWidth = inputData.width;
|
||||
int inputHeight = inputData.height;
|
||||
int kernelWidth = kernel.width;
|
||||
int kernelHeight = kernel.height;
|
||||
if ((kernelWidth <= 0) || ((kernelWidth & 1) != 1))
|
||||
throw new IllegalArgumentException("Kernel must have odd width");
|
||||
if ((kernelHeight <= 0) || ((kernelHeight & 1) != 1))
|
||||
throw new IllegalArgumentException("Kernel must have odd height");
|
||||
int kernelWidthRadius = kernelWidth >>> 1;
|
||||
int kernelHeightRadius = kernelHeight >>> 1;
|
||||
|
||||
ArrayData outputData = new ArrayData(inputWidth, inputHeight);
|
||||
for (int i = inputWidth - 1; i >= 0; i--)
|
||||
{
|
||||
for (int j = inputHeight - 1; j >= 0; j--)
|
||||
{
|
||||
double newValue = 0.0;
|
||||
for (int kw = kernelWidth - 1; kw >= 0; kw--)
|
||||
for (int kh = kernelHeight - 1; kh >= 0; kh--)
|
||||
newValue += kernel.get(kw, kh) * inputData.get(
|
||||
bound(i + kw - kernelWidthRadius, inputWidth),
|
||||
bound(j + kh - kernelHeightRadius, inputHeight));
|
||||
outputData.set(i, j, (int)Math.round(newValue / kernelDivisor));
|
||||
}
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
public static ArrayData[] getArrayDatasFromImage(String filename) throws IOException
|
||||
{
|
||||
BufferedImage inputImage = ImageIO.read(new File(filename));
|
||||
int width = inputImage.getWidth();
|
||||
int height = inputImage.getHeight();
|
||||
int[] rgbData = inputImage.getRGB(0, 0, width, height, null, 0, width);
|
||||
ArrayData reds = new ArrayData(width, height);
|
||||
ArrayData greens = new ArrayData(width, height);
|
||||
ArrayData blues = new ArrayData(width, height);
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int rgbValue = rgbData[y * width + x];
|
||||
reds.set(x, y, (rgbValue >>> 16) & 0xFF);
|
||||
greens.set(x, y, (rgbValue >>> 8) & 0xFF);
|
||||
blues.set(x, y, rgbValue & 0xFF);
|
||||
}
|
||||
}
|
||||
return new ArrayData[] { reds, greens, blues };
|
||||
}
|
||||
|
||||
public static void writeOutputImage(String filename, ArrayData[] redGreenBlue) throws IOException
|
||||
{
|
||||
ArrayData reds = redGreenBlue[0];
|
||||
ArrayData greens = redGreenBlue[1];
|
||||
ArrayData blues = redGreenBlue[2];
|
||||
BufferedImage outputImage = new BufferedImage(reds.width, reds.height,
|
||||
BufferedImage.TYPE_INT_ARGB);
|
||||
for (int y = 0; y < reds.height; y++)
|
||||
{
|
||||
for (int x = 0; x < reds.width; x++)
|
||||
{
|
||||
int red = bound(reds.get(x, y), 256);
|
||||
int green = bound(greens.get(x, y), 256);
|
||||
int blue = bound(blues.get(x, y), 256);
|
||||
outputImage.setRGB(x, y, (red << 16) | (green << 8) | blue | -0x01000000);
|
||||
}
|
||||
}
|
||||
ImageIO.write(outputImage, "PNG", new File(filename));
|
||||
return;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException
|
||||
{
|
||||
int kernelWidth = Integer.parseInt(args[2]);
|
||||
int kernelHeight = Integer.parseInt(args[3]);
|
||||
int kernelDivisor = Integer.parseInt(args[4]);
|
||||
System.out.println("Kernel size: " + kernelWidth + "x" + kernelHeight +
|
||||
", divisor=" + kernelDivisor);
|
||||
int y = 5;
|
||||
ArrayData kernel = new ArrayData(kernelWidth, kernelHeight);
|
||||
for (int i = 0; i < kernelHeight; i++)
|
||||
{
|
||||
System.out.print("[");
|
||||
for (int j = 0; j < kernelWidth; j++)
|
||||
{
|
||||
kernel.set(j, i, Integer.parseInt(args[y++]));
|
||||
System.out.print(" " + kernel.get(j, i) + " ");
|
||||
}
|
||||
System.out.println("]");
|
||||
}
|
||||
|
||||
ArrayData[] dataArrays = getArrayDatasFromImage(args[0]);
|
||||
for (int i = 0; i < dataArrays.length; i++)
|
||||
dataArrays[i] = convolute(dataArrays[i], kernel, kernelDivisor);
|
||||
writeOutputImage(args[1], dataArrays);
|
||||
return;
|
||||
}
|
||||
}
|
||||
76
Task/Image-convolution/JavaScript/image-convolution.js
Normal file
76
Task/Image-convolution/JavaScript/image-convolution.js
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
// Image imageIn, Array kernel, function (Error error, Image imageOut)
|
||||
// precondition: Image is loaded
|
||||
// returns loaded Image to asynchronous callback function
|
||||
function convolve(imageIn, kernel, callback) {
|
||||
var dim = Math.sqrt(kernel.length),
|
||||
pad = Math.floor(dim / 2);
|
||||
|
||||
if (dim % 2 !== 1) {
|
||||
return callback(new RangeError("Invalid kernel dimension"), null);
|
||||
}
|
||||
|
||||
var w = imageIn.width,
|
||||
h = imageIn.height,
|
||||
can = document.createElement('canvas'),
|
||||
cw,
|
||||
ch,
|
||||
ctx,
|
||||
imgIn, imgOut,
|
||||
datIn, datOut;
|
||||
|
||||
can.width = cw = w + pad * 2; // add padding
|
||||
can.height = ch = h + pad * 2; // add padding
|
||||
|
||||
ctx = can.getContext('2d');
|
||||
ctx.fillStyle = '#000'; // fill with opaque black
|
||||
ctx.fillRect(0, 0, cw, ch);
|
||||
ctx.drawImage(imageIn, pad, pad);
|
||||
|
||||
imgIn = ctx.getImageData(0, 0, cw, ch);
|
||||
datIn = imgIn.data;
|
||||
|
||||
imgOut = ctx.createImageData(w, h);
|
||||
datOut = imgOut.data;
|
||||
|
||||
var row, col, pix, i, dx, dy, r, g, b;
|
||||
|
||||
for (row = pad; row <= h; row++) {
|
||||
for (col = pad; col <= w; col++) {
|
||||
r = g = b = 0;
|
||||
|
||||
for (dx = -pad; dx <= pad; dx++) {
|
||||
for (dy = -pad; dy <= pad; dy++) {
|
||||
i = (dy + pad) * dim + (dx + pad); // kernel index
|
||||
pix = 4 * ((row + dy) * cw + (col + dx)); // image index
|
||||
r += datIn[pix++] * kernel[i];
|
||||
g += datIn[pix++] * kernel[i];
|
||||
b += datIn[pix ] * kernel[i];
|
||||
}
|
||||
}
|
||||
|
||||
pix = 4 * ((row - pad) * w + (col - pad)); // destination index
|
||||
datOut[pix++] = (r + .5) ^ 0;
|
||||
datOut[pix++] = (g + .5) ^ 0;
|
||||
datOut[pix++] = (b + .5) ^ 0;
|
||||
datOut[pix ] = 255; // we want opaque image
|
||||
}
|
||||
}
|
||||
|
||||
// reuse canvas
|
||||
can.width = w;
|
||||
can.height = h;
|
||||
|
||||
ctx.putImageData(imgOut, 0, 0);
|
||||
|
||||
var imageOut = new Image();
|
||||
|
||||
imageOut.addEventListener('load', function () {
|
||||
callback(null, imageOut);
|
||||
});
|
||||
|
||||
imageOut.addEventListener('error', function (error) {
|
||||
callback(error, null);
|
||||
});
|
||||
|
||||
imageOut.src = can.toDataURL('image/png');
|
||||
}
|
||||
9
Task/Image-convolution/Julia/image-convolution.julia
Normal file
9
Task/Image-convolution/Julia/image-convolution.julia
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
using FileIO, Images
|
||||
|
||||
img = load("image.jpg")
|
||||
|
||||
sharpenkernel = reshape([-1.0, -1.0, -1.0, -1.0, 9.0, -1.0, -1.0, -1.0, -1.0], (3,3))
|
||||
|
||||
imfilt = imfilter(img, sharpenkernel)
|
||||
|
||||
save("imagesharper.png", imfilt)
|
||||
116
Task/Image-convolution/Kotlin/image-convolution.kotlin
Normal file
116
Task/Image-convolution/Kotlin/image-convolution.kotlin
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
// version 1.2.10
|
||||
|
||||
import kotlin.math.round
|
||||
import java.awt.image.*
|
||||
import java.io.File
|
||||
import javax.imageio.*
|
||||
|
||||
class ArrayData(val width: Int, val height: Int) {
|
||||
var dataArray = IntArray(width * height)
|
||||
|
||||
operator fun get(x: Int, y: Int) = dataArray[y * width + x]
|
||||
|
||||
operator fun set(x: Int, y: Int, value: Int) {
|
||||
dataArray[y * width + x] = value
|
||||
}
|
||||
}
|
||||
|
||||
fun bound(value: Int, endIndex: Int) = when {
|
||||
value < 0 -> 0
|
||||
value < endIndex -> value
|
||||
else -> endIndex - 1
|
||||
}
|
||||
|
||||
fun convolute(
|
||||
inputData: ArrayData,
|
||||
kernel: ArrayData,
|
||||
kernelDivisor: Int
|
||||
): ArrayData {
|
||||
val inputWidth = inputData.width
|
||||
val inputHeight = inputData.height
|
||||
val kernelWidth = kernel.width
|
||||
val kernelHeight = kernel.height
|
||||
if (kernelWidth <= 0 || (kernelWidth and 1) != 1)
|
||||
throw IllegalArgumentException("Kernel must have odd width")
|
||||
if (kernelHeight <= 0 || (kernelHeight and 1) != 1)
|
||||
throw IllegalArgumentException("Kernel must have odd height")
|
||||
val kernelWidthRadius = kernelWidth ushr 1
|
||||
val kernelHeightRadius = kernelHeight ushr 1
|
||||
|
||||
val outputData = ArrayData(inputWidth, inputHeight)
|
||||
for (i in inputWidth - 1 downTo 0) {
|
||||
for (j in inputHeight - 1 downTo 0) {
|
||||
var newValue = 0.0
|
||||
for (kw in kernelWidth - 1 downTo 0) {
|
||||
for (kh in kernelHeight - 1 downTo 0) {
|
||||
newValue += kernel[kw, kh] * inputData[
|
||||
bound(i + kw - kernelWidthRadius, inputWidth),
|
||||
bound(j + kh - kernelHeightRadius, inputHeight)
|
||||
].toDouble()
|
||||
outputData[i, j] = round(newValue / kernelDivisor).toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return outputData
|
||||
}
|
||||
|
||||
fun getArrayDatasFromImage(filename: String): Array<ArrayData> {
|
||||
val inputImage = ImageIO.read(File(filename))
|
||||
val width = inputImage.width
|
||||
val height = inputImage.height
|
||||
val rgbData = inputImage.getRGB(0, 0, width, height, null, 0, width)
|
||||
val reds = ArrayData(width, height)
|
||||
val greens = ArrayData(width, height)
|
||||
val blues = ArrayData(width, height)
|
||||
for (y in 0 until height) {
|
||||
for (x in 0 until width) {
|
||||
val rgbValue = rgbData[y * width + x]
|
||||
reds[x, y] = (rgbValue ushr 16) and 0xFF
|
||||
greens[x,y] = (rgbValue ushr 8) and 0xFF
|
||||
blues[x, y] = rgbValue and 0xFF
|
||||
}
|
||||
}
|
||||
return arrayOf(reds, greens, blues)
|
||||
}
|
||||
|
||||
fun writeOutputImage(filename: String, redGreenBlue: Array<ArrayData>) {
|
||||
val (reds, greens, blues) = redGreenBlue
|
||||
val outputImage = BufferedImage(
|
||||
reds.width, reds.height, BufferedImage.TYPE_INT_ARGB
|
||||
)
|
||||
for (y in 0 until reds.height) {
|
||||
for (x in 0 until reds.width) {
|
||||
val red = bound(reds[x , y], 256)
|
||||
val green = bound(greens[x , y], 256)
|
||||
val blue = bound(blues[x, y], 256)
|
||||
outputImage.setRGB(
|
||||
x, y, (red shl 16) or (green shl 8) or blue or -0x01000000
|
||||
)
|
||||
}
|
||||
}
|
||||
ImageIO.write(outputImage, "PNG", File(filename))
|
||||
}
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val kernelWidth = args[2].toInt()
|
||||
val kernelHeight = args[3].toInt()
|
||||
val kernelDivisor = args[4].toInt()
|
||||
println("Kernel size: $kernelWidth x $kernelHeight, divisor = $kernelDivisor")
|
||||
var y = 5
|
||||
val kernel = ArrayData(kernelWidth, kernelHeight)
|
||||
for (i in 0 until kernelHeight) {
|
||||
print("[")
|
||||
for (j in 0 until kernelWidth) {
|
||||
kernel[j, i] = args[y++].toInt()
|
||||
print(" ${kernel[j, i]} ")
|
||||
}
|
||||
println("]")
|
||||
}
|
||||
|
||||
val dataArrays = getArrayDatasFromImage(args[0])
|
||||
for (i in 0 until dataArrays.size) {
|
||||
dataArrays[i] = convolute(dataArrays[i], kernel, kernelDivisor)
|
||||
}
|
||||
writeOutputImage(args[1], dataArrays)
|
||||
}
|
||||
95
Task/Image-convolution/Liberty-BASIC/image-convolution.basic
Normal file
95
Task/Image-convolution/Liberty-BASIC/image-convolution.basic
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
dim result( 300, 300), image( 300, 300), mask( 100, 100)
|
||||
w =128
|
||||
h =128
|
||||
|
||||
nomainwin
|
||||
|
||||
WindowWidth = 460
|
||||
WindowHeight = 210
|
||||
|
||||
open "Convolution" for graphics_nsb_nf as #w
|
||||
|
||||
#w "trapclose [quit]"
|
||||
|
||||
#w "down ; fill darkblue"
|
||||
|
||||
hw = hwnd( #w)
|
||||
calldll #user32,"GetDC", hw as ulong, hdc as ulong
|
||||
|
||||
loadbmp "img", "alpha25.bmp"' 128x128 pixels
|
||||
#w "drawbmp img 20, 20"
|
||||
|
||||
#w "up ; color white ; goto 292 20 ; down ; box 420 148"
|
||||
#w "up ; goto 180 60 ; down ; backcolor darkblue ; color cyan"
|
||||
#w "\"; "Convolved with"
|
||||
|
||||
for y =0 to 127 ' fill in the input matrix
|
||||
for x =0 to 127
|
||||
xx =x + 20
|
||||
yy =y + 20
|
||||
CallDLL #gdi32, "GetPixel", hdc as uLong, xx as long, yy as long, pixcol as ulong
|
||||
call getRGB pixcol, b, g, r
|
||||
image( x, y) =b
|
||||
'#w "color "; image( x, y); " 0 "; 255 -image( x, y)
|
||||
'#w "set "; x + 20; " "; y +20 +140
|
||||
next x
|
||||
next y
|
||||
|
||||
#w "flush"
|
||||
print " Input matrix filled."
|
||||
|
||||
#w "size 8"
|
||||
for y =0 to 2 ' fill in the mask matrix
|
||||
for x =0 to 2
|
||||
read mask
|
||||
mask( x, y) =mask
|
||||
if mask = ( 0 -1) then #w "color yellow" else #w "color red"
|
||||
#w "set "; 8 *x +200; " "; 8 *y +80
|
||||
next x
|
||||
next y
|
||||
data -1,-1,-1,-1,9,-1,-1,-1,-1
|
||||
|
||||
#w "flush"
|
||||
print " Mask matrix filled."
|
||||
|
||||
#w "size 1"
|
||||
mxx =0: mnn =0
|
||||
|
||||
for x =0 to 127 -2 ' since any further overlaps image edge
|
||||
for y =0 to 127 -2
|
||||
result( x, y) =0
|
||||
for kx =0 to 2
|
||||
for ky =0 to 2
|
||||
result( x, y) =result( x, y) +image( x +kx, y +ky) *mask( kx, ky)
|
||||
next ky
|
||||
if mxx <result( x, y) then mxx =result( x, y)
|
||||
if mnn >result( x, y) then mnn =result( x, y)
|
||||
next kx
|
||||
scan
|
||||
next y
|
||||
next x
|
||||
|
||||
range =mxx -mnn
|
||||
for x =0 to 127 -2
|
||||
for y =0 to 127 -2
|
||||
c =int( 255 *( result( x, y) -mnn) /range)
|
||||
'#w "color "; c; " "; c; " "; c
|
||||
if c >128 then #w "color white" else #w "color black"
|
||||
#w "set "; x +292 +1; " "; y +20 +1
|
||||
scan
|
||||
next y
|
||||
next x
|
||||
#w "flush"
|
||||
|
||||
wait
|
||||
|
||||
sub getRGB pixcol, byref r, byref g, byref b
|
||||
b = int( pixcol / (256 *256))
|
||||
g = int( ( pixcol - b *256 *256) / 256)
|
||||
r = int( pixcol - b *256 *256 - g *256)
|
||||
end sub
|
||||
|
||||
[quit]
|
||||
close #w
|
||||
CallDLL #user32, "ReleaseDC", hw as ulong, hdc as ulong
|
||||
end
|
||||
168
Task/Image-convolution/MATLAB/image-convolution.m
Normal file
168
Task/Image-convolution/MATLAB/image-convolution.m
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
function testConvImage
|
||||
Im = [1 2 1 5 5 ; ...
|
||||
1 2 7 9 9 ; ...
|
||||
5 5 5 5 5 ; ...
|
||||
5 2 2 2 2 ; ...
|
||||
1 1 1 1 1 ]; % Sample image for example illustration only
|
||||
Ker = [1 2 1 ; ...
|
||||
2 4 2 ; ...
|
||||
1 2 1 ]; % Gaussian smoothing (without normalizing)
|
||||
fprintf('Original image:\n')
|
||||
disp(Im)
|
||||
fprintf('Original kernel:\n')
|
||||
disp(Ker)
|
||||
fprintf('Padding with zeroes:\n')
|
||||
disp(convImage(Im, Ker, 'zeros'))
|
||||
fprintf('Padding with fives:\n')
|
||||
disp(convImage(Im, Ker, 'value', 5))
|
||||
fprintf('Duplicating border pixels to pad image:\n')
|
||||
disp(convImage(Im, Ker, 'extend'))
|
||||
fprintf('Renormalizing kernel and using only values within image:\n')
|
||||
disp(convImage(Im, Ker, 'partial'))
|
||||
fprintf('Only processing inner (non-border) pixels:\n')
|
||||
disp(convImage(Im, Ker, 'none'))
|
||||
% Ker = [1 2 1 ; ...
|
||||
% 2 4 2 ; ...
|
||||
% 1 2 1 ]./16;
|
||||
% Im = imread('testConvImageTestImage.png', 'png');
|
||||
% figure
|
||||
% imshow(imresize(Im, 10))
|
||||
% title('Original image')
|
||||
% figure
|
||||
% imshow(imresize(convImage(Im, Ker, 'zeros'), 10))
|
||||
% title('Padding with zeroes')
|
||||
% figure
|
||||
% imshow(imresize(convImage(Im, Ker, 'value', 50), 10))
|
||||
% title('Padding with fifty: 50')
|
||||
% figure
|
||||
% imshow(imresize(convImage(Im, Ker, 'extend'), 10))
|
||||
% title('Duplicating border pixels to pad image')
|
||||
% figure
|
||||
% imshow(imresize(convImage(Im, Ker, 'partial'), 10))
|
||||
% title('Renormalizing kernel and using only values within image')
|
||||
% figure
|
||||
% imshow(imresize(convImage(Im, Ker, 'none'), 10))
|
||||
% title('Only processing inner (non-border) pixels')
|
||||
end
|
||||
|
||||
function ImOut = convImage(Im, Ker, varargin)
|
||||
% ImOut = convImage(Im, Ker)
|
||||
% Filters an image using sliding-window kernel convolution.
|
||||
% Convolution is done layer-by-layer. Use rgb2gray if single-layer needed.
|
||||
% Zero-padding convolution will be used if no border handling is specified.
|
||||
% Im - Array containing image data (output from imread)
|
||||
% Ker - 2-D array to convolve image, needs odd number of rows and columns
|
||||
% ImOut - Filtered image, same dimensions and datatype as Im
|
||||
%
|
||||
% ImOut = convImage(Im, Ker, 'zeros')
|
||||
% Image will be padded with zeros when calculating convolution
|
||||
% (useful for magnitude calculations).
|
||||
%
|
||||
% ImOut = convImage(Im, Ker, 'value', padVal)
|
||||
% Image will be padded with padVal when calculating convolution
|
||||
% (possibly useful for emphasizing certain data with unusual kernel)
|
||||
%
|
||||
% ImOut = convImage(Im, Ker, 'extend')
|
||||
% Image will be padded with the value of the closest image pixel
|
||||
% (useful for smoothing or blurring filters).
|
||||
%
|
||||
% ImOut = convImage(Im, Ker, 'partial')
|
||||
% Image will not be padded. Borders will be convoluted with only valid pixels,
|
||||
% and convolution matrix will be renormalized counting only the pixels within
|
||||
% the image (also useful for smoothing or blurring filters).
|
||||
%
|
||||
% ImOut = convImage(Im, Ker, 'none')
|
||||
% Image will not be padded. Convolution will only be applied to inner pixels
|
||||
% (useful for edge and corner detection filters)
|
||||
|
||||
% Handle input
|
||||
if mod(size(Ker, 1), 2) ~= 1 || mod(size(Ker, 2), 2) ~= 1
|
||||
eid = sprintf('%s:evenRowsCols', mfilename);
|
||||
error(eid,'''Ker'' parameter must have odd number of rows and columns.')
|
||||
elseif nargin > 4
|
||||
eid = sprintf('%s:maxrhs', mfilename);
|
||||
error(eid, 'Too many input arguments.');
|
||||
elseif nargin == 4 && ~strcmp(varargin{1}, 'value')
|
||||
eid = sprintf('%s:invalidParameterCombination', mfilename);
|
||||
error(eid, ['The ''padVal'' parameter is only valid with the ' ...
|
||||
'''value'' option.'])
|
||||
elseif nargin < 4 && strcmp(varargin{1}, 'value')
|
||||
eid = sprintf('%s:minrhs', mfilename);
|
||||
error(eid, 'Not enough input arguments.')
|
||||
elseif nargin < 3
|
||||
method = 'zeros';
|
||||
else
|
||||
method = lower(varargin{1});
|
||||
if ~any(strcmp(method, {'zeros' 'value' 'extend' 'partial' 'none'}))
|
||||
eid = sprintf('%s:invalidParameter', mfilename);
|
||||
error(eid, 'Invalid option parameter. Must be one of:%s', ...
|
||||
sprintf('\n\t\t%s', ...
|
||||
'zeros', 'value', 'extend', 'partial', 'none'))
|
||||
end
|
||||
end
|
||||
|
||||
% Gather information and prepare for convolution
|
||||
[nImRows, nImCols, nImLayers] = size(Im);
|
||||
classIm = class(Im);
|
||||
Im = double(Im);
|
||||
ImOut = zeros(nImRows, nImCols, nImLayers);
|
||||
[nKerRows, nKerCols] = size(Ker);
|
||||
nPadRows = nImRows+nKerRows-1;
|
||||
nPadCols = nImCols+nKerCols-1;
|
||||
padH = (nKerRows-1)/2;
|
||||
padW = (nKerCols-1)/2;
|
||||
|
||||
% Convolute on a layer-by-layer basis
|
||||
for k = 1:nImLayers
|
||||
if strcmp(method, 'zeros')
|
||||
ImOut(:, :, k) = conv2(Im(:, :, k), Ker, 'same');
|
||||
elseif strcmp(method, 'value')
|
||||
padding = varargin{2}.*ones(nPadRows, nPadCols);
|
||||
padding(padH+1:end-padH, padW+1:end-padW) = Im(:, :, k);
|
||||
ImOut(:, :, k) = conv2(padding, Ker, 'valid');
|
||||
elseif strcmp(method, 'extend')
|
||||
padding = zeros(nPadRows, nPadCols);
|
||||
padding(padH+1:end-padH, padW+1:end-padW) = Im(:, :, k); % Middle
|
||||
padding(1:padH, 1:padW) = Im(1, 1, k); % TopLeft
|
||||
padding(end-padH+1:end, 1:padW) = Im(end, 1, k); % BotLeft
|
||||
padding(1:padH, end-padW+1:end) = Im(1, end, k); % TopRight
|
||||
padding(end-padH+1:end, end-padW+1:end) = Im(end, end, k);% BotRight
|
||||
padding(padH+1:end-padH, 1:padW) = ...
|
||||
repmat(Im(:, 1, k), 1, padW); % Left
|
||||
padding(padH+1:end-padH, end-padW+1:end) = ...
|
||||
repmat(Im(:, end, k), 1, padW); % Right
|
||||
padding(1:padH, padW+1:end-padW) = ...
|
||||
repmat(Im(1, :, k), padH, 1); % Top
|
||||
padding(end-padH+1:end, padW+1:end-padW) = ...
|
||||
repmat(Im(end, :, k), padH, 1); % Bottom
|
||||
ImOut(:, :, k) = conv2(padding, Ker, 'valid');
|
||||
elseif strcmp(method, 'partial')
|
||||
ImOut(padH+1:end-padH, padW+1:end-padW, k) = ...
|
||||
conv2(Im(:, :, k), Ker, 'valid'); % Middle
|
||||
unprocessed = true(nImRows, nImCols);
|
||||
unprocessed(padH+1:end-padH, padW+1:end-padW) = false; % Border
|
||||
for r = 1:nImRows
|
||||
for c = 1:nImCols
|
||||
if unprocessed(r, c)
|
||||
limitedIm = Im(max(1, r-padH):min(nImRows, r+padH), ...
|
||||
max(1, c-padW):min(nImCols, c+padW), k);
|
||||
limitedKer = Ker(max(1, 2-r+padH): ...
|
||||
min(nKerRows, nKerRows+nImRows-r-padH), ...
|
||||
max(1, 2-c+padW):...
|
||||
min(nKerCols, nKerCols+nImCols-c-padW));
|
||||
limitedKer = limitedKer.*sum(Ker(:))./ ...
|
||||
sum(limitedKer(:));
|
||||
ImOut(r, c, k) = sum(sum(limitedIm.*limitedKer));
|
||||
end
|
||||
end
|
||||
end
|
||||
else % method is 'none'
|
||||
ImOut(:, :, k) = Im(:, :, k);
|
||||
ImOut(padH+1:end-padH, padW+1:end-padW, k) = ...
|
||||
conv2(Im(:, :, k), Ker, 'valid');
|
||||
end
|
||||
end
|
||||
|
||||
% Convert back to former image data type
|
||||
ImOut = cast(ImOut, classIm);
|
||||
end
|
||||
3
Task/Image-convolution/Maple/image-convolution.maple
Normal file
3
Task/Image-convolution/Maple/image-convolution.maple
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
pic:=Import("smiling_dog.jpg"):
|
||||
mask := Matrix([[1,2,3],[4,5,6],[7,8,9]]);
|
||||
pic := ImageTools:-Convolution(pic, mask);
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
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] ]
|
||||
118
Task/Image-convolution/Nim/image-convolution.nim
Normal file
118
Task/Image-convolution/Nim/image-convolution.nim
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
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
|
||||
55
Task/Image-convolution/OCaml/image-convolution-1.ocaml
Normal file
55
Task/Image-convolution/OCaml/image-convolution-1.ocaml
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
let get_rgb img x y =
|
||||
let _, r_channel,_,_ = img in
|
||||
let width = Bigarray.Array2.dim1 r_channel
|
||||
and height = Bigarray.Array2.dim2 r_channel in
|
||||
if (x < 0) || (x >= width) then (0,0,0) else
|
||||
if (y < 0) || (y >= height) then (0,0,0) else (* feed borders with black *)
|
||||
get_pixel img x y
|
||||
|
||||
|
||||
let convolve_get_value img kernel divisor offset = fun x y ->
|
||||
let sum_r = ref 0.0
|
||||
and sum_g = ref 0.0
|
||||
and sum_b = ref 0.0 in
|
||||
|
||||
for i = -1 to 1 do
|
||||
for j = -1 to 1 do
|
||||
let r, g, b = get_rgb img (x+i) (y+j) in
|
||||
sum_r := !sum_r +. kernel.(j+1).(i+1) *. (float r);
|
||||
sum_g := !sum_g +. kernel.(j+1).(i+1) *. (float g);
|
||||
sum_b := !sum_b +. kernel.(j+1).(i+1) *. (float b);
|
||||
done;
|
||||
done;
|
||||
( !sum_r /. divisor +. offset,
|
||||
!sum_g /. divisor +. offset,
|
||||
!sum_b /. divisor +. offset )
|
||||
|
||||
|
||||
let color_to_int (r,g,b) =
|
||||
(truncate r,
|
||||
truncate g,
|
||||
truncate b)
|
||||
|
||||
let bounded (r,g,b) =
|
||||
((max 0 (min r 255)),
|
||||
(max 0 (min g 255)),
|
||||
(max 0 (min b 255)))
|
||||
|
||||
|
||||
let convolve_value ~img ~kernel ~divisor ~offset =
|
||||
let _, r_channel,_,_ = img in
|
||||
let width = Bigarray.Array2.dim1 r_channel
|
||||
and height = Bigarray.Array2.dim2 r_channel in
|
||||
|
||||
let res = new_img ~width ~height in
|
||||
|
||||
let conv = convolve_get_value img kernel divisor offset in
|
||||
|
||||
for y = 0 to pred height do
|
||||
for x = 0 to pred width do
|
||||
let color = conv x y in
|
||||
let color = color_to_int color in
|
||||
put_pixel res (bounded color) x y;
|
||||
done;
|
||||
done;
|
||||
(res)
|
||||
35
Task/Image-convolution/OCaml/image-convolution-2.ocaml
Normal file
35
Task/Image-convolution/OCaml/image-convolution-2.ocaml
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
let emboss img =
|
||||
let kernel = [|
|
||||
[| -2.; -1.; 0. |];
|
||||
[| -1.; 1.; 1. |];
|
||||
[| 0.; 1.; 2. |];
|
||||
|] in
|
||||
convolve_value ~img ~kernel ~divisor:1.0 ~offset:0.0;
|
||||
;;
|
||||
|
||||
let sharpen img =
|
||||
let kernel = [|
|
||||
[| -1.; -1.; -1. |];
|
||||
[| -1.; 9.; -1. |];
|
||||
[| -1.; -1.; -1. |];
|
||||
|] in
|
||||
convolve_value ~img ~kernel ~divisor:1.0 ~offset:0.0;
|
||||
;;
|
||||
|
||||
let sobel_emboss img =
|
||||
let kernel = [|
|
||||
[| -1.; -2.; -1. |];
|
||||
[| 0.; 0.; 0. |];
|
||||
[| 1.; 2.; 1. |];
|
||||
|] in
|
||||
convolve_value ~img ~kernel ~divisor:1.0 ~offset:0.5;
|
||||
;;
|
||||
|
||||
let box_blur img =
|
||||
let kernel = [|
|
||||
[| 1.; 1.; 1. |];
|
||||
[| 1.; 1.; 1. |];
|
||||
[| 1.; 1.; 1. |];
|
||||
|] in
|
||||
convolve_value ~img ~kernel ~divisor:9.0 ~offset:0.0;
|
||||
;;
|
||||
23
Task/Image-convolution/Octave/image-convolution.octave
Normal file
23
Task/Image-convolution/Octave/image-convolution.octave
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
function [r, g, b] = rgbconv2(a, c)
|
||||
r = im2uint8(mat2gray(conv2(a(:,:,1), c)));
|
||||
g = im2uint8(mat2gray(conv2(a(:,:,2), c)));
|
||||
b = im2uint8(mat2gray(conv2(a(:,:,3), c)));
|
||||
endfunction
|
||||
|
||||
im = jpgread("Lenna100.jpg");
|
||||
emboss = [-2, -1, 0;
|
||||
-1, 1, 1;
|
||||
0, 1, 2 ];
|
||||
sobel = [-1., -2., -1.;
|
||||
0., 0., 0.;
|
||||
1., 2., 1. ];
|
||||
sharpen = [ -1.0, -1.0, -1.0;
|
||||
-1.0, 9.0, -1.0;
|
||||
-1.0, -1.0, -1.0 ];
|
||||
|
||||
[r, g, b] = rgbconv2(im, emboss);
|
||||
jpgwrite("LennaEmboss.jpg", r, g, b, 100);
|
||||
[r, g, b] = rgbconv2(im, sobel);
|
||||
jpgwrite("LennaSobel.jpg", r, g, b, 100);
|
||||
[r, g, b] = rgbconv2(im, sharpen);
|
||||
jpgwrite("LennaSharpen.jpg", r, g, b, 100);
|
||||
11
Task/Image-convolution/Perl/image-convolution.pl
Normal file
11
Task/Image-convolution/Perl/image-convolution.pl
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
use strict;
|
||||
use warnings;
|
||||
|
||||
use PDL;
|
||||
use PDL::Image2D;
|
||||
|
||||
my $kernel = pdl [[-2, -1, 0],[-1, 1, 1], [0, 1, 2]]; # emboss
|
||||
|
||||
my $image = rpic 'pythagoras_tree.png';
|
||||
my $smoothed = conv2d $image, $kernel, {Boundary => 'Truncate'};
|
||||
wpic $smoothed, 'pythagoras_convolution.png';
|
||||
119
Task/Image-convolution/Phix/image-convolution.phix
Normal file
119
Task/Image-convolution/Phix/image-convolution.phix
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
(notonline)-->
|
||||
<span style="color: #000080;font-style:italic;">--
|
||||
-- demo\rosetta\Image_convolution.exw
|
||||
-- ==================================
|
||||
--</span>
|
||||
<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,
|
||||
-- imFileImageLoadBitmap, peekNS, wait_key, 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>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<span style="color: #000080;font-style:italic;">-- 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>
|
||||
<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>
|
||||
<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>
|
||||
<span style="color: #000080;font-style:italic;">-- 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>
|
||||
<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>
|
||||
<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>
|
||||
<span style="color: #000080;font-style:italic;">-- 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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #000000;">new_image</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">original</span>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<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>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
|
||||
|
||||
<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>
|
||||
<span style="color: #008080;">return</span> <span style="color: #000000;">new_img</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
|
||||
<span style="color: #7060A8;">IupOpen</span><span style="color: #0000FF;">()</span>
|
||||
|
||||
<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>
|
||||
<span style="color: #000000;">TITLE</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Image convolution"</span>
|
||||
<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>
|
||||
<span style="color: #000080;font-style:italic;">--imImage im1 = imFileImageLoadBitmap("Lenna50.jpg",0,pError)
|
||||
--imImage im1 = imFileImageLoadBitmap("Lenna100.jpg",0,pError)
|
||||
--imImage im1 = imFileImageLoadBitmap("Lena.ppm",0,pError)</span>
|
||||
<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>
|
||||
<span style="color: #000080;font-style:italic;">--imImage im1 = imFileImageLoadBitmap("Quantum_frog.512.png",0,pError)</span>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
|
||||
<span style="color: #7060A8;">abort</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
|
||||
<span style="color: #000080;font-style:italic;">--(see also Color_quantization.exw if not an IM_RGB image)</span>
|
||||
|
||||
<span style="color: #004080;">Ihandle</span> <span style="color: #000000;">dlg</span><span style="color: #0000FF;">,</span>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<span style="color: #000000;">label1</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">(),</span>
|
||||
<span style="color: #000000;">label2</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">IupLabel</span><span style="color: #0000FF;">()</span>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<span style="color: #000080;font-style:italic;">-- IupSetAttributeHandle(label2, "IMAGE", NULL)</span>
|
||||
<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>
|
||||
<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>
|
||||
<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>
|
||||
<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;">IupRefresh</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dlg</span><span style="color: #0000FF;">)</span>
|
||||
<span style="color: #008080;">return</span> <span style="color: #004600;">IUP_DEFAULT</span>
|
||||
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
|
||||
<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>
|
||||
|
||||
<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>
|
||||
<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>
|
||||
<!--
|
||||
25
Task/Image-convolution/PicoLisp/image-convolution.l
Normal file
25
Task/Image-convolution/PicoLisp/image-convolution.l
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
(scl 3)
|
||||
|
||||
(de ppmConvolution (Ppm Kernel)
|
||||
(let (Len (length (car Kernel)) Radius (/ Len 2))
|
||||
(make
|
||||
(chain (head Radius Ppm))
|
||||
(for (Y Ppm T (cdr Y))
|
||||
(NIL (nth Y Len)
|
||||
(chain (tail Radius Y)) )
|
||||
(link
|
||||
(make
|
||||
(chain (head Radius (get Y (inc Radius))))
|
||||
(for (X (head Len Y) T)
|
||||
(NIL (nth X 1 Len)
|
||||
(chain (tail Radius (get X (inc Radius)))) )
|
||||
(link
|
||||
(make
|
||||
(for C 3
|
||||
(let Val 0
|
||||
(for K Len
|
||||
(for L Len
|
||||
(inc 'Val
|
||||
(* (get X K L C) (get Kernel K L)) ) ) )
|
||||
(link (min 255 (max 0 (*/ Val 1.0)))) ) ) ) )
|
||||
(map pop X) ) ) ) ) ) ) )
|
||||
12
Task/Image-convolution/Python/image-convolution-1.py
Normal file
12
Task/Image-convolution/Python/image-convolution-1.py
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#!/bin/python
|
||||
from PIL import Image, ImageFilter
|
||||
|
||||
if __name__=="__main__":
|
||||
im = Image.open("test.jpg")
|
||||
|
||||
kernelValues = [-2,-1,0,-1,1,1,0,1,2] #emboss
|
||||
kernel = ImageFilter.Kernel((3,3), kernelValues)
|
||||
|
||||
im2 = im.filter(kernel)
|
||||
|
||||
im2.show()
|
||||
17
Task/Image-convolution/Python/image-convolution-2.py
Normal file
17
Task/Image-convolution/Python/image-convolution-2.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/python
|
||||
import numpy as np
|
||||
from scipy.ndimage.filters import convolve
|
||||
from scipy.misc import imread, imshow
|
||||
|
||||
if __name__=="__main__":
|
||||
im = imread("test.jpg", mode="RGB")
|
||||
im = np.array(im, dtype=float) #Convert to float to prevent clipping colors
|
||||
|
||||
kernel = np.array([[[0,-2,0],[0,-1,0],[0,0,0]],
|
||||
[[0,-1,0],[0,1,0],[0,1,0]],
|
||||
[[0,0,0],[0,1,0],[0,2,0]]])#emboss
|
||||
|
||||
im2 = convolve(im, kernel)
|
||||
im3 = np.array(np.clip(im2, 0, 255), dtype=np.uint8) #Apply color clipping
|
||||
|
||||
imshow(im3)
|
||||
50
Task/Image-convolution/Racket/image-convolution.rkt
Normal file
50
Task/Image-convolution/Racket/image-convolution.rkt
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
#lang typed/racket
|
||||
(require images/flomap racket/flonum)
|
||||
|
||||
(provide flomap-convolve)
|
||||
|
||||
(: perfect-square? (Nonnegative-Fixnum -> (U Nonnegative-Fixnum #f)))
|
||||
(define (perfect-square? n)
|
||||
(define rt-n (integer-sqrt n))
|
||||
(and (= n (sqr rt-n)) rt-n))
|
||||
|
||||
(: flomap-convolve (flomap FlVector -> flomap))
|
||||
(define (flomap-convolve F K)
|
||||
(unless (flomap? F) (error "arg1 not a flowmap"))
|
||||
(unless (flvector? K) (error "arg2 not a flvector"))
|
||||
(define R (perfect-square? (flvector-length K)))
|
||||
(cond
|
||||
[(not (and R (odd? R))) (error "K is not odd-sided square")]
|
||||
[else
|
||||
(define R/2 (quotient R 2))
|
||||
(define R/-2 (quotient R -2))
|
||||
(define-values (sz-w sz-h) (flomap-size F))
|
||||
(define-syntax-rule (convolution c x y i)
|
||||
(if (= 0 c)
|
||||
(flomap-ref F c x y) ; c=3 is alpha channel
|
||||
(for*/fold: : Flonum
|
||||
((acc : Flonum 0.))
|
||||
((k (in-range 0 (add1 R/2)))
|
||||
(l (in-range 0 (add1 R/2)))
|
||||
(kl (in-value (+ (* k R) l)))
|
||||
(kx (in-value (+ x k R/-2)))
|
||||
(ly (in-value (+ y l R/-2)))
|
||||
#:when (< 0 kx (sub1 sz-w))
|
||||
#:when (< 0 ly (sub1 sz-h)))
|
||||
(+ acc (* (flvector-ref K kl) (flomap-ref F c kx ly))))))
|
||||
|
||||
(inline-build-flomap 4 sz-w sz-h convolution)]))
|
||||
|
||||
(module* test racket
|
||||
(require racket/draw images/flomap racket/flonum (only-in 2htdp/image save-image))
|
||||
(require (submod ".."))
|
||||
(define flmp (bitmap->flomap (read-bitmap "jpg/271px-John_Constable_002.jpg")))
|
||||
(save-image
|
||||
(flomap->bitmap (flomap-convolve flmp (flvector 1.)))
|
||||
"out/convolve-unit-1x1.png")
|
||||
(save-image
|
||||
(flomap->bitmap (flomap-convolve flmp (flvector 0. 0. 0. 0. 1. 0. 0. 0. 0.)))
|
||||
"out/convolve-unit-3x3.png")
|
||||
(save-image
|
||||
(flomap->bitmap (flomap-convolve flmp (flvector -1. -1. -1. -1. 4. -1. -1. -1. -1.)))
|
||||
"out/convolve-etch-3x3.png"))
|
||||
8
Task/Image-convolution/Raku/image-convolution-1.raku
Normal file
8
Task/Image-convolution/Raku/image-convolution-1.raku
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
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';
|
||||
30
Task/Image-convolution/Raku/image-convolution-2.raku
Normal file
30
Task/Image-convolution/Raku/image-convolution-2.raku
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
# 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;
|
||||
}
|
||||
57
Task/Image-convolution/Ruby/image-convolution.rb
Normal file
57
Task/Image-convolution/Ruby/image-convolution.rb
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
class Pixmap
|
||||
# Apply a convolution kernel to a whole image
|
||||
def convolute(kernel)
|
||||
newimg = Pixmap.new(@width, @height)
|
||||
pb = ProgressBar.new(@width) if $DEBUG
|
||||
@width.times do |x|
|
||||
@height.times do |y|
|
||||
apply_kernel(x, y, kernel, newimg)
|
||||
end
|
||||
pb.update(x) if $DEBUG
|
||||
end
|
||||
pb.close if $DEBUG
|
||||
newimg
|
||||
end
|
||||
|
||||
# Applies a convolution kernel to produce a single pixel in the destination
|
||||
def apply_kernel(x, y, kernel, newimg)
|
||||
x0 = x==0 ? 0 : x-1
|
||||
y0 = y==0 ? 0 : y-1
|
||||
x1 = x
|
||||
y1 = y
|
||||
x2 = x+1==@width ? x : x+1
|
||||
y2 = y+1==@height ? y : y+1
|
||||
|
||||
r = g = b = 0.0
|
||||
[x0, x1, x2].zip(kernel).each do |xx, kcol|
|
||||
[y0, y1, y2].zip(kcol).each do |yy, k|
|
||||
r += k * self[xx,yy].r
|
||||
g += k * self[xx,yy].g
|
||||
b += k * self[xx,yy].b
|
||||
end
|
||||
end
|
||||
newimg[x,y] = RGBColour.new(luma(r), luma(g), luma(b))
|
||||
end
|
||||
|
||||
# Function for clamping values to those that we can use with colors
|
||||
def luma(value)
|
||||
if value < 0
|
||||
0
|
||||
elsif value > 255
|
||||
255
|
||||
else
|
||||
value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Demonstration code using the teapot image from Tk's widget demo
|
||||
teapot = Pixmap.open('teapot.ppm')
|
||||
[ ['Emboss', [[-2.0, -1.0, 0.0], [-1.0, 1.0, 1.0], [0.0, 1.0, 2.0]]],
|
||||
['Sharpen', [[-1.0, -1.0, -1.0], [-1.0, 9.0, -1.0], [-1.0, -1.0, -1.0]]],
|
||||
['Blur', [[0.1111,0.1111,0.1111],[0.1111,0.1111,0.1111],[0.1111,0.1111,0.1111]]],
|
||||
].each do |label, kernel|
|
||||
savefile = 'teapot_' + label.downcase + '.ppm'
|
||||
teapot.convolute(kernel).save(savefile)
|
||||
end
|
||||
77
Task/Image-convolution/Tcl/image-convolution.tcl
Normal file
77
Task/Image-convolution/Tcl/image-convolution.tcl
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
package require Tk
|
||||
|
||||
# Function for clamping values to those that we can use with colors
|
||||
proc tcl::mathfunc::luma channel {
|
||||
set channel [expr {round($channel)}]
|
||||
if {$channel < 0} {
|
||||
return 0
|
||||
} elseif {$channel > 255} {
|
||||
return 255
|
||||
} else {
|
||||
return $channel
|
||||
}
|
||||
}
|
||||
# Applies a convolution kernel to produce a single pixel in the destination
|
||||
proc applyKernel {srcImage x y -- kernel -> dstImage} {
|
||||
set x0 [expr {$x==0 ? 0 : $x-1}]
|
||||
set y0 [expr {$y==0 ? 0 : $y-1}]
|
||||
set x1 $x
|
||||
set y1 $y
|
||||
set x2 [expr {$x+1==[image width $srcImage] ? $x : $x+1}]
|
||||
set y2 [expr {$y+1==[image height $srcImage] ? $y : $y+1}]
|
||||
|
||||
set r [set g [set b 0.0]]
|
||||
foreach X [list $x0 $x1 $x2] kcol $kernel {
|
||||
foreach Y [list $y0 $y1 $y2] k $kcol {
|
||||
lassign [$srcImage get $X $Y] rPix gPix bPix
|
||||
set r [expr {$r + $k * $rPix}]
|
||||
set g [expr {$g + $k * $gPix}]
|
||||
set b [expr {$b + $k * $bPix}]
|
||||
}
|
||||
}
|
||||
|
||||
$dstImage put [format "#%02x%02x%02x" \
|
||||
[expr {luma($r)}] [expr {luma($g)}] [expr {luma($b)}]]\
|
||||
-to $x $y
|
||||
}
|
||||
# Apply a convolution kernel to a whole image
|
||||
proc convolve {srcImage kernel {dstImage ""}} {
|
||||
if {$dstImage eq ""} {
|
||||
set dstImage [image create photo]
|
||||
}
|
||||
set w [image width $srcImage]
|
||||
set h [image height $srcImage]
|
||||
for {set x 0} {$x < $w} {incr x} {
|
||||
for {set y 0} {$y < $h} {incr y} {
|
||||
applyKernel $srcImage $x $y -- $kernel -> $dstImage
|
||||
}
|
||||
}
|
||||
return $dstImage
|
||||
}
|
||||
|
||||
# Demonstration code using the teapot image from Tk's widget demo
|
||||
image create photo teapot -file $tk_library/demos/images/teapot.ppm
|
||||
pack [labelframe .src -text Source] -side left
|
||||
pack [label .src.l -image teapot]
|
||||
foreach {label kernel} {
|
||||
Emboss {
|
||||
{-2. -1. 0.}
|
||||
{-1. 1. 1.}
|
||||
{ 0. 1. 2.}
|
||||
}
|
||||
Sharpen {
|
||||
{-1. -1. -1}
|
||||
{-1. 9. -1}
|
||||
{-1. -1. -1}
|
||||
}
|
||||
Blur {
|
||||
{.1111 .1111 .1111}
|
||||
{.1111 .1111 .1111}
|
||||
{.1111 .1111 .1111}
|
||||
}
|
||||
} {
|
||||
set name [string tolower $label]
|
||||
update
|
||||
pack [labelframe .$name -text $label] -side left
|
||||
pack [label .$name.l -image [convolve teapot $kernel]]
|
||||
}
|
||||
147
Task/Image-convolution/Wren/image-convolution.wren
Normal file
147
Task/Image-convolution/Wren/image-convolution.wren
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
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.loadFromFile(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)
|
||||
Loading…
Add table
Add a link
Reference in a new issue