Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a Data Converter to Display 3D Volume as Images

I would like to write a data converter tool. I need analyze the bitstream in a file to display the 2D cross-sections of a 3D volume.

The dataset I am trying to view can be found here: https://figshare.com/articles/SSOCT_test_dataset_for_OCTproZ/12356705.

It's the file titled: burned_wood_with_tape_1664x512x256_12bit.raw (832 MB)

Would extremely appreciate some direction. Willing to award a bounty if I could get some software to display the dataset as images using a data conversion.

As I'm totally new to this concept, I don't have code to show for this problem. However, here's a little something I tried using inspiration from other questions on SO:

import rawpy
import imageio

path = "Datasets/burned_wood_with_tape_1664x512x256_12bit.raw"
for item in path:
    item_path = path + item
    raw = rawpy.imread(item_path)
    rgb = raw.postprocess()
    rawpy.imshow(rgb)
like image 233
Raiyan Chowdhury Avatar asked Nov 02 '20 15:11

Raiyan Chowdhury


1 Answers

Down below I implemented next visualization.

Example RAW file burned_wood_with_tape_1664x512x256_12bit.raw consists of 1664 samples per A-scan, 512 A-scans per B-scan, 16 B-scans per buffer, 16 buffers per volume, and 2 volumes in this file, each sample is encoded as 2-bytes unsigned integer in little endian order, only 12 higher bits are used, lower 4 bits contain zeros. Samples are centered approximately around 2^15, to be precise data has these stats min 0 max 47648 mean 32757 standard deviation 454.5.

I draw gray images of size 1664 x 512, there are total 16 * 16 * 2 = 512 such images (frames) in a file. I draw animated frames on screen using matplotlib library, also rendering these animation into GIF file. One example of rendered GIF at reduced quality is located after code.

To render/draw images of different resulting resolution you need to change code line with plt.rcParams['figure.figsize'], this fig size contains (widht_in_inches, height_in_inches), by default DPI (dots per inch) equals to 100, meaning that if you want to have resulting GIF of resolution 720x265 then you need to set this figure size to (7.2, 2.65). Also resulting GIF contains animation of a bit smaller resolution because axes and padding is included into resulting figure size.

My next code needs pip modules to be installed one time by command python -m pip install numpy matplotlib.

Try it online!

# Needs: python -m pip install numpy matplotlib
def oct_show(file, *, begin = 0, end = None):
    import os, numpy as np, matplotlib, matplotlib.pyplot as plt, matplotlib.animation
    plt.rcParams['figure.figsize'] = (7.2, 2.65) # (4.8, 1.75) (7.2, 2.65) (9.6, 3.5)
    sizeX, sizeY, cnt, bits = 1664, 512, 16 * 16 * 2, 12
    stepX, stepY = 16, 8
    fps = 5
    try:
        fsize, opened_here = None, False
        if type(file) is str:
            fsize = os.path.getsize(file)
            file, opened_here = open(file, 'rb'), True
        by = (bits + 7) // 8
        if end is None and fsize is not None:
            end = fsize // (sizeX * sizeY * by)
        imgs = []
        file.seek(begin * sizeY * sizeX * by)
        a = file.read((end - begin) * sizeY * sizeX * by)
        a = np.frombuffer(a, dtype = np.uint16)
        a = a.reshape(end - begin, sizeY, sizeX)
        amin, amax, amean, stdd = np.amin(a), np.amax(a), np.mean(a), np.std(a)
        print('min', amin, 'max', amax, 'mean', round(amean, 1), 'std_dev', round(stdd, 3))
        a = (a.astype(np.float32) - amean) / stdd
        a = np.maximum(0.1, np.minimum(a * 128 + 128.5, 255.1)).astype(np.uint8)
        a = a[:, :, :, None].repeat(3, axis = -1)
        
        fig, ax = plt.subplots()
        plt.subplots_adjust(left = 0.08, right = 0.99, bottom = 0.06, top = 0.97)
        for i in range(a.shape[0]):
            title = ax.text(
                0.5, 1.02, f'Frame {i}',
                size = plt.rcParams['axes.titlesize'],
                ha = 'center', transform = ax.transAxes,
            )
            imgs.append([ax.imshow(a[i], interpolation = 'antialiased'), title])
        ani = matplotlib.animation.ArtistAnimation(plt.gcf(), imgs, interval = 1000 // fps)
        print('Saving animated frames to GIF...', flush = True)
        ani.save(file.name + '.gif', writer = 'imagemagick', fps = fps)
        print('Showing animated frames on screen...', flush = True)
        plt.show()
    finally:
        if opened_here:
            file.close()

oct_show('burned_wood_with_tape_1664x512x256_12bit.raw')

Example output GIF:

gif

like image 150
Arty Avatar answered Sep 30 '22 07:09

Arty