我想在Python中使用edge()
Matlab函数:
mask = double(edge(mask,'canny',threshold));
我试图找到一个函数,它相当于Python中的edge()
Matlab函数。我尝试过Python中的cv2.Canny()
函数,但是它与Matlab函数不同(您可以在这里阅读关于差异的解释:https://dsp.stackexchange.com/questions/4716/differences-between-opencv-canny-and-matlab-canny)。我试过在那个论坛上建议先用高斯模糊对图像进行模糊处理,但结果还是和matlab的不一样。在
所以,我找到了一些Matlab canny边缘检测器代码,我正试图将这些代码转换成内置的edge()
函数,就像Matlab一样。我发现的密码是:
第一个代码:
^{pr2}$第二个代码:
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);
发件人: https://www.mathworks.com/matlabcentral/fileexchange/46859-canny-edge-detection
我试图将其转换为内置的edge()
matlab函数:
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
(您可以通过在matlab中键入“edit edge”而不加引号来查看代码)
有没有人有什么建议,或者有与matlab edge()
函数相同的canny边缘检测器Python代码?任何建议或答案都会很有帮助。谢谢您。在
请澄清您的意图:
您想用python编写一个与MATLABs edge()函数等价的函数,并实现Canny? (如果是的话,你为什么把所有的选项都放在最后的代码引用中?您只需要strcmp(method,'canny')节)
如果你已经有了这么好的MATLAB代码,它揭示了canny impl。你为什么不逐行翻译呢?
总的来说,解决方法是:
最后注意:如果你看到使用OpenCV等效函数对你不起作用,你必须在C++中编写OpenCV代码,因为只有这样你才能进入调试器的OpenCV实现,并找出它与Matlab实现的区别。在编写您自己的自定义MATLAB函数,它只执行您需要的功能,没有其他功能。如果你想要canny,编写你自己的MATLAB函数来完成这个任务。
在有了最少的可工作的MATLAB代码之后,逐行将其翻译成python,同时在每个步骤之后输出MATLAB代码和python代码的调试图像,以验证您是否正确。
相关问题 更多 >
编程相关推荐