Advertisement
Guest User

Untitled

a guest
Feb 21st, 2017
70
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 28.00 KB | None | 0 0
  1. '''<b>ExportToCellH5</b> exports measurements, objects and object relationships,
  2. and images to the CellH5 data format.
  3. <hr>
  4. <h4>File structure</h4>
  5. In multiprocessing-mode, CellProfiler will create satellite .cellh5 files that
  6. are linked to the one that you specify using this module. The only thing
  7. to note is that you must keep all .cellh5 files that are generated together
  8. if you move them to a new folder.
  9. '''
  10.  
  11. import os
  12. import tempfile
  13.  
  14. import h5py
  15. import numpy as np
  16. import scipy.ndimage
  17.  
  18. import cellprofiler.module as cpm
  19. import cellprofiler.measurement as cpmeas
  20. import cellprofiler.setting as cps
  21. from cellprofiler.gui.help import \
  22. USING_METADATA_TAGS_REF, USING_METADATA_HELP_REF
  23. from cellprofiler.modules.identify import R_PARENT
  24. from cellprofiler.preferences import \
  25. IO_FOLDER_CHOICE_HELP_TEXT, IO_WITH_METADATA_HELP_TEXT
  26. from cellprofiler.setting import YES, NO
  27. from cellprofiler.gui.help import \
  28. USING_METADATA_TAGS_REF, USING_METADATA_HELP_REF
  29. import cellh5
  30. import cellh5.cellh5write
  31. import numpy as np
  32.  
  33. OFF_OBJECTS_COUNT = 0
  34. OFF_IMAGES_COUNT = 1
  35.  
  36. COLORS = [("Red", "0xFF0000"),
  37. ("Green", "0x00FF00"),
  38. ("Blue", "0x0000FF")]
  39.  
  40.  
  41. class ExportToCellH5(cpm.Module):
  42. #
  43. # TODO: model z and t. Currently, CellProfiler would analyze each
  44. # stack plane independently. I think the easiest way to handle
  45. # z and t would be to add them to the site path if they are
  46. # used in the experiment (e.g. a time series would have a
  47. # path of "/plate/well/site/time")
  48. #
  49. # I can add two more optional metadata keys that would let
  50. # users capture this.
  51. #
  52. # The more-complicated choice would be to store the data in a
  53. # stack which would mean reworking the indices in every segmentation
  54. # after the first. There are some legacy measurements that are
  55. # really object numbers, so these would require a lot of work
  56. # to get right. Also, the resulting segmentations are a little
  57. # artificial since they seem to say that every object is one
  58. # pixel thick in the T or Z direction.
  59. #
  60.  
  61. module_name = "ExportToCellH5"
  62. variable_revision_number = 1
  63. category = ["File Processing"]
  64.  
  65. SUBFILE_KEY = "subfile"
  66. IGNORE_METADATA = "None"
  67.  
  68. def create_settings(self):
  69. '''Create the settings for the ExportToCellH5 module'''
  70. self.directory = cps.DirectoryPath(
  71. "Output file location",
  72. doc="""
  73. This setting lets you choose the folder for the output files.
  74. %(IO_FOLDER_CHOICE_HELP_TEXT)s
  75. """ % globals())
  76.  
  77. def get_directory_fn():
  78. '''Get the directory for the CellH5 file'''
  79. return self.directory.get_absolute_path()
  80.  
  81. def set_directory_fn(path):
  82. dir_choice, custom_path = self.directory.get_parts_from_path(path)
  83. self.directory.join_parts(dir_choice, custom_path)
  84.  
  85. self.file_name = cps.FilenameText(
  86. "Output file name", "DefaultOut.ch5",
  87. get_directory_fn=get_directory_fn,
  88. set_directory_fn=set_directory_fn,
  89. metadata=True,
  90. browse_msg="Choose CellH5 file",
  91. mode=cps.FilenameText.MODE_APPEND,
  92. exts=[("CellH5 file (*.cellh5)", "*.ch5"),
  93. ("HDF5 file (*.h5)", "*.h5"),
  94. ("All files (*.*", "*.*")],
  95. doc="""
  96. This setting lets you name your CellH5 file. If you choose an
  97. existing file, CellProfiler will add new data to the file
  98. or overwrite existing locations.
  99. <p>%(IO_WITH_METADATA_HELP_TEXT)s %(USING_METADATA_TAGS_REF)s.
  100. For instance, if you have a metadata tag named
  101. "Plate", you can create a per-plate folder by selecting one the subfolder options
  102. and then specifying the subfolder name as "\g<Plate>". The module will
  103. substitute the metadata values for the current image set for any metadata tags in the
  104. folder name.%(USING_METADATA_HELP_REF)s.</p>
  105.  
  106. """ % globals())
  107. self.overwrite_ok = cps.Binary(
  108. "Overwrite existing data without warning?", False,
  109. doc="""
  110. Select <i>%(YES)s</i> to automatically overwrite any existing data
  111. for a site. Select <i>%(NO)s</i> to be prompted first.
  112.  
  113. If you are running the pipeline on a computing cluster,
  114. select <i>%(YES)s</i> unless you want execution to stop because you
  115. will not be prompted to intervene. Also note that two instances
  116. of CellProfiler cannot write to the same file at the same time,
  117. so you must ensure that separate names are used on a cluster.
  118. """ % globals())
  119. self.repack = cps.Binary(
  120. "Repack after analysis", True,
  121. doc="""
  122. This setting determines whether CellProfiler in multiprocessing mode
  123. repacks the data at the end of analysis. If you select <i>%(YES)s</i>,
  124. CellProfiler will combine all of the satellite files into a single
  125. file upon completion. This option requires some extra temporary disk
  126. space and takes some time at the end of analysis, but results in
  127. a single file which may occupy less disk space. If you select
  128. <i>%(NO)s</i>, CellProfiler will create a master file using the
  129. name that you give and this file will have links to individual
  130. data files that contain the actual data. Using the data generated by
  131. this option requires that you keep the master file and the linked
  132. files together when copying them to a new folder.
  133. """ % globals())
  134. self.plate_metadata = cps.Choice(
  135. "Plate metadata", [], value="Plate",
  136. choices_fn=self.get_metadata_choices,
  137. doc="""
  138. This is the metadata tag that identifies the plate name of
  139. the images for the current cycle. Choose <i>None</i> if
  140. your assay does not have metadata for plate name. If your
  141. assay is slide-based, you can use a metadata item that identifies
  142. the slide as the choice for this setting and set the well
  143. and site metadata items to <i>None</i>.""")
  144. self.well_metadata = cps.Choice(
  145. "Well metadata", [], value="Well",
  146. choices_fn=self.get_metadata_choices,
  147. doc="""This is the metadata tag that identifies the well name
  148. for the images in the current cycle. Choose <i>None</i> if
  149. your assay does not have metadata for the well.""")
  150. self.site_metadata = cps.Choice(
  151. "Site metadata", [], value="Site",
  152. choices_fn=self.get_metadata_choices,
  153. doc=
  154. """This is the metadata tag that identifies the site name
  155. for the images in the current cycle. Choose <i>None</i> if
  156. your assay doesn't divide wells up into sites or if this
  157. tag is not required for other reasons.""")
  158. self.divider = cps.Divider()
  159. self.wants_to_choose_measurements = cps.Binary(
  160. "Choose measurements?", False,
  161. doc="""
  162. This setting lets you choose between exporting all measurements or
  163. just the ones that you choose. Select <i>%(YES)s</i> to pick the
  164. measurements to be exported. Select <i>%(NO)s</i> to automatically
  165. export all measurements available at this stage of the pipeline.
  166. """ % globals())
  167. self.measurements = cps.MeasurementMultiChoice(
  168. "Measurements to export",
  169. doc="""
  170. <i>(Used only if choosing measurements.)</i>
  171. <br>
  172. This setting lets you choose individual measurements to be exported.
  173. Check the measurements you want to export.
  174. """)
  175. self.objects_to_export = []
  176. self.add_objects_button = cps.DoSomething(
  177. "Add objects to export", "Add objects",
  178. self.add_objects)
  179. self.images_to_export = []
  180. self.add_image_button = cps.DoSomething(
  181. "Add an image to export", "Add image",
  182. self.add_image)
  183. self.objects_count = cps.HiddenCount(self.objects_to_export)
  184. self.images_count = cps.HiddenCount(self.images_to_export)
  185.  
  186. def add_objects(self, can_delete=True):
  187. group = cps.SettingsGroup()
  188. self.objects_to_export.append(group)
  189. group.append(
  190. "objects_name",
  191. cps.ObjectNameSubscriber(
  192. "Objects name", value="Nuclei",
  193. doc="""
  194. This setting lets you choose the objects you want to export.
  195. <b>ExportToCellH5</b> will write the segmentation of the objects
  196. to your CellH5 file so that they can be saved and used by other
  197. applications that support the format.
  198. """))
  199. group.append(
  200. "Remover",
  201. cps.RemoveSettingButton(
  202. "Remove the objects above", "Remove",
  203. self.objects_to_export, group))
  204.  
  205. def add_image(self, can_delete=True):
  206. group = cps.SettingsGroup()
  207. self.images_to_export.append(group)
  208. group.append("image_name",
  209. cps.ImageNameSubscriber(
  210. "Image name", value="DNA",
  211. doc="""
  212. This setting lets you choose the images you want to export.
  213. <b>ExportToCellH5</b> will write the image
  214. to your CellH5 file so that it can be used by other
  215. applications that support the format.
  216. """
  217. ))
  218. group.append("remover",
  219. cps.RemoveSettingButton(
  220. "Remove the image above", "Remove",
  221. self.objects_to_export, group))
  222.  
  223. def get_metadata_choices(self, pipeline):
  224. columns = pipeline.get_measurement_columns(self)
  225. choices = [self.IGNORE_METADATA]
  226. for column in columns:
  227. object_name, feature_name, column_type = column[:3]
  228. if object_name == cpmeas.IMAGE and \
  229. column_type.startswith(cpmeas.COLTYPE_VARCHAR) and \
  230. feature_name.startswith(cpmeas.C_METADATA + "_"):
  231. choices.append(feature_name.split("_", 1)[1])
  232. return choices
  233.  
  234. def settings(self):
  235. result = [
  236. self.objects_count, self.images_count,
  237. self.directory, self.file_name, self.overwrite_ok, self.repack,
  238. self.plate_metadata, self.well_metadata, self.site_metadata,
  239. self.wants_to_choose_measurements, self.measurements]
  240. for objects_group in self.objects_to_export:
  241. result += objects_group.pipeline_settings()
  242. for images_group in self.images_to_export:
  243. result += images_group.pipeline_settings()
  244. return result
  245.  
  246. def visible_settings(self):
  247. result = [
  248. self.directory, self.file_name, self.overwrite_ok, self.repack,
  249. self.plate_metadata, self.well_metadata, self.site_metadata,
  250. self.divider, self.wants_to_choose_measurements]
  251. if self.wants_to_choose_measurements:
  252. result.append(self.measurements)
  253.  
  254. for group in self.objects_to_export:
  255. result += group.visible_settings()
  256. result.append(self.add_objects_button)
  257. for group in self.images_to_export:
  258. result += group.visible_settings()
  259. result.append(self.add_image_button)
  260. return result
  261.  
  262. def get_path_to_master_file(self, measurements):
  263. return os.path.join(self.directory.get_absolute_path(measurements),
  264. self.file_name.value)
  265.  
  266. def get_site_path(self, workspace, image_number):
  267. '''Get the plate / well / site tuple that identifies a field of view
  268.  
  269. workspace - workspace for the analysis containing the metadata
  270. measurements to be mined.
  271.  
  272. image_number - the image number for the field of view
  273.  
  274. returns a tuple which can be used for the hierarchical path
  275. to the group for a particular field of view
  276. '''
  277. m = workspace.measurements
  278. path = []
  279. for setting in self.plate_metadata, self.well_metadata, self.site_metadata:
  280. if setting.value == self.IGNORE_METADATA:
  281. path.append("NA")
  282. else:
  283. feature = "_".join((cpmeas.C_METADATA, setting.value))
  284. path.append(m[cpmeas.IMAGE, feature, image_number])
  285. return tuple(path)
  286.  
  287. def get_subfile_name(self, workspace):
  288. '''Contact the UI to find the cellh5 file to use to store results
  289.  
  290. Internally, this tells the UI to create a link from the master file
  291. to the plate / well / site group that will be used to store results.
  292. Then, the worker writes into that file.
  293. '''
  294. master_file_name = self.get_path_to_master_file(workspace.measurements)
  295. path = self.get_site_path(
  296. workspace,
  297. workspace.measurements.image_set_number)
  298. return workspace.interaction_request(
  299. self, master_file_name, os.getpid(), path, headless_ok=True)
  300.  
  301. def handle_interaction(self, master_file, pid, path):
  302. '''Handle an analysis worker / UI interaction
  303.  
  304. This function is used to coordinate linking a group in the master file
  305. with a group in a subfile that is reserved for a particular
  306. analysis worker. Upon entry, the worker should be sure to have
  307. flushed and closed its subfile.
  308.  
  309. master_file - the master cellh5 file which has links to groups
  310. for each field of view
  311. pid - the process ID or other unique identifier of the worker
  312. talking to the master
  313. path - The combination of (Plate, Well, Site) that should be used
  314. as the folder path to the data.
  315.  
  316. returns the name of the subfile to be used. After return, the
  317. subfile has been closed by the UI and a link has been established
  318. to the group named by the path.
  319. '''
  320. master_dict = self.get_dictionary().setdefault(master_file, {})
  321. if pid not in master_dict:
  322. md_head, md_tail = os.path.splitext(master_file)
  323. subfile = "%s_%s%s" % (md_head, str(pid), md_tail)
  324. master_dict[pid] = subfile
  325. else:
  326. subfile = master_dict[pid]
  327.  
  328. ch5_master = cellh5.cellh5write.CH5MasterFile(master_file, "a")
  329. try:
  330. ch5_master.add_link_to_coord(self._to_ch5_coord(*path), subfile)
  331. finally:
  332. ch5_master.close()
  333.  
  334. return subfile
  335.  
  336. def _to_ch5_coord(self, plate, well, site):
  337. return cellh5.CH5PositionCoordinate(plate, well, site)
  338.  
  339. def run(self, workspace):
  340. m = workspace.measurements
  341. object_set = workspace.object_set
  342. #
  343. # get plate / well / site as tuple
  344. #
  345. path = self.get_site_path(workspace, m.image_set_number)
  346. subfile_name = self.get_subfile_name(workspace)
  347.  
  348. ### create CellH5 file
  349. with cellh5.cellh5write.CH5FileWriter(subfile_name, mode="a") as c5_file:
  350. ### add Postion (==plate, well, site) triple
  351. c5_pos = c5_file.add_position(self._to_ch5_coord(*path))
  352.  
  353. for ch_idx, object_group in enumerate(self.objects_to_export):
  354. objects_name = object_group.objects_name.value
  355. objects = object_set.get_objects(objects_name)
  356. labels = objects.segmented
  357. if ch_idx == 0:
  358. ### get shape of 5D cube
  359. shape5D = (len(self.objects_to_export), 1, 1,
  360. labels.shape[0], labels.shape[1])
  361. dtype5D = np.uint16
  362.  
  363. ### create lablel writer for incremental writing
  364. c5_label_writer = c5_pos.add_label_image(shape=shape5D, dtype=dtype5D)
  365. c5_label_def = cellh5.cellh5write.CH5ImageRegionDefinition()
  366.  
  367. c5_label_writer.write(labels, c=ch_idx, t=0, z=0)
  368. c5_label_def.add_row(region_name=objects_name, channel_idx=ch_idx)
  369.  
  370. if len(self.objects_to_export) > 0:
  371. ### finalize the writer
  372. c5_label_writer.write_definition(c5_label_def)
  373. c5_label_writer.finalize()
  374.  
  375. n_channels = 0
  376. max_scale = 1
  377. max_i = 1
  378. max_j = 1
  379. for image_group in self.images_to_export:
  380. image = m.get_image(image_group.image_name.value)
  381. pixel_data = image.pixel_data
  382. if pixel_data.ndim == 3:
  383. n_channels += min(pixel_data.shape[2], 3)
  384. else:
  385. n_channels += 1
  386. max_scale = max(image.scale, max_scale)
  387. max_i = max(pixel_data.shape[0], max_i)
  388. max_j = max(pixel_data.shape[1], max_j)
  389.  
  390. ### get shape of 5D cube
  391. shape5D = (n_channels, 1, 1, max_i, max_j)
  392. for dtype in (np.uint8, np.uint16, np.uint32, np.uint64):
  393. if max_scale <= np.iinfo(dtype).max:
  394. dtype5D = dtype
  395. break
  396.  
  397. ### create image writer for incremental writing
  398. c5_image_writer = c5_pos.add_image(shape=shape5D, dtype=dtype5D)
  399. c5_image_def = cellh5.cellh5write.CH5ImageChannelDefinition()
  400.  
  401. ch_idx = 0
  402. for image_group in self.images_to_export:
  403. image_name = image_group.image_name.value
  404. image = m.get_image(image_name).pixel_data
  405. scale = m.get_image(image_name).scale
  406. if not np.issubdtype(image.dtype, np.dtype(bool).type):
  407. if scale == 1:
  408. scale = max_scale
  409. image = image * scale
  410. if image.ndim == 3:
  411. for c in range(min(image.shape[2], 3)):
  412. color_name, html_color = COLORS[c]
  413. c5_image_writer.write(
  414. image[:, :, c].astype(dtype5D),
  415. c=ch_idx, t=0, z=0)
  416. c5_image_def.add_row(
  417. channel_name="_".join((image_name, color_name)),
  418. description="%s %s intensity" %
  419. (image_name, color_name),
  420. is_physical=True,
  421. voxel_size=(1, 1, 1),
  422. color=html_color)
  423. ch_idx += 1
  424. else:
  425. c5_image_writer.write(
  426. image.astype(dtype5D),
  427. c=ch_idx, t=0, z=0)
  428. c5_image_def.add_row(
  429. channel_name=image_name,
  430. description=image_name,
  431. is_physical=True,
  432. voxel_size=(1, 1, 1),
  433. color="0xFFFFFF")
  434. ch_idx += 1
  435. c5_image_writer.write_definition(c5_image_def)
  436. c5_image_writer.finalize()
  437.  
  438. columns = workspace.pipeline.get_measurement_columns(self)
  439. if self.wants_to_choose_measurements:
  440. to_keep = set([
  441. (self.measurements.get_measurement_object(s),
  442. self.measurements.get_measurement_feature(s))
  443. for s in self.measurements.selections])
  444.  
  445. def keep(column):
  446. return (column[0], column[1]) in to_keep
  447.  
  448. columns = filter(keep, columns)
  449. #
  450. # I'm breaking the data up into the most granular form so that
  451. # it's clearer how it's organized. I'm expecting that you would
  452. # organize it differently when actually storing.
  453. #
  454.  
  455. ### 0) extract object information (i.e. object_label_no)
  456. ### 1) extract all single cell features and write it as feature matrix (for e.g. classification)
  457. ### 2) extract Center
  458. ### 3) create artifical Bounding box... usefull for displaying it in fiji lateron
  459. ### 4) Don't see the point of features extracted on "Image" the only real and useful feature there is "Count" which can be deduced from single cell information
  460.  
  461. ### 0) and 1) filter columns for cellular features
  462. feature_cols = filter(
  463. lambda xxx: (xxx[0] not in (cpmeas.EXPERIMENT, cpmeas.IMAGE)) and
  464. m.has_feature(xxx[0], xxx[1]), columns)
  465.  
  466. ### iterate over objects to export
  467. for ch_idx, object_group in enumerate(self.objects_to_export):
  468. objects_name = object_group.objects_name.value
  469. objects = object_set.get_objects(objects_name)
  470.  
  471. ### find features for that object
  472. feature_cols_per_object = filter(lambda xxx: xxx[0] == objects_name, feature_cols)
  473.  
  474. c5_object_writer = c5_pos.add_region_object(objects_name)
  475. object_labels = objects.indices
  476.  
  477. c5_object_writer.write(t=0, object_labels=np.array(object_labels))
  478. c5_object_writer.write_definition()
  479. c5_object_writer.finalize()
  480.  
  481. ### iterate over all cellular feature to get feature matrix
  482.  
  483. n_features = len(feature_cols_per_object)
  484. if n_features > 0:
  485. feature_names = []
  486. feature_matrix = []
  487. for column in feature_cols_per_object:
  488. object_name, feature_name = column[:2]
  489. values = m[object_name, feature_name]
  490.  
  491. feature_names.append(feature_name)
  492. feature_matrix.append(values[:, np.newaxis])
  493.  
  494. feature_matrix = np.concatenate(feature_matrix, axis=1)
  495.  
  496. c5_feature_writer = c5_pos.add_object_feature_matrix(
  497. object_name=object_name,
  498. feature_name="object_features",
  499. n_features=n_features, dtype=np.float32)
  500. c5_feature_writer.write(feature_matrix)
  501. c5_feature_writer.write_definition(feature_names)
  502. c5_feature_writer.finalize()
  503.  
  504. ### iterate over Location to create bounding_box and center
  505. c5_bbox = c5_pos.add_object_bounding_box(
  506. object_name=objects_name)
  507.  
  508. if objects.count > 0:
  509. ijv = objects.ijv
  510. min_x = scipy.ndimage.minimum(
  511. ijv[:, 1], ijv[:, 2], objects.indices)
  512. max_x = scipy.ndimage.maximum(
  513. ijv[:, 1], ijv[:, 2], objects.indices)
  514. min_y = scipy.ndimage.minimum(
  515. ijv[:, 0], ijv[:, 2], objects.indices)
  516. max_y = scipy.ndimage.maximum(
  517. ijv[:, 0], ijv[:, 2], objects.indices)
  518. location_x = scipy.ndimage.mean(
  519. ijv[:, 1], ijv[:, 2], objects.indices)
  520. location_y = scipy.ndimage.mean(
  521. ijv[:, 0], ijv[:, 2], objects.indices)
  522. bb = np.c_[min_x, max_x, min_y, max_y]
  523. else:
  524. bb = np.zeros((0, 4))
  525. location_x = np.zeros(0)
  526. location_y = np.zeros(0)
  527.  
  528. c5_bbox.write(bb.astype(np.int32))
  529. c5_bbox.write_definition()
  530. c5_bbox.finalize()
  531.  
  532. c5_center = c5_pos.add_object_center(object_name=objects_name)
  533. locations = {'x': location_x, 'y': location_y}
  534. cent = np.column_stack(
  535. [locations[axis] for axis in c5_center.dtype.names])
  536.  
  537. c5_center.write(cent.astype(np.int32))
  538. c5_center.write_definition()
  539. c5_center.finalize()
  540. #
  541. # The last part deals with relationships between segmentations.
  542. # The most typical relationship is "Parent" which is explained below,
  543. # but you can also have things like first nearest and second nearest
  544. # neighbor or in tracking, the relationship between the segmentation
  545. # of the previous and next frames.
  546. #
  547. for key in m.get_relationship_groups():
  548. relationships = m.get_relationships(
  549. key.module_number, key.relationship,
  550. key.object_name1, key.object_name2,
  551. [m.image_set_number])
  552. for image_number1, image_number2, \
  553. object_number1, object_number2 in relationships:
  554. if image_number1 == image_number2 and \
  555. key.relationship == R_PARENT:
  556. #
  557. # Object 1 is the parent to object 2 - this is the
  558. # most common relationship, so if you can only record
  559. # one, this is it. "Parent" usually means that
  560. # the child's segmentation was seeded by the parent
  561. # segmentation (e.g. Parent = nucleus, child = cell),
  562. # but can also be something like Parent = cell,
  563. # child = all organelles within the cell
  564. #
  565. # object_name1 is the name of the parent segmentation
  566. # object_name2 is the name of the child segmentation
  567. # object_number1 is the index used to label the
  568. # parent in the parent segmentation
  569. # object_number2 is the index used to label the
  570. # child in the child segmentation
  571. continue
  572. if image_number1 != m.image_set_number:
  573. path1 = self.get_site_path(workspace, image_number1)
  574. else:
  575. path1 = path
  576. if image_number2 != m.image_set_number:
  577. path2 = self.get_site_path(workspace, image_number2)
  578. else:
  579. path2 = path
  580. #
  581. # TODO: this is sort of extra credit, but the relationships
  582. # relate an object in one segmentation to another.
  583. # For tracking, these can be in different image
  584. # sets, (e.g. the cell at time T and at time T+1).
  585. # So, given object 1 and object 2, path1 and path2
  586. # tell you how the objects are related between planes.
  587. pass
  588.  
  589. def post_run(self, workspace):
  590. if self.repack:
  591. ### to be implemented with
  592. ### ch5_master.repack()
  593. return
  594. measurements = workspace.measurements
  595. fd, temp_name = tempfile.mkstemp(
  596. suffix=".ch5",
  597. dir=self.directory.get_absolute_path())
  598.  
  599. master_name = self.get_path_to_master_file(workspace.measurements)
  600. src = h5py.File(master_name, "r")
  601. dest = h5py.File(temp_name)
  602. os.close(fd)
  603. for key in src:
  604. dest.copy(src[key], dest, expand_external=True)
  605. src.close()
  606. dest.close()
  607. os.unlink(master_name)
  608. os.rename(temp_name, master_name)
  609.  
  610. def prepare_settings(self, setting_values):
  611. objects_count, images_count = [int(x) for x in setting_values[:2]]
  612. del self.objects_to_export[:]
  613. while len(self.objects_to_export) < objects_count:
  614. self.add_objects()
  615. del self.images_to_export[:]
  616. while len(self.images_to_export) < images_count:
  617. self.add_image()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement