You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It maybe nice to have a similar feature like obliqueslice in MATLAB. I now have an ugly but working script:
using LinearAlgebra
using LazyGrids
using CoordinateTransformations, Rotations, StaticArrays, Interpolations
meshgrid(y,x) = (ndgrid(x,y)[[2,1]]...,)
""" obliqueslice(v, point, normal; method=Linear(), fillvalue::Real=0)Extract an oblique slice from a 3-D volume `v`, by using the `point` on the output slice and`normal` to the output slice.# Arguments- `point::Vector`: vector containing X, Y, Z coordinates of the point in which output slicepasses through.- `normal:Vector`: a normal vector to the output slice.- `method`: `Constant()` for nearest neighbor interpolation, `Linear()` for linearinterpolation.- `fillvalue::Real=0`: Numeric scalar value used to fill pixels in the output slice that areoutside the limits of the volume.# Output Arguments- `slice`: interpolated values on the oblique plane.- `xdata, ydata, zdata`: the X, Y and Z coordinates of the extracted slice in volume `v`."""functionobliqueslice(v, point, normal; method=Linear(), fillvalue::Real=0)
point =Float64.(point)
sz =size(v)
xhalf, yhalf, zhalf =ntuple(i ->round(sz[i] /2+1e-12), Val(3))
# Initial normal vector along z axis
ẑ = [0., 0., 1.]
# Unit normal vector
n̂ =normalize(normal)
n̂ =normalize(normal)
# Compute axis of rotationif ẑ == n̂
W = n̂
else
W = ẑ × n̂
normalize!(W)
end# Compute angle of rotation in radians
angle =acos(ẑ ⋅ n̂)
# Quaternion rotation matrix
t_quat =quat_matrix(W, -angle)
# X, Y and Z coordinates of a plane with origin as the center
(xp, yp), zp =let
planeSize =3*maximum(sz)
xrange =round(-planeSize/2):round(planeSize/2)
yrange =round(-planeSize/2):round(planeSize/2)
meshgrid(yrange, xrange), zeros(length(yrange), length(xrange))
end# Rotate coordinates of a plane
xr, yr, zr =similar(xp), similar(yp), similar(zp)
for i ineachindex(xp)
coords =SVector(xp[i], yp[i], 0.0)
xr[i], yr[i], zr[i] = t_quat * coords
end# Shift user input point, relative to input volume having origin as center
point[1] -= yhalf
point[2] -= xhalf
point[3] -= zhalf
# Find the shortest distance between the plane that passes through input point and origin
D = n̂[1]*point[1] + n̂[2]*point[2] + n̂[3]*point[3]
# Translate a plane that passes from origin to input point
xq =@. xr + D*n̂[1] + yhalf
yq =@. yr + D*n̂[2] + xhalf
zq =@. zr + D*n̂[3] + zhalf
# Obtain slice at desired coordinates using interpolation
nodes = (axes(v,2), axes(v,1), axes(v,3))
vpermute =permutedims(v, (2,1,3))
itp =interpolate(nodes, vpermute, Gridded(method))
etp =extrapolate(itp, fillvalue)
# Make bounding box around the data in oblique slice
slicelimit =@. (xq>=1) & (xq<=sz[2]) & (yq>=1) & (yq<=sz[1]) & (zq>=1) & (zq<=sz[3])
slicerange =find_bounding_box(slicelimit)
XData = xq[slicerange[1], slicerange[2]]
YData = yq[slicerange[1], slicerange[2]]
ZData = zq[slicerange[1], slicerange[2]]
croppedslice =etp.(XData, YData, ZData)
croppedslice, XData, YData, ZData
end"Return Quaternion matrix for a rotation by a given angle `θ` about a fixed axis `w`."functionquat_matrix(w, θ)
a_x, a_y, a_z = w
c =cos(θ)
s =sin(θ)
t1 = c + a_x^2*(1-c)
t2 = a_x*a_y*(1-c) - a_z*s
t3 = a_x*a_z*(1-c) + a_y*s
t4 = a_y*a_x*(1-c) + a_z*s
t5 = c + a_y^2*(1-c)
t6 = a_y*a_z*(1-c)-a_x*s
t7 = a_z*a_x*(1-c)-a_y*s
t8 = a_z*a_y*(1-c)+a_x*s
t9 = c+a_z^2*(1-c)
r =RotMatrix{3}(t1, t2, t3, t4, t5, t6, t7, t8, t9)
q =QuatRotation(r)
end"Find the position of the smallest box containing the 2D `region`."functionfind_bounding_box(region)
edges =Vector{CartesianIndex}(undef, 4)
for j inaxes(region,2), i inaxes(region,1)
if region[i,j]
edges[1] =CartesianIndex(i, j)
breakendendfor i inaxes(region,1), j inaxes(region,2)
if region[i,j]
edges[2] =CartesianIndex(i, j)
breakendendfor j inreverse(axes(region,2)), i inreverse(axes(region,1))
if region[i,j]
edges[3] =CartesianIndex(i, j)
breakendendfor i inreverse(axes(region,1)), j inreverse(axes(region,2))
if region[i,j]
edges[4] =CartesianIndex(i, j)
breakendend
imin, imax =extrema(x -> x[1], edges)
jmin, jmax =extrema(x -> x[2], edges)
imin:imax, jmin:jmax
end
A simple comparison shows identical results with MATLAB defaults:
using PyPlot
point = [4,4,6]
normal = [1,1,1]
v = [i + (j-1)*10 + (k-1)*20 for i in 1:10, j in 1:20, k in 1:20]
slice, XData, YData, ZData = obliqueslice(v, point, normal)
imshow(slice, cmap="gray")
Julia:
MATLAB:
Is this already available somewhere in Makie? If not, please consider adding a similar feature like this! The sample code above is not so elegant, but simply for demonstration purpose.
The text was updated successfully, but these errors were encountered:
Can we create an oblique slice from any kind of functions in 3 dimension, e.g. f(x,y) = x^2 + y^2 ?
If you mean f(x,y,z) = x^2 + y^2 + z^2, with this kind of approach we first need to generate a discrete 3d array from the analytical formula. Something like
point = [4.0,4.0,6.0]
normal = [1,1,1]
v = [x^2+ y^2+ z^2for x in0:1.0:10, y in0:1.0:10, z in0:1.0:10]
slice, XData, YData, ZData =obliqueslice(v, point, normal)
should work? The tricky part may be how to handle the size of oblique slices, and what values to set for outliers.
It maybe nice to have a similar feature like
obliqueslice
in MATLAB. I now have an ugly but working script:A simple comparison shows identical results with MATLAB defaults:
Julia:
MATLAB:
Is this already available somewhere in Makie? If not, please consider adding a similar feature like this! The sample code above is not so elegant, but simply for demonstration purpose.
The text was updated successfully, but these errors were encountered: