1 module daffodil.filter.convolve; 2 3 import std.range; 4 import std.algorithm; 5 6 import daffodil.image; 7 8 /** 9 * Convolve a flat 2D matrix with a given center over an image and return the result. 10 * 11 * With a matrix [0.5, 0.5] with width 2 and center [0, 0] convolved over an image 12 * each resulting pixel will be a 50:50 mix of itself and its right neighbour. 13 * 14 * TODO: Abstract away matrix, width and center into a kernel 15 */ 16 auto convolved(V)(const Image!V image, const real[] matrix, int width, int[2] center) { 17 auto height = matrix.length / width; 18 auto ret = image.dup; 19 20 foreach (imageY; 0..image.height) { 21 foreach (imageX; 0..image.width) { 22 // Make sure weighting always adds up to 1. Fixes corners and incorrect/incomplete matrices. 23 real accum = 0; 24 25 // Accumulate color by weighing adjacent pixels according to given matrix. 26 auto color = ret.newColor(); 27 28 foreach (indexY; 0..height) { 29 auto matrixY = indexY - center[1]; 30 if (matrixY + imageY < 0 || matrixY + imageY >= image.height) continue; 31 32 foreach (indexX; 0..width) { 33 auto matrixX = indexX - center[0]; 34 if (matrixX + imageX < 0 || matrixX + imageX >= image.width) continue; 35 36 auto matrixValue = matrix[indexX + indexY * width]; 37 accum += matrixValue; 38 39 //TODO: Shorthand once color operation is implemented 40 color = color + image[imageX + matrixX, imageY + matrixY] * matrixValue; 41 } 42 } 43 44 ret[imageX, imageY] = color * (1/accum); 45 } 46 } 47 48 return ret; 49 } 50 /// Ditto 51 auto convolved(string axis, V)(const Image!V image, const real[] matrix, int center) { 52 auto ret = image.dup; 53 54 static if (canFind(axis, 'x')) { 55 // Apply matrix horizontally 56 ret = ret.convolved(matrix, cast(int)matrix.length, [center, 0]); 57 } 58 59 static if (canFind(axis, 'y')) { 60 // Apply matrix vertically 61 ret = ret.convolved(matrix, 1, [0, center]); 62 } 63 64 return ret; 65 } 66 /// Ditto 67 auto convolved(string axis, V)(const Image!V image, const real[] matrix) { 68 return image.convolved!axis(matrix, cast(int)(matrix.length / 2)); 69 } 70 71 //TODO: Add tests