Skip to content

Commit 7a4b991

Browse files
committed
Update docstring and styling
1 parent 4f4fba8 commit 7a4b991

File tree

1 file changed

+158
-153
lines changed

1 file changed

+158
-153
lines changed

rawtools/raw2img.py

Lines changed: 158 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
#!/usr/bin/python3.8
2-
# -*- coding: utf-8 -*-
3-
'''
1+
"""Split RAW format into N image slices
42
Created on Jul 27, 2018
53
64
@author: Ni Jiang, Tim Parker
7-
'''
5+
"""
86

97
import logging
108
import os
@@ -22,160 +20,167 @@
2220

2321

2422
def slice_to_img(args, slice, x, y, bitdepth, image_bitdepth, old_min, old_max, new_min, new_max, ofp):
25-
"""Convert byte data of a slice into an image
23+
"""Convert byte data of a slice into an image
2624
27-
Args:
28-
args (Namespace): arguments object
29-
slice (numpy.ndarray): slice data
30-
x (int): width of the slice as an image
31-
y (int): height of the slice as an image
32-
ofp (str): intended output path of the image to be saved
25+
Args:
26+
args (Namespace): arguments object
27+
slice (numpy.ndarray): slice data
28+
x (int): width of the slice as an image
29+
y (int): height of the slice as an image
30+
ofp (str): intended output path of the image to be saved
3331
34-
"""
35-
slice = slice.reshape([y,x])
32+
"""
33+
slice = slice.reshape([y, x])
3634

37-
if bitdepth != image_bitdepth:
38-
slice = scale(slice, old_min, old_max, new_min, new_max)
39-
slice = np.floor(slice)
35+
if bitdepth != image_bitdepth:
36+
slice = scale(slice, old_min, old_max, new_min, new_max)
37+
slice = np.floor(slice)
38+
39+
if not args.dryrun:
40+
Image.fromarray(slice.astype(image_bitdepth)).save(ofp)
4041

41-
if not args.dryrun:
42-
Image.fromarray(slice.astype(image_bitdepth)).save(ofp)
4342

4443
def extract_slices(args, fp):
45-
"""Extract each slice of a volume, one by one and save it as an image
46-
47-
Args:
48-
args (Namespace): arguments object
49-
50-
"""
51-
def update(*args):
52-
pbar.update()
53-
54-
# Set an images directory for the volume
55-
imgs_dir = os.path.splitext(fp)[0]
56-
logging.debug(f"Slices directory: '{imgs_dir}'")
57-
dat_fp = f"{os.path.splitext(fp)[0]}.dat"
58-
logging.debug(f"DAT filepath: '{dat_fp}'")
59-
60-
# Create images directory if does not exist
61-
try:
62-
if not os.path.exists(imgs_dir):
63-
os.makedirs(imgs_dir)
64-
# else:
65-
# logging.warning(f"Output directory for slices already exists '{imgs_dir}'.")
66-
except:
67-
raise
68-
# Images directory is created and ready
69-
else:
70-
# Get dimensions of the volume
71-
metadata = dat.read(dat_fp)
72-
x, y, z = metadata['xdim'], metadata['ydim'], metadata['zdim']
73-
xth, yth, zth = metadata['x_thickness'], metadata['y_thickness'], metadata['z_thickness']
74-
logging.debug(f"Volume dimensions: <{x}, {y}, {z}> for '{fp}'")
75-
logging.debug(f"Slice thicknesses: <{xth}, {yth}, {zth}> for '{fp}'")
76-
77-
bitdepth = determine_bit_depth(fp, (x,y,z))
78-
logging.debug(f"Detected bit depth '{bitdepth}' for '{fp}'")
79-
80-
# Pad the index for the slice in its filename based on the
81-
# number of digits for the total count of slices
82-
digits = len(str(z))
83-
num_format = '{:0'+str(digits)+'d}'
84-
85-
# Set slice dimensions
86-
img_size = x * y
87-
offset = img_size * np.dtype(bitdepth).itemsize
88-
89-
# Determine scaling parameters per volume for output images
90-
# Equate the image format to numpy dtype
91-
if args.format == 'tif':
92-
image_bitdepth = 'uint16'
93-
elif args.format == 'png':
94-
image_bitdepth = 'uint8'
95-
else:
96-
image_bitdepth = 'uint8'
97-
98-
# Construct transformation function
99-
# If input bitdepth is an integer, get the max and min with iinfo
100-
if np.issubdtype(np.dtype(bitdepth), np.integer):
101-
old_min = np.iinfo(np.dtype(bitdepth)).min
102-
old_max = np.iinfo(np.dtype(bitdepth)).max
103-
# Otherwise, assume float32 input
104-
else:
105-
old_min, old_max = find_float_range(fp, dtype=bitdepth, buffer_size=offset)
106-
# If output image bit depth is an integer, get the max and min with iinfo
107-
if np.issubdtype(np.dtype(image_bitdepth), np.integer):
108-
new_min = np.iinfo(np.dtype(image_bitdepth)).min
109-
new_max = np.iinfo(np.dtype(image_bitdepth)).max
110-
# Otherwise, assume float32 output
111-
else:
112-
new_min = np.finfo(np.dtype(image_bitdepth)).min
113-
new_max = np.finfo(np.dtype(image_bitdepth)).max
114-
115-
logging.debug(f"{bitdepth} ({old_min}, {old_max}) -> {image_bitdepth} ({new_min}, {new_max})")
116-
117-
# Extract data from volume, slice-by-slice
118-
slices = []
119-
120-
description = f"Extracting slices from {os.path.basename(fp)} ({bitdepth})"
121-
pbar = tqdm(total = z, desc=description)
122-
with open(fp, 'rb') as ifp:
123-
# Dedicate N CPUs for processing
124-
with Pool(args.threads) as p:
125-
# For each slice in the volume...
126-
for i in range(0, z):
127-
# Read slice data, and set job data for each process
128-
ifp.seek(i*offset)
129-
chunk = np.fromfile(ifp, dtype=bitdepth, count = img_size, sep="")
130-
ofp = os.path.join(imgs_dir, f"{os.path.splitext(os.path.basename(fp))[0]}_{num_format.format(i)}.{args.format}")
131-
# Check if the image already exists
132-
if os.path.exists(ofp) and not args.force:
133-
pbar.update()
134-
continue
135-
p.apply_async(slice_to_img, args=(args, chunk, x, y, bitdepth, image_bitdepth, old_min, old_max, new_min, new_max, ofp), callback=update)
136-
p.close()
137-
p.join()
138-
pbar.close()
139-
pbar = None
44+
"""Extract each slice of a volume, one by one and save it as an image
45+
46+
Args:
47+
args (Namespace): arguments object
48+
49+
"""
50+
def update(*args):
51+
pbar.update()
52+
53+
# Set an images directory for the volume
54+
imgs_dir = os.path.splitext(fp)[0]
55+
logging.debug(f"Slices directory: '{imgs_dir}'")
56+
dat_fp = f"{os.path.splitext(fp)[0]}.dat"
57+
logging.debug(f"DAT filepath: '{dat_fp}'")
58+
59+
# Create images directory if does not exist
60+
try:
61+
if not os.path.exists(imgs_dir):
62+
os.makedirs(imgs_dir)
63+
# else:
64+
# logging.warning(f"Output directory for slices already exists '{imgs_dir}'.")
65+
except:
66+
raise
67+
# Images directory is created and ready
68+
else:
69+
# Get dimensions of the volume
70+
metadata = dat.read(dat_fp)
71+
x, y, z = metadata['xdim'], metadata['ydim'], metadata['zdim']
72+
xth, yth, zth = metadata['x_thickness'], metadata['y_thickness'], metadata['z_thickness']
73+
logging.debug(f"Volume dimensions: <{x}, {y}, {z}> for '{fp}'")
74+
logging.debug(f"Slice thicknesses: <{xth}, {yth}, {zth}> for '{fp}'")
75+
76+
bitdepth = determine_bit_depth(fp, (x, y, z))
77+
logging.debug(f"Detected bit depth '{bitdepth}' for '{fp}'")
78+
79+
# Pad the index for the slice in its filename based on the
80+
# number of digits for the total count of slices
81+
digits = len(str(z))
82+
num_format = '{:0'+str(digits)+'d}'
83+
84+
# Set slice dimensions
85+
img_size = x * y
86+
offset = img_size * np.dtype(bitdepth).itemsize
87+
88+
# Determine scaling parameters per volume for output images
89+
# Equate the image format to numpy dtype
90+
if args.format == 'tif':
91+
image_bitdepth = 'uint16'
92+
elif args.format == 'png':
93+
image_bitdepth = 'uint8'
94+
else:
95+
image_bitdepth = 'uint8'
96+
97+
# Construct transformation function
98+
# If input bitdepth is an integer, get the max and min with iinfo
99+
if np.issubdtype(np.dtype(bitdepth), np.integer):
100+
old_min = np.iinfo(np.dtype(bitdepth)).min
101+
old_max = np.iinfo(np.dtype(bitdepth)).max
102+
# Otherwise, assume float32 input
103+
else:
104+
old_min, old_max = find_float_range(
105+
fp, dtype=bitdepth, buffer_size=offset)
106+
# If output image bit depth is an integer, get the max and min with iinfo
107+
if np.issubdtype(np.dtype(image_bitdepth), np.integer):
108+
new_min = np.iinfo(np.dtype(image_bitdepth)).min
109+
new_max = np.iinfo(np.dtype(image_bitdepth)).max
110+
# Otherwise, assume float32 output
111+
else:
112+
new_min = np.finfo(np.dtype(image_bitdepth)).min
113+
new_max = np.finfo(np.dtype(image_bitdepth)).max
114+
115+
logging.debug(
116+
f"{bitdepth} ({old_min}, {old_max}) -> {image_bitdepth} ({new_min}, {new_max})")
117+
118+
# Extract data from volume, slice-by-slice
119+
slices = []
120+
121+
description = f"Extracting slices from {os.path.basename(fp)} ({bitdepth})"
122+
pbar = tqdm(total=z, desc=description)
123+
with open(fp, 'rb') as ifp:
124+
# Dedicate N CPUs for processing
125+
with Pool(args.threads) as p:
126+
# For each slice in the volume...
127+
for i in range(0, z):
128+
# Read slice data, and set job data for each process
129+
ifp.seek(i*offset)
130+
chunk = np.fromfile(ifp, dtype=bitdepth,
131+
count=img_size, sep="")
132+
ofp = os.path.join(
133+
imgs_dir, f"{os.path.splitext(os.path.basename(fp))[0]}_{num_format.format(i)}.{args.format}")
134+
# Check if the image already exists
135+
if os.path.exists(ofp) and not args.force:
136+
pbar.update()
137+
continue
138+
p.apply_async(slice_to_img, args=(args, chunk, x, y, bitdepth, image_bitdepth,
139+
old_min, old_max, new_min, new_max, ofp), callback=update)
140+
p.close()
141+
p.join()
142+
pbar.close()
143+
pbar = None
144+
140145

141146
def main(args):
142-
start_time = time()
143-
144-
# Collect all volumes and validate their metadata
145-
try:
146-
# Gather all files
147-
args.files = []
148-
for p in args.path:
149-
for root, dirs, files in os.walk(p):
150-
for filename in files:
151-
args.files.append(os.path.join(root, filename))
152-
153-
# Append any loose, explicitly defined paths to .RAW files
154-
args.files.extend([ f for f in args.path if f.endswith('.raw') ])
155-
156-
# Get all RAW files
157-
args.files = [ f for f in args.files if f.endswith('.raw') ]
158-
logging.debug(f"All files: {args.files}")
159-
args.files = list(set(args.files)) # remove duplicates
160-
logging.info(f"Found {len(args.files)} volume(s).")
161-
logging.debug(f"Unique files: {args.files}")
162-
163-
# Validate that a DAT file exists for each volume
164-
for fp in args.files:
165-
dat_fp = f"{os.path.splitext(fp)[0]}.dat" # .DAT filepath
166-
logging.debug(f"Validating DAT file: '{dat_fp}'")
167-
# Try to extract the dimensions to make sure that the file exists
168-
dat.read(dat_fp)
169-
except Exception as err:
170-
logging.error(err)
171-
else:
172-
# For each provided volume...
173-
pbar = tqdm(total = len(args.files), desc=f"Overall progress")
174-
for fp in args.files:
175-
logging.debug(f"Processing '{fp}'")
176-
# Extract slices for all volumes in provided folder
177-
extract_slices(args, fp)
178-
pbar.update()
179-
pbar.close()
180-
181-
logging.debug(f'Total execution time: {time() - start_time} seconds')
147+
start_time = time()
148+
149+
# Collect all volumes and validate their metadata
150+
try:
151+
# Gather all files
152+
args.files = []
153+
for p in args.path:
154+
for root, dirs, files in os.walk(p):
155+
for filename in files:
156+
args.files.append(os.path.join(root, filename))
157+
158+
# Append any loose, explicitly defined paths to .RAW files
159+
args.files.extend([f for f in args.path if f.endswith('.raw')])
160+
161+
# Get all RAW files
162+
args.files = [f for f in args.files if f.endswith('.raw')]
163+
logging.debug(f"All files: {args.files}")
164+
args.files = list(set(args.files)) # remove duplicates
165+
logging.info(f"Found {len(args.files)} volume(s).")
166+
logging.debug(f"Unique files: {args.files}")
167+
168+
# Validate that a DAT file exists for each volume
169+
for fp in args.files:
170+
dat_fp = f"{os.path.splitext(fp)[0]}.dat" # .DAT filepath
171+
logging.debug(f"Validating DAT file: '{dat_fp}'")
172+
# Try to extract the dimensions to make sure that the file exists
173+
dat.read(dat_fp)
174+
except Exception as err:
175+
logging.error(err)
176+
else:
177+
# For each provided volume...
178+
pbar = tqdm(total=len(args.files), desc=f"Overall progress")
179+
for fp in args.files:
180+
logging.debug(f"Processing '{fp}'")
181+
# Extract slices for all volumes in provided folder
182+
extract_slices(args, fp)
183+
pbar.update()
184+
pbar.close()
185+
186+
logging.debug(f'Total execution time: {time() - start_time} seconds')

0 commit comments

Comments
 (0)