Mercurial > repos > lldelisle > upload_roi_and_measures_to_omero
comparison upload_omero_roi_results.py @ 0:d507ce86f0d0 draft default tip
planemo upload for repository https://github.com/lldelisle/tools-lldelisle/tree/master/tools/upload_roi_and_measures_to_omero commit 68de74426a3f93a240d64cb416f608ba7caca6eb
author | lldelisle |
---|---|
date | Fri, 16 Dec 2022 21:02:41 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d507ce86f0d0 |
---|---|
1 import argparse | |
2 import json | |
3 import os | |
4 import re | |
5 import tempfile | |
6 | |
7 import numpy as np | |
8 | |
9 import omero | |
10 from omero.gateway import BlitzGateway | |
11 from omero.rtypes import rdouble, rstring | |
12 | |
13 import pandas as pd | |
14 | |
15 file_base_name_exportedTIFF = re.compile(r"^.*__(\d+)__0__0__\d+__\d+$") | |
16 file_base_name_original = re.compile(r"^.*__(\d+)$") | |
17 | |
18 non_roi_value = -1 | |
19 | |
20 non_numeric_columns = ["Label", "Date", "Version", "IlastikProject", | |
21 "Preprocess"] | |
22 | |
23 | |
24 def get_image_id(image_file_name): | |
25 # Check the file name | |
26 # corresponds to the expected: | |
27 match = \ | |
28 file_base_name_exportedTIFF.findall(image_file_name.replace(".tiff", | |
29 "")) | |
30 if len(match) == 0: | |
31 match = \ | |
32 file_base_name_original.findall(image_file_name.replace(".tiff", | |
33 "")) | |
34 if len(match) == 0: | |
35 raise Exception(f"{image_file_name} does not match" | |
36 "the expected format") | |
37 # Get the image_id | |
38 image_id = int(match[0]) | |
39 return image_id | |
40 | |
41 | |
42 def get_omero_credentials(config_file): | |
43 if config_file is None: # IDR connection | |
44 omero_username = "public" | |
45 omero_password = "public" | |
46 else: # other omero instance | |
47 with open(config_file) as f: | |
48 cfg = json.load(f) | |
49 omero_username = cfg["username"] | |
50 omero_password = cfg["password"] | |
51 | |
52 if omero_username == "" or omero_password == "": | |
53 omero_username = "public" | |
54 omero_password = "public" | |
55 return (omero_username, omero_password) | |
56 | |
57 | |
58 def clean(image_id, omero_username, omero_password, omero_host, omero_secured, | |
59 verbose): | |
60 with BlitzGateway( | |
61 omero_username, omero_password, host=omero_host, secure=omero_secured | |
62 ) as conn: | |
63 roi_service = conn.getRoiService() | |
64 img = conn.getObject("Image", image_id) | |
65 rois = roi_service.findByImage(image_id, None, conn.SERVICE_OPTS).rois | |
66 # Delete existing rois | |
67 if len(rois) > 0: | |
68 if verbose: | |
69 print(f"Removing {len(rois)} existing ROIs.") | |
70 conn.deleteObjects("Roi", [roi.getId().val | |
71 for roi | |
72 in rois], | |
73 wait=True) | |
74 # Delete existing table named Results_from_Fiji | |
75 for ann in img.listAnnotations(): | |
76 if ann.OMERO_TYPE == omero.model.FileAnnotationI: | |
77 if ann.getFileName() == "Results_from_Fiji": | |
78 if verbose: | |
79 print("Removing the table Results_from_Fiji.") | |
80 conn.deleteObjects("OriginalFile", [ann.getFile().id], | |
81 wait=True) | |
82 | |
83 | |
84 def upload( | |
85 image_id, | |
86 df, | |
87 roi_files, | |
88 omero_username, | |
89 omero_password, | |
90 omero_host, | |
91 omero_secured, | |
92 verbose, | |
93 ): | |
94 with BlitzGateway( | |
95 omero_username, omero_password, host=omero_host, secure=omero_secured | |
96 ) as conn: | |
97 updateService = conn.getUpdateService() | |
98 img = conn.getObject("Image", image_id) | |
99 # Create ROIs: | |
100 roi_ids = [] | |
101 # roi_big_circle_ids = [] | |
102 # roi_spine_ids = [] | |
103 for i, ro_file in enumerate(roi_files): | |
104 # Create a polygon | |
105 my_poly = omero.model.PolygonI() | |
106 # Add the coordinates | |
107 with open(ro_file, "r") as f: | |
108 coos = f.readlines() | |
109 coos_formatted = ", ".join([line.strip().replace("\t", ",") | |
110 for line in coos]) | |
111 my_poly.setPoints(rstring(coos_formatted)) | |
112 # Add a name | |
113 my_poly.setTextValue(rstring("ROI" + str(i))) | |
114 # Create a omero ROI | |
115 my_new_roi = omero.model.RoiI() | |
116 my_new_roi.addShape(my_poly) | |
117 # Attach it to the image | |
118 my_new_roi.setImage(img._obj) | |
119 my_new_roi = updateService.saveAndReturnObject(my_new_roi) | |
120 roi_ids.append(my_new_roi.getId().val) | |
121 if verbose: | |
122 print(f"Created ROI{i} {my_new_roi.getId().val}.") | |
123 # Check if there is an elongation ROI associated: | |
124 if os.path.exists(ro_file.replace("roi_coordinates", | |
125 "elongation_rois")): | |
126 # Get the coordinates | |
127 with open( | |
128 ro_file.replace("roi_coordinates", "elongation_rois"), | |
129 "r" | |
130 ) as f: | |
131 all_coos = f.readlines() | |
132 # Get the circles coos | |
133 circles_coos = [line for line in all_coos | |
134 if len(line.split("\t")) == 3] | |
135 for j, circle_coo in enumerate(circles_coos): | |
136 # Create an ellipse | |
137 my_ellipse = omero.model.EllipseI() | |
138 # Get the characteristics from text file | |
139 xleft, ytop, width = [ | |
140 float(v) for v in circle_coo.strip().split("\t") | |
141 ] | |
142 # Add it to the ellipse | |
143 my_ellipse.setRadiusX(rdouble(width / 2.0)) | |
144 my_ellipse.setRadiusY(rdouble(width / 2.0)) | |
145 my_ellipse.setX(rdouble(xleft + width / 2)) | |
146 my_ellipse.setY(rdouble(ytop + width / 2)) | |
147 # Add a name | |
148 my_ellipse.setTextValue( | |
149 rstring("inscribedCircle" + str(i) + "_" + str(j)) | |
150 ) | |
151 # Create a omero ROI | |
152 my_new_roi = omero.model.RoiI() | |
153 my_new_roi.addShape(my_ellipse) | |
154 # Attach it to the image | |
155 my_new_roi.setImage(img._obj) | |
156 my_new_roi = updateService.saveAndReturnObject(my_new_roi) | |
157 if verbose: | |
158 print( | |
159 f"Created ROI inscribedCircle {i}_{j}:" | |
160 f"{my_new_roi.getId().val}." | |
161 ) | |
162 # I store the id of the first circle: | |
163 # if j == 0: | |
164 # roi_big_circle_ids.append(my_new_roi.getId().val) | |
165 if len(all_coos) > len(circles_coos): | |
166 # Create a polyline for the spine | |
167 my_poly = omero.model.PolylineI() | |
168 coos_formatted = ", ".join( | |
169 [ | |
170 line.strip().replace("\t", ",") | |
171 for line in all_coos[len(circles_coos):] | |
172 ] | |
173 ) | |
174 my_poly.setPoints(rstring(coos_formatted)) | |
175 # Add a name | |
176 my_poly.setTextValue(rstring("spine" + str(i))) | |
177 # Create a omero ROI | |
178 my_new_roi = omero.model.RoiI() | |
179 my_new_roi.addShape(my_poly) | |
180 # Attach it to the image | |
181 my_new_roi.setImage(img._obj) | |
182 my_new_roi = updateService.saveAndReturnObject(my_new_roi) | |
183 if verbose: | |
184 print(f"Created ROI spine{i}:" | |
185 f" {my_new_roi.getId().val}.") | |
186 # roi_spine_ids.append(my_new_roi.getId().val) | |
187 else: | |
188 if verbose: | |
189 print("No spine found") | |
190 # roi_spine_ids.append(non_roi_value) | |
191 # else: | |
192 # roi_big_circle_ids.append(non_roi_value) | |
193 # roi_spine_ids.append(non_roi_value) | |
194 | |
195 # Create the table: | |
196 table_name = "Results_from_Fiji" | |
197 columns = [] | |
198 for col_name in df.columns[1:]: | |
199 if col_name in non_numeric_columns: | |
200 columns.append(omero.grid.StringColumn(col_name, "", 256, [])) | |
201 else: | |
202 columns.append(omero.grid.DoubleColumn(col_name, "", [])) | |
203 | |
204 # From Claire's groovy: | |
205 # table_columns[size] = new TableDataColumn("Roi", size, ROIData) | |
206 columns.append(omero.grid.RoiColumn("Roi", "", [])) | |
207 # For the moment (20220729), | |
208 # the table support only one ROI column with link... | |
209 # if 'Elongation_index' in df.columns[1:]: | |
210 # columns.append(omero.grid.RoiColumn('Roi_maxCircle', '', [])) | |
211 # columns.append(omero.grid.RoiColumn('Roi_Spine', '', [])) | |
212 # columns.append(omero.grid.RoiColumn('Roi_main', '', [])) | |
213 | |
214 resources = conn.c.sf.sharedResources() | |
215 repository_id = \ | |
216 resources.repositories().descriptions[0].getId().getValue() | |
217 table = resources.newTable(repository_id, table_name) | |
218 table.initialize(columns) | |
219 | |
220 data = [] | |
221 for col_name in df.columns[1:]: | |
222 if col_name in non_numeric_columns: | |
223 data.append( | |
224 omero.grid.StringColumn( | |
225 col_name, "", 256, | |
226 df[col_name].astype("string").to_list() | |
227 ) | |
228 ) | |
229 else: | |
230 data.append( | |
231 omero.grid.DoubleColumn(col_name, "", | |
232 df[col_name].to_list()) | |
233 ) | |
234 data.append(omero.grid.RoiColumn("Roi", "", roi_ids)) | |
235 # if verbose: | |
236 # print("Columns are " + " ".join(df.columns[1:])) | |
237 # if 'Elongation_index' in df.columns[1:]: | |
238 # if verbose: | |
239 # print("Adding 2 rois columns") | |
240 # print(roi_ids) | |
241 # print(roi_big_circle_ids) | |
242 # data.append(omero.grid.RoiColumn('Roi_maxCircle', '', | |
243 # roi_big_circle_ids)) | |
244 # data.append(omero.grid.RoiColumn('Roi_Spine', '', | |
245 # roi_spine_ids)) | |
246 # data.append(omero.grid.RoiColumn('Roi_main', '', roi_ids)) | |
247 | |
248 table.addData(data) | |
249 orig_file = table.getOriginalFile() | |
250 table.close() | |
251 # when we are done, close. | |
252 | |
253 # Load the table as an original file | |
254 | |
255 orig_file_id = orig_file.id.val | |
256 # ...so you can attach this data to an object e.g. Image | |
257 file_ann = omero.model.FileAnnotationI() | |
258 # use unloaded OriginalFileI | |
259 file_ann.setFile(omero.model.OriginalFileI(orig_file_id, False)) | |
260 file_ann = updateService.saveAndReturnObject(file_ann) | |
261 link = omero.model.ImageAnnotationLinkI() | |
262 link.setParent(omero.model.ImageI(image_id, False)) | |
263 link.setChild(omero.model.FileAnnotationI( | |
264 file_ann.getId().getValue(), False | |
265 )) | |
266 updateService.saveAndReturnObject(link) | |
267 if verbose: | |
268 print("Successfully created a Table with results.") | |
269 | |
270 | |
271 def scan_and_upload( | |
272 roi_directory, | |
273 summary_results, | |
274 omero_username, | |
275 omero_password, | |
276 omero_host="idr.openmicroscopy.org", | |
277 omero_secured=False, | |
278 verbose=False, | |
279 ): | |
280 # First get the summary results | |
281 full_df = pd.read_csv(summary_results) | |
282 # Loop over the image names | |
283 for image_file_name in np.unique(full_df["Label"]): | |
284 # Get the image_id | |
285 image_id = get_image_id(image_file_name) | |
286 if verbose: | |
287 print(f"Image:{image_id} is in the table." | |
288 " Cleaning old results.") | |
289 clean( | |
290 image_id, omero_username, omero_password, omero_host, | |
291 omero_secured, verbose | |
292 ) | |
293 # Subset the result to the current image | |
294 df = full_df[full_df["Label"] == image_file_name] | |
295 if np.isnan(df["Area"].to_list()[0]): | |
296 # No ROI has been detected | |
297 if verbose: | |
298 print("No ROI was found.") | |
299 continue | |
300 n_rois = df.shape[0] | |
301 if verbose: | |
302 print(f"I found {n_rois} measurements.") | |
303 # Check the corresponding rois exists | |
304 roi_files = [ | |
305 os.path.join( | |
306 roi_directory, | |
307 image_file_name.replace(".tiff", "_tiff") | |
308 + "__" | |
309 + str(i) | |
310 + "_roi_coordinates.txt", | |
311 ) | |
312 for i in range(n_rois) | |
313 ] | |
314 for ro_file in roi_files: | |
315 if not os.path.exists(ro_file): | |
316 raise Exception(f"Could not find {ro_file}") | |
317 upload( | |
318 image_id, | |
319 df, | |
320 roi_files, | |
321 omero_username, | |
322 omero_password, | |
323 omero_host, | |
324 omero_secured, | |
325 verbose, | |
326 ) | |
327 # Update the full_df with image id: | |
328 full_df["id"] = [ | |
329 get_image_id(image_file_name) | |
330 for image_file_name in full_df["Label"] | |
331 ] | |
332 # Attach it to the dataset: | |
333 with BlitzGateway( | |
334 omero_username, omero_password, host=omero_host, | |
335 secure=omero_secured | |
336 ) as conn: | |
337 full_df["dataset_id"] = [ | |
338 a.id | |
339 for id in full_df["id"] | |
340 for a in conn.getObject("Image", id).getAncestry() | |
341 if a.OMERO_CLASS == "Dataset" | |
342 ] | |
343 dir = tempfile.mkdtemp() | |
344 for dataset_id in np.unique(full_df["dataset_id"]): | |
345 df = full_df[full_df["dataset_id"] == dataset_id] | |
346 first_date = df["Date"].to_list()[0] | |
347 file_to_upload = os.path.join( | |
348 dir, "Results_from_Fiji_" + first_date + ".csv" | |
349 ) | |
350 df.to_csv(file_to_upload, index=False) | |
351 dataset = conn.getObject("Dataset", dataset_id) | |
352 # create the original file and file annotation | |
353 # (uploads the file etc.) | |
354 # namespace = "my.custom.demo.namespace" | |
355 file_ann = conn.createFileAnnfromLocalFile( | |
356 file_to_upload | |
357 ) # , mimetype="text/plain", ns=namespace, desc=None) | |
358 print( | |
359 "Attaching FileAnnotation to Dataset: ", | |
360 "File ID:", | |
361 file_ann.getId(), | |
362 ",", | |
363 file_ann.getFile().getName(), | |
364 "Size:", | |
365 file_ann.getFile().getSize(), | |
366 ) | |
367 dataset.linkAnnotation(file_ann) # link it to dataset. | |
368 | |
369 | |
370 if __name__ == "__main__": | |
371 p = argparse.ArgumentParser() | |
372 p.add_argument("-oh", "--omero-host", type=str, | |
373 default="idr.openmicroscopy.org") | |
374 p.add_argument("--omero-secured", action="store_true", default=True) | |
375 p.add_argument("-cf", "--config-file", dest="config_file", | |
376 default=None) | |
377 p.add_argument("--rois", type=str, default=None) | |
378 p.add_argument("--summaryResults", type=str, default=None) | |
379 p.add_argument("--verbose", action="store_true") | |
380 args = p.parse_args() | |
381 scan_and_upload( | |
382 args.rois, | |
383 args.summaryResults, | |
384 *get_omero_credentials(args.config_file), | |
385 omero_host=args.omero_host, | |
386 omero_secured=args.omero_secured, | |
387 verbose=args.verbose, | |
388 ) |