Jump to content

Canny edge detector: Difference between revisions

More idiomatic D code
(Simpler D code)
(More idiomatic D code)
Line 419:
import std.math: PI, floor, exp, pow, hypot, fmod, atan2;
import std.typecons: tuple, Tuple;
import std.string: text;
 
enum MAX_BRIGHTNESS = 255;
Line 451 ⟶ 452:
 
 
Tuple!(Pixel[],BMPheader) loadBMP(in string fileName) nothrow {
scope(exit) if (filePtr) fclose(filePtr);
 
auto filePtr = fopen((fileName ~ "\0").ptr, "rb");
if (filePtr == null) {
perrorthrow new Exception("loadBMP: fopen()");
return typeof(return).init;
}
 
BMPheader header;
if (fread(&header, header.sizeof, 1, filePtr) != 1) {
fclosethrow new Exception(filePtr"loadBMP: fread header");
return typeof(return).init;
}
 
// verify that this is a bmp file by check bitmap id
if (header.smagic != 0x4D42) {
fprintf(stderr,throw new Exception(text("NotloadBMP: not a BMP file: magic=%u\n", header.smagic);
fclose(filePtr header.smagic));
return typeof(return).init;
}
 
if (header.compress_type != 0) {
fprintf(stderr,throw new Exception("Warning,loadBMP: compression is not supported.\n");
fclose(filePtr);
return typeof(return).init;
}
 
// move file point to the beginning of bitmap data
Line 484 ⟶ 478:
foreach (ref bi; bitmapImage) {
ubyte c = void;
if (fread(&c, ubyte.sizeof, 1, filePtr) != 1) {// slow
fclosethrow new Exception(filePtr"loadBMP: fread bitmap data.");
return typeof(return).init;
}
bi = c;
}
 
fclose(filePtr);
return tuple(bitmapImage, header);
}
 
 
intvoid saveBMP(in string fileName, const ref BMPheader header,
// Return: true on error.
in Pixel[] data) nothrow {
int saveBMP(in string fileName, const ref BMPheader header,
scope(exit) if (filePtr) fclose(filePtr);
in Pixel[] data) nothrow {
 
auto fpfilePtr = fopen((fileName ~ "\0").ptr, "wb");
if (fp == null)
if (filePtr == return true;null)
throw new Exception("saveBMP: fopen()");
 
immutable uint moffset = BMPheader.sizeof +
((1U << header.bitspp) * 4);
 
// generate and write new BMP header
BMPheader newHeader = header;
newHeader.smagic = 0x4D42;
newHeader.filesz = moffset + header.bmp_bytesz;
newHeader.creator1 = 0;
newHeader.creator2 = 0;
newHeader.bmp_offset = moffset;
fwrite(&newHeader, 1, newHeader.sizeof, fp);
 
static// structwrite Rgbnew {BMP header
if (fwrite(&newHeader, 1, newHeader.sizeof, fp1, filePtr) != 1);
ubyte r, g, b, nothing;
throw new Exception("saveBMP: fwrite BMP header.");
}
 
// Writewrite palette
foreach (i; 0 .. (1U << header.bitspp)) {
immutablestatic color =struct Rgb(cast(ubyte)i, {
ubyte r, g, b, cast(ubyte)i,nothing;
}
cast(ubyte)i);
 
fwrite(&color, 1, Rgb.sizeof, fp);
immutable colorEntry = Rgb(cast(ubyte)i,
cast(ubyte)i,
cast(ubyte)i);
if (fwrite(&color, 1colorEntry, Rgb.sizeof, fp1, filePtr) != 1);
throw new Exception("saveBMP: fwrite palette.");
}
 
// write bitmap data
foreach (di; data) {
immutable ubyte c = cast(ubyte)di;
if (fwrite(&c, ubyte.sizeof, 1, fpfilePtr); != 1) // slow
throw new Exception("saveBMP: fwrite bitmap data.");
}
 
fclose(fp);
return false;
}
 
 
// if normnormalize is true, map pixels to range 0...MAX_BRIGHTNESS
void convolution(bool normalize)(in Pixel[] inp, Pixel[] outp, in float[] kernel,
in int nx, in int ny, in int kn, in boolfloat[] norm)kernel,
in int nx, in int ny, in int ih, 45, 50kn);
pure nothrow {
immutable int khalf = kn / 2;
float pMin = float.max, pMax = -float.max;
 
static if (normnormalize) {
foreach (m; khalf .. nx - khalf) {
foreach (n; khalf .. ny - khalf) {
float pixel = 0.0;
int c;
foreach (j; -khalf .. khalf + 1) {
foreach (i; -khalf .. khalf + 1) {
pixel += inp[(n - j) * nx + m - i] * kernel[c];
c++;
}
if (pixel < pMin)
pMin = pixel;
if (pixel > pMax)
pMax = pixel;
}
 
if (pixel < pMin) pMin = pixel;
foreach (m; khalf .. nx - khalf)
if (pixel > pMax) pMinpMax = pixel;
}
}
}
 
foreach (m; khalf .. nx - khalf) {
foreach (n; khalf .. ny - khalf) {
float pixel = 0.0;
int c;
foreach (j; -khalf .. khalf + 1) {
foreach (i; -khalf .. khalf + 1) {
pixel += inp[(n - j) * nx + m - i] * kernel[c];
c++;
}
return 1; }
 
static if (normnormalize)
pixel = MAX_BRIGHTNESS * (pixel - pMin) / (pMax - pMin);
outp[n * nx + m] = cast(Pixel)pixel;
}
}
}
 
Line 589 ⟶ 586:
kernelSize = 2 * int(2*sigma) + 3;
*/
void gaussianFilter(float sigma)(in Pixel[] inp, Pixel[] outp,
in int nx, in int ny, float sigma) nothrow {
enumimmutable int n = 2 * cast(int)(2 * sigma) + 3;
/*enum*/ immutable float mean = cast(float)floor(n / 2.0);
auto kernel = new float[n * n] kernel;
 
debug fprintf(stderr,
"gaussianFilter: kernel size %d, sigma=%g\n",
n, sigma);
 
int c;
foreach (i; 0 .. n) {
foreach (j; 0 .. n) {
kernel[c] = exp(-0.5 * (pow((i - mean) / sigma, 2.0) +
Line 606 ⟶ 604:
c++;
}
}
convolution(inp, outp, kernel[], nx, ny, n, true);
 
convolution!(true)(inp, outp, kernel[], nx, ny, n, true);
}
 
Line 619:
tMin, and tMax are lower and upper thresholds.
*/
Pixel[] cannyEdgeDetection(float sigma)(in Pixel[] inp,
const ref BMPheader header,
in int tMin, in int tMax, float sigma)
nothrow {
immutable int nx = header.width;
immutable int ny = header.height;
auto outp = new Pixel[header.bmp_bytesz];
auto G = new Pixel[nx * ny];
auto after_Gx = new Pixel[nx * ny];
auto after_Gy = new Pixel[nx * ny];
auto nms = new Pixel[nx * ny];
 
gaussianFilter!(sigma)(inp, outp, nx, ny, sigma);
 
__gshared immutable float[] Gx = [-1, 0, 1,
Line 641 ⟶ 637:
-1,-2,-1];
 
convolution(outp,auto after_Gx, Gx,= new Pixel[nx, ny,* 3, false)ny];
convolution(outp,auto after_Gy, Gy,= new Pixel[nx, ny,* 3, false)ny];
 
convolution!(false)(outp, after_Gx, Gx, nx, ny, 3);
int Gmax;
convolution!(false)(outp, after_Gy, Gy, nx, ny, 3);
 
auto G = new Pixel[nx * ny];
foreach (i; 1 .. nx - 1)
foreach (j; 1 .. ny - 1) {
immutable int c = i + nx * j;
G[c] = cast(Pixel)hypot(after_Gx[c], after_Gy[c]);
if (G[c] > Gmax)
Gmax = G[c];
}
 
// Non-maximum suppression, straightforward implementation.
auto after_Gxnms = new Pixel[nx * ny];
foreach (i; 1 .. nx - 1)
foreach (j; 1 .. ny - 1) {
Line 702 ⟶ 700:
immutable int t = edges[nedges];
 
int[8] nbsneighbours = void; // neighbours
nbsneighbours[0] = t - nx; // nn
nbsneighbours[1] = t + nx; // ss
nbsneighbours[2] = t + 1; // ww
nbsneighbours[3] = t - 1; // ee
nbsneighbours[4] = nbsneighbours[0] + 1; // nw
nbsneighbours[5] = nbsneighbours[0] - 1; // ne
nbsneighbours[6] = nbsneighbours[1] + 1; // sw
nbsneighbours[7] = nbsneighbours[1] - 1; // se
 
foreach (k; 0 .. 8)
if (nms[nbsneighbours[k]] >= tMin && outp[nbs[k]] == 0) {
outp[nbsneighbours[k]] == 0) MAX_BRIGHTNESS;{
edgesoutp[nedgesneighbours[k]] = nbs[k]MAX_BRIGHTNESS;
edges[nedges] = neighbours[k];
nedges++;
}
Line 728 ⟶ 727:
 
 
intvoid main(in string[] args) nothrow {
if (args.length < 2) {
printf("Usage: %s image.bmp\n", (args[0] ~ "\0").ptr);
return 1;
}
 
const inputBitmap_ih = loadBMP(args[1]);
const inputBitmap = inputBitmap_ih[0];
constimmutable ih = inputBitmap_ih[1];
if (inputBitmap.length == 0)
return 1;
 
printf("Info: %d x %d x %d\n", ih.width, ih.height, ih.bitspp);
constsaveBMP("out.bmp", outputBitmap =ih, cannyEdgeDetection!(1.0f)(inputBitmap,
 
ih, 45, 50, 1.0f));
const outputBitmap = cannyEdgeDetection!(1.0f)(inputBitmap,
ih, 45, 50);
if (outputBitmap.length == 0)
return 1;
 
if (saveBMP("out.bmp", ih, outputBitmap))
return 1;
 
return 0;
}</lang>
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.