From f00ce6b9dabea8b1b99e40c12d38ad92f755b5ca Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 11:57:28 -0500 Subject: [PATCH 01/10] Update categorizer.py --- LabGym/categorizer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/LabGym/categorizer.py b/LabGym/categorizer.py index d15cba73..fafcd2f7 100644 --- a/LabGym/categorizer.py +++ b/LabGym/categorizer.py @@ -1193,7 +1193,7 @@ def train_pattern_recognizer(self,data_path,model_path,out_path=None,dim=64,chan self.train_pattern_recognizer_onfly(out_folder,model_path,out_path=out_path,dim=dim,channel=channel,time_step=time_step,level=level,include_bodyparts=include_bodyparts,std=std,background_free=background_free,black_background=black_background,behavior_mode=behavior_mode,social_distance=social_distance) - def train_animation_analyzer(self,data_path,model_path,out_path=None,dim=64,channel=1,time_step=15,level=2,aug_methods=[],augvalid=True,include_bodyparts=True,std=0,background_free=True,black_background=True,behavior_mode=0,social_distance=0,out_folder=None): + def train_animation_analyzer(self,data_path,model_path,out_path=None,dim=64,channel=1,time_step=15,level=2,aug_methods=[],augvalid=True,include_bodyparts=True,std=0,background_free=True,black_background=True,behavior_mode=0,social_distance=0,color_costar=False,out_folder=None): # data_path: the folder that stores all the prepared training examples # model_path: the path to the trained Animation Analyzer @@ -1210,6 +1210,7 @@ def train_animation_analyzer(self,data_path,model_path,out_path=None,dim=64,chan # black_background: whether to set background # behavior_mode: 0--non-interactive, 1--interactive basic, 2--interactive advanced, 3--static images # social_distance: a threshold (folds of size of a single animal) on whether to include individuals that are not main character in behavior examples + # color_costar: in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations # out_folder: if not None, will output all the augmented data to this folder filters=8 @@ -1394,7 +1395,7 @@ def train_animation_analyzer(self,data_path,model_path,out_path=None,dim=64,chan self.train_animation_analyzer_onfly(out_folder,model_path,out_path=out_path,dim=dim,channel=channel,time_step=time_step,level=level,include_bodyparts=include_bodyparts,std=std,background_free=background_free,black_background=black_background,behavior_mode=behavior_mode,social_distance=social_distance) - def train_combnet(self,data_path,model_path,out_path=None,dim_tconv=32,dim_conv=64,channel=1,time_step=15,level_tconv=1,level_conv=2,aug_methods=[],augvalid=True,include_bodyparts=True,std=0,background_free=True,black_background=True,behavior_mode=0,social_distance=0,out_folder=None): + def train_combnet(self,data_path,model_path,out_path=None,dim_tconv=32,dim_conv=64,channel=1,time_step=15,level_tconv=1,level_conv=2,aug_methods=[],augvalid=True,include_bodyparts=True,std=0,background_free=True,black_background=True,behavior_mode=0,social_distance=0,color_costar=False,out_folder=None): # data_path: the folder that stores all the prepared training examples # model_path: the path to the trained Categorizer @@ -1413,6 +1414,7 @@ def train_combnet(self,data_path,model_path,out_path=None,dim_tconv=32,dim_conv= # black_background: whether to set background black # behavior_mode: 0--non-interactive, 1--interactive basic, 2--interactive advanced, 3--static images # social_distance: a threshold (folds of size of a single animal) on whether to include individuals that are not main character in behavior examples + # color_costar: in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations # out_folder: if not None, will output all the augmented data to this folder print('Training Categorizer with both Animation Analyzer and Pattern Recognizer using the behavior examples in: '+str(data_path)) From 9a5722d6c7851da31bff8513f7a74cc90d83b431 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 12:01:43 -0500 Subject: [PATCH 02/10] Update categorizer.py --- LabGym/categorizer.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/LabGym/categorizer.py b/LabGym/categorizer.py index fafcd2f7..994f4a3c 100644 --- a/LabGym/categorizer.py +++ b/LabGym/categorizer.py @@ -1265,7 +1265,12 @@ def train_animation_analyzer(self,data_path,model_path,out_path=None,dim=64,chan else: black_code=1 - parameters={'classnames':list(self.classnames),'dim_tconv':int(dim),'channel':int(channel),'time_step':int(time_step),'network':1,'level_tconv':int(level),'inner_code':int(inner_code),'std':int(std),'background_free':int(background_code),'black_background':int(black_code),'behavior_kind':int(behavior_mode),'social_distance':int(social_distance)} + if color_costar: + color_code=0 + else: + color_code=1 + + parameters={'classnames':list(self.classnames),'dim_tconv':int(dim),'channel':int(channel),'time_step':int(time_step),'network':1,'level_tconv':int(level),'inner_code':int(inner_code),'std':int(std),'background_free':int(background_code),'black_background':int(black_code),'behavior_kind':int(behavior_mode),'social_distance':int(social_distance),'color_code':int(color_code)} pd_parameters=pd.DataFrame.from_dict(parameters) pd_parameters.to_csv(os.path.join(model_path,'model_parameters.txt'),index=False) @@ -1462,7 +1467,12 @@ def train_combnet(self,data_path,model_path,out_path=None,dim_tconv=32,dim_conv= else: black_code=1 - parameters={'classnames':list(self.classnames),'dim_tconv':int(dim_tconv),'dim_conv':int(dim_conv),'channel':int(channel),'time_step':int(time_step),'network':2,'level_tconv':int(level_tconv),'level_conv':int(level_conv),'inner_code':int(inner_code),'std':int(std),'background_free':int(background_code),'black_background':int(black_code),'behavior_kind':int(behavior_mode),'social_distance':int(social_distance)} + if color_costar: + color_code=0 + else: + color_code=1 + + parameters={'classnames':list(self.classnames),'dim_tconv':int(dim_tconv),'dim_conv':int(dim_conv),'channel':int(channel),'time_step':int(time_step),'network':2,'level_tconv':int(level_tconv),'level_conv':int(level_conv),'inner_code':int(inner_code),'std':int(std),'background_free':int(background_code),'black_background':int(black_code),'behavior_kind':int(behavior_mode),'social_distance':int(social_distance),'color_code':int(color_code)} pd_parameters=pd.DataFrame.from_dict(parameters) pd_parameters.to_csv(os.path.join(model_path,'model_parameters.txt'),index=False) From 0ecdec44e0a025763cb863465fa4fa1e86ed21c1 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 12:08:37 -0500 Subject: [PATCH 03/10] Update categorizer.py --- LabGym/categorizer.py | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/LabGym/categorizer.py b/LabGym/categorizer.py index 994f4a3c..7da81a16 100644 --- a/LabGym/categorizer.py +++ b/LabGym/categorizer.py @@ -1717,7 +1717,7 @@ def train_pattern_recognizer_onfly(self,data_path,model_path,out_path=None,dim=3 print('No train / validation folder!') - def train_animation_analyzer_onfly(self,data_path,model_path,out_path=None,dim=32,channel=1,time_step=15,level=2,include_bodyparts=True,std=0,background_free=True,black_background=True,behavior_mode=0,social_distance=0): + def train_animation_analyzer_onfly(self,data_path,model_path,out_path=None,dim=32,channel=1,time_step=15,level=2,include_bodyparts=True,std=0,background_free=True,black_background=True,behavior_mode=0,social_distance=0,color_costar=False): # data_path: the folder that stores all the prepared training examples # model_path: the path to the trained Animation Analyzer @@ -1732,6 +1732,7 @@ def train_animation_analyzer_onfly(self,data_path,model_path,out_path=None,dim=3 # black_background: whether to set background # behavior_mode: 0--non-interactive, 1--interactive basic, 2--interactive advanced, 3--static images # social_distance: a threshold (folds of size of a single animal) on whether to include individuals that are not main character in behavior examples + # color_costar: in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations filters=8 @@ -1777,7 +1778,12 @@ def train_animation_analyzer_onfly(self,data_path,model_path,out_path=None,dim=3 else: black_code=1 - parameters={'classnames':list(train_data.classmapping.keys()),'dim_tconv':int(dim),'channel':int(channel),'time_step':int(time_step),'network':1,'level_tconv':int(level),'inner_code':int(inner_code),'std':int(std),'background_free':int(background_code),'black_background':int(black_code),'behavior_kind':int(behavior_mode),'social_distance':int(social_distance)} + if color_costar: + color_code=0 + else: + color_code=1 + + parameters={'classnames':list(train_data.classmapping.keys()),'dim_tconv':int(dim),'channel':int(channel),'time_step':int(time_step),'network':1,'level_tconv':int(level),'inner_code':int(inner_code),'std':int(std),'background_free':int(background_code),'black_background':int(black_code),'behavior_kind':int(behavior_mode),'social_distance':int(social_distance),'color_code':int(color_code)} pd_parameters=pd.DataFrame.from_dict(parameters) pd_parameters.to_csv(os.path.join(model_path,'model_parameters.txt'),index=False) @@ -1827,7 +1833,7 @@ def train_animation_analyzer_onfly(self,data_path,model_path,out_path=None,dim=3 print('No train / validation folder!') - def train_combnet_onfly(self,data_path,model_path,out_path=None,dim_tconv=32,dim_conv=64,channel=1,time_step=15,level_tconv=1,level_conv=2,include_bodyparts=True,std=0,background_free=True,black_background=True,behavior_mode=0,social_distance=0): + def train_combnet_onfly(self,data_path,model_path,out_path=None,dim_tconv=32,dim_conv=64,channel=1,time_step=15,level_tconv=1,level_conv=2,include_bodyparts=True,std=0,background_free=True,black_background=True,behavior_mode=0,social_distance=0,color_costar=False): # data_path: the folder that stores all the prepared training examples # model_path: the path to the trained Animation Analyzer @@ -1844,6 +1850,7 @@ def train_combnet_onfly(self,data_path,model_path,out_path=None,dim_tconv=32,dim # black_background: whether to set background # behavior_mode: 0--non-interactive, 1--interactive basic, 2--interactive advanced, 3--static images # social_distance: a threshold (folds of size of a single animal) on whether to include individuals that are not main character in behavior examples + # color_costar: in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations print('Training Categorizer with both Animation Analyzer and Pattern Recognizer using the behavior examples in: '+str(data_path)) self.log.append('Training Categorizer with both Animation Analyzer and Pattern Recognizer using the behavior examples in: '+str(data_path)) @@ -1882,7 +1889,12 @@ def train_combnet_onfly(self,data_path,model_path,out_path=None,dim_tconv=32,dim else: black_code=1 - parameters={'classnames':list(train_data.classmapping.keys()),'dim_tconv':int(dim_tconv),'dim_conv':int(dim_conv),'channel':int(channel),'time_step':int(time_step),'network':2,'level_tconv':int(level_tconv),'level_conv':int(level_conv),'inner_code':int(inner_code),'std':int(std),'background_free':int(background_code),'black_background':int(black_code),'behavior_kind':int(behavior_mode),'social_distance':int(social_distance)} + if color_costar: + color_code=0 + else: + color_code=1 + + parameters={'classnames':list(train_data.classmapping.keys()),'dim_tconv':int(dim_tconv),'dim_conv':int(dim_conv),'channel':int(channel),'time_step':int(time_step),'network':2,'level_tconv':int(level_tconv),'level_conv':int(level_conv),'inner_code':int(inner_code),'std':int(std),'background_free':int(background_code),'black_background':int(black_code),'behavior_kind':int(behavior_mode),'social_distance':int(social_distance),'color_code':int(color_code)} pd_parameters=pd.DataFrame.from_dict(parameters) pd_parameters.to_csv(os.path.join(model_path,'model_parameters.txt'),index=False) From e43d081758bfdb64b9a382c99a6ce051b5ff1738 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 12:13:42 -0500 Subject: [PATCH 04/10] Update categorizer.py --- LabGym/categorizer.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/LabGym/categorizer.py b/LabGym/categorizer.py index 7da81a16..5a0c8124 100644 --- a/LabGym/categorizer.py +++ b/LabGym/categorizer.py @@ -1974,6 +1974,14 @@ def test_categorizer(self,groundtruth_path,model_path,result_path=None): print('The behavior mode of the Categorizer: Interactive basic.') elif behavior_mode==2: print('The behavior mode of the Categorizer: Interactive advanced (Social distance '+str(parameters['social_distance'][0])+').') + if 'color_code' in list(parameters.keys()): + color_code=int(parameters['color_code'][0]) + if color_code==0: + print('The Categorizer recognizes RGB scale main character and RGB scale supporting characters.') + else: + print('The Categorizer recognizes RGB scale main character and grayscale supporting characters.') + else: + print('The Categorizer recognizes RGB scale main character and grayscale supporting characters.') else: print('The behavior mode of the Categorizer: Static images (non-interactive).') network=int(parameters['network'][0]) From be3bc375d595f910a16a607dce1edcb9c482ce17 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 12:19:21 -0500 Subject: [PATCH 05/10] Update gui_categorizer.py --- LabGym/gui_categorizer.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/LabGym/gui_categorizer.py b/LabGym/gui_categorizer.py index afaf3e92..4e5eb284 100644 --- a/LabGym/gui_categorizer.py +++ b/LabGym/gui_categorizer.py @@ -91,6 +91,7 @@ def __init__(self, parent): self.background_free=True # whether to include background in animations self.black_background=True # whether to set background black self.social_distance=0 # a threshold (folds of size of a single animal) on whether to include individuals that are not main character in behavior examples + self.color_costar=False # in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations self.display_window() @@ -222,6 +223,12 @@ def specify_mode(self,event): else: self.social_distance=0 dialog1.Destroy() + dialog1=wx.MessageDialog(self,'Make both main and supporting characters RGB scale?\nSelect "No" if dont know what it is.','(Optional) RGB supporting characters?',wx.YES_NO|wx.ICON_QUESTION) + if dialog1.ShowModal()==wx.ID_YES: + self.color_costar=True + else: + self.color_costar=False + dialog3.Destroy() self.text_detection.SetLabel('Only Detector-based detection method is available for the selected behavior mode.') else: self.behavior_mode=3 From cab9c81354d9b19bf8af8eed1130aa4d91335594 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 12:24:39 -0500 Subject: [PATCH 06/10] Update gui_categorizer.py --- LabGym/gui_categorizer.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/LabGym/gui_categorizer.py b/LabGym/gui_categorizer.py index 4e5eb284..535b5ff7 100644 --- a/LabGym/gui_categorizer.py +++ b/LabGym/gui_categorizer.py @@ -228,7 +228,7 @@ def specify_mode(self,event): self.color_costar=True else: self.color_costar=False - dialog3.Destroy() + dialog1.Destroy() self.text_detection.SetLabel('Only Detector-based detection method is available for the selected behavior mode.') else: self.behavior_mode=3 @@ -1101,6 +1101,7 @@ def __init__(self, parent): self.background_free=True # whether to include background in animations self.black_background=True # whether to set background black self.social_distance=0 # a threshold (folds of size of a single animal) on whether to include individuals that are not main character in behavior examples + self.color_costar=False # in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations self.out_folder=None # if not None, the folder stores the augmented examples self.training_onfly=False # whether to train a Categorizer using behavior examples that are already augmented previously @@ -1271,6 +1272,12 @@ def specify_categorizer(self,event): else: self.social_distance=0 dialog1.Destroy() + dialog1=wx.MessageDialog(self,'Make both main and supporting characters RGB scale?\nSelect "No" if dont know what it is.','(Optional) RGB supporting characters?',wx.YES_NO|wx.ICON_QUESTION) + if dialog1.ShowModal()==wx.ID_YES: + self.color_costar=True + else: + self.color_costar=False + dialog1.Destroy() else: self.behavior_mode=3 self.text_length.SetLabel('No need to specify this since the selected behavior mode is "Static images".') @@ -1564,7 +1571,8 @@ def train_categorizer(self,event): CA=Categorizers() if self.animation_analyzer is False: if self.behavior_mode>=3: - self.length=self.std=0 + self.length=0 + self.std=0 self.include_bodyparts=False else: self.channel=3 @@ -1576,9 +1584,9 @@ def train_categorizer(self,event): if self.behavior_mode==2: self.channel=3 if self.training_onfly: - CA.train_combnet_onfly(self.data_path,self.path_to_categorizer,out_path=self.out_path,dim_tconv=self.dim_tconv,dim_conv=self.dim_conv,channel=self.channel,time_step=self.length,level_tconv=self.level_tconv,level_conv=self.level_conv,include_bodyparts=self.include_bodyparts,std=self.std,background_free=self.background_free,black_background=self.black_background,behavior_mode=self.behavior_mode,social_distance=self.social_distance) + CA.train_combnet_onfly(self.data_path,self.path_to_categorizer,out_path=self.out_path,dim_tconv=self.dim_tconv,dim_conv=self.dim_conv,channel=self.channel,time_step=self.length,level_tconv=self.level_tconv,level_conv=self.level_conv,include_bodyparts=self.include_bodyparts,std=self.std,background_free=self.background_free,black_background=self.black_background,behavior_mode=self.behavior_mode,social_distance=self.social_distance,color_costar=self.color_costar) else: - CA.train_combnet(self.data_path,self.path_to_categorizer,out_path=self.out_path,dim_tconv=self.dim_tconv,dim_conv=self.dim_conv,channel=self.channel,time_step=self.length,level_tconv=self.level_tconv,level_conv=self.level_conv,aug_methods=self.aug_methods,augvalid=self.augvalid,include_bodyparts=self.include_bodyparts,std=self.std,background_free=self.background_free,black_background=self.black_background,behavior_mode=self.behavior_mode,social_distance=self.social_distance,out_folder=self.out_folder) + CA.train_combnet(self.data_path,self.path_to_categorizer,out_path=self.out_path,dim_tconv=self.dim_tconv,dim_conv=self.dim_conv,channel=self.channel,time_step=self.length,level_tconv=self.level_tconv,level_conv=self.level_conv,aug_methods=self.aug_methods,augvalid=self.augvalid,include_bodyparts=self.include_bodyparts,std=self.std,background_free=self.background_free,black_background=self.black_background,behavior_mode=self.behavior_mode,social_distance=self.social_distance,color_costar=self.color_costar,out_folder=self.out_folder) From e2f6de1ca518b32e2b14bdfc28812767494dc3f0 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 13:06:35 -0500 Subject: [PATCH 07/10] Update analyzebehavior_dt.py --- LabGym/analyzebehavior_dt.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/LabGym/analyzebehavior_dt.py b/LabGym/analyzebehavior_dt.py index 35d56d9d..65c9f04e 100644 --- a/LabGym/analyzebehavior_dt.py +++ b/LabGym/analyzebehavior_dt.py @@ -492,13 +492,14 @@ def detect_track_individuals(self,frames,batch_size,frame_count_analyze,backgrou self.animations[animal_name][i][frame_count_analyze+1-batch_size+batch_count]=np.array(animation) - def detect_track_interact(self,frames,batch_size,frame_count_analyze,background_free=True,black_background=True): + def detect_track_interact(self,frames,batch_size,frame_count_analyze,background_free=True,black_background=True,color_costar=False): # frames: frames that the Detector runs on # batch_size: for batch inferencing by the Detector # frame_count_analyze: the analyzed frame count # background_free: whether to include background in animations # black_background: whether to set background black + # color_costar: in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations tensor_frames=[torch.as_tensor(frame.astype('float32').transpose(2,0,1)) for frame in frames] inputs=[{'image':tensor_frame} for tensor_frame in tensor_frames] @@ -626,7 +627,10 @@ def detect_track_interact(self,frames,batch_size,frame_count_analyze,background_ if background_free: blob=frame*cv2.cvtColor(all_masks[i],cv2.COLOR_GRAY2BGR) if other_mask is not None: - other_blob=cv2.cvtColor(cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)*other_mask,cv2.COLOR_GRAY2BGR) + if color_costar: + other_blob=frame*cv2.cvtColor(other_mask,cv2.COLOR_GRAY2BGR) + else: + other_blob=cv2.cvtColor(cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)*other_mask,cv2.COLOR_GRAY2BGR) blob=cv2.add(blob,other_blob) if black_background is False: if other_mask is not None: From 7afab80cd3bbcb717bbb554289f6c451787c8135 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 13:13:08 -0500 Subject: [PATCH 08/10] Update analyzebehavior_dt.py --- LabGym/analyzebehavior_dt.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/LabGym/analyzebehavior_dt.py b/LabGym/analyzebehavior_dt.py index 65c9f04e..d0d9ce2e 100644 --- a/LabGym/analyzebehavior_dt.py +++ b/LabGym/analyzebehavior_dt.py @@ -681,11 +681,12 @@ def detect_track_interact(self,frames,batch_size,frame_count_analyze,background_ self.track_animal_interact(frame_count_analyze+1-batch_size+batch_count,all_contours,other_contours,all_centers,all_heights,inners=all_inners,other_inners=other_inners,blobs=all_blobs) - def acquire_information(self,batch_size=1,background_free=True,black_background=True): + def acquire_information(self,batch_size=1,background_free=True,black_background=True,color_costar=False): # batch_size: for batch inferencing by the Detector # background_free: whether to include background in animations # black_background: whether to set background black + # color_costar: in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations print('Acquiring information in each frame...') self.log.append('Acquiring information in each frame...') @@ -732,7 +733,7 @@ def acquire_information(self,batch_size=1,background_free=True,black_background= if batch_count==batch_size: batch_count=0 if self.behavior_mode==2: - self.detect_track_interact(batch,batch_size,frame_count_analyze,background_free=background_free,black_background=black_background) + self.detect_track_interact(batch,batch_size,frame_count_analyze,background_free=background_free,black_background=black_background,color_costar=color_costar) else: self.detect_track_individuals(batch,batch_size,frame_count_analyze,background_free=background_free,black_background=black_background,animation=animation) batch=[] @@ -1919,11 +1920,12 @@ def generate_data_interact_basic(self,background_free=True,black_background=True print('Behavior example generation completed!') - def generate_data_interact_advance(self,background_free=True,black_background=True,skip_redundant=1): + def generate_data_interact_advance(self,background_free=True,black_background=True,skip_redundant=1,color_costar=False): # background_free: whether to include background in animations # black_background: whether to set background black # skip_redundant: the interval (in frames) of two consecutively generated behavior example pairs + # color_costar: in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations print('Generating behavior examples...') print(datetime.datetime.now()) @@ -2077,7 +2079,10 @@ def generate_data_interact_advance(self,background_free=True,black_background=Tr if background_free: blob=frame*cv2.cvtColor(all_masks[i],cv2.COLOR_GRAY2BGR) if other_mask is not None: - other_blob=cv2.cvtColor(cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)*other_mask,cv2.COLOR_GRAY2BGR) + if color_costar: + other_blob=frame*cv2.cvtColor(other_mask,cv2.COLOR_GRAY2BGR) + else: + other_blob=cv2.cvtColor(cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)*other_mask,cv2.COLOR_GRAY2BGR) blob=cv2.add(blob,other_blob) if black_background is False: if other_mask is not None: From 62bc8575dde29c24dbccb4b295cb16c4c98bea72 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 13:57:32 -0500 Subject: [PATCH 09/10] Update gui_analyzer.py and gui_categorizer.py --- LabGym/gui_analyzer.py | 9 ++++++++- LabGym/gui_categorizer.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/LabGym/gui_analyzer.py b/LabGym/gui_analyzer.py index 9daa13dd..0273915c 100644 --- a/LabGym/gui_analyzer.py +++ b/LabGym/gui_analyzer.py @@ -131,6 +131,7 @@ def __init__(self, parent): self.black_background=True # whether to set background black self.normalize_distance=True # whether to normalize the distance (in pixel) to the animal contour area self.social_distance=0 # a threshold (folds of size of a single animal) on whether to include individuals that are not main character in behavior examples + self.color_costar=False # in 'interactive advanced' mode, whether to make the supporting roles RGB scale in animations self.specific_behaviors={} # sex or identity-specific behaviors self.correct_ID=False # whether to use sex or identity-specific behaviors to guide ID correction when ID switching is likely to happen @@ -400,6 +401,12 @@ def select_categorizer(self,event): self.social_distance=int(parameters['social_distance'][0]) if self.social_distance==0: self.social_distance=float('inf') + if 'color_code' in parameters: + color_code=int(parameters['color_code'][0]) + if color_code==0: + self.color_costar=True + else: + self.color_costar=False self.text_detection.SetLabel('Only Detector-based detection method is available for the selected Categorizer.') if self.behavior_mode==3: self.text_detection.SetLabel('Only Detector-based detection method is available for the selected Categorizer.') @@ -1034,7 +1041,7 @@ def analyze_behaviors(self,event): if self.behavior_mode==1: AAD.acquire_information_interact_basic(batch_size=self.detector_batch,background_free=self.background_free,black_background=self.black_background) else: - AAD.acquire_information(batch_size=self.detector_batch,background_free=self.background_free,black_background=self.black_background) + AAD.acquire_information(batch_size=self.detector_batch,background_free=self.background_free,black_background=self.black_background,color_costar=self.color_costar) if self.behavior_mode!=1: AAD.craft_data() if self.path_to_categorizer is not None: diff --git a/LabGym/gui_categorizer.py b/LabGym/gui_categorizer.py index 535b5ff7..05a3f780 100644 --- a/LabGym/gui_categorizer.py +++ b/LabGym/gui_categorizer.py @@ -680,7 +680,7 @@ def generate_data(self,event): elif self.behavior_mode==1: AAD.generate_data_interact_basic(background_free=self.background_free,black_background=self.black_background,skip_redundant=self.skip_redundant) else: - AAD.generate_data_interact_advance(background_free=self.background_free,black_background=self.black_background,skip_redundant=self.skip_redundant) + AAD.generate_data_interact_advance(background_free=self.background_free,black_background=self.black_background,skip_redundant=self.skip_redundant,color_costar=self.color_costar) From b5c78d4ff485a14ea1a6c1356aa63a31ac989847 Mon Sep 17 00:00:00 2001 From: Yujia Hu Date: Thu, 8 Jan 2026 16:29:21 -0500 Subject: [PATCH 10/10] Update gui_analyzer.py --- LabGym/gui_analyzer.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/LabGym/gui_analyzer.py b/LabGym/gui_analyzer.py index 0273915c..7e492186 100644 --- a/LabGym/gui_analyzer.py +++ b/LabGym/gui_analyzer.py @@ -1359,12 +1359,16 @@ def input_file(self,event): dialog=wx.FileDialog(self,'Select the all_events.xlsx file.','',wildcard='all_events file (*.xlsx)|*.xlsx',style=wx.FD_OPEN) if dialog.ShowModal()==wx.ID_OK: all_events_file=Path(dialog.GetPath()) - self.names_and_colors={} + names_and_colors={} self.events_probability,self.time_points,behavior_names=parse_all_events_file(all_events_file) colors=[('#ffffff',str(hex_code)) for hex_code in mpl.colors.cnames.values()] for color,behavior in zip(colors,behavior_names): - self.names_and_colors[behavior]=color + names_and_colors[behavior]=color self.text_inputfile.SetLabel(f'all_events.xlsx path: {all_events_file}') + if self.names_and_colors is None: + self.names_and_colors=names_and_colors + else: + self.names_and_colors=None dialog.Destroy()