Canny edge detector: Difference between revisions

m
m (added whitespace and split some long lines (with equations) into multiple lines.)
m (→‎{{header|Wren}}: Minor tidy)
 
(9 intermediate revisions by 6 users not shown)
Line 3:
;Task:
Write a program that performs so-called [[wp:Canny edge detector|canny edge detection]] on an image.
 
 
 
A possible algorithm consists of the following steps:
 
# '''Noise reduction.''' &nbsp; May be performed by [[wp:Gaussian blur|Gaussian filter]]. <br> &nbsp;
# Compute '''intensity gradient''' &nbsp; (matrices <math>G_x</math> and <math>G_y</math>) &nbsp; and its '''magnitude''' &nbsp; <math>G</math>:<br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <math>G=\sqrt{G_x^2+G_y^2}</math><br>May be performed by [[image convolution|convolution of an image]] with [[wp:Sobel operator|Sobel operators]]. <br> &nbsp;
# '''Non-maximum suppression.''' &nbsp; <br>For each pixel compute the orientation of intensity gradient vector: &nbsp; <math>\theta = {\rm atan2}\left(G_y, \, G_x\right)</math>. &nbsp; &nbsp; <br>Transform &nbsp; angle <math>\theta</math> &nbsp; to one of four directions: &nbsp; 0,&nbsp;45,&nbsp;90,&nbsp;135&nbsp;degrees. &nbsp; &nbsp; <br>Compute new array &nbsp; <math>N</math>: &nbsp; &nbsp; if &nbsp; &nbsp; &nbsp; &nbsp; <math>G\left(p_a\right)<G\left(p\right)<G\left(p_b\right)</math><br>where &nbsp; <math>p</math> &nbsp; is the current pixel, &nbsp; <math>p_a</math> &nbsp; and &nbsp; <math>p_b</math> &nbsp; are the two neighbour pixels in the direction of gradient, &nbsp; <br>then &nbsp; &nbsp; <math>N(p) = G(p)</math>, &nbsp; &nbsp; &nbsp; otherwise &nbsp; <math>N(p) = 0</math>. &nbsp; <br>Nonzero pixels in resulting array correspond to local maxima of &nbsp; <math>G</math> &nbsp; in direction &nbsp; <math>\theta(p)</math>. <br> &nbsp;
# '''Tracing edges with hysteresis.''' &nbsp; <br>At this stage two thresholds for the values of &nbsp; <math>G</math> &nbsp; are introduced: &nbsp; <math>T_{min}</math> &nbsp; and &nbsp; <math>T_{max}</math>. &nbsp; <br>Starting from pixels with &nbsp; <math>N(p) \geqslant T_{max}</math>, &nbsp; <br>find all paths of pixels with &nbsp; <math>N(p) \geqslant T_{min}</math> &nbsp; and put them to the resulting image.
<br><br>
 
=={{header|C}}==
The following program reads an 8 bits per pixel grayscale [[wp:BMP file format|BMP]] file and saves the result to `out.bmp'. Compile with `-lm'.
<langsyntaxhighlight lang="c">#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
Line 467:
free((pixel_t*)out_bitmap_data);
return 0;
}</langsyntaxhighlight>
 
=={{header|D}}==
{{trans|C}}
This version retains some of the style of the original C version. This code is faster than the C version, even with the DMD compiler. This version loads and saves PGM images, using the module of the Grayscale image Task.
<langsyntaxhighlight lang="d">import core.stdc.stdio, std.math, std.typecons, std.string, std.conv,
std.algorithm, std.ascii, std.array, bitmap, grayscale_image;
 
Line 671 ⟶ 670:
printf("Image size: %d x %d\n", imIn.nx, imIn.ny);
imIn.cannyEdgeDetection(45, 50, 1.0f).savePGM("lena_canny.pgm");
}</langsyntaxhighlight>
 
=={{header|Go}}==
{{libheader|Imger}}
Line 680 ⟶ 678:
 
Note that on Linux the extension of the example image file name needs to be changed from .PNG to .png in order for the library used to recognize it.
<langsyntaxhighlight lang="go">package main
 
import (
Line 703 ⟶ 701:
log.Fatal("Could not write Canny image to disk")
}
}</langsyntaxhighlight>
 
=={{header|J}}==
<p>In this solution images are represented as 2D arrays of pixels, with first and second axes representing down and right respectively. Each processing step has a specific pixel representation. In the original and Gaussian-filtered images, array elements represent monochromatic intensity values as numbers ranging from 0 (black) to 255 (white). In the intensity gradient image, gradient values are vectors, and are represented as complex numbers, with real and imaginary components representing down and right respectively. </p>
<p>Detected edge and non-edge points are represented as ones and zeros respectively. An edge is a set of connected edge points (points adjacent horizontally, vertically, or diagonally are considered to be connected). In the final image, each edge is represented by assigning its set of points a common unique value. </p>
<langsyntaxhighlight Jlang="j">NB. 2D convolution, filtering, ...
 
convolve =: 4 : 'x apply (($x) partition y)'
Line 797 ⟶ 794:
canny =: step5 @ step4 @ step3 @ step2 @ step1
 
</syntaxhighlight>
</lang>
<p>The above implementation solves the 'inner problem' of Canny Edge Detection in the J language, with no external dependencies. J's Qt IDE provides additional support including interfaces to image file formats, graphic displays, and the user. The following code exercises these features</p>
 
<p>The file 'valve.png' referenced in this code is from one of several Wikipedia articles on edge detection. It can be viewed at [https://upload.wikimedia.org/wikipedia/commons/2/2e/Valve_gaussian_%282%29.PNG[https://upload.wikimedia.org/wikipedia/commons/2/2e/Valve_gaussian_%282%29.PNG]]</p>
<syntaxhighlight lang="j">
<lang J>
require 'gl2'
coclass 'edge'
Line 859 ⟶ 856:
form_close=: exit bind 0
 
run''</langsyntaxhighlight>
 
 
=={{header|Java}}==
El código es de Tom Gibara [The code is from Tom Gibara] (http://www.tomgibara.com/)
 
Se implementa utilizando una sola clase Java. [It is implemented using a single Java class.]
<langsyntaxhighlight Javalang="java">import java.awt.image.BufferedImage;
import java.util.Arrays;
 
Line 1,429 ⟶ 1,424:
}
}</langsyntaxhighlight>
 
 
=={{header|Julia}}==
{{works with|Julia|0.6}}
<langsyntaxhighlight lang="julia">using Images
 
canny_edges = canny(img, sigma = 1.4, upperThreshold = 0.80, lowerThreshold = 0.20)</lang>
 
canny_edges = canny(img, sigma = 1.4, upperThreshold = 0.80, lowerThreshold = 0.20)</syntaxhighlight>
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">Export["out.bmp", EdgeDetect[Import[InputString[]]]];</langsyntaxhighlight>
Mathematica uses canny edge detection by default. This seems so cheaty next to all of these giant answers...
 
=={{header|MATLAB}} / {{header|Octave}}==
There is a function in the image processing toolbox [http://www.mathworks.com/help/images/ref/edge.html edge], that has Canny Edge Detection as one of its options.
<langsyntaxhighlight MATLABlang="matlab">BWImage = edge(GrayscaleImage,'canny');</langsyntaxhighlight>
 
=={{header|Nim}}==
{{trans|D}}
Line 1,451 ⟶ 1,441:
We use the PNG image present on Wikipedia article as input and produce a PNG grayscale image as result.
 
<langsyntaxhighlight Nimlang="nim">import lenientops
import math
import nimPNG
Line 1,641 ⟶ 1,631:
echo "File ", Input, " processed. Result is available in file ", Output
else:
echo "Error: ", status.error</langsyntaxhighlight>
=={{header|Perl}}==
Used a [https://raw.githubusercontent.com/abend/Image-EdgeDetect/master/lib/Image/EdgeDetect.pm non-CPAN module] by [https://github.com/abend Sasha Kovar]
<syntaxhighlight lang="perl"># 20220120 Perl programming solution
 
use strict;
use warnings;
 
use lib '/home/hkdtam/lib';
use Image::EdgeDetect;
 
my $detector = Image::EdgeDetect->new();
$detector->process('./input.jpg', './output.jpg') or die; # na.cx/i/pHYdUrV.jpg</syntaxhighlight>
Output: [https://drive.google.com/file/d/1ww21DHz-IQTaFKNLC2I2No_fHUehYooG/view (Offsite image file) ]
=={{header|Phix}}==
{{libheader|Phix/pGUI}}
Ported from demo\Arwen32dibdemo\manip.exw (menu entry Manipulate/Filter/Detect Edges, windows-32-bit only) to pGUI.
<!--<syntaxhighlight lang="phix">(notonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Canny_Edge_Detection.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,
-- imFileImageLoadBitmap, and 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;">TITLE</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Canny Edge Detection"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">IMGFILE</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"Valve.png"</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">C_E_D</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: #0000FF;">-</span><span style="color: #000000;">1</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: #0000FF;">{-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8</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: #0000FF;">{-</span><span style="color: #000000;">1</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: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">}}</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">detect_edges</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;">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: #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;">C_E_D</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;">C_E_D</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;">C_E_D</span><span style="color: #0000FF;">),</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- read original pixels and make them grey,</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: #004080;">integer</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">c1</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c2</span><span style="color: #0000FF;">,</span><span style="color: #000000;">c3</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: #000000;">grey</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">((</span><span style="color: #000000;">c1</span><span style="color: #0000FF;">*</span><span style="color: #000000;">114</span><span style="color: #0000FF;">+</span><span style="color: #000000;">c2</span><span style="color: #0000FF;">*</span><span style="color: #000000;">587</span><span style="color: #0000FF;">+</span><span style="color: #000000;">c3</span><span style="color: #0000FF;">*</span><span style="color: #000000;">299</span><span style="color: #0000FF;">)/</span><span style="color: #000000;">1000</span><span style="color: #0000FF;">)</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: #0000FF;">{</span><span style="color: #000000;">grey</span><span style="color: #0000FF;">,</span><span style="color: #000000;">grey</span><span style="color: #0000FF;">,</span><span style="color: #000000;">grey</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: #000080;font-style:italic;">-- then apply an edge detection filter</span>
<span style="color: #004080;">sequence</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;">C_E_D</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: #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: #000000;">IMGFILE</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">assert</span><span style="color: #0000FF;">(</span><span style="color: #000000;">im1</span><span style="color: #0000FF;">!=</span><span style="color: #004600;">NULL</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"error opening "</span><span style="color: #0000FF;">&</span><span style="color: #000000;">IMGFILE</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">Ihandle</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;">IupImageFromImImage</span><span style="color: #0000FF;">(</span><span style="color: #000000;">im1</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;">detect_edges</span><span style="color: #0000FF;">(</span><span style="color: #000000;">im1</span><span style="color: #0000FF;">))</span>
<span style="color: #004080;">Ihandle</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;">IupHbox</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: #008000;">`TITLE="%s"`</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: #7060A8;">IupMainLoop</span><span style="color: #0000FF;">()</span>
<span style="color: #7060A8;">IupClose</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
=={{header|PHP}}==
PHP implementation
<syntaxhighlight lang="php">
<lang PHP>
// input: r,g,b in range 0..255
function RGBtoHSV($r, $g, $b) {
Line 1,727 ⟶ 1,796:
imagedestroy($im);
 
</syntaxhighlight>
</lang>
 
=={{header|Phix}}==
{{improve|Phix|Port to pGUI for linux and 64 bit compatibility.}}
The file demo\Arwen32dibdemo\manip.exw in the standard distribution contains a menu entry for this, Manipulate/Filter/Detect Edges, along with 15 or so other effects. It is however windows-32-bit only, and could do with being ported to pGUI.
 
=={{header|Python}}==
 
In Python, Canny edge detection would normally be done using [http://scikit-image.org/docs/dev/auto_examples/plot_canny.html scikit-image] or OpenCV-Python. Here is an approach using numpy/scipy:
 
<langsyntaxhighlight lang="python">#!/bin/python
import numpy as np
from scipy.ndimage.filters import convolve, gaussian_filter
Line 1,822 ⟶ 1,886:
im = imread("test.jpg", mode="L") #Open image, convert to greyscale
finalEdges = CannyEdgeDetector(im)
imshow(finalEdges)</langsyntaxhighlight>
=={{header|Raku}}==
Admittedly laziness always prevails so an off-the-shelf function from ImageMagick is used instead.
 
cannyedge.c
<syntaxhighlight lang="c">#include <stdio.h>
#include <string.h>
#include <magick/MagickCore.h>
 
int CannyEdgeDetector(
const char *infile, const char *outfile,
double radius, double sigma, double lower, double upper ) {
 
ExceptionInfo *exception;
Image *image, *processed_image, *output;
ImageInfo *input_info;
 
exception = AcquireExceptionInfo();
input_info = CloneImageInfo((ImageInfo *) NULL);
(void) strcpy(input_info->filename, infile);
image = ReadImage(input_info, exception);
output = NewImageList();
processed_image = CannyEdgeImage(image,radius,sigma,lower,upper,exception);
(void) AppendImageToList(&output, processed_image);
(void) strcpy(output->filename, outfile);
WriteImage(input_info, output);
// after-party clean up
DestroyImage(image);
output=DestroyImageList(output);
input_info=DestroyImageInfo(input_info);
exception=DestroyExceptionInfo(exception);
MagickCoreTerminus();
 
return 0;
}</syntaxhighlight>
cannyedge.raku
<syntaxhighlight lang="raku" line># 20220103 Raku programming solution
use NativeCall;
sub CannyEdgeDetector(CArray[uint8], CArray[uint8], num64, num64, num64, num64
) returns int32 is native( '/home/hkdtam/LibCannyEdgeDetector.so' ) {*};
 
CannyEdgeDetector( # imagemagick.org/script/command-line-options.php#canny
CArray[uint8].new( 'input.jpg'.encode.list, 0), # pbs.org/wgbh/nova/next/wp-content/uploads/2013/09/fingerprint-1024x575.jpg
CArray[uint8].new( 'output.jpg'.encode.list, 0),
0e0, 2e0, 0.05e0, 0.05e0
)</syntaxhighlight>
{{out}}
<pre>export PKG_CONFIG_PATH=/usr/lib/pkgconfig
gcc -Wall -fPIC -shared -o LibCannyEdgeDetector.so cannyedge.c `pkg-config --cflags --libs MagickCore`
raku -c cannyedge.raku && ./cannyedge.raku</pre>
Output: [https://drive.google.com/file/d/1k9F53egoFP0Sl4uBR85nai8IwC43BkYZ/view (Offsite image file) ]
=={{header|Tcl}}==
{{libheader|crimp}}
<langsyntaxhighlight lang="tcl">package require crimp
package require crimp::pgm
 
Line 1,842 ⟶ 1,957:
writePGM $outputFile [crimp filter canny sobel [readPGM $inputFile]]
}
cannyFilterFile {*}$argv</langsyntaxhighlight>
=={{header|Wren}}==
{{trans|C}}
{{libheader|DOME}}
{{libheader|Wren-check}}
<syntaxhighlight lang="wren">import "dome" for Window
import "graphics" for Canvas, Color, ImageData
import "math" for Math
import "./check" for Check
 
var MaxBrightness = 255
 
class Canny {
construct new(inFile, outFile) {
Window.title = "Canny edge detection"
var image1 = ImageData.load(inFile)
var w = image1.width
var h = image1.height
Window.resize(w * 2 + 20, h)
Canvas.resize(w * 2 + 20, h)
var image2 = ImageData.create(outFile, w, h)
var pixels = List.filled(w * h, 0)
var ix = 0
// convert image1 to gray scale as a list of pixels
for (y in 0...h) {
for (x in 0...w) {
var c1 = image1.pget(x, y)
var lumin = (0.2126 * c1.r + 0.7152 * c1.g + 0.0722 * c1.b).floor
pixels[ix] = lumin
ix = ix + 1
}
}
 
// find edges
var data = cannyEdgeDetection(pixels, w, h, 45, 50, 1)
 
// write to image2
ix = 0
for (y in 0...h) {
for (x in 0...w) {
var d = data[ix]
var c = Color.rgb(d, d, d)
image2.pset(x, y, c)
ix = ix + 1
}
}
 
// display the two images side by side
image1.draw(0, 0)
image2.draw(w + 20, 0)
 
// save image2 to outFile
image2.saveToFile(outFile)
}
 
init() {}
 
// If normalize is true, map pixels to range 0..MaxBrightness
convolution(input, output, kernel, nx, ny, kn, normalize) {
Check.ok((kn % 2) == 1)
Check.ok(nx > kn && ny > kn)
var khalf = (kn / 2).floor
var min = Num.largest
var max = -min
if (normalize) {
for (m in khalf...nx-khalf) {
for (n in khalf...ny-khalf) {
var pixel = 0
var c = 0
for (j in -khalf..khalf) {
for (i in -khalf..khalf) {
pixel = pixel + input[(n-j)*nx + m - i] * kernel[c]
c = c + 1
}
}
if (pixel < min) min = pixel
if (pixel > max) max = pixel
}
}
}
 
for (m in khalf...nx-khalf) {
for (n in khalf...ny-khalf) {
var pixel = 0
var c = 0
for (j in -khalf..khalf) {
for (i in -khalf..khalf) {
pixel = pixel + input[(n-j)*nx + m - i] * kernel[c]
c = c + 1
}
}
if (normalize) pixel = MaxBrightness * (pixel - min) / (max - min)
output[n * nx + m] = pixel.truncate
}
}
}
 
gaussianFilter(input, output, nx, ny, sigma) {
var n = 2 * (2 * sigma).truncate + 3
var mean = (n / 2).floor
var kernel = List.filled(n * n, 0)
System.print("Gaussian filter: kernel size = %(n), sigma = %(sigma)")
var c = 0
for (i in 0...n) {
for (j in 0...n) {
var t = (-0.5 * (((i - mean) / sigma).pow(2) + ((j - mean) / sigma).pow(2))).exp
kernel[c] = t / (2 * Num.pi * sigma * sigma)
c = c + 1
}
}
convolution(input, output, kernel, nx, ny, n, true)
}
 
// Returns the square root of 'x' squared + 'y' squared.
hypot(x, y) { (x*x + y*y).sqrt }
 
cannyEdgeDetection(input, nx, ny, tmin, tmax, sigma) {
var output = List.filled(input.count, 0)
gaussianFilter(input, output, nx, ny, sigma)
var Gx = [-1, 0, 1, -2, 0, 2, -1, 0, 1]
var afterGx = List.filled(input.count, 0)
convolution(output, afterGx, Gx, nx, ny, 3, false)
var Gy = [1, 2, 1, 0, 0, 0, -1, -2, -1]
var afterGy = List.filled(input.count, 0)
convolution(output, afterGy, Gy, nx, ny, 3, false)
var G = List.filled(input.count, 0)
for (i in 1..nx-2) {
for (j in 1..ny-2) {
var c = i + nx * j
G[c] = hypot(afterGx[c], afterGy[c]).floor
}
}
 
// non-maximum suppression: straightforward implementation
var nms = List.filled(input.count, 0)
for (i in 1..nx-2) {
for (j in 1..ny-2) {
var c = i + nx * j
var nn = c - nx
var ss = c + nx
var ww = c + 1
var ee = c - 1
var nw = nn + 1
var ne = nn - 1
var sw = ss + 1
var se = ss - 1
var temp = Math.atan(afterGy[c], afterGx[c]) + Num.pi
var dir = (temp % Num.pi) / Num.pi * 8
if (((dir <= 1 || dir > 7) && G[c] > G[ee] && G[c] > G[ww]) || // O°
((dir > 1 && dir <= 3) && G[c] > G[nw] && G[c] > G[se]) || // 45°
((dir > 3 && dir <= 5) && G[c] > G[nn] && G[c] > G[ss]) || // 90°
((dir > 5 && dir <= 7) && G[c] > G[ne] && G[c] > G[sw])) { // 135°
nms[c] = G[c]
} else {
nms[c] = 0
}
}
}
 
// tracing edges with hysteresis: non-recursive implementation
var edges = List.filled((input.count/2).floor, 0)
for (i in 0...output.count) output[i] = 0
var c = 1
for (j in 1..ny-2) {
for (i in 1..nx-2) {
if (nms[c] >= tmax && output[c] == 0) {
// trace edges
output[c] = MaxBrightness
var nedges = 1
edges[0] = c
while (true) {
nedges = nedges - 1
var t = edges[nedges]
var nbs = [ // neighbors
t - nx, // nn
t + nx, // ss
t + 1, // ww
t - 1, // ee
t - nx + 1, // nw
t - nx - 1, // ne
t + nx + 1, // sw
t + nx - 1 // se
]
for (n in nbs) {
if (nms[n] >= tmin && output[n] == 0) {
output[n] = MaxBrightness
edges[nedges] = n
nedges = nedges + 1
}
}
if (nedges == 0) break
}
}
c = c + 1
}
}
return output
}
 
update() {}
 
draw(alpha) {}
}
var Game = Canny.new("Valve_original.png", "Valve_monchrome_canny.png")</syntaxhighlight>
 
=={{header|Yabasic}}==
{{trans|Phix}}
<syntaxhighlight lang="yabasic">// Rosetta Code problem: http://rosettacode.org/wiki/Canny_edge_detector
// Adapted from Phix to Yabasic by Galileo, 01/2022
 
import ReadFromPPM2
 
MaxBrightness = 255
 
readPPM("Valve.ppm")
print "Be patient, please ..."
 
width = peek("winwidth")
height = peek("winheight")
dim pixels(width, height), C_E_D(3, 3)
 
data -1, -1, -1, -1, 8, -1, -1, -1, -1
for i = 0 to 2
for j = 0 to 2
read C_E_D(i, j)
next
next
 
// convert image to gray scale
for y = 1 to height
for x = 1 to width
c$ = right$(getbit$(x, y, x, y), 6)
r = dec(left$(c$, 2))
g = dec(mid$(c$, 3, 2))
b = dec(right$(c$, 2))
lumin = floor(0.2126 * r + 0.7152 * g + 0.0722 * b)
pixels(x, y) = lumin
next
next
 
dim new_image(width, height)
 
divisor = 1
 
// apply an edge detection filter
for y = 2 to height-2
for x = 2 to width-2
newrgb = 0
for i = -1 to 1
for j = -1 to 1
newrgb = newrgb + C_E_D(i+1, j+1) * pixels(x+i, y+j)
next
new_image(x, y) = max(min(newrgb / divisor,255),0)
next
next
next
 
// show result
 
for x = 1 to width
for y = 1 to height
c = new_image(x, y)
color c, c, c
dot x, y
next
next</syntaxhighlight>
9,482

edits