Reputation: 11
I want to use the edge()
Matlab function inside Python:
mask = double(edge(mask,'canny',threshold));
I am trying to find a function that equivalent to the edge()
Matlab function in Python. I tried the cv2.Canny()
function in Python but, it's different from the Matlab one (you can read the explanation on the differences here: https://dsp.stackexchange.com/questions/4716/differences-between-opencv-canny-and-matlab-canny ). I have tried the suggestion in that forum to blur the image first with gaussian blur, but the result still different from the matlab one.
So, I found some Matlab canny edge detector code, and I am trying to turn this code into the built-in edge()
function like the Matlab one. The codes that I found are:
First code:
clear all;
clc;
%Input image
img = imread ('gambar.jpg');
%Show input image
figure, imshow(img);
img = rgb2gray(img);
img = double (img);
%Value for Thresholding
T_Low = 0.2;
T_High = 0.5;
%Gaussian Filter Coefficient
B = [2, 4, 5, 4, 2; 4, 9, 12, 9, 4;5, 12, 15, 12, 5;4, 9, 12, 9, 4;2, 4, 5, 4, 2 ];
B = 1/159.* B;
%Convolution of image by Gaussian Coefficient
A=conv2(img, B, 'same');
%Filter for horizontal and vertical direction
KGx = [-1, 0, 1; -2, 0, 2; -1, 0, 1];
KGy = [1, 2, 1; 0, 0, 0; -1, -2, -1];
%Convolution by image by horizontal and vertical filter
Filtered_X = conv2(A, KGx, 'same');
Filtered_Y = conv2(A, KGy, 'same');
%Calculate directions/orientations
arah = atan2 (Filtered_Y, Filtered_X);
arah = arah*180/pi;
pan=size(A,1);
leb=size(A,2);
%Adjustment for negative directions, making all directions positive
for i=1:pan
for j=1:leb
if (arah(i,j)<0)
arah(i,j)=360+arah(i,j);
end;
end;
end;
arah2=zeros(pan, leb);
%Adjusting directions to nearest 0, 45, 90, or 135 degree
for i = 1 : pan
for j = 1 : leb
if ((arah(i, j) >= 0 ) && (arah(i, j) < 22.5) || (arah(i, j) >= 157.5) && (arah(i, j) < 202.5) || (arah(i, j) >= 337.5) && (arah(i, j) <= 360))
arah2(i, j) = 0;
elseif ((arah(i, j) >= 22.5) && (arah(i, j) < 67.5) || (arah(i, j) >= 202.5) && (arah(i, j) < 247.5))
arah2(i, j) = 45;
elseif ((arah(i, j) >= 67.5 && arah(i, j) < 112.5) || (arah(i, j) >= 247.5 && arah(i, j) < 292.5))
arah2(i, j) = 90;
elseif ((arah(i, j) >= 112.5 && arah(i, j) < 157.5) || (arah(i, j) >= 292.5 && arah(i, j) < 337.5))
arah2(i, j) = 135;
end;
end;
end;
figure, imagesc(arah2); colorbar;
%Calculate magnitude
magnitude = (Filtered_X.^2) + (Filtered_Y.^2);
magnitude2 = sqrt(magnitude);
BW = zeros (pan, leb);
%Non-Maximum Supression
for i=2:pan-1
for j=2:leb-1
if (arah2(i,j)==0)
BW(i,j) = (magnitude2(i,j) == max([magnitude2(i,j), magnitude2(i,j+1), magnitude2(i,j-1)]));
elseif (arah2(i,j)==45)
BW(i,j) = (magnitude2(i,j) == max([magnitude2(i,j), magnitude2(i+1,j-1), magnitude2(i-1,j+1)]));
elseif (arah2(i,j)==90)
BW(i,j) = (magnitude2(i,j) == max([magnitude2(i,j), magnitude2(i+1,j), magnitude2(i-1,j)]));
elseif (arah2(i,j)==135)
BW(i,j) = (magnitude2(i,j) == max([magnitude2(i,j), magnitude2(i+1,j+1), magnitude2(i-1,j-1)]));
end;
end;
end;
BW = BW.*magnitude2;
figure, imshow(BW);
%Hysteresis Thresholding
T_Low = T_Low * max(max(BW));
T_High = T_High * max(max(BW));
T_res = zeros (pan, leb);
for i = 1 : pan
for j = 1 : leb
if (BW(i, j) < T_Low)
T_res(i, j) = 0;
elseif (BW(i, j) > T_High)
T_res(i, j) = 1;
%Using 8-connected components
elseif ( BW(i+1,j)>T_High || BW(i-1,j)>T_High || BW(i,j+1)>T_High || BW(i,j-1)>T_High || BW(i-1, j-1)>T_High || BW(i-1, j+1)>T_High || BW(i+1, j+1)>T_High || BW(i+1, j-1)>T_High)
T_res(i,j) = 1;
end;
end;
end;
edge_final = uint8(T_res.*255);
%Show final edge detection result
figure, imshow(edge_final);
Second code:
function [eout, dx, dy] = canny_edge(image_scan, smoothing_kernel, derivative_kernel)
thresh = [0.2 0.5];
sigma = sqrt(2);
thinning = true;
H = [];
kx = 1;
ky = 1;
[m,n] = size(image_scan);
e = false(m,n);
% Magic numbers
PercentOfPixelsNotEdges = .7; % Used for selecting thresholds
ThresholdRatio = .4; % Low thresh is this fraction of the high.
dx = imfilter(image_scan, smoothing_kernel', 'conv', 'replicate');
dx = imfilter(dx, derivative_kernel, 'conv', 'replicate');
% Compute smoothed numerical gradient of image I along y (vertical)
% direction. GY corresponds to dG/dy, where G is the Gaussian Smoothed
% version of image I.
dy = imfilter(image_scan, smoothing_kernel, 'conv', 'replicate');
dy = imfilter(dy, derivative_kernel', 'conv', 'replicate');
% Calculate Magnitude of Gradient
magGrad = hypot(dx, dy);
% Normalize for threshold selection
magmax = max(magGrad(:));
if magmax > 0
magGrad = magGrad / magmax;
end
% Determine Hysteresis Thresholds
[lowThresh, highThresh] = selectThresholds(thresh, magGrad, PercentOfPixelsNotEdges, ThresholdRatio, mfilename);
% Perform Non-Maximum Suppression Thining and Hysteresis Thresholding of Edge
% Strength
eout = thinAndThreshold(e, dx, dy, magGrad, lowThresh, highThresh);
thresh = [lowThresh highThresh];
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Local Function : selectThresholds
%
function [lowThresh, highThresh] = selectThresholds(thresh, magGrad, PercentOfPixelsNotEdges, ThresholdRatio, ~)
[m,n] = size(magGrad);
% Select the thresholds
if isempty(thresh)
counts=imhist(magGrad, 64);
highThresh = find(cumsum(counts) > PercentOfPixelsNotEdges*m*n,...
1,'first') / 64;
lowThresh = ThresholdRatio*highThresh;
elseif length(thresh)==1
highThresh = thresh;
if thresh>=1
error(message('images:edge:thresholdMustBeLessThanOne'))
end
lowThresh = ThresholdRatio*thresh;
elseif length(thresh)==2
lowThresh = thresh(1);
highThresh = thresh(2);
if (lowThresh >= highThresh) || (highThresh >= 1)
error(message('images:edge:thresholdOutOfRange'))
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Local Function : thinAndThreshold
%
function H = thinAndThreshold(E, dx, dy, magGrad, lowThresh, highThresh)
% Perform Non-Maximum Suppression Thining and Hysteresis Thresholding of Edge
% Strength
% We will accrue indices which specify ON pixels in strong edgemap
% The array e will become the weak edge map.
idxStrong = [];
for dir = 1:4
idxLocalMax = cannyFindLocalMaxima(dir,dx,dy,magGrad);
idxWeak = idxLocalMax(magGrad(idxLocalMax) > lowThresh);
E(idxWeak)=1;
idxStrong = [idxStrong; idxWeak(magGrad(idxWeak) > highThresh)]; %#ok<AGROW>
end
[m,n] = size(E);
if ~isempty(idxStrong) % result is all zeros if idxStrong is empty
rstrong = rem(idxStrong-1, m)+1;
cstrong = floor((idxStrong-1)/m)+1;
H = bwselect(E, cstrong, rstrong, 8);
else
H = zeros(m, n);
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Local Function : cannyFindLocalMaxima
%
function idxLocalMax = cannyFindLocalMaxima(direction,ix,iy,mag)
%
% This sub-function helps with the non-maximum suppression in the Canny
% edge detector. The input parameters are:
%
% direction - the index of which direction the gradient is pointing,
% read from the diagram below. direction is 1, 2, 3, or 4.
% ix - input image filtered by derivative of gaussian along x
% iy - input image filtered by derivative of gaussian along y
% mag - the gradient magnitude image
%
% there are 4 cases:
%
% The X marks the pixel in question, and each
% 3 2 of the quadrants for the gradient vector
% O----0----0 fall into two cases, divided by the 45
% 4 | | 1 degree line. In one case the gradient
% | | vector is more horizontal, and in the other
% O X O it is more vertical. There are eight
% | | divisions, but for the non-maximum suppression
% (1)| |(4) we are only worried about 4 of them since we
% O----O----O use symmetric points about the center pixel.
% (2) (3)
[m,n] = size(mag);
% Find the indices of all points whose gradient (specified by the
% vector (ix,iy)) is going in the direction we're looking at.
switch direction
case 1
idx = find((iy<=0 & ix>-iy) | (iy>=0 & ix<-iy));
case 2
idx = find((ix>0 & -iy>=ix) | (ix<0 & -iy<=ix));
case 3
idx = find((ix<=0 & ix>iy) | (ix>=0 & ix<iy));
case 4
idx = find((iy<0 & ix<=iy) | (iy>0 & ix>=iy));
end
% Exclude the exterior pixels
if ~isempty(idx)
v = mod(idx,m);
extIdx = (v==1 | v==0 | idx<=m | (idx>(n-1)*m));
idx(extIdx) = [];
end
ixv = ix(idx);
iyv = iy(idx);
gradmag = mag(idx);
% Do the linear interpolations for the interior pixels
switch direction
case 1
d = abs(iyv./ixv);
gradmag1 = mag(idx+m).*(1-d) + mag(idx+m-1).*d;
gradmag2 = mag(idx-m).*(1-d) + mag(idx-m+1).*d;
case 2
d = abs(ixv./iyv);
gradmag1 = mag(idx-1).*(1-d) + mag(idx+m-1).*d;
gradmag2 = mag(idx+1).*(1-d) + mag(idx-m+1).*d;
case 3
d = abs(ixv./iyv);
gradmag1 = mag(idx-1).*(1-d) + mag(idx-m-1).*d;
gradmag2 = mag(idx+1).*(1-d) + mag(idx+m+1).*d;
case 4
d = abs(iyv./ixv);
gradmag1 = mag(idx-m).*(1-d) + mag(idx-m-1).*d;
gradmag2 = mag(idx+m).*(1-d) + mag(idx+m+1).*d;
end
idxLocalMax = idx(gradmag>=gradmag1 & gradmag>=gradmag2);
From: https://www.mathworks.com/matlabcentral/fileexchange/46859-canny-edge-detection
Which I am trying to convert into this built-in edge()
matlab function:
function [eout,thresh,gv_45,gh_135] = edge(varargin)
args = matlab.images.internal.stringToChar(varargin);
[a,method,thresh,sigma,thinning,H,kx,ky] = parse_inputs(args{:});
% Check that the user specified a valid number of output arguments
if ~any(strcmp(method,{'sobel','roberts','prewitt'})) && (nargout>2)
error(message('images:edge:tooManyOutputs'))
end
% Transform to a double precision intensity image if necessary
isPrewittOrSobel = strcmp(method,'sobel') || strcmp(method,'prewitt');
if ~isPrewittOrSobel && ~isfloat(a) && ~strcmp(method,'approxcanny')
a = im2single(a);
end
[m,n] = size(a);
if strcmp(method,'canny')
% Magic numbers
PercentOfPixelsNotEdges = .7; % Used for selecting thresholds
ThresholdRatio = .4; % Low thresh is this fraction of the high.
% Calculate gradients using a derivative of Gaussian filter
[dx, dy] = smoothGradient(a, sigma);
% Calculate Magnitude of Gradient
magGrad = hypot(dx, dy);
% Normalize for threshold selection
magmax = max(magGrad(:));
if magmax > 0
magGrad = magGrad / magmax;
end
% Determine Hysteresis Thresholds
[lowThresh, highThresh] = selectThresholds(thresh, magGrad, PercentOfPixelsNotEdges, ThresholdRatio, mfilename);
% Perform Non-Maximum Suppression Thining and Hysteresis Thresholding of Edge
% Strength
e = thinAndThreshold(dx, dy, magGrad, lowThresh, highThresh);
thresh = [lowThresh highThresh];
elseif strcmp(method,'approxcanny')
e = computeapproxcanny(a, thresh);
elseif strcmp(method,'canny_old')
% Magic numbers
GaussianDieOff = .0001;
PercentOfPixelsNotEdges = .7; % Used for selecting thresholds
ThresholdRatio = .4; % Low thresh is this fraction of the high.
% Design the filters - a gaussian and its derivative
pw = 1:30; % possible widths
ssq = sigma^2;
width = find(exp(-(pw.*pw)/(2*ssq))>GaussianDieOff,1,'last');
if isempty(width)
width = 1; % the user entered a really small sigma
end
t = (-width:width);
gau = exp(-(t.*t)/(2*ssq))/(2*pi*ssq); % the gaussian 1D filter
% Find the directional derivative of 2D Gaussian (along X-axis)
% Since the result is symmetric along X, we can get the derivative along
% Y-axis simply by transposing the result for X direction.
[x,y]=meshgrid(-width:width,-width:width);
dgau2D=-x.*exp(-(x.*x+y.*y)/(2*ssq))/(pi*ssq);
% Convolve the filters with the image in each direction
% The canny edge detector first requires convolution with
% 2D Gaussian, and then with the derivative of a Gaussian.
% Since Gaussian filter is separable, for smoothing, we can use
% two 1D convolutions in order to achieve the effect of convolving
% with 2D Gaussian. We convolve along rows and then columns.
%smooth the image out
aSmooth=imfilter(a,gau,'conv','replicate'); % run the filter across rows
aSmooth=imfilter(aSmooth,gau','conv','replicate'); % and then across columns
%apply directional derivatives
ax = imfilter(aSmooth, dgau2D, 'conv','replicate');
ay = imfilter(aSmooth, dgau2D', 'conv','replicate');
mag = sqrt((ax.*ax) + (ay.*ay));
magmax = max(mag(:));
if magmax>0
mag = mag / magmax; % normalize
end
% Select the thresholds
if isempty(thresh)
counts=imhist(mag, 64);
highThresh = find(cumsum(counts) > PercentOfPixelsNotEdges*m*n,...
1,'first') / 64;
lowThresh = ThresholdRatio*highThresh;
thresh = [lowThresh highThresh];
elseif length(thresh)==1
highThresh = thresh;
if thresh>=1
error(message('images:edge:singleThresholdOutOfRange'))
end
lowThresh = ThresholdRatio*thresh;
thresh = [lowThresh highThresh];
elseif length(thresh)==2
lowThresh = thresh(1);
highThresh = thresh(2);
if (lowThresh >= highThresh) || (highThresh >= 1)
error(message('images:edge:thresholdOutOfRange'))
end
end
% The next step is to do the non-maximum suppression. We will accrue
% indices which specify ON pixels in strong edgemap The array e will become
% the weak edge map.
e = cannyFindLocalMaxima(ax,ay,mag,lowThresh);
if ~isempty(e)
[rstrong,cstrong] = find(mag>highThresh & e);
if ~isempty(rstrong) % result is all zeros if idxStrong is empty
e = bwselect(e, cstrong, rstrong, 8);
e = bwmorph(e, 'thin', 1); % Thin double (or triple) pixel wide contours
end
end
elseif any(strcmp(method, {'log','zerocross'}))
% The output edge map:
e = false(m,n);
rr = 2:m-1; cc=2:n-1;
% We don't use image blocks here
if isempty(H)
fsize = ceil(sigma*3) * 2 + 1; % choose an odd fsize > 6*sigma;
op = fspecial('log',fsize,sigma);
else
op = H;
end
op = op - sum(op(:))/numel(op); % make the op to sum to zero
b = imfilter(a,op,'replicate');
if isempty(thresh)
thresh = 0.75 * sum(abs(b(:)),'double') / numel(b);
end
% Look for the zero crossings: +-, -+ and their transposes
% We arbitrarily choose the edge to be the negative point
[rx,cx] = find( b(rr,cc) < 0 & b(rr,cc+1) > 0 ...
& abs( b(rr,cc)-b(rr,cc+1) ) > thresh ); % [- +]
e((rx+1) + cx*m) = 1;
[rx,cx] = find( b(rr,cc-1) > 0 & b(rr,cc) < 0 ...
& abs( b(rr,cc-1)-b(rr,cc) ) > thresh ); % [+ -]
e((rx+1) + cx*m) = 1;
[rx,cx] = find( b(rr,cc) < 0 & b(rr+1,cc) > 0 ...
& abs( b(rr,cc)-b(rr+1,cc) ) > thresh); % [- +]'
e((rx+1) + cx*m) = 1;
[rx,cx] = find( b(rr-1,cc) > 0 & b(rr,cc) < 0 ...
& abs( b(rr-1,cc)-b(rr,cc) ) > thresh); % [+ -]'
e((rx+1) + cx*m) = 1;
% Most likely this covers all of the cases. Just check to see if there
% are any points where the LoG was precisely zero:
[rz,cz] = find( b(rr,cc)==0 );
if ~isempty(rz)
% Look for the zero crossings: +0-, -0+ and their transposes
% The edge lies on the Zero point
zero = (rz+1) + cz*m; % Linear index for zero points
zz = (b(zero-1) < 0 & b(zero+1) > 0 ...
& abs( b(zero-1)-b(zero+1) ) > 2*thresh); % [- 0 +]'
e(zero(zz)) = 1;
zz = (b(zero-1) > 0 & b(zero+1) < 0 ...
& abs( b(zero-1)-b(zero+1) ) > 2*thresh); % [+ 0 -]'
e(zero(zz)) = 1;
zz = (b(zero-m) < 0 & b(zero+m) > 0 ...
& abs( b(zero-m)-b(zero+m) ) > 2*thresh); % [- 0 +]
e(zero(zz)) = 1;
zz = (b(zero-m) > 0 & b(zero+m) < 0 ...
& abs( b(zero-m)-b(zero+m) ) > 2*thresh); % [+ 0 -]
e(zero(zz)) = 1;
end
else % one of the easy methods (roberts,sobel,prewitt)
if isPrewittOrSobel
isSobel = strcmp(method, 'sobel');
scale = 4; % for calculating the automatic threshold
offset = [0 0 0 0]; % offsets used in the computation of the threshold
[bx, by, b] = edgesobelprewittmex(a, isSobel, kx, ky);
elseif strcmp(method, 'roberts')
x_mask = [1 0; 0 -1]/2; % Roberts approximation to diagonal derivative
y_mask = [0 1;-1 0]/2;
scale = 6;
offset = [-1 1 1 -1];
% compute the gradient in x and y direction
bx = imfilter(a,x_mask,'replicate');
by = imfilter(a,y_mask,'replicate');
% compute the magnitude
b = kx*bx.*bx + ky*by.*by;
else
error(message('images:edge:invalidEdgeDetectionMethod', method))
end
if (nargout > 2) % if gradients are requested
gv_45 = bx;
gh_135 = by;
end
% Determine the threshold; see page 514 of
% "Digital Imaging Processing" by William K. Pratt
if isempty(thresh) % Determine cutoff based on RMS estimate of noise
% Mean of the magnitude squared image is a
% value that's roughly proportional to SNR
cutoff = scale * sum(b(:),'double') / numel(b);
thresh = sqrt(cutoff);
else
% Use relative tolerance specified by the user
cutoff = (thresh).^2;
end
if thinning
e = computeedge(b,bx,by,kx,ky,int8(offset),100*eps,cutoff);
else
e = b > cutoff;
end
end
if nargout==0
imshow(e);
else
eout = e;
end
if isempty(a)
if nargout==2
if nargin == 2
if strcmp(method,'canny')
thresh = nan(1,2);
else
thresh = nan(1);
end
end
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Local Function : parse_inputs
%
function [I,Method,Thresh,Sigma,Thinning,H,kx,ky] = parse_inputs(varargin)
% OUTPUTS:
% I Image Data
% Method Edge detection method
% Thresh Threshold value
% Sigma standard deviation of Gaussian
% H Filter for Zero-crossing detection
% kx,ky From Directionality vector
narginchk(1,5)
I = varargin{1};
validateattributes(I,{'numeric','logical'},{'real','nonsparse','2d'},mfilename,'I',1);
% Defaults
Method = 'sobel';
Direction = 'both';
Thinning = true;
methods = {'canny','approxcanny','canny_old','prewitt','sobel','marr-hildreth','log','roberts','zerocross'};
directions = {'both','horizontal','vertical'};
options = {'thinning','nothinning'};
% Now parse the nargin-1 remaining input arguments
% First get the strings - we do this because the interpretation of the
% rest of the arguments will depend on the method.
nonstr = []; % ordered indices of non-string arguments
for i = 2:nargin
if ischar(varargin{i})
str = lower(varargin{i});
j = find(strcmp(str,methods));
k = find(strcmp(str,directions));
l = find(strcmp(str,options));
if ~isempty(j)
Method = methods{j(1)};
if strcmp(Method,'marr-hildreth')
error(message('images:removed:syntax','EDGE(I,''marr-hildreth'',...)','EDGE(I,''log'',...)'))
end
elseif ~isempty(k)
Direction = directions{k(1)};
elseif ~isempty(l)
if strcmp(options{l(1)},'thinning')
Thinning = true;
else
Thinning = false;
end
else
error(message('images:edge:invalidInputString', varargin{ i }))
end
else
nonstr = [nonstr i]; %#ok<AGROW>
end
end
% Now get the rest of the arguments
[Thresh,Sigma,H,kx,ky] = images.internal.parseNonStringInputsEdge(varargin,Method,Direction,nonstr);
validateattributes(Thresh,{'numeric'},{'real'},mfilename,'thresh',3);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Local Function : smoothGradient
%
function [GX, GY] = smoothGradient(I, sigma)
% Create an even-length 1-D separable Derivative of Gaussian filter
% Determine filter length
filterExtent = ceil(4*sigma);
x = -filterExtent:filterExtent;
% Create 1-D Gaussian Kernel
c = 1/(sqrt(2*pi)*sigma);
gaussKernel = c * exp(-(x.^2)/(2*sigma^2));
% Normalize to ensure kernel sums to one
gaussKernel = gaussKernel/sum(gaussKernel);
% Create 1-D Derivative of Gaussian Kernel
derivGaussKernel = gradient(gaussKernel);
% Normalize to ensure kernel sums to zero
negVals = derivGaussKernel < 0;
posVals = derivGaussKernel > 0;
derivGaussKernel(posVals) = derivGaussKernel(posVals)/sum(derivGaussKernel(posVals));
derivGaussKernel(negVals) = derivGaussKernel(negVals)/abs(sum(derivGaussKernel(negVals)));
% Compute smoothed numerical gradient of image I along x (horizontal)
% direction. GX corresponds to dG/dx, where G is the Gaussian Smoothed
% version of image I.
GX = imfilter(I, gaussKernel', 'conv', 'replicate');
GX = imfilter(GX, derivGaussKernel, 'conv', 'replicate');
% Compute smoothed numerical gradient of image I along y (vertical)
% direction. GY corresponds to dG/dy, where G is the Gaussian Smoothed
% version of image I.
GY = imfilter(I, gaussKernel, 'conv', 'replicate');
GY = imfilter(GY, derivGaussKernel', 'conv', 'replicate');
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Local Function : selectThresholds
%
function [lowThresh, highThresh] = selectThresholds(thresh, magGrad, PercentOfPixelsNotEdges, ThresholdRatio, ~)
[m,n] = size(magGrad);
% Select the thresholds
if isempty(thresh)
counts=imhist(magGrad, 64);
highThresh = find(cumsum(counts) > PercentOfPixelsNotEdges*m*n,...
1,'first') / 64;
lowThresh = ThresholdRatio*highThresh;
elseif length(thresh)==1
highThresh = thresh;
if thresh>=1
error(message('images:edge:singleThresholdOutOfRange'))
end
lowThresh = ThresholdRatio*thresh;
elseif length(thresh)==2
lowThresh = thresh(1);
highThresh = thresh(2);
if (lowThresh >= highThresh) || (highThresh >= 1)
error(message('images:edge:thresholdOutOfRange'))
end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Local Function : thinAndThreshold
%
function H = thinAndThreshold(dx, dy, magGrad, lowThresh, highThresh)
% Perform Non-Maximum Suppression Thining and Hysteresis Thresholding of
% Edge Strength
% We will accrue indices which specify ON pixels in strong edgemap
% The array e will become the weak edge map.
E = cannyFindLocalMaxima(dx,dy,magGrad,lowThresh);
if ~isempty(E)
[rstrong,cstrong] = find(magGrad>highThresh & E);
if ~isempty(rstrong) % result is all zeros if idxStrong is empty
H = bwselect(E, cstrong, rstrong, 8);
else
H = false(size(E));
end
else
H = false(size(E));
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Local Function : computeapproxcanny
%
function e = computeapproxcanny(a, thresh)
a = im2uint8(a);
if isempty(a)
e = logical([]);
else
if isempty(thresh)
e = images.internal.ocvcanny(a);
else
if numel(thresh) == 1
e = images.internal.ocvcanny(a, 0.4*thresh, thresh);
else
e = images.internal.ocvcanny(a, thresh(2), thresh(1));
end
end
e = logical(e);
end
(you can see the code by typing "edit edge" without quotes inside matlab)
Does anyone have any suggestion or have canny edge detector Python code that is same as matlab edge()
function? Any suggestion or answer would be very helpful. Thank you.
Upvotes: 1
Views: 3019
Reputation: 351
Please clarify your intent:
Do you want to write a function in python which is equivalent to MATLABs edge() function, with Canny implementation? (if so, why did you put all of the options in your last code quote? you need only strcmp(method,'canny') section)
If you already have such a wonderful MATLAB code that reveals the canny impl. why wouldn't you translate it line by line?
in general, the way to go is:
Write your own custom MATLAB function that does only what you need, with no other capabilities. if you want canny, write your own MATLAB function that does only that.
After having minimal working MATLAB code, translate it line by line to python, while outputting aside debug images after each step both from the MATLAB code and the python code, for verifying you're on the right track.
Final note: If you see using OpenCV equivalent functions doesn't work for you, you will have to write your OpenCV code in C++, since only in that way you will be able to get into OpenCV's implementation with the debugger and find out how it differs from MATLABs implementation.
Upvotes: 2