1 module dcv.example.rht; 2 3 /** 4 * Randomized Hough Transform example using dcv library. 5 */ 6 7 import std.stdio : writeln; 8 import std.datetime : StopWatch; 9 import std.math : fabs, PI, sin, cos, rint; 10 import std.typecons : tuple; 11 12 import mir.ndslice; 13 14 import dcv.core.image : Image, ImageFormat; 15 import dcv.core.utils : clip; 16 import dcv.io : imread, imwrite; 17 import dcv.imgproc; 18 import dcv.features.rht; 19 20 void plotLine(T, Line, Color)(Slice!(Contiguous, [3], T*) img, Line line, Color color) 21 { 22 int height = cast(int)img.length!0; 23 int width = cast(int)img.length!1; 24 if (line.m == double.infinity) 25 { 26 auto x = line.b; 27 if (x >= 0 && x < width) 28 foreach (y; 0 .. height) 29 { 30 img[cast(int)y, cast(int)x, 0 .. 3] = color; 31 } 32 } 33 else 34 { 35 foreach (x; 0 .. 1000) 36 { 37 auto y = line.m * x + line.b; 38 if (x >= 0 && x < width && y >= 0 && y < height) 39 { 40 img[cast(int)y, cast(int)x, 0 .. 3] = color; 41 } 42 } 43 } 44 } 45 46 void plotCircle(T, Circle, Color)(Slice!(Contiguous, [3], T*) img, Circle circle, Color color) 47 { 48 int height = cast(int)img.length!0; 49 int width = cast(int)img.length!1; 50 // quick and dirty circle plot 51 foreach (t; 0 .. 360) 52 { 53 int x = cast(int)rint(circle.x + circle.r * cos(t * PI / 180)); 54 int y = cast(int)rint(circle.y + circle.r * sin(t * PI / 180)); 55 if (x >= 0 && x < width && y >= 0 && y < height) 56 img[y, x, 0 .. 3] = color; 57 } 58 } 59 60 int main(string[] args) 61 { 62 63 string impath = (args.length < 2) ? "../data/img.png" : args[1]; 64 65 Image img = imread(impath); // read an image from filesystem. 66 67 if (img.empty) 68 { // check if image is properly read. 69 writeln("Cannot read image at: " ~ impath); 70 return 1; 71 } 72 73 Slice!(Contiguous, [3], float*) imslice = img.sliced.as!float.slice; // convert Image data type from ubyte to float 74 75 auto gray = imslice.rgb2gray; // convert rgb image to grayscale 76 77 auto gaussianKernel = gaussian!float(2, 3, 3); // create gaussian convolution kernel (sigma, kernel width and height) 78 79 auto blur = gray.conv(gaussianKernel); 80 auto canny = blur.canny!ubyte(150); 81 82 auto lines = RhtLines().epouchs(35).iterations(500).minCurve(70); 83 StopWatch s; 84 s.start; 85 auto linesRange = lines(canny); 86 foreach (line; linesRange) 87 { 88 writeln(line); 89 plotLine(imslice, line, [1.0, 1.0, 1.0]); 90 } 91 s.stop; 92 writeln("RHT lines took ", s.peek.msecs, "ms"); 93 writeln("Points left after lines:", linesRange.points.length); 94 auto circles = RhtCircles().epouchs(15).iterations(2000).minCurve(50); 95 s.reset; 96 s.start; 97 foreach (circle; circles(canny, linesRange.points[])) 98 { 99 writeln(circle); 100 plotCircle(imslice, circle, [1.0, 1.0, 1.0]); 101 } 102 s.stop; 103 writeln("RHT circles took ", s.peek.msecs, "ms"); 104 105 // write resulting images on the filesystem. 106 blur.map!(v => v.clip!ubyte).slice.imwrite(ImageFormat.IF_RGB, "./result/outblur.png"); 107 canny.map!(v => v.clip!ubyte).slice.imwrite(ImageFormat.IF_MONO, "./result/canny.png"); 108 imslice.map!(v => v.clip!ubyte).slice.imwrite(ImageFormat.IF_RGB, "./result/rht.png"); 109 110 return 0; 111 }