1 module dcv.example.convolution; 2 3 /** 4 * Spatial image filtering example using dcv library. 5 */ 6 7 import std.stdio : writeln; 8 import std.datetime : StopWatch; 9 import std.math : abs; 10 import std.array : array; 11 12 import mir.ndslice; 13 14 import dcv.core : Image, ranged, ImageFormat; 15 import dcv.io : imread, imwrite; 16 import dcv.imgproc; 17 import dcv.plot; 18 19 int main(string[] args) 20 { 21 string impath = (args.length < 2) ? "../data/lena.png" : args[1]; 22 23 Image img = imread(impath); // read an image from filesystem. 24 25 if (img.empty) 26 { // check if image is properly read. 27 writeln("Cannot read image at: " ~ impath); 28 return 1; 29 } 30 31 Slice!(Contiguous, [3], float*) imslice = img 32 .sliced // slice image data 33 .as!float // convert it to float 34 .slice; // make a copy. 35 36 auto gray = imslice.rgb2gray; // convert rgb image to grayscale 37 38 auto gaussianKernel = gaussian!float(2, 5, 5); // create gaussian convolution kernel (sigma, kernel width and height) 39 auto sobelXKernel = sobel!real(GradientDirection.DIR_X); // sobel operator for horizontal (X) gradients 40 auto laplacianKernel = laplacian!double; // laplacian kernel, similar to matlabs fspecial('laplacian', alpha) 41 auto logKernel = laplacianOfGaussian!float(1, 5, 5); // laplacian of gaussian, similar to matlabs fspecial('log', alpha, width, height) 42 43 // perform convolution for each kernel 44 auto blur = imslice.conv(gaussianKernel); 45 auto xgrads = gray.conv(sobelXKernel); 46 auto laplaceEdges = gray.conv(laplacianKernel); 47 auto logEdges = gray.conv(logKernel); 48 49 // calculate canny edges 50 auto cannyEdges = gray.canny!ubyte(75); 51 52 // perform bilateral blurring 53 auto bilBlur = imslice.bilateralFilter!float(10.0f, 10.0f, 5); 54 55 // Add salt and pepper noise at input image green channel 56 auto noisyImage = imslice.slice; 57 auto saltNPepperNoise = noisyImage[0 .. $, 0 .. $, 1].saltNPepper(0.15f); 58 // ... and perform median blurring on noisy image 59 auto medBlur = noisyImage.medianFilter(5); 60 61 // scale values from 0 to 255 to preview gradient direction and magnitude 62 xgrads.ranged(0, 255); 63 // Take absolute values and range them from 0 to 255, to preview edges 64 laplaceEdges = laplaceEdges.map!(a => abs(a)).slice.ranged(0.0f, 255.0f); 65 logEdges = logEdges.map!(a => abs(a)).slice.ranged(0.0f, 255.0f); 66 67 // Show images on screen 68 img.imshow("Original"); 69 bilBlur.imshow("Bilateral Blurring"); 70 noisyImage.imshow("Salt and Pepper noise at green channel for Median"); 71 medBlur.imshow("Median Blurring"); 72 blur.imshow("Gaussian Blurring"); 73 xgrads.imshow("Sobel X"); 74 laplaceEdges.imshow("Laplace"); 75 logEdges.imshow("Laplacian of Gaussian"); 76 cannyEdges.imshow("Canny Edges"); 77 78 waitKey(); 79 80 return 0; 81 } 82 83 auto saltNPepper(T, SliceKind kind)(Slice!(kind, [2], T*) input, float saturation) 84 { 85 import std.range : lockstep; 86 import std.random : uniform; 87 88 int err; 89 ulong pixelCount = input.length!0*input.length!1; 90 ulong noisyPixelCount = cast(typeof(pixelCount))(pixelCount * saturation); 91 92 auto noisyPixels = slice!size_t(noisyPixelCount); 93 foreach(ref e; noisyPixels) 94 { 95 e = uniform(0, pixelCount); 96 } 97 98 auto imdata = input.reshape([pixelCount], err); 99 100 assert(err == 0); 101 102 foreach(salt, pepper; lockstep(noisyPixels[0 .. $ / 2], noisyPixels[$ / 2 .. $])) 103 { 104 imdata[salt] = cast(T)255; 105 imdata[pepper] = cast(T)0; 106 } 107 return input; 108 }