-
Notifications
You must be signed in to change notification settings - Fork 19
/
mm3_Subtract.py
executable file
·149 lines (127 loc) · 5.97 KB
/
mm3_Subtract.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env python3
from __future__ import print_function, division
import six
# import modules
import sys
import os
import time
import inspect
import argparse
import yaml
import traceback
import glob
from pprint import pprint # for human readable file output
try:
import cPickle as pickle
except:
import pickle
import multiprocessing
from multiprocessing import Pool #, Lock
import numpy as np
import warnings
from skimage.external import tifffile as tiff
# user modules
# realpath() will make your script run, even if you symlink it
cmd_folder = os.path.realpath(os.path.abspath(
os.path.split(inspect.getfile(inspect.currentframe()))[0]))
if cmd_folder not in sys.path:
sys.path.insert(0, cmd_folder)
# This makes python look for modules in ./external_lib
cmd_subfolder = os.path.realpath(os.path.abspath(
os.path.join(os.path.split(inspect.getfile(
inspect.currentframe()))[0], "external_lib")))
if cmd_subfolder not in sys.path:
sys.path.insert(0, cmd_subfolder)
# this is the mm3 module with all the useful functions and classes
import mm3_helpers as mm3
# when using this script as a function and not as a library the following will execute
if __name__ == "__main__":
'''mm3_Subtract.py averages empty channels and then subtractions them from channels with cells'''
parser = argparse.ArgumentParser(prog='python mm3_Subtract.py',
description='Subtract background from phase contrast and fluorescent channels.')
parser.add_argument('-f', '--paramfile', type=str,
required=True, help='Yaml file containing parameters.')
parser.add_argument('-o', '--fov', type=str,
required=False, help='List of fields of view to analyze. Input "1", "1,2,3", or "1-10", etc.')
parser.add_argument('-j', '--nproc', type=int,
required=False, help='Number of processors to use.')
parser.add_argument('-c', '--color', type=str,
required=False, help='Color plane to subtract. "c1", "c2", etc.')
namespace = parser.parse_args()
# Load the project parameters file
mm3.information('Loading experiment parameters.')
if namespace.paramfile:
param_file_path = namespace.paramfile
else:
mm3.warning('No param file specified. Using 100X template.')
param_file_path = 'yaml_templates/params_SJ110_100X.yaml'
p = mm3.init_mm3_helpers(param_file_path) # initialized the helper library
if namespace.fov:
if '-' in namespace.fov:
user_spec_fovs = range(int(namespace.fov.split("-")[0]),
int(namespace.fov.split("-")[1])+1)
else:
user_spec_fovs = [int(val) for val in namespace.fov.split(",")]
else:
user_spec_fovs = []
# number of threads for multiprocessing
if namespace.nproc:
p['num_analyzers'] = namespace.nproc
mm3.information('Using {} threads for multiprocessing.'.format(p['num_analyzers']))
# which color channel with which to do subtraction
if namespace.color:
sub_plane = namespace.color
else:
sub_plane = 'c1'
# Create folders for subtracted info if they don't exist
if p['output'] == 'TIFF':
if not os.path.exists(p['empty_dir']):
os.makedirs(p['empty_dir'])
if not os.path.exists(p['sub_dir']):
os.makedirs(p['sub_dir'])
# load specs file
specs = mm3.load_specs()
# make list of FOVs to process (keys of specs file)
fov_id_list = sorted([fov_id for fov_id in specs.keys()])
# remove fovs if the user specified so
if user_spec_fovs:
fov_id_list[:] = [fov for fov in fov_id_list if fov in user_spec_fovs]
mm3.information("Found %d FOVs to process." % len(fov_id_list))
# determine if we are doing fluorescence or phase subtraction, and set flags
if sub_plane == p['phase_plane']:
align = True # used when averaging empties
sub_method = 'phase' # used in subtract_fov_stack
else:
align = False
sub_method = 'fluor'
### Make average empty channels ###############################################################
if not p['subtract']['do_empties']:
mm3.information("Loading precalculated empties.")
pass # just skip this part and go to subtraction
else:
mm3.information("Calculating averaged empties for channel {}.".format(sub_plane))
need_empty = [] # list holds fov_ids of fov's that did not have empties
for fov_id in fov_id_list:
# send to function which will create empty stack for each fov.
averaging_result = mm3.average_empties_stack(fov_id, specs,
color=sub_plane, align=align)
# add to list for FOVs that need to be given empties from other FOvs
if not averaging_result:
need_empty.append(fov_id)
# deal with those problem FOVs without empties
have_empty = list(set(fov_id_list).difference(set(need_empty))) # fovs with empties
for fov_id in need_empty:
from_fov = min(have_empty, key=lambda x: abs(x-fov_id)) # find closest FOV with an empty
copy_result = mm3.copy_empty_stack(from_fov, fov_id, color=sub_plane)
### Subtract ##################################################################################
if p['subtract']['do_subtraction']:
mm3.information("Subtracting channels for channel {}.".format(sub_plane))
for fov_id in fov_id_list:
# send to function which will create empty stack for each fov.
subtraction_result = mm3.subtract_fov_stack(fov_id, specs,
color=sub_plane, method=sub_method)
mm3.information("Finished subtraction.")
# Else just end, they only wanted to do empty averaging.
else:
mm3.information("Skipping subtraction.")
pass