|
8 | 8 |
|
9 | 9 |
|
10 | 10 | def nd2_to_binary(ops): |
11 | | - """ finds nd2 files and writes them to binaries |
| 11 | + """finds nd2 files and writes them to binaries |
12 | 12 |
|
13 | 13 | Parameters |
14 | 14 | ---------- |
@@ -39,72 +39,83 @@ def nd2_to_binary(ops): |
39 | 39 | for file_name in fs: |
40 | 40 | # open nd2 |
41 | 41 | nd2_file = nd2.ND2File(file_name) |
42 | | - im = nd2_file.asarray() |
| 42 | + nd2_dims = {k: i for i, k in enumerate(nd2_file.sizes)} |
43 | 43 |
|
44 | | - # expand dimensions to have [Time (T), Depth (Z), Channel (C), Height (Y), Width (X)]. |
45 | | - if 'T' not in nd2_file.sizes: |
46 | | - im = np.expand_dims(im, 0) |
47 | | - if 'C' not in nd2_file.sizes: |
48 | | - im = np.expand_dims(im, -3) |
49 | | - if 'Z' not in nd2_file.sizes: |
50 | | - im = np.expand_dims(im, 1) |
| 44 | + valid_dimensions = "TZCYX" |
| 45 | + assert set(nd2_dims) <= set( |
| 46 | + valid_dimensions |
| 47 | + ), f"Unknown dimensions {set(nd2_dims)-set(valid_dimensions)} in file {file_name}." |
51 | 48 |
|
52 | | - nplanes = nd2_file.sizes['Z'] if 'Z' in nd2_file.sizes else 1 |
53 | | - nchannels = nd2_file.sizes['C'] if 'C' in nd2_file.sizes else 1 |
54 | | - nframes = nd2_file.sizes['T'] if 'T' in nd2_file.sizes else 1 |
| 49 | + # Sort the dimensions in the order of TZCYX, skipping the missing ones. |
| 50 | + im = nd2_file.asarray().transpose( |
| 51 | + [nd2_dims[x] for x in valid_dimensions if x in nd2_dims] |
| 52 | + ) |
55 | 53 |
|
56 | | - iblocks = np.arange(0, nframes, ops1[0]['batch_size']) |
| 54 | + # Expand array to include the missing dimensions. |
| 55 | + for i, dim in enumerate("TZC"): |
| 56 | + if dim not in nd2_dims: |
| 57 | + im = np.expand_dims(im, i) |
| 58 | + |
| 59 | + nplanes = nd2_file.sizes["Z"] if "Z" in nd2_file.sizes else 1 |
| 60 | + nchannels = nd2_file.sizes["C"] if "C" in nd2_file.sizes else 1 |
| 61 | + nframes = nd2_file.sizes["T"] if "T" in nd2_file.sizes else 1 |
| 62 | + |
| 63 | + iblocks = np.arange(0, nframes, ops1[0]["batch_size"]) |
57 | 64 | if iblocks[-1] < nframes: |
58 | 65 | iblocks = np.append(iblocks, nframes) |
59 | 66 |
|
60 | 67 | if nchannels > 1: |
61 | | - nfunc = ops1[0]['functional_chan'] - 1 |
| 68 | + nfunc = ops1[0]["functional_chan"] - 1 |
62 | 69 | else: |
63 | 70 | nfunc = 0 |
64 | 71 |
|
65 | | - if im.dtype.type == np.uint16: |
66 | | - im = (im // 2).astype(np.int16) |
67 | | - elif im.dtype.type == np.int32: |
68 | | - im = (im // 2).astype(np.int16) |
69 | | - elif im.dtype.type != np.int16: |
70 | | - im = im.astype(np.int16) |
| 72 | + assert im.max() < 32768 and im.min() >= -32768, "image data is out of range" |
| 73 | + im = im.astype(np.int16) |
71 | 74 |
|
72 | 75 | # loop over all frames |
73 | 76 | for ichunk, onset in enumerate(iblocks[:-1]): |
74 | 77 | offset = iblocks[ichunk + 1] |
75 | 78 | im_p = np.array(im[onset:offset, :, :, :, :]) |
76 | | - im2mean = im_p.mean(axis = 0).astype(np.float32) / len(iblocks) |
| 79 | + im2mean = im_p.mean(axis=0).astype(np.float32) / len(iblocks) |
77 | 80 | for ichan in range(nchannels): |
78 | 81 | nframes = im_p.shape[0] |
79 | 82 | im2write = im_p[:, :, ichan, :, :] |
80 | 83 | for j in range(0, nplanes): |
81 | 84 | if iall == 0: |
82 | | - ops1[j]['meanImg'] = np.zeros((im_p.shape[3], im_p.shape[4]), np.float32) |
83 | | - if nchannels>1: |
84 | | - ops1[j]['meanImg_chan2'] = np.zeros((im_p.shape[3], im_p.shape[4]), np.float32) |
85 | | - ops1[j]['nframes'] = 0 |
| 85 | + ops1[j]["meanImg"] = np.zeros( |
| 86 | + (im_p.shape[3], im_p.shape[4]), np.float32 |
| 87 | + ) |
| 88 | + if nchannels > 1: |
| 89 | + ops1[j]["meanImg_chan2"] = np.zeros( |
| 90 | + (im_p.shape[3], im_p.shape[4]), np.float32 |
| 91 | + ) |
| 92 | + ops1[j]["nframes"] = 0 |
86 | 93 | if ichan == nfunc: |
87 | | - ops1[j]['meanImg'] += np.squeeze(im2mean[j, ichan, :, :]) |
88 | | - reg_file[j].write(bytearray(im2write[:, j, :, :].astype('int16'))) |
| 94 | + ops1[j]["meanImg"] += np.squeeze(im2mean[j, ichan, :, :]) |
| 95 | + reg_file[j].write( |
| 96 | + bytearray(im2write[:, j, :, :].astype("int16")) |
| 97 | + ) |
89 | 98 | else: |
90 | | - ops1[j]['meanImg_chan2'] += np.squeeze(im2mean[j, ichan, :, :]) |
91 | | - reg_file_chan2[j].write(bytearray(im2write[:, j, :, :].astype('int16'))) |
92 | | - |
93 | | - ops1[j]['nframes'] += im2write.shape[0] |
| 99 | + ops1[j]["meanImg_chan2"] += np.squeeze(im2mean[j, ichan, :, :]) |
| 100 | + reg_file_chan2[j].write( |
| 101 | + bytearray(im2write[:, j, :, :].astype("int16")) |
| 102 | + ) |
| 103 | + |
| 104 | + ops1[j]["nframes"] += im2write.shape[0] |
94 | 105 | ik += nframes |
95 | 106 | iall += nframes |
96 | | - |
| 107 | + |
97 | 108 | nd2_file.close() |
98 | 109 |
|
99 | 110 | # write ops files |
100 | | - do_registration = ops1[0]['do_registration'] |
| 111 | + do_registration = ops1[0]["do_registration"] |
101 | 112 | for ops in ops1: |
102 | | - ops['Ly'] = im.shape[3] |
103 | | - ops['Lx'] = im.shape[4] |
| 113 | + ops["Ly"] = im.shape[3] |
| 114 | + ops["Lx"] = im.shape[4] |
104 | 115 | if not do_registration: |
105 | | - ops['yrange'] = np.array([0, ops['Ly']]) |
106 | | - ops['xrange'] = np.array([0, ops['Lx']]) |
107 | | - np.save(ops['ops_path'], ops) |
| 116 | + ops["yrange"] = np.array([0, ops["Ly"]]) |
| 117 | + ops["xrange"] = np.array([0, ops["Lx"]]) |
| 118 | + np.save(ops["ops_path"], ops) |
108 | 119 | # close all binary files and write ops files |
109 | 120 | for j in range(0, nplanes): |
110 | 121 | reg_file[j].close() |
|
0 commit comments