I think I’m done with it.
It was not that easy, considering the various schemes gradient
implement, as well as the fact that it can be invoked without arguments.
For those interested, that’s the current source code:
#@cli gradient : { x | y | z | c }...{ x | y | z | c },_scheme,_boundary_conditions : (no arg)
#@cli : Compute the gradient components (first derivatives) of selected images, along specified axes.
#@cli : (eq. to 'g').\n
#@cli : 'scheme' can be { -1=backward | 0=centered | 1=forward | 2=sobel | 3=rotation-invariant (default) | \
# 4=deriche | 5=vanvliet }.
#@cli : 'boundary_conditions' can be { 0=dirichlet | 1=neumann | 2=periodic | 3=mirror }.
#@cli : (no arg) compute all significant components.
#@cli : Default values: 'scheme=0' and 'boundary_conditions=1'.
#@cli : $ image.jpg gradient
#@cli : $$ https://gmic.eu/oldtutorial/_gradient
gradient :
_gmic_s="$?" axes,scheme,boundary,is_noarg=${"_gradient_get_args $*"}
v + _gradient $axes,$scheme,$boundary v -
if $is_noarg noarg fi
# Parse and check arguments.
_gradient_get_args : skip "${1=},${2=},${3=}"
is_noarg=0
l[]
if ['$1']==0 axes,scheme,boundary=,0,1 is_noarg=1 # No 1st arg
else
is_axes={"s=['$1'];fill(s,k,isin(s[k],'xyzc'));min(s)"}
if !$is_axes axes,scheme,boundary=,0,1 is_noarg=1 # Invalid 1st arg
elif ['$2']==0 axes,scheme,boundary=$1,0,1 # No 2nd arg
else
is_scheme={"isint($2) && inrange($2,-1,5)"}
if !$is_scheme axes,scheme,boundary=,0,1 is_noarg=1 # Invalid 2nd arg
elif ['$3']==0 axes,scheme,boundary=$1,$2,1 # No 3rd arg
else
is_boundary={"isint($3) && inrange($3,0,3)"}
if !$is_boundary axes,scheme,boundary=,0,1 is_noarg=1 # Invalid 3rd arg
else axes,scheme,boundary=${1-3}
fi
fi
fi
fi
onfail axes,scheme,boundary=,0,1 is_noarg=1 # Invalid arguments
endl
u $axes,$scheme,$boundary,$is_noarg
# Main command.
_gradient :
axes,scheme,boundary=${1=},${2=},${3=}
# Display log message.
if '$axes'!=0 s_axes=" along axes '"$axes"'" fi
s0,s1,s2,s3,s4,s5,s6=backward,centered,forward,sobel,rotation-invariant,deriche,vanvliet
s_scheme=${s{$scheme+1}}
s0,s1,s2,s3=dirichlet,neumann,periodic,mirror
s_boundary=${s$boundary}
e[0--3] "Compute gradient of image$?"$s_axes", with "$s_scheme" scheme and "$s_boundary" boundary conditions."
sx,sy,sz,sc=",",;,/,^
# Process images.
repeat $! l[$<] nm={n}
laxes=$axes if '$laxes'==0 if d>1 laxes=xyz else laxes=xy fi fi
('$laxes')
repeat w
a={`i[#1,$>]`} s=${s$a}
if ${gradient_$a} [gradient_$a]
elif $scheme==-1 # Backward
(-1${s}1${s}0) +correlate[0] .,$boundary rm..
elif $scheme==0 # Centered
(-0.5${s}0${s}0.5) +correlate[0] .,$boundary rm..
elif $scheme==1 # Forward
(0${s}-1${s}1) +correlate[0] .,$boundary rm..
elif $scheme==2 # Sobel
if _'$a'==_'x' (-1,0,1;-2,0,2;-1,0,1)
elif _'$a'==_'y' (-1,-2,-1;0,0,0;1,2,1)
else (-0.5${s}0${s}0.5)
fi
+correlate[0] .,$boundary rm..
elif $scheme==3 # Rotation-invariant
A,B={[0.25*(2-sqrt(2)),0.5*(sqrt(2)-1)]}
if _'$a'==_'x' (-$A,0,$A;-$B,0,$B;-$A,0,$A)
elif _'$a'==_'y' (-$A,-$B,-$A;0,0,0;$A,$B,$A)
else (-0.5${s}0${s}0.5)
fi
+correlate[0] .,$boundary rm..
else # Deriche/Vanvliet
s4,s5=deriche,vanvliet com=${s$scheme}
if $boundary<2 +$com[0] 0,1,$a,$boundary
else
if _'$a'==_'x' +r[0] {0,[w+2,h,d,s]},0,$boundary,0.5 $com. 0,1,$a shrink_x. 1
elif _'$a'==_'y' +r[0] {0,[w,h+2,d,s]},0,$boundary,0,0.5 $com. 0,1,$a shrink_y. 1
elif _'$a'==_'z' +r[0] {0,[w,h,d+2,s]},0,$boundary,0,0,0.5 $com. 0,1,$a shrink_z. 1
fi
fi
fi
nm. gradient_$a
done
rm[0,1]
nm $nm
endl done
u $is_noaarg
I’ve tried disabling the native command gradient
so that the custom one can be used instead. So far, it seemed to work well.
I’ll build pre-release binaries with all that included.