Example 21f: Digitising structures from the visible human dataset.

This example has been mostly superseded by example a/digitise. The newer example is being actively improved all the time. (and is what this code is based on) It automatically handles slices that are not all parallel. You can limit the number of textures in memory and it loads and frees them automatically as required. When working with the Visible Human data there are some discontinuties in the raw image set, a set of mappings to realign these planes has been worked out.

This example describes the process of digitising structures from slices from the visible human project, or any other stack of images.
The process occurs in 2 stages.

The first stage is to place the images in a format which the example_21f script can use. This has a number of parts.
1. Obtain and crop images. These can be placed in a single image file directory. For the visible human dataset this can be done using the cropit perl script.
2. Create 2d elements for each slice. These must have a single element in each file with the corresponding plane number. It is important to translate these images so that the original bottom left corner of the image is 0,0. This will ensure that your structures do not need translating if comparing them with other structures. These node and elem files can be generated using the exnode_exelem_creator perl script.
3. Place these node and element files in the same directory used to run example_21f. Due to memory contraints only load a maximum of 30 images.

The second stage is the actual digitisation stage.This is shown in this example. Execute the whole comfile rather than line by line.
By running example_21f you will have a stack of images in the appropriate 3dimensional space.

A gtk widget is drawn with appropriate buttons to allow easy movement up and down the stack. When the 'normal' button is toggled a view is generated normal to the slice and with appropriate clipping planes, such that any node or data point created lies on that image plane.

Experiment by clicking data points on a slice and then move up and down the stack. Each time you go up or down the stack, the appropriate .exdata file corresponding to that slice is saved.

Additional things to try.
Toggle out of 'Normal' mode
In the command window type
visibleoff       #This turns the visibility for everything off
visibleon "data" #This turns on the visibility for all your data points
                 #Do not edit the data points as they are not
                 #constrained in the z plane.(Use 'Normal' mode)

This example can also be used to create nodes and elements. We shall digitise a 1d network such as the femoral artery (situated slightly up and to the right of the bone).
In the command window type
digitise "femoral_artery" #This creates an element group
                 #"femoral_artery" and adjusts the node and element
                 #creator tools appropriately.
#Now click nodes (creating elements) on the artery on each slice.
#Toggle out of 'Normal" mode.
editnode "femoral_artery" #This creates arrow glyphs in the x and y
                 #planes. Clicking on these arrows will constrain the
                 # node in the z plane despite not being in 'Normal' mode.


The comfile run by this example is as follows:

#!/product/cmiss/bin/cmgui_optimised

# ........................................................................

# Description : loads nodes, elements and textures for digitisation 
#               saves .exdata files with slicename.          
#               This comfile must be in same directory as imageslice no and elem files
#               Load entire example rather than line by line.

# ........................................................................
use CmUtils;
use File::KGlob qw(fglob);

# You may need to adjust these lines for your dataset
$set = 'VM';
$format = 'jpg';    #Best to use tifs rather than jpg files
$imagesize = 211.2; #Images are square this is the physical size of the image
$imagefile_directory = '';

# Should not need to change anything below this point
$image_index = 0;
%g_elem = ();  # list of defined graphical elements
@imagelist = ();   # list of image numbers

gfx set point 3;
gfx cre material red       diff 1 0 0     amb 1 0 0     specular 0.8 0.8 0.8 shininess 0.8;
gfx create material green ambient 0 0.6 0 diffuse 0 0.6 0 emission 0 0 0 specular 0.8 0.8 0.8 alpha 1 shininess 0.8
gfx create material purple ambient 1 0 1 diffuse 1 0 1 emission 0 0 0 specular 1 1 1 alpha 1 shininess 0.74
gfx create material bluey ambient 0 0.2 0.4 diffuse 0 0.5 1 emission 0 0 0 specular 0.5 0.5 0.5 alpha 1 shininess 0.8
gfx create material gold ambient 1 0.7 0 diffuse 1 0.7 0 emission 0 0 0 specular 1 1 0.8 alpha 1 shininess 0.8


sub digitise { #group
  my ($digit_group) = @_;
  gfx cre egroup $digit_group;
  gfx modify g_element $digit_group general clear circle_discretization 6 default_coordinate default_coordinate element_discretization "3*3*3" native_discretization none;
  gfx modify g_element $digit_group lines select_on material default selected_material default_selected;
  gfx modify g_element $digit_group node_points glyph sphere general size "2*2*2" centre 0,0,0 select_on material green selected_material purple;
  gfx modify g_element $digit_group cylinders constant_radius 0.5 select_on material default selected_material default_selected;
  gfx create element_creator #and adjust accordingly;
  gfx element_creator coordinate_field coordinates;
  gfx element_creator create;
  gfx element_creator group $digit_group;
  gfx element_creator dimension 1;
  gfx node_tool open_dialog;
  gfx node_tool coordinate_field coordinates;
  gfx node_tool create;
  gfx node_tool group $digit_group;
  gfx mod win 1 set node_tool;
}
print "defining subroutine \"digitise GROUP\"\n";

sub makemask { #makes editing mask for editnode
  gfx define field edit.x edit_mask field coordinates edit_mask 1 0 0;
  gfx define field edit.y edit_mask field coordinates edit_mask 0 1 0;
  gfx define field edit.z edit_mask field coordinates edit_mask 0 0 1;
  gfx define field x_dirn coordinate_system rectangular_cartesian constant number_of_values 3 values 1 0 0;
  gfx define field y_dirn coordinate_system rectangular_cartesian constant number_of_values 3 values 0 1 0;
  gfx define field z_dirn coordinate_system rectangular_cartesian constant number_of_values 3 values 0 0 1;
}

sub viewslice{
  my $num = shift;
  my $name = sprintf("$set%04d", $previous);
  my $name = sprintf("$set%04d", $num);
  visibleoff($previous);
  visibleon($name);
  $name .= "_data";

  unless ($g_elem{$name}) {
    gfx create dgroup $name;
    $g_elem{$name}=1;
  }
  gfx modify g_elem $name data_points glyph sphere size 2 material green;
  gfx data_tool coord coordinates create edit group $name;
  }


sub editnode { #group name
  my ($group) = @_;
  if (!$maskmade){makemask};
  gfx modify g_element $group node_points coordinate coordinates glyph sphere size "1*1*1" centre 0,0,0 select_on material green selected_material purple;
 # gfx modify g_element $group node_points coordinate edit.z glyph arrow_solid size "5*1*1" centre 0,0,0 orientation z_dirn scale_factors "0*0*0" draw_selected material gold selected_material gold;
  gfx modify g_element $group node_points coordinate edit.x glyph arrow_solid size "5*1*1" centre 0,0,0 orientation x_dirn scale_factors "0*0*0" draw_selected material red selected_material red;
  gfx modify g_element $group node_points coordinate edit.y glyph arrow_solid size "5*1*1" centre 0,0,0 orientation y_dirn scale_factors "0*0*0" draw_selected material bluey selected_material bluey;
   gfx node_tool edit;
   gfx node_tool no_create;
   gfx node_tool no_define;
  $maskmade=1;
}
print "defining subroutine \"editnode GROUP\"\n";

sub loadImage {   # name, size, image_format(extension)
  my ($name, $size, $format) = @_;
  gfx read node example $name;
  gfx read elem example $name;
  gfx modify g_element $name lines invisible;

  my $width  = $size;
  my $height = $size;
  gfx create texture $name image example "$imagefile_directory$name.$format" width $width height $height decal;
  gfx create material $name ambient 1 1 1 diffuse 1 1 1 emission 1 1 1 alpha 1.0 texture $name;
  gfx modify g_element $name surface material $name;
  $g_elem{$name} = 1;
}

sub loadExdata {
  my $data = shift;
  gfx read data $data;
  $data .= "_data";
  gfx modify g_element $data data_points glyph sphere size 2 material green;
  $g_elem{$data} = 1;
}

sub loadImageSet {   # name, number_of_images, image_format(extension)
  my ($name, $format) = @_;
  print "Loading images $name*.$format <<\n";
  foreach my $file (fglob ("{$name*.exnode}", $example)) {
    my ($slice, $number) = ($file =~ /($name(\d+))\./);
    print "$number ";
    loadImage($slice, $imagesize, $format);
    push @imagelist, $number;
    if (-f "$slice.exdata") {
      loadExdata($slice);
    }
  }
  print ">>\n";
  @imagelist = sort {$a <=> $b} @imagelist;
}

sub visible {
  my ($pattern) = @_;
  foreach my $name (grep {/$pattern/}  keys %g_elem) {
    print "Turning $name ", $g_elem{$name} ? "off" : "on", "\n";
    gfx set vis $name;
    $g_elem{$name} = 1 - $g_elem{$name};
  }  
}

sub visibleon {
  my ($pattern) = @_;
  foreach my $name (grep {/$pattern/} keys %g_elem) {
    unless ($g_elem{$name}) {
      print "Turning $name on\n";
      gfx set vis $name on;
      $g_elem{$name} = 1;
    }
  }  
}

sub visibleoff {
  my ($pattern) = @_;
  foreach my $name (grep {/$pattern/} keys %g_elem) {
    if ($g_elem{$name}) {
      print "Turning $name off\n";
      gfx set vis $name off;
      $g_elem{$name} = 0;
    }
  }  
}


loadImageSet($set, $format);
createwin(1);
gfx modify window 1 layout simple ortho_axes z -y eye_spacing 0.25 width 1154 height 980

use CmUtils::ViewNormal;

$CmUtils::ViewNormal::Scale = 135;
$CmUtils::ViewNormal::ViewRange = 4;

sub trace {
  my $num = shift;
  my $name = sprintf("$set%04d", $previous);
  save($name);
  
  $name = sprintf("$set%04d", $num);
  visibleoff('.');
  visibleon($name);

  $name = sprintf("$example$set%04d", $num);
  viewNormal($name);
  $name .= "_data";
  unless ($g_elem{$name}) {
    gfx create dgroup $name;
    $g_elem{$name}=1;
  }
  gfx modify g_elem $name data_points glyph sphere size 2 material green;
  gfx data_tool coord coordinates create edit group $name;
}


sub save {
  my $name = shift;
  if (defined $g_elem{"${name}_data"}) {
    gfx write data $name group "${name}_data";
  }
}

{
use Gtk;

sub myloop {
  while (Gtk->events_pending()) {
    Gtk->main_iteration();
  }
  return ("OK");
}

attach gtk start_detection perl_action &cmiss::myloop() ;
init Gtk;
attach gtk end_detection ;
set_locale Gtk;

$false = 0;
$true = 1;

sub constrain {
  my ($val) = @_;
  foreach $image_index (0 .. $#imagelist) {
    return $imagelist[$image_index] if $imagelist[$image_index] >= $val;
  }
  $image_index = $#imagelist;
  return $imagelist[$image_index];
}

$set_number = new Gtk::Entry();
$set_number->signal_connect(activate => sub { $previous = $current; $current = constrain($set_number->get_text()); trace_or_viewCurrent();});
$next = new Gtk::Button( "  Next  " );
$next->signal_connect(clicked => sub { $previous = $current; $image_index = ($image_index == $#imagelist) ? 0 : $image_index + 1; $current = $imagelist[$image_index];trace_or_viewCurrent();});
$prev = new Gtk::Button( "Previous" );
$prev->signal_connect(clicked => sub { $previous = $current; $image_index = ($image_index == 0) ? $#imagelist : $image_index - 1; $current = $imagelist[$image_index];trace_or_viewCurrent();});
$modus = new Gtk::ToggleButton( " Normal " );
$modus->signal_connect("clicked", \&changemodus );

$box = new Gtk::HBox( "box" );
$box->spacing(15);
$box->add($prev);
$box->add($set_number);
$box->add($next);
$box->add($modus);

$window = new Gtk::Window( "toplevel" );
$window->set_title("Image Stack");
$window->signal_connect(delete_event => sub { return $false; });
$window->border_width(15);
$window->add($box);
$window->show_all();

sub changemodus  {
  $togglebutton = $_[0];

  if ( $togglebutton->active ) {
    $mode=1;
  } else {
    $mode=2;
    gfx modify win 1 image view_all
  }
  trace_or_viewCurrent();
}

sub trace_or_viewCurrent  {
 if($mode==1){
 $set_number->set_text($current);
 trace($current);
  }
 if ($mode==2) {
 $set_number->set_text($current);
 viewslice ($current);
 }
}
$current = $imagelist[$image_index]; # image currently being traced
trace_or_viewCurrent();

myloop();
}

Files used by this example are:

Name             Modified     Size

example_21f.com 22-Nov-2001 9.0k VM1100.exelem 21-Nov-2001 1.5k VM1100.exnode 21-Nov-2001 394 VM1100.jpg 21-Nov-2001 56k VM1105.exelem 21-Nov-2001 1.5k VM1105.exnode 21-Nov-2001 394 VM1105.jpg 21-Nov-2001 56k VM1110.exelem 21-Nov-2001 1.5k VM1110.exnode 21-Nov-2001 394 VM1110.jpg 21-Nov-2001 56k

Download the entire example:

Name                      Modified     Size

examples_2_21_21f.tar.gz 19-Aug-2006 213k

Html last generated: Sun Mar 6 05:50:10 2016

Input last modified: Fri Mar 12 10:16:05 2004


CMISS Help / Examples / 2 / 21 / 21f