cellects 0.2.7__py3-none-any.whl → 0.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -33,7 +33,7 @@ from cellects.image_analysis.shape_descriptors import from_shape_descriptors_cla
33
33
  from cellects.image_analysis.morphological_operations import create_ellipse, rank_from_top_to_bottom_from_left_to_right, \
34
34
  get_quick_bounding_boxes, get_bb_with_moving_centers, get_contours, keep_one_connected_component, box_counting_dimension, prepare_box_counting
35
35
  from cellects.image_analysis.progressively_add_distant_shapes import ProgressivelyAddDistantShapes
36
- from cellects.core.one_image_analysis import OneImageAnalysis
36
+ from cellects.core.one_image_analysis import OneImageAnalysis, init_params
37
37
  from cellects.utils.load_display_save import read_and_rotate, video2numpy
38
38
  from cellects.image_analysis.morphological_operations import shape_selection, draw_img_with_mask
39
39
 
@@ -98,8 +98,8 @@ class ProgramOrganizer:
98
98
  self.one_arena_done: bool = False
99
99
  self.reduce_image_dim: bool = False
100
100
  self.first_exp_ready_to_run: bool = False
101
- self.data_to_save = {'first_image': False, 'coordinates': False, 'exif': False, 'vars': False}
102
- self.sample_number = None
101
+ self.data_to_save = {'first_image': False, 'exif': False, 'vars': False}
102
+ self.sample_number = 1
103
103
  self.top = None
104
104
  self.motion = None
105
105
  self.analysis_instance = None
@@ -121,6 +121,7 @@ class ProgramOrganizer:
121
121
  self.one_row_per_frame = None
122
122
  self.not_analyzed_individuals = None
123
123
  self.visualize: bool = True
124
+ self.network_shaped: bool = False
124
125
 
125
126
  def update_variable_dict(self):
126
127
  """
@@ -243,6 +244,7 @@ class ProgramOrganizer:
243
244
  self.data_list = insensitive_glob(self.all['radical'] + '*' + self.all['extension']) # Provides a list ordered by last modification date
244
245
  self.all['folder_list'] = []
245
246
  self.all['folder_number'] = 1
247
+ self.vars['first_detection_frame'] = 0
246
248
  if len(self.data_list) > 0:
247
249
  self._sort_data_list()
248
250
  self.sample_number = self.all['first_folder_sample_number']
@@ -318,8 +320,7 @@ class ProgramOrganizer:
318
320
  """
319
321
  Set the analyzed individuals variable in the dataset.
320
322
  """
321
- if self.sample_number is not None:
322
- self.vars['analyzed_individuals'] = np.arange(self.sample_number) + 1
323
+ self.vars['analyzed_individuals'] = np.arange(self.sample_number) + 1
323
324
  if self.not_analyzed_individuals is not None:
324
325
  self.vars['analyzed_individuals'] = np.delete(self.vars['analyzed_individuals'],
325
326
  self.not_analyzed_individuals - 1)
@@ -349,7 +350,10 @@ class ProgramOrganizer:
349
350
  It updates the state of various attributes based on the loaded data
350
351
  and logs appropriate messages.
351
352
  """
353
+ self.analysis_instance = None
352
354
  self.first_im = None
355
+ self.first_image = None
356
+ self.last_image = None
353
357
  current_global_pathway = self.all['global_pathway']
354
358
  folder_number = self.all['folder_number']
355
359
  if folder_number > 1:
@@ -362,7 +366,7 @@ class ProgramOrganizer:
362
366
  if data_to_run_cellects_quickly is None:
363
367
  data_to_run_cellects_quickly = {}
364
368
 
365
- if ('validated_shapes' in data_to_run_cellects_quickly) and ('coordinates' in data_to_run_cellects_quickly) and ('all' in data_to_run_cellects_quickly):
369
+ if ('validated_shapes' in data_to_run_cellects_quickly) and ('all' in data_to_run_cellects_quickly) and ('bb_coord' in data_to_run_cellects_quickly['all']['vars']):
366
370
  logging.info("Success to load Data to run Cellects quickly.pkl from the user chosen directory")
367
371
  self.all = data_to_run_cellects_quickly['all']
368
372
  # If you want to add a new variable, first run an updated version of all_vars_dict,
@@ -387,8 +391,7 @@ class ProgramOrganizer:
387
391
  self.update_folder_id(self.all['sample_number_per_folder'][0], self.all['folder_list'][0])
388
392
  self.get_first_image()
389
393
  self.get_last_image()
390
- (ccy1, ccy2, ccx1, ccx2, self.left, self.right, self.top, self.bot) = data_to_run_cellects_quickly[
391
- 'coordinates']
394
+ (ccy1, ccy2, ccx1, ccx2, self.top, self.bot, self.left, self.right) = data_to_run_cellects_quickly['all']['vars']['bb_coord']
392
395
  if self.all['automatically_crop']:
393
396
  self.first_image.crop_coord = [ccy1, ccy2, ccx1, ccx2]
394
397
  logging.info("Crop first image")
@@ -447,11 +450,6 @@ class ProgramOrganizer:
447
450
  if self.data_to_save['first_image']:
448
451
  data_to_run_cellects_quickly['validated_shapes'] = self.first_image.im_combinations[self.current_combination_id]['binary_image']
449
452
  data_to_run_cellects_quickly['shape_number'] = self.first_image.im_combinations[self.current_combination_id]['shape_number']
450
- # data_to_run_cellects_quickly['converted_image'] = self.first_image.im_combinations[self.current_combination_id]['converted_image']
451
- if self.data_to_save['coordinates']:
452
- data_to_run_cellects_quickly['coordinates'] = self._list_coordinates()
453
- logging.info("When they exist, do overwrite unaltered video")
454
- self.all['overwrite_unaltered_videos'] = True
455
453
  if self.data_to_save['exif']:
456
454
  self.vars['exif'] = self.extract_exif()
457
455
  self.all['vars'] = self.vars
@@ -459,7 +457,7 @@ class ProgramOrganizer:
459
457
  pickle_rick = PickleRick()
460
458
  pickle_rick.write_file(data_to_run_cellects_quickly, 'Data to run Cellects quickly.pkl')
461
459
 
462
- def _list_coordinates(self):
460
+ def list_coordinates(self):
463
461
  """
464
462
  Summarize the coordinates of images and video.
465
463
 
@@ -475,10 +473,9 @@ class ProgramOrganizer:
475
473
 
476
474
  """
477
475
  if self.first_image.crop_coord is None:
478
- self.first_image.crop_coord = [0, self.first_image.image.shape[0], 0,
479
- self.first_image.image.shape[1]]
480
- videos_coordinates = self.first_image.crop_coord + [self.left, self.right, self.top, self.bot]
481
- return videos_coordinates
476
+ self.first_image.crop_coord = [0, self.first_image.image.shape[0], 0, self.first_image.image.shape[1]]
477
+ self.vars['bb_coord'] = self.first_image.crop_coord + [self.top, self.bot, self.left, self.right]
478
+ self.all['overwrite_unaltered_videos'] = True
482
479
 
483
480
  def get_first_image(self, first_im: NDArray=None, sample_number: int=None):
484
481
  """
@@ -488,24 +485,22 @@ class ProgramOrganizer:
488
485
  depending on whether the data is an image or a video. It performs necessary
489
486
  preprocessing and initializes relevant attributes for subsequent analysis.
490
487
  """
488
+ if sample_number is not None:
489
+ self.sample_number = sample_number
491
490
  self.reduce_image_dim = False
492
491
  if first_im is not None:
493
492
  self.first_im = first_im
494
- if sample_number is not None:
495
- self.sample_number = sample_number
496
493
  else:
497
494
  logging.info("Load first image")
498
- just_read_image = self.first_im is not None
499
- # just_read_image = self.analysis_instance is not None
500
495
  if self.all['im_or_vid'] == 1:
501
- if not just_read_image:
496
+ if self.analysis_instance is None:
502
497
  self.analysis_instance = video2numpy(self.data_list[0])
503
498
  self.sample_number = len(self.data_list)
504
499
  self.vars['img_number'] = self.analysis_instance.shape[0]
505
500
  self.first_im = self.analysis_instance[0, ...]
501
+ self.vars['dims'] = self.analysis_instance.shape[:3]
506
502
  else:
507
503
  self.first_im = self.analysis_instance[self.vars['first_detection_frame'], ...]
508
- self.vars['dims'] = self.analysis_instance.shape[:3]
509
504
 
510
505
  else:
511
506
  self.vars['img_number'] = len(self.data_list)
@@ -519,7 +514,8 @@ class ProgramOrganizer:
519
514
  self.reduce_image_dim = True
520
515
  if self.reduce_image_dim:
521
516
  self.first_im = self.first_im[:, :, 0]
522
- self.first_image = OneImageAnalysis(self.first_im)
517
+
518
+ self.first_image = OneImageAnalysis(self.first_im, self.sample_number)
523
519
  self.vars['already_greyscale'] = self.first_image.already_greyscale
524
520
  if self.vars['already_greyscale']:
525
521
  self.vars["convert_for_origin"] = {"bgr": np.array((1, 1, 1), dtype=np.uint8), "logical": "None"}
@@ -546,16 +542,7 @@ class ProgramOrganizer:
546
542
  self.last_im = last_im
547
543
  else:
548
544
  if self.all['im_or_vid'] == 1:
549
- cap = cv2.VideoCapture(self.data_list[0])
550
- counter = 0
551
- while cap.isOpened() and counter < self.vars['img_number']:
552
- ret, frame = cap.read()
553
- if self.reduce_image_dim:
554
- frame = frame[:, :, 0]
555
- self.analysis_instance[-1, ...] = frame
556
- counter += 1
557
- self.last_im = frame
558
- cap.release()
545
+ self.last_im = self.analysis_instance[-1, ...]
559
546
  else:
560
547
  is_landscape = self.first_image.image.shape[0] < self.first_image.image.shape[1]
561
548
  self.last_im = read_and_rotate(self.data_list[-1], self.first_im, self.all['raw_images'], is_landscape)
@@ -574,7 +561,8 @@ class ProgramOrganizer:
574
561
  """
575
562
  self.vars['time_step_is_arbitrary'] = True
576
563
  if self.all['im_or_vid'] == 1:
577
- self.vars['dims'] = self.analysis_instance.shape
564
+ if not 'dims' in self.vars:
565
+ self.vars['dims'] = self.analysis_instance.shape[:3]
578
566
  timings = np.arange(self.vars['dims'][0])
579
567
  else:
580
568
  timings = np.arange(len(self.data_list))
@@ -662,15 +650,15 @@ class ProgramOrganizer:
662
650
  self.first_image.im_combinations[self.current_combination_id]['converted_image'] = bracket_to_uint8_image_contrast(greyscale)
663
651
  self.first_image.im_combinations[self.current_combination_id]['shape_number'] = shape_number
664
652
 
665
- def fast_last_image_segmentation(self, biomask: NDArray[np.uint8] = None, backmask: NDArray[np.uint8] = None):
653
+ def fast_last_image_segmentation(self, bio_mask: NDArray[np.uint8] = None, back_mask: NDArray[np.uint8] = None):
666
654
  """
667
655
  Segment the first or subsequent image in a series for biological and background masks.
668
656
 
669
657
  Parameters
670
658
  ----------
671
- biomask : NDArray[np.uint8], optional
659
+ bio_mask : NDArray[np.uint8], optional
672
660
  The biological mask to be applied to the image.
673
- backmask : NDArray[np.uint8], optional
661
+ back_mask : NDArray[np.uint8], optional
674
662
  The background mask to be applied to the image.
675
663
 
676
664
  Returns
@@ -688,14 +676,14 @@ class ProgramOrganizer:
688
676
  self.vars['convert_for_motion'] = {"logical": 'None', "PCA": np.ones(3, dtype=np.uint8)}
689
677
  self.cropping(is_first_image=False)
690
678
  self.last_image.convert_and_segment(self.vars['convert_for_motion'], self.vars["color_number"],
691
- biomask, backmask, self.first_image.subtract_background,
679
+ bio_mask, back_mask, self.first_image.subtract_background,
692
680
  self.first_image.subtract_background2,
693
681
  rolling_window_segmentation=self.vars["rolling_window_segmentation"],
694
682
  filter_spec=self.vars["filter_spec"])
695
683
  if self.vars['drift_already_corrected'] and not self.last_image.drift_correction_already_adjusted and not self.vars["rolling_window_segmentation"]['do']:
696
684
  self.last_image.check_if_image_border_attest_drift_correction()
697
685
  self.last_image.convert_and_segment(self.vars['convert_for_motion'], self.vars["color_number"],
698
- biomask, backmask, self.first_image.subtract_background,
686
+ bio_mask, back_mask, self.first_image.subtract_background,
699
687
  self.first_image.subtract_background2,
700
688
  allowed_window=self.last_image.drift_mask_coord,
701
689
  filter_spec=self.vars["filter_spec"])
@@ -713,6 +701,102 @@ class ProgramOrganizer:
713
701
  greyscale = self.last_image.image
714
702
  self.last_image.im_combinations[self.current_combination_id]['converted_image'] = bracket_to_uint8_image_contrast(greyscale)
715
703
 
704
+ def save_user_masks(self, bio_mask=None, back_mask=None):
705
+ self.all["bio_mask"] = None
706
+ self.all["back_mask"] = None
707
+ if self.all['keep_cell_and_back_for_all_folders']:
708
+ self.all["bio_mask"] = bio_mask
709
+ self.all["back_mask"] = back_mask
710
+
711
+ def full_first_image_segmentation(self, first_param_known: bool, bio_mask: NDArray[np.uint8] = None, back_mask: NDArray[np.uint8] = None):
712
+ if bio_mask.any():
713
+ shape_nb, ordered_image = cv2.connectedComponents((bio_mask > 0).astype(np.uint8))
714
+ shape_nb -= 1
715
+ bio_mask = np.nonzero(bio_mask)
716
+ else:
717
+ shape_nb = 0
718
+ bio_mask = None
719
+ if back_mask.any():
720
+ back_mask = np.nonzero(back_mask)
721
+ else:
722
+ back_mask = None
723
+ self.save_user_masks(bio_mask=bio_mask, back_mask=back_mask)
724
+ if self.visualize or len(self.first_im.shape) == 2:
725
+ if not first_param_known and self.all['scale_with_image_or_cells'] == 0 and self.all["set_spot_size"]:
726
+ self.get_average_pixel_size()
727
+ else:
728
+ self.starting_blob_hsize_in_pixels = None
729
+ self.fast_first_image_segmentation()
730
+ if not self.vars['several_blob_per_arena'] and bio_mask is not None and shape_nb == self.sample_number and self.first_image.im_combinations[self.current_combination_id]['shape_number'] != self.sample_number:
731
+ self.first_image.im_combinations[self.current_combination_id]['shape_number'] = shape_nb
732
+ self.first_image.shape_number = shape_nb
733
+ self.first_image.validated_shapes = (ordered_image > 0).astype(np.uint8)
734
+ self.first_image.im_combinations[self.current_combination_id]['binary_image'] = self.first_image.validated_shapes
735
+ else:
736
+
737
+ params = init_params()
738
+ params['is_first_image'] = True
739
+ params['blob_nb'] = self.sample_number
740
+ if self.vars["color_number"] > 2:
741
+ params['kmeans_clust_nb'] = self.vars["color_number"]
742
+ params['bio_mask'] = self.all["bio_mask"]
743
+ params['back_mask'] = self.all["back_mask"]
744
+ params['filter_spec'] = self.vars["filter_spec"]
745
+
746
+ if first_param_known:
747
+ if self.all['scale_with_image_or_cells'] == 0:
748
+ self.get_average_pixel_size()
749
+ else:
750
+ self.starting_blob_hsize_in_pixels = None
751
+ params['several_blob_per_arena'] = self.vars['several_blob_per_arena']
752
+ params['blob_shape'] = self.all['starting_blob_shape']
753
+ params['blob_size'] = self.starting_blob_hsize_in_pixels
754
+
755
+ self.first_image.find_color_space_combinations(params)
756
+
757
+ def full_last_image_segmentation(self, bio_mask: NDArray[np.uint8] = None, back_mask: NDArray[np.uint8] = None):
758
+ if bio_mask.any():
759
+ bio_mask = np.nonzero(bio_mask)
760
+ else:
761
+ bio_mask = None
762
+ if back_mask.any():
763
+ back_mask = np.nonzero(back_mask)
764
+ else:
765
+ back_mask = None
766
+ if self.last_im is None:
767
+ self.get_last_image()
768
+ self.cropping(False)
769
+ self.get_background_to_subtract()
770
+ if self.visualize or (len(self.first_im.shape) == 2 and not self.network_shaped):
771
+ self.fast_last_image_segmentation(bio_mask=bio_mask, back_mask=back_mask)
772
+ else:
773
+ arenas_mask = None
774
+ if self.all['are_gravity_centers_moving'] != 1:
775
+ cr = [self.top, self.bot, self.left, self.right]
776
+ arenas_mask = np.zeros_like(self.first_image.validated_shapes)
777
+ for _i in np.arange(len(self.vars['analyzed_individuals'])):
778
+ if self.vars['arena_shape'] == 'circle':
779
+ ellipse = create_ellipse(cr[1][_i] - cr[0][_i], cr[3][_i] - cr[2][_i])
780
+ arenas_mask[cr[0][_i]: cr[1][_i], cr[2][_i]:cr[3][_i]] = ellipse
781
+ else:
782
+ arenas_mask[cr[0][_i]: cr[1][_i], cr[2][_i]:cr[3][_i]] = 1
783
+ if self.network_shaped:
784
+ self.last_image.network_detection(arenas_mask, csc_dict=self.vars["convert_for_motion"], lighter_background=None, bio_mask=bio_mask, back_mask=back_mask)
785
+ else:
786
+ ref_image = self.first_image.validated_shapes
787
+ params = init_params()
788
+ params['is_first_image'] = False
789
+ params['several_blob_per_arena'] = self.vars['several_blob_per_arena']
790
+ params['blob_nb'] = self.sample_number
791
+ params['arenas_mask'] = arenas_mask
792
+ params['ref_image'] = ref_image
793
+ params['subtract_background'] = self.first_image.subtract_background
794
+ params['bio_mask'] = bio_mask
795
+ params['back_mask'] = back_mask
796
+ params['filter_spec'] = self.vars["filter_spec"]
797
+
798
+ self.last_image.find_color_space_combinations(params)
799
+
716
800
  def cropping(self, is_first_image: bool):
717
801
  """
718
802
  Crops the image based on specified conditions and settings.
@@ -731,19 +815,14 @@ class ProgramOrganizer:
731
815
  if is_first_image:
732
816
  if not self.first_image.cropped:
733
817
  if (not self.all['overwrite_unaltered_videos'] and os.path.isfile('Data to run Cellects quickly.pkl')):
818
+ self.first_image.get_crop_coordinates()
734
819
  pickle_rick = PickleRick()
735
820
  data_to_run_cellects_quickly = pickle_rick.read_file('Data to run Cellects quickly.pkl')
736
- if data_to_run_cellects_quickly is not None:
737
- if 'coordinates' in data_to_run_cellects_quickly:
738
- logging.info("Get crop coordinates from Data to run Cellects quickly.pkl")
739
- (ccy1, ccy2, ccx1, ccx2, self.left, self.right, self.top, self.bot) = \
740
- data_to_run_cellects_quickly['coordinates']
741
- self.first_image.crop_coord = [ccy1, ccy2, ccx1, ccx2]
742
- else:
743
- self.first_image.get_crop_coordinates()
744
- else:
745
- self.first_image.get_crop_coordinates()
746
-
821
+ if data_to_run_cellects_quickly is not None and 'bb_coord' in data_to_run_cellects_quickly['all']['vars']:
822
+ logging.info("Get crop coordinates from Data to run Cellects quickly.pkl")
823
+ (ccy1, ccy2, ccx1, ccx2, self.top, self.bot, self.left, self.right) = \
824
+ data_to_run_cellects_quickly['all']['vars']['bb_coord']
825
+ self.first_image.crop_coord = [ccy1, ccy2, ccx1, ccx2]
747
826
  else:
748
827
  self.first_image.get_crop_coordinates()
749
828
  if self.all['automatically_crop']:
@@ -777,26 +856,27 @@ class ProgramOrganizer:
777
856
  connectivity=8)
778
857
  self.first_image.shape_number -= 1
779
858
  if self.all['scale_with_image_or_cells'] == 0:
780
- self.vars['average_pixel_size'] = np.square(
781
- self.all['image_horizontal_size_in_mm'] /
782
- self.first_im.shape[1])
859
+ self.vars['average_pixel_size'] = np.square(self.all['image_horizontal_size_in_mm'] /
860
+ self.first_im.shape[1])
783
861
  else:
784
- self.vars['average_pixel_size'] = np.square(
785
- self.all['starting_blob_hsize_in_mm'] /
786
- np.mean(self.first_image.stats[1:, 2]))
862
+ if len(self.first_image.stats[1:, 2]) > 0:
863
+ self.vars['average_pixel_size'] = np.square(self.all['starting_blob_hsize_in_mm'] /
864
+ np.mean(self.first_image.stats[1:, 2]))
865
+ else:
866
+ self.vars['average_pixel_size'] = 1.
867
+ self.vars['output_in_mm'] = False
868
+
787
869
  if self.all['set_spot_size']:
788
- self.starting_blob_hsize_in_pixels = (
789
- self.all['starting_blob_hsize_in_mm'] /
790
- np.sqrt(self.vars['average_pixel_size']))
870
+ self.starting_blob_hsize_in_pixels = (self.all['starting_blob_hsize_in_mm'] /
871
+ np.sqrt(self.vars['average_pixel_size']))
791
872
  else:
792
873
  self.starting_blob_hsize_in_pixels = None
793
874
 
794
875
  if self.all['automatic_size_thresholding']:
795
876
  self.vars['first_move_threshold'] = 10
796
877
  else:
797
- self.vars['first_move_threshold'] = np.round(
798
- self.all['first_move_threshold_in_mm²'] /
799
- self.vars['average_pixel_size']).astype(np.uint8)
878
+ self.vars['first_move_threshold'] = np.round(self.all['first_move_threshold_in_mm²'] /
879
+ self.vars['average_pixel_size']).astype(np.uint8)
800
880
  logging.info(f"The average pixel size is: {self.vars['average_pixel_size']} mm²")
801
881
 
802
882
  def get_background_to_subtract(self):
@@ -905,19 +985,10 @@ class ProgramOrganizer:
905
985
  - 'continue' (bool): Whether to continue processing.
906
986
  - 'message' (str): Informational or error message.
907
987
 
908
- Raises
909
- ------
910
- None
911
-
912
988
  Notes
913
989
  -----
914
990
  This function relies on the existence of certain attributes and variables
915
991
  defined in the class instance.
916
-
917
- Examples
918
- --------
919
- >>> self.delineate_each_arena()
920
- {'continue': True, 'message': ''}
921
992
  """
922
993
  analysis_status = {"continue": True, "message": ""}
923
994
  if not self.vars['several_blob_per_arena'] and (self.sample_number > 1):
@@ -927,9 +998,9 @@ class ProgramOrganizer:
927
998
  pickle_rick = PickleRick()
928
999
  data_to_run_cellects_quickly = pickle_rick.read_file('Data to run Cellects quickly.pkl')
929
1000
  if data_to_run_cellects_quickly is not None:
930
- if 'coordinates' in data_to_run_cellects_quickly:
931
- (ccy1, ccy2, ccx1, ccx2, self.left, self.right, self.top, self.bot) = \
932
- data_to_run_cellects_quickly['coordinates']
1001
+ if 'bb_coord' in data_to_run_cellects_quickly['all']['vars']:
1002
+ (ccy1, ccy2, ccx1, ccx2, self.top, self.bot, self.left, self.right) = \
1003
+ data_to_run_cellects_quickly['all']['vars']['bb_coord']
933
1004
  self.first_image.crop_coord = [ccy1, ccy2, ccx1, ccx2]
934
1005
  if (self.first_image.image.shape[0] == (ccy2 - ccy1)) and (
935
1006
  self.first_image.image.shape[1] == (ccx2 - ccx1)): # maybe useless now
@@ -940,7 +1011,6 @@ class ProgramOrganizer:
940
1011
  motion_list = None
941
1012
  if self.all['are_gravity_centers_moving']:
942
1013
  motion_list = self._segment_blob_motion(sample_size=5)
943
- # if self.all['im_or_vid'] == 1:
944
1014
  self.get_bounding_boxes(are_gravity_centers_moving=self.all['are_gravity_centers_moving'] == 1,
945
1015
  motion_list=motion_list, all_specimens_have_same_direction=self.all['all_specimens_have_same_direction'])
946
1016
 
@@ -958,6 +1028,8 @@ class ProgramOrganizer:
958
1028
  self._whole_image_bounding_boxes()
959
1029
  self.sample_number = 1
960
1030
  self._set_analyzed_individuals()
1031
+ self.vars['arena_coord'] = []
1032
+ self.list_coordinates()
961
1033
  return analysis_status
962
1034
 
963
1035
  def _segment_blob_motion(self, sample_size: int) -> list:
@@ -1220,12 +1292,18 @@ class ProgramOrganizer:
1220
1292
  logging.info("Create origins and background lists")
1221
1293
  if self.top is None:
1222
1294
  self._whole_image_bounding_boxes()
1295
+
1296
+ if not self.first_image.validated_shapes.any():
1297
+ if self.vars['convert_for_motion'] is not None:
1298
+ self.vars['convert_for_origin'] = self.vars['convert_for_motion']
1299
+ self.fast_first_image_segmentation()
1223
1300
  first_im = self.first_image.validated_shapes
1224
1301
  self.vars['origin_list'] = []
1225
1302
  self.vars['background_list'] = []
1226
1303
  self.vars['background_list2'] = []
1227
1304
  for rep in np.arange(len(self.vars['analyzed_individuals'])):
1228
- self.vars['origin_list'].append(first_im[self.top[rep]:self.bot[rep], self.left[rep]:self.right[rep]])
1305
+ origin_coord = np.nonzero(first_im[self.top[rep]:self.bot[rep], self.left[rep]:self.right[rep]])
1306
+ self.vars['origin_list'].append(origin_coord)
1229
1307
  if self.vars['subtract_background']:
1230
1308
  for rep in np.arange(len(self.vars['analyzed_individuals'])):
1231
1309
  self.vars['background_list'].append(
@@ -1610,23 +1688,6 @@ class ProgramOrganizer:
1610
1688
  self.last_image.bgr = draw_img_with_mask(self.last_image.bgr, self.last_image.bgr.shape[:2], minmax,
1611
1689
  self.vars['arena_shape'], last_visualization)
1612
1690
 
1613
- # cr = ((self.top[i], self.bot[i]),
1614
- # (self.left[i], self.right[i]))
1615
- # if self.vars['arena_shape'] == 'circle':
1616
- # ellipse = create_ellipse(cr[0][1] - cr[0][0], cr[1][1] - cr[1][0])
1617
- # ellipse = np.stack((ellipse, ellipse, ellipse), axis=2).astype(np.uint8)
1618
- # first_visualization *= ellipse
1619
- # self.first_image.bgr[cr[0][0]:cr[0][1], cr[1][0]:cr[1][1], ...] *= (1 - ellipse)
1620
- # self.first_image.bgr[cr[0][0]:cr[0][1], cr[1][0]:cr[1][1], ...] += first_visualization
1621
- # if last_visualization is not None:
1622
- # last_visualization *= ellipse
1623
- # self.last_image.bgr[cr[0][0]:cr[0][1], cr[1][0]:cr[1][1], ...] *= (1 - ellipse)
1624
- # self.last_image.bgr[cr[0][0]:cr[0][1], cr[1][0]:cr[1][1], ...] += last_visualization
1625
- # else:
1626
- # self.first_image.bgr[cr[0][0]:cr[0][1], cr[1][0]:cr[1][1], ...] = first_visualization
1627
- # if last_visualization is not None:
1628
- # self.last_image.bgr[cr[0][0]:cr[0][1], cr[1][0]:cr[1][1], ...] = last_visualization
1629
-
1630
1691
 
1631
1692
  def save_tables(self, with_last_image: bool=True):
1632
1693
  """
@@ -1654,13 +1715,11 @@ class ProgramOrganizer:
1654
1715
  del self.one_row_per_arena
1655
1716
  except PermissionError:
1656
1717
  logging.error("Never let one_row_per_arena.csv open when Cellects runs")
1657
- self.message_from_thread.emit(f"Never let one_row_per_arena.csv open when Cellects runs")
1658
1718
  try:
1659
1719
  self.one_row_per_frame.to_csv("one_row_per_frame.csv", sep=";", index=False, lineterminator='\n')
1660
1720
  del self.one_row_per_frame
1661
1721
  except PermissionError:
1662
1722
  logging.error("Never let one_row_per_frame.csv open when Cellects runs")
1663
- self.message_from_thread.emit(f"Never let one_row_per_frame.csv open when Cellects runs")
1664
1723
  if self.all['extension'] == '.JPG':
1665
1724
  extension = '.PNG'
1666
1725
  else:
@@ -1677,11 +1736,11 @@ class ProgramOrganizer:
1677
1736
  for key in ['analyzed_individuals', 'night_mode', 'expert_mode', 'is_auto', 'arena', 'video_option', 'compute_all_options', 'vars', 'dims', 'origin_list', 'background_list', 'background_list2', 'descriptors', 'folder_list', 'sample_number_per_folder']:
1678
1737
  global_settings.pop(key, None)
1679
1738
  software_settings.update(global_settings)
1739
+ software_settings.pop('video_list', None)
1680
1740
  software_settings = pd.DataFrame.from_dict(software_settings, columns=["Setting"], orient='index')
1681
1741
  try:
1682
1742
  software_settings.to_csv("software_settings.csv", sep=";")
1683
1743
  except PermissionError:
1684
1744
  logging.error("Never let software_settings.csv open when Cellects runs")
1685
- self.message_from_thread.emit(f"Never let software_settings.csv open when Cellects runs")
1686
1745
 
1687
1746
 
@@ -13,6 +13,7 @@ from cellects.utils.utilitarian import insensitive_glob
13
13
  from cellects.core.motion_analysis import MotionAnalysis
14
14
  from cellects.image_analysis.morphological_operations import create_ellipse
15
15
  from cellects.image_analysis.image_segmentation import convert_subtract_and_filter_video
16
+ from cellects.core.one_image_analysis import init_params
16
17
  from cellects.utils.load_display_save import write_video_sets, readim, display_network_methods
17
18
  from cellects.image_analysis.network_functions import NetworkDetection
18
19
 
@@ -54,7 +55,9 @@ def run_image_analysis(po, PCA: bool=True, last_im:NDArray=None):
54
55
  if PCA:
55
56
  po.fast_first_image_segmentation()
56
57
  else:
57
- po.first_image.find_first_im_csc()
58
+ params = init_params()
59
+ params['is_first_image'] = True
60
+ po.first_image.find_color_space_combinations(params)
58
61
  po.cropping(is_first_image=True)
59
62
  po.get_average_pixel_size()
60
63
  po.delineate_each_arena()
@@ -113,6 +116,7 @@ def run_all_arenas(po):
113
116
  po.instantiate_tables()
114
117
  for i, arena in enumerate(po.vars['analyzed_individuals']):
115
118
  l = [i, arena, po.vars, True, True, False, None]
119
+ # l = [i, arena, po.vars, False, True, False, None]
116
120
  analysis_i = MotionAnalysis(l)
117
121
  po.add_analysis_visualization_to_first_and_last_images(i, analysis_i.efficiency_test_1,
118
122
  analysis_i.efficiency_test_2)
@@ -124,35 +128,21 @@ def run_all_arenas(po):
124
128
  po.update_one_row_per_frame(i * po.vars['img_number'],
125
129
  arena * po.vars['img_number'],
126
130
  analysis_i.one_row_per_frame)
127
- # Save cytosol_oscillations
128
- if not pd.isna(analysis_i.one_descriptor_per_arena["first_move"]):
129
- if po.vars['oscilacyto_analysis']:
130
- oscil_i = pd.DataFrame(
131
- np.c_[np.repeat(arena,
132
- analysis_i.clusters_final_data.shape[0]), analysis_i.clusters_final_data],
133
- columns=['arena', 'mean_pixel_period', 'phase', 'cluster_size', 'edge_distance', 'coord_y',
134
- 'coord_x'])
135
- if po.one_row_per_oscillating_cluster is None:
136
- po.one_row_per_oscillating_cluster = oscil_i
137
- else:
138
- po.one_row_per_oscillating_cluster = pd.concat((po.one_row_per_oscillating_cluster, oscil_i))
131
+ # Keep the tables
132
+ one_row_per_arena = po.one_row_per_arena
133
+ one_row_per_frame = po.one_row_per_frame
139
134
  po.save_tables()
135
+ po.one_row_per_arena = one_row_per_arena
136
+ po.one_row_per_frame = one_row_per_frame
140
137
  cv2.imwrite(f"Analysis efficiency, last image.jpg", po.last_image.bgr)
141
138
  cv2.imwrite(f"Analysis efficiency, {np.ceil(po.vars['img_number'] / 10).astype(np.uint64)}th image.jpg",
142
139
  po.first_image.bgr)
140
+ return po
143
141
 
144
- def detect_network_in_one_image(im_path, save_path):
142
+ def detect_network_in_one_image(im_path, save_path=None):
145
143
  im = readim(im_path)
146
- im = im[100:870, 200:1000]
144
+ # im = im[100:870, 200:1000]
147
145
  greyscale_image = im.mean(axis=2)
148
146
  net = NetworkDetection(greyscale_image, add_rolling_window=True)
149
147
  net.get_best_network_detection_method()
150
148
  display_network_methods(net, save_path)
151
-
152
-
153
-
154
- if __name__ == "__main__":
155
- po = load_data(pathway=os.getcwd() + "/data/experiment", sample_number=1, extension='tif')
156
- po = run_image_analysis(po)
157
- po = write_videos(po)
158
- run_all_arenas(po)
@@ -97,6 +97,7 @@ class FirstWindow(MainTabsType):
97
97
  # self.im_or_vid_label = FixedText('Image list or Videos:', tip="What type of data do(es) contain(s) folder(s)?", night_mode=self.parent().po.all['night_mode'])
98
98
  self.im_or_vid = Combobox(["Image list", "Videos"], self.parent().po.all['im_or_vid'], night_mode=self.parent().po.all['night_mode'])
99
99
  self.im_or_vid.setFixedWidth(150)
100
+ self.im_or_vid.currentTextChanged.connect(self.im2vid)
100
101
  # Set their positions on layout
101
102
  self.second_row_layout.addItem(self.horizontal_space)
102
103
  self.second_row_layout.addWidget(self.im_or_vid_label)
@@ -121,7 +122,7 @@ class FirstWindow(MainTabsType):
121
122
  if self.parent().po.all['extension'] == '.JPG':
122
123
  self.parent().po.all['radical'] = ''
123
124
  self.parent().po.all['extension'] = '.mp4'
124
- self.arena_number_label = FixedText('Arena number per video:',
125
+ self.arena_number_label = FixedText('Arena number per folder:',
125
126
  tip=FW["Arena_number_per_folder"]["tips"], #"If this number is not always the same (depending on the video), it can be changed later",
126
127
  night_mode=self.parent().po.all['night_mode'])
127
128
  what = 'Videos'
@@ -152,7 +153,6 @@ class FirstWindow(MainTabsType):
152
153
  self.third_row_widget.setLayout(self.third_row_layout)
153
154
  self.Vlayout.addWidget(self.third_row_widget)
154
155
  # If im_or_vid changes, adjust these 2 widgets
155
- self.im_or_vid.currentTextChanged.connect(self.im2vid)
156
156
 
157
157
  # 3) Get the path to the right folder:
158
158
  # Open the layout:
@@ -293,7 +293,8 @@ class FirstWindow(MainTabsType):
293
293
  """
294
294
  Toggle between processing images or videos based on UI selection.
295
295
  """
296
- if self.im_or_vid.currentText() == "Image list":
296
+ self.parent().po.all['im_or_vid'] = self.im_or_vid.currentIndex()
297
+ if self.im_or_vid.currentIndex() == 0:
297
298
  what = 'Images'
298
299
  if self.parent().po.all['extension'] == '.mp4':
299
300
  self.parent().po.all['radical'] = 'IMG_'
@@ -376,7 +377,7 @@ class FirstWindow(MainTabsType):
376
377
  """
377
378
  if len(self.parent().po.all['folder_list']) == 0 and len(self.parent().po.data_list) == 0:
378
379
  if self.parent().po.all['im_or_vid'] == 1:
379
- error_message = f"There is no videos ({self.parent().po.all['extension']})in the selected folder and its sub-folders"
380
+ error_message = f"There is no videos ({self.parent().po.all['extension']}) in the selected folder and its sub-folders"
380
381
  else:
381
382
  error_message = f"There is no images ({self.parent().po.all['extension']}) in the selected folder and its sub-folders"
382
383
  self.message.setText(error_message)
@@ -510,6 +511,8 @@ class FirstWindow(MainTabsType):
510
511
  self.required_outputs.setVisible(False)
511
512
  self.Run_all_directly.setVisible(False)
512
513
  self.next.setVisible(False)
514
+ self.instantiate = True
515
+ self.video_tab.set_not_usable()
513
516
  # 2) Load the dict
514
517
  self.thread["LoadDataToRunCellectsQuickly"].start()
515
518
  self.thread["LoadDataToRunCellectsQuickly"].message_from_thread.connect(self.load_data_quickly_finished)