3d analysis and rendering of damage in a steel tension sampleΒΆ

This recipe demonstrate how to analyze the cavities in a steel sample deformed under tension loading.

Get the complete Python source code: steel_damage_analysis.py

The 3d data set is a 8 bits binary file with size 341x341x246. First you need to define the path to the 3d volume:

data_dir = '../../examples/data'
scan_name = 'steel_431x431x246_uint8'
scan_path = os.path.join(data_dir, scan_name + '.raw')

Then load the volume in memory thanks to the :pymicro:file:file_utils:HST_read function:

data = HST_read(scan_path, header_size=0)

The reconstructed tomographic volume is not align with the cartesian axes, so rotate the volume by 15 degrees:

data = ndimage.rotate(data, 15.5, axes=(1, 0), reshape=False)

The result of these operations can be quickly observed using regular pyplot functions such as imshow. Here we look at slice number 87 where a ring artifact is present. We will take care of those later.

../_images/steel_431x431x246_uint8_data.png

The entire volume is binarized using a simple threshold with the value 100:

data_bin = np.where(np.greater(data, 100), 0, 255).astype(np.uint8)

And cavities are labeled using standard scipy tools:

label_im, nb_labels = ndimage.label(data_bin)

3465 labels have been found, the result can be observed on slice 87 using pyplot:

../_images/steel_431x431x246_uint8_label.png

We use a simple algorithm to remove ring articfacts (assuming the cavities are convex): the center of mass of each label is compute and if it does not lie inside the label, the corresponding voxels are set to 0. Here 11 rings were removed.

# simple ring removal artifact
coms = ndimage.measurements.center_of_mass(data_bin / 255, labels=label_im, \
                                           index=range(1, nb_labels + 1))
rings = 0
for i in range(nb_labels):
    com_x = round(coms[i][0])
    com_y = round(coms[i][1])
    com_z = round(coms[i][2])
    if not label_im[com_x, com_y, com_z] == i + 1:
        print 'likely found a ring artifact at (%d, %d, %d) for label = %d, value is %d' \
              % (com_x, com_y, com_z, (i + 1), label_im[com_x, com_y, com_z])
        data_bin[label_im == (i + 1)] = 0
        rings += 1
print 'removed %d rings artifacts' % rings

The outside of the sample needs a little love, it is by far the largest label here so after inverting the labeled image and running a binary closing it can be set to a fixed value (155 here) in the data_bin array.

print('labeling and using a fixed color around the specimen')
# the outside is by far the largest label here
mask_outside = (sizes >= ndimage.maximum(sizes))
print('inverting the image so that outside is now 1')
data_inv = 1 - label_im
outside = mask_outside[data_inv]
outside = ndimage.binary_closing(outside, iterations=3)
# fix the image border
outside[0:3, :, :] = 1;
outside[-3:, :, :] = 1;
outside[:, 0:3, :] = 1;
../_images/steel_431x431x246_uint8_outside.png

At this point the segmented volume can be written to the disk for later use using the HST_write function:

plt.subplots_adjust(left=0.1, right=0.95, top=0.95, bottom=0.1)