backback

Figure 9: Curvature-based NPR

_vmhead.png

This uses the vmhead2.nhdr Visible Male CT Head dataset that is created by following instructions on this page. We start by blurring the volume along the Z direction (which is rather slow), in order to reduce the stair-case artifacts between slices. This is followed by a trick to nix the sample-centering field in the header (so as to not confuse hoover):

unu resample -i vmhead2.nhdr \
   -s = = x1 -k cubic:1.5,1,0 -o vol.nhdr
mv -f vol.nhdr tmptmp; grep -v centers tmptmp >! vol.nhdr

Creating the curvature-based transfer functions is somewhat painful as usual:

echo "-1 1 -1 1" \
 | unu reshape -s 2 2 \
 | unu resample -s 256 256 -k tent -o xramp.nrrd

echo "1 1 -1 -1" \
 | unu reshape -s 2 2 \
 | unu resample -s 256 256 -k tent -o yramp.nrrd

unu join -i xramp.nrrd yramp.nrrd -a 0 -incr \
 | unu project -a 0 -m l2 -o radius.nrrd

unu 2op atan2 xramp.nrrd yramp.nrrd \
 | unu 2op / - 0.7853975 \
 | unu 2op + - 1 \
 | unu 3op clamp 0 - 4 -o angle.nrrd



echo "0 0      0.065 0      0.35  1       1 1" \
 | unu reshape -s 2 4 \
 | unu imap -i radius.nrrd -m - \
 | unu gamma -g 1.1 \
 | unu resample -s 256 256 -k tent -o thresh.nrrd
echo "0 0      0.3 1      1.7  1       2 0" \
 | unu reshape -s 2 4 \
 | unu imap -i angle.nrrd -m - \
 | unu 2op x - thresh.nrrd \
 | unu 2op - 1 - -o valley.nrrd

echo "0 0      0.235 0      0.43  1       1 1" \
 | unu reshape -s 2 4 \
 | unu imap -i radius.nrrd -m - \
 | unu gamma -g 0.8 \
 | unu resample -s 256 256 -k tent -o thresh.nrrd
echo "2 0   2.1 0    2.5 1      3.5  1   3.9 0    4 0" \
 | unu reshape -s 2 6 \
 | unu imap -i angle.nrrd -m - \
 | unu 2op x - thresh.nrrd \
 | unu 2op + 1 - -o crease.nrrd

unu 2op x valley.nrrd crease.nrrd \
 | unu reshape -s 1 256 256 \
 | unu pad -min 0 0 0 -max 2 M M \
 | unu axinfo -a 0 -l "RGB" \
 | unu axinfo -a 1 -l "gage(k1)" -mm -0.7 0.7 \
 | unu axinfo -a 2 -l "gage(k2)" -mm -0.7 0.7 -o valcre-skin-txf.nrrd



echo "0 0      0.13 0      0.35  1       1 1" \
 | unu reshape -s 2 4 \
 | unu imap -i radius.nrrd -m - \
 | unu gamma -g 0.8 \
 | unu resample -s 256 256 -k tent -o thresh.nrrd
echo "0 0      0.3 1      1.7  1       2 0" \
 | unu reshape -s 2 4 \
 | unu imap -i angle.nrrd -m - \
 | unu 2op x - thresh.nrrd \
 | unu 2op - 1 - -o valley.nrrd

echo "0 0      0.23 0      0.50  1       1 1" \
 | unu reshape -s 2 4 \
 | unu imap -i radius.nrrd -m - \
 | unu gamma -g 0.7 \
 | unu resample -s 256 256 -k tent -o thresh.nrrd
echo "2 0   2.1 0    2.5 1      3.5  1   3.9 0    4 0" \
 | unu reshape -s 2 6 \
 | unu imap -i angle.nrrd -m - \
 | unu 2op x - thresh.nrrd \
 | unu 2op + 1 - -o crease.nrrd

unu 2op x valley.nrrd crease.nrrd \
 | unu reshape -s 1 256 256 \
 | unu pad -min 0 0 0 -max 2 M M \
 | unu axinfo -a 0 -l "RGB" \
 | unu axinfo -a 1 -l "gage(k1)" -mm -0.7 0.7 \
 | unu axinfo -a 2 -l "gage(k2)" -mm -0.7 0.7 -o valcre-bone-txf.nrrd



echo "0 1" \
 | unu reshape -s 2 \
 | unu resample -s 512 -k tent -o ramp.nrrd

unu imap -i ramp.nrrd -r -m gooch.txt \
 | unu 2op / - 255 \
 | unu 2op - 1 - \
 | unu 2op x 0.75 - \
 | unu 2op - 1 - \
 | unu flip -a 1 \
 | unu axinfo -a 0 -l RGB \
 | unu axinfo -a 1 -l ndotl -mm -0.5 0.9 -o gooch-txf.nrrd

echo "-1 0 -1 0" \
 | unu reshape -s 2 2 \
 | unu resample -s 300 300 -k tent -o xramp.nrrd

echo "-1 -1 1 1" \
 | unu reshape -s 2 2 \
 | unu resample -s 300 300 -k tent -o yramp.nrrd

unu imap -r -i ramp.nrrd -m sil1.txt \
 | unu axinfo -a 0 -l "RGB" \
 | unu axinfo -a 1 -l "ndotv" -mm -1 1 -o sil1-txf.nrrd

unu join -i xramp.nrrd yramp.nrrd -a 0 -incr \
 | unu project -a 0 -m l2 \
 | unu 2op gt - 1.000 \
 | unu resample -s = x1 -k gauss:6,3 \
 | unu reshape -s 1 300 300 \
 | unu pad -min 0 0 0 -max 2 M M \
 | unu axinfo -a 0 -l "RGB" \
 | unu axinfo -a 1 -l "GTdotV" -mm 0.0 0.9 \
 | unu axinfo -a 2 -l "NdotV" -mm -1.0 1.0 -o sil2-skin-txf.nrrd

unu join -i xramp.nrrd yramp.nrrd -a 0 -incr \
 | unu project -a 0 -m l2 \
 | unu 2op gt - 1.000 \
 | unu resample -s = x1 -k gauss:6,3 \
 | unu reshape -s 1 300 300 \
 | unu pad -min 0 0 0 -max 2 M M \
 | unu axinfo -a 0 -l "RGB" \
 | unu axinfo -a 1 -l "GTdotV" -mm 0.0 1.3 \
 | unu axinfo -a 2 -l "NdotV" -mm -1.0 1.0 -o sil2-bone-txf.nrrd


rm -f ramp.nrrd xramp.nrrd yramp.nrrd angle.nrrd radius.nrrd 
rm -f thresh.nrrd valley.nrrd crease.nrrd

The gkms program is used to create the opacity functions:

gkms txf -max 2000 900 -v 668 -top 516 747 -w 800 -o - \
 | unu 2op x - 1.2 \
 | unu 2op min - 1.0 -o skin-txf.nrrd

gkms txf -max 2000 900 -v 950 -g 150 -gw 0 \
   -top 1800 916 -w 700 -step -o tmp.nrrd
gkms txf -max 2000 900 -v 1300 -top 1070 150 -w 0 -step -o - \
 | unu resample -s = x1 = -k gauss:3,3 \
 | unu 2op max tmp.nrrd - -o bone-txf.nrrd
rm -f tmp.nrrd

Setting up the render command and making the six images:

setenv BIS 750
setenv NT 50
setenv STEP 0.0007
setenv BG "0.65 0.65 0.65"

alias MITER miter -i vol.nhdr \
  -at -0.1 -0.15 0.07 -up 0 0 -1 -fr -5.1 -5 1.8 -rh \
  -dn -1 -di 0 -df 1 -ar \
  -ur -0.87 0.87 -vr -1.04 0.7 \
  -k00 cubic:1,1,0 -k11 cubicd:1,1,0 -k22 cubicdd:1,1,0 -rn \
  -ld 2 -7 -6 -ads 0.8 0.0 0 -step $STEP \
  -is $BIS $BIS -nt $NT

MITER -txf skin-txf.nrrd gooch-txf.nrrd \
  sil1-txf.nrrd -o skin-sil1-rend.nrrd
MITER -txf skin-txf.nrrd gooch-txf.nrrd \
  sil2-skin-txf.nrrd -o skin-sil-rend.nrrd
MITER -txf skin-txf.nrrd gooch-txf.nrrd \
  valcre-skin-txf.nrrd -o skin-vc-rend.nrrd
MITER -txf skin-txf.nrrd gooch-txf.nrrd \
  sil2-skin-txf.nrrd valcre-skin-txf.nrrd -o skin-silvc-rend.nrrd

MITER -txf bone-txf.nrrd gooch-txf.nrrd \
  sil1-txf.nrrd -o bone-sil1-rend.nrrd
MITER -txf bone-txf.nrrd gooch-txf.nrrd \
  sil2-bone-txf.nrrd -o bone-sil-rend.nrrd
MITER -txf bone-txf.nrrd gooch-txf.nrrd \
  valcre-bone-txf.nrrd -o bone-vc-rend.nrrd
MITER -txf bone-txf.nrrd gooch-txf.nrrd \
  sil2-bone-txf.nrrd valcre-bone-txf.nrrd -o bone-silvc-rend.nrrd

foreach surf ( skin bone )
  foreach what ( sil vc silvc )
    overrgb -i ${surf}-${what}-rend.nrrd \
      -g 1.25 -b $BG -o vmhead-${surf}-${what}.png
  end
end

Putting these together into a figure:

unu resample -i vmhead-skin-sil.png -s = x0.5 x0.5 -k hann:6 \
 | unu crop -min 0 0 0 -max M M-2 M-1 \
 | unu pad -min 0 0 0 -max M M+2 M+1 -b pad -v 255 -o a.png
unu resample -i vmhead-skin-vc.png -s = x0.5 x0.5 -k hann:6 \
 | unu crop -min 0 0 1 -max M M-2 M \
 | unu pad -min 0 0 -1 -max M M+2 M -b pad -v 255 -o b.png
unu join -i a.png b.png -a 2 -o A.png
unu resample -i vmhead-bone-sil.png -s = x0.5 x0.5 -k hann:6 \
 | unu crop -min 0 2 0 -max M M-2 M-1 \
 | unu pad -min 0 -2 0 -max M M+2 M+1 -b pad -v 255 -o a.png
unu resample -i vmhead-bone-vc.png -s = x0.5 x0.5 -k hann:6 \
 | unu crop -min 0 2 1 -max M M-2 M \
 | unu pad -min 0 -2 -1 -max M M+2 M -b pad -v 255 -o b.png
unu join -i a.png b.png -a 2 -o B.png
rm -f a.png b.png 
unu join -i A.png vmhead-skin-silvc.png \
            B.png vmhead-bone-silvc.png -a 1 -o vmhead.png
rm -f A.png B.png

unu resample -i vmhead.png -s = x0.35 x0.35 -o _vmhead.png ; xv _vmhead.png
unu resample -i vmhead.png -s = x0.13 x0.13 -o __vmhead.png ; xv __vmhead.png