From 780559d77bb12920a24f6cd470f049d40439dc3c Mon Sep 17 00:00:00 2001 From: whitekirin <113206109@gms.tcu.edu.tw> Date: Sun, 19 Oct 2025 16:56:00 +0800 Subject: [PATCH] The Stage is Xception+U-Net+Xception and U-Net estimates Convolution --- Calculate_Process/Calculate.py | 12 +- .../__pycache__/Calculate.cpython-311.pyc | Bin 6788 -> 6840 bytes .../__pycache__/Calculate.cpython-312.pyc | Bin 0 -> 6279 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 169 -> 189 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 175 bytes Image_Process/Image_Generator.py | 60 +- .../Image_Mask_Ground_Truth_Processing.py | 262 +++ .../Image_Generator.cpython-311.pyc | Bin 10796 -> 11678 bytes .../Image_Generator.cpython-312.pyc | Bin 0 -> 11000 bytes ...sk_Ground_Truth_Processing.cpython-311.pyc | Bin 0 -> 13420 bytes .../image_enhancement.cpython-311.pyc | Bin 0 -> 13260 bytes .../image_enhancement.cpython-312.pyc | Bin 0 -> 10607 bytes Image_Process/image_enhancement.py | 366 ++- Image_Process/load_and_ImageGenerator.py | 58 - Load_process/LoadData.py | 9 +- Load_process/Load_Indepentend.py | 69 +- .../__pycache__/LoadData.cpython-311.pyc | Bin 2616 -> 2765 bytes .../__pycache__/LoadData.cpython-312.pyc | Bin 0 -> 2413 bytes .../Load_Indepentend.cpython-311.pyc | Bin 4199 -> 5125 bytes .../Load_Indepentend.cpython-312.pyc | Bin 0 -> 3631 bytes .../__pycache__/Loading_Tools.cpython-311.pyc | Bin 5637 -> 5650 bytes .../__pycache__/Loading_Tools.cpython-312.pyc | Bin 0 -> 5215 bytes .../file_processing.cpython-311.pyc | Bin 4181 -> 3792 bytes .../file_processing.cpython-312.pyc | Bin 0 -> 3418 bytes Load_process/file_processing.py | 10 +- Model_Loss/CIOU_Loss.py | 315 +++ Model_Loss/Loss.py | 18 +- Model_Loss/Perceptual_Loss.py | 116 + Model_Loss/Segmentation_Loss.py | 22 + .../__pycache__/CIOU_Loss.cpython-311.pyc | Bin 0 -> 16175 bytes Model_Loss/__pycache__/Loss.cpython-311.pyc | Bin 1428 -> 1738 bytes Model_Loss/__pycache__/Loss.cpython-312.pyc | Bin 0 -> 1262 bytes .../Perceptual_Loss.cpython-311.pyc | Bin 0 -> 5618 bytes .../Segmentation_Loss.cpython-311.pyc | Bin 0 -> 1793 bytes .../binary_cross_entropy.cpython-311.pyc | Bin 0 -> 6305 bytes Model_Loss/binary_cross_entropy.py | 145 ++ README.md | 122 +- Training_Tools/PreProcess.py | 96 +- Training_Tools/Tools.py | 59 - .../__pycache__/PreProcess.cpython-311.pyc | Bin 5703 -> 8646 bytes .../__pycache__/PreProcess.cpython-312.pyc | Bin 0 -> 5616 bytes .../__pycache__/Tools.cpython-311.pyc | Bin 3985 -> 1450 bytes .../__pycache__/Tools.cpython-312.pyc | Bin 0 -> 1271 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 166 -> 186 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 172 bytes __pycache__/Processing_image.cpython-311.pyc | Bin 0 -> 1978 bytes .../claculate_output_data.cpython-311.pyc | Bin 0 -> 5186 bytes ...ing_data_with_segmentation.cpython-311.pyc | Bin 0 -> 152 bytes __pycache__/main.cpython-311.pyc | Bin 0 -> 8643 bytes .../test_binary_cross_entropy.cpython-311.pyc | Bin 0 -> 4415 bytes __pycache__/test_bounding_box.cpython-311.pyc | Bin 0 -> 2608 bytes __pycache__/test_main.cpython-311.pyc | Bin 0 -> 7102 bytes __pycache__/test_mask_loading.cpython-311.pyc | Bin 0 -> 3307 bytes __pycache__/test_model_branch.cpython-311.pyc | Bin 0 -> 4192 bytes .../test_processing_main.cpython-311.pyc | Bin 0 -> 6539 bytes __pycache__/test_segmentation.cpython-311.pyc | Bin 0 -> 2321 bytes .../testing_Labels_Accuracy.cpython-311.pyc | Bin 0 -> 9005 bytes .../ValidationTheEnterData.cpython-311.pyc | Bin 1104 -> 1117 bytes .../ValidationTheEnterData.cpython-312.pyc | Bin 0 -> 961 bytes a00.xml | 26 + .../__pycache__/__init__.cpython-311.pyc | Bin 175 -> 188 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 174 bytes .../all_model_tools.cpython-311.pyc | Bin 3231 -> 3161 bytes .../all_model_tools.cpython-312.pyc | Bin 0 -> 3031 bytes all_models_tools/all_model_tools.py | 21 +- .../pre_train_model_construction.py | 116 - annotation_files.txt | Bin 0 -> 15738 bytes annotation_question_files.txt | Bin 0 -> 7558 bytes draw_tools/Grad_cam.py | 38 +- draw_tools/Saliency_Map.py | 195 ++ .../__pycache__/Grad_cam.cpython-311.pyc | Bin 6768 -> 7161 bytes .../__pycache__/Grad_cam.cpython-312.pyc | Bin 0 -> 6497 bytes .../__pycache__/Saliency_Map.cpython-311.pyc | Bin 0 -> 9193 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 169 -> 182 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 168 bytes draw_tools/__pycache__/draw.cpython-311.pyc | Bin 5635 -> 5637 bytes draw_tools/__pycache__/draw.cpython-312.pyc | Bin 0 -> 5064 bytes draw_tools/draw.py | 76 +- experiments/Model_All_Step.py | 210 -- experiments/Models/GastroSegNet_Model.py | 91 + .../Models/Xception_Model_Modification.py | 148 ++ experiments/Models/__init__.py | 0 .../GastroSegNet_Model.cpython-311.pyc | Bin 0 -> 5059 bytes ...ception_Model_Modification.cpython-311.pyc | Bin 0 -> 11162 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 190 bytes .../__pycache__/pytorch_Model.cpython-311.pyc | Bin 0 -> 2448 bytes experiments/Models/pytorch_Model.py | 30 + .../Training/Identification_Block_Training.py | 461 ++++ .../Training/Segmentation_Block_Training.py | 467 ++++ experiments/Training/__init__.py | 2 + ...ntification_Block_Training.cpython-311.pyc | Bin 0 -> 29242 bytes ...egmentation_Block_Training.cpython-311.pyc | Bin 0 -> 27038 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 351 bytes .../Model_All_Step.cpython-311.pyc | Bin 13057 -> 18141 bytes .../Model_All_Step.cpython-312.pyc | Bin 0 -> 15569 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 170 -> 183 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 169 bytes .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 169 bytes .../__pycache__/experiment.cpython-311.pyc | Bin 13205 -> 23799 bytes .../__pycache__/experiment.cpython-312.pyc | Bin 0 -> 13669 bytes .../__pycache__/experiment.cpython-313.pyc | Bin 0 -> 12811 bytes .../__pycache__/pytorch_Model.cpython-311.pyc | Bin 3406 -> 13252 bytes .../__pycache__/pytorch_Model.cpython-312.pyc | Bin 0 -> 2211 bytes experiments/experiment.py | 518 +++-- experiments/pytorch_Model.py | 81 - main.py | 152 +- merge_class/__pycache__/merge.cpython-311.pyc | Bin 4979 -> 4984 bytes merge_class/__pycache__/merge.cpython-312.pyc | Bin 0 -> 4446 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 441 -> 454 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 435 bytes .../__pycache__/processing.cpython-311.pyc | Bin 3080 -> 2217 bytes .../__pycache__/processing.cpython-312.pyc | Bin 0 -> 3449 bytes .../processing_for_cut_image.cpython-311.pyc | Bin 4573 -> 3427 bytes .../processing_for_cut_image.cpython-312.pyc | Bin 0 -> 3030 bytes model_data_processing/processing.py | 93 +- .../processing_for_cut_image.py | 22 +- pyproject.toml | 21 + test.ipynb | 1973 ++++++++++++++++- test_binary_cross_entropy.py | 68 + test_bounding_box.py | 66 + test_bounding_box_result.png | Bin 0 -> 1874 bytes test_main.py | 121 + test_mask_loading.py | 58 + test_model_branch.py | 91 + test_processing_main.py | 117 + test_segmentation.py | 48 + testing_Labels_Accuracy.py | 214 +- training_files.txt | Bin 0 -> 8350 bytes training_question_files.txt | Bin 0 -> 3860 bytes utils/Stomach_Config.py | 73 + .../Stomach_Config.cpython-311.pyc | Bin 0 -> 4548 bytes .../Stomach_Config.cpython-312.pyc | Bin 0 -> 1662 bytes uv.lock | 1404 ++++++++++++ 133 files changed, 7619 insertions(+), 1121 deletions(-) create mode 100644 Calculate_Process/__pycache__/Calculate.cpython-312.pyc create mode 100644 Calculate_Process/__pycache__/__init__.cpython-312.pyc create mode 100644 Image_Process/Image_Mask_Ground_Truth_Processing.py create mode 100644 Image_Process/__pycache__/Image_Generator.cpython-312.pyc create mode 100644 Image_Process/__pycache__/Image_Mask_Ground_Truth_Processing.cpython-311.pyc create mode 100644 Image_Process/__pycache__/image_enhancement.cpython-311.pyc create mode 100644 Image_Process/__pycache__/image_enhancement.cpython-312.pyc delete mode 100644 Image_Process/load_and_ImageGenerator.py create mode 100644 Load_process/__pycache__/LoadData.cpython-312.pyc create mode 100644 Load_process/__pycache__/Load_Indepentend.cpython-312.pyc create mode 100644 Load_process/__pycache__/Loading_Tools.cpython-312.pyc create mode 100644 Load_process/__pycache__/file_processing.cpython-312.pyc create mode 100644 Model_Loss/CIOU_Loss.py create mode 100644 Model_Loss/Perceptual_Loss.py create mode 100644 Model_Loss/Segmentation_Loss.py create mode 100644 Model_Loss/__pycache__/CIOU_Loss.cpython-311.pyc create mode 100644 Model_Loss/__pycache__/Loss.cpython-312.pyc create mode 100644 Model_Loss/__pycache__/Perceptual_Loss.cpython-311.pyc create mode 100644 Model_Loss/__pycache__/Segmentation_Loss.cpython-311.pyc create mode 100644 Model_Loss/__pycache__/binary_cross_entropy.cpython-311.pyc create mode 100644 Model_Loss/binary_cross_entropy.py create mode 100644 Training_Tools/__pycache__/PreProcess.cpython-312.pyc create mode 100644 Training_Tools/__pycache__/Tools.cpython-312.pyc create mode 100644 Training_Tools/__pycache__/__init__.cpython-312.pyc create mode 100644 __pycache__/Processing_image.cpython-311.pyc create mode 100644 __pycache__/claculate_output_data.cpython-311.pyc create mode 100644 __pycache__/generate_training_data_with_segmentation.cpython-311.pyc create mode 100644 __pycache__/main.cpython-311.pyc create mode 100644 __pycache__/test_binary_cross_entropy.cpython-311.pyc create mode 100644 __pycache__/test_bounding_box.cpython-311.pyc create mode 100644 __pycache__/test_main.cpython-311.pyc create mode 100644 __pycache__/test_mask_loading.cpython-311.pyc create mode 100644 __pycache__/test_model_branch.cpython-311.pyc create mode 100644 __pycache__/test_processing_main.cpython-311.pyc create mode 100644 __pycache__/test_segmentation.cpython-311.pyc create mode 100644 __pycache__/testing_Labels_Accuracy.cpython-311.pyc create mode 100644 _validation/__pycache__/ValidationTheEnterData.cpython-312.pyc create mode 100644 a00.xml create mode 100644 all_models_tools/__pycache__/__init__.cpython-312.pyc create mode 100644 all_models_tools/__pycache__/all_model_tools.cpython-312.pyc delete mode 100644 all_models_tools/pre_train_model_construction.py create mode 100644 annotation_files.txt create mode 100644 annotation_question_files.txt create mode 100644 draw_tools/Saliency_Map.py create mode 100644 draw_tools/__pycache__/Grad_cam.cpython-312.pyc create mode 100644 draw_tools/__pycache__/Saliency_Map.cpython-311.pyc create mode 100644 draw_tools/__pycache__/__init__.cpython-312.pyc create mode 100644 draw_tools/__pycache__/draw.cpython-312.pyc delete mode 100644 experiments/Model_All_Step.py create mode 100644 experiments/Models/GastroSegNet_Model.py create mode 100644 experiments/Models/Xception_Model_Modification.py create mode 100644 experiments/Models/__init__.py create mode 100644 experiments/Models/__pycache__/GastroSegNet_Model.cpython-311.pyc create mode 100644 experiments/Models/__pycache__/Xception_Model_Modification.cpython-311.pyc create mode 100644 experiments/Models/__pycache__/__init__.cpython-311.pyc create mode 100644 experiments/Models/__pycache__/pytorch_Model.cpython-311.pyc create mode 100644 experiments/Models/pytorch_Model.py create mode 100644 experiments/Training/Identification_Block_Training.py create mode 100644 experiments/Training/Segmentation_Block_Training.py create mode 100644 experiments/Training/__init__.py create mode 100644 experiments/Training/__pycache__/Identification_Block_Training.cpython-311.pyc create mode 100644 experiments/Training/__pycache__/Segmentation_Block_Training.cpython-311.pyc create mode 100644 experiments/Training/__pycache__/__init__.cpython-311.pyc create mode 100644 experiments/__pycache__/Model_All_Step.cpython-312.pyc create mode 100644 experiments/__pycache__/__init__.cpython-312.pyc create mode 100644 experiments/__pycache__/__init__.cpython-313.pyc create mode 100644 experiments/__pycache__/experiment.cpython-312.pyc create mode 100644 experiments/__pycache__/experiment.cpython-313.pyc create mode 100644 experiments/__pycache__/pytorch_Model.cpython-312.pyc delete mode 100644 experiments/pytorch_Model.py create mode 100644 merge_class/__pycache__/merge.cpython-312.pyc create mode 100644 model_data_processing/__pycache__/__init__.cpython-312.pyc create mode 100644 model_data_processing/__pycache__/processing.cpython-312.pyc create mode 100644 model_data_processing/__pycache__/processing_for_cut_image.cpython-312.pyc create mode 100644 pyproject.toml create mode 100644 test_binary_cross_entropy.py create mode 100644 test_bounding_box.py create mode 100644 test_bounding_box_result.png create mode 100644 test_main.py create mode 100644 test_mask_loading.py create mode 100644 test_model_branch.py create mode 100644 test_processing_main.py create mode 100644 test_segmentation.py create mode 100644 training_files.txt create mode 100644 training_question_files.txt create mode 100644 utils/Stomach_Config.py create mode 100644 utils/__pycache__/Stomach_Config.cpython-311.pyc create mode 100644 utils/__pycache__/Stomach_Config.cpython-312.pyc create mode 100644 uv.lock diff --git a/Calculate_Process/Calculate.py b/Calculate_Process/Calculate.py index e80953f..8a479c7 100644 --- a/Calculate_Process/Calculate.py +++ b/Calculate_Process/Calculate.py @@ -22,11 +22,11 @@ class Calculate(): DataFrame = pd.DataFrame( { "loss" : "{:.2f}".format(Loss), - "precision" : "{:.2f}".format(Precision * 100), - "recall" : "{:.2f}".format(Recall * 100), - "accuracy" : "{:.2f}".format(Accuracy * 100), - "f1" : "{:.2f}".format(F1 * 100), - "AUC" : "{:.2f}".format(AUC * 100) + "precision" : "{:.2f}".format(Precision), + "recall" : "{:.2f}".format(Recall), + "accuracy" : "{:.2f}".format(Accuracy), + "f1" : "{:.2f}".format(F1), + "AUC" : "{:.2f}".format(AUC) }, index = [0] ) self.History.append(DataFrame) @@ -40,7 +40,7 @@ class Calculate(): F1_Mean = np.mean(self.F1_Record) AUC_Mean = np.mean(self.AUC_Record) - Mean_DataFram = self.Construction_To_DataFrame(Loss_Mean, Accuracy_Mean, Precision_Mean, Recall_Mean, F1_Mean, AUC_Mean) + Mean_DataFram = self.Construction_To_DataFrame(Loss_Mean, Accuracy_Mean * 100, Precision_Mean * 100, Recall_Mean * 100, F1_Mean * 100, AUC_Mean * 100) return Mean_DataFram diff --git a/Calculate_Process/__pycache__/Calculate.cpython-311.pyc b/Calculate_Process/__pycache__/Calculate.cpython-311.pyc index 099f6990379f930b416a3abde8b1e0c95dd84d98..20f6370f560a4442f3f817621ab2d1a619324a29 100644 GIT binary patch delta 625 zcmZoM-C@eJoR^o20SF#VRm|APQ^{l;sGpIao2p-)ky(Eo{3R&^AQ#kMt+cK%s~7(ijjd~I>Tf~F0sjZ!jh9$G4oG8 z&nC&pJozA-`eZj2FmLibu&C7J^(=fK*~wKb{9GwabJ$Xt(;3&WOg3fr|=7?fkI603)$?2k;#T7Y=8`8@2?PuAq zFuN#ibVb_ehOFxR_*wBQA}-3BU6D1rAud0?ep3B{qKo2MSH!h$NGQzbpT)m|`J#l* z6$zcm&p3kkIf3Sa{m}yRhveo2PJKrE6vir628J4DD9r+;S)nu=gkHwRz_1#KA)uDM zhCP@;lgaO8%H*|NdW@Qr?{F<)JU_XSyVfTt^rBPfh49o18QB-ZvoGXUT&S+Qm|ORO zfx(f|tTlnS4>e3>Y6A zf_qu5sNh~f>n|wx6M#>8$D+waRfy6Hko80`A(wtPgBEQK@ GQcVE)#HVlo delta 502 zcmdmC+G5JHoR^o20SIJGZ=`SJsbrG3)i2L4$}TQQOitAgD9TSSO3aN9s4U4ZO3sM) zOD*5LgGru=apmS4EGCRx+(3=YK>WF4vOK5ssjFEw1H4sBU3iBMc6qaj zxFT(FLsoTu{H*vD5j&Vy#$A-Pxgu+GLtK7({iON@MJt>aR$LS}xFT+FLqcIb|1AC$ z%qx;ta$b}$x*}mT`7lQi7YEQ*uxHaY%X9iNPCh0e!&D?ac{P_FqxR%mTuT^dPOj&! z6$^~NkeG8Juk=EB{YM4{Nk^tHAab(@&mI;=-N~$iW{ldKZ3OqSS}6j}dkOMwkrIed z1`#SCLKQ^tfd~ZsNh~hXm?R~`=sj6hN`ldUvYAv90NTxln*aa+ diff --git a/Calculate_Process/__pycache__/Calculate.cpython-312.pyc b/Calculate_Process/__pycache__/Calculate.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e9fc3497901695207e5567828678d3c2cb97eca GIT binary patch literal 6279 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 U(Lb@n|0UW~s?ygOqLS|a0RRxKK>z>% literal 0 HcmV?d00001 diff --git a/Calculate_Process/__pycache__/__init__.cpython-311.pyc b/Calculate_Process/__pycache__/__init__.cpython-311.pyc index 3406166d95ef7487bf08ff5ed29468dd93797b8f..ad077434ee1d2d951bf82bb236f6925d7665785b 100644 GIT binary patch delta 76 zcmZ3IW3%rxzvWD(EV_SknGt J@!pBWUI4Y(63GAn diff --git a/Calculate_Process/__pycache__/__init__.cpython-312.pyc b/Calculate_Process/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0069b7a58eef5002d5eebe95534db649d93686d4 GIT binary patch literal 175 zcmX@j%ge<81bY{7W`O9&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<>z7*6Ht_&UX+-d znU@|@T#}!gn4A%xoS2uKS_G4c52!53F9HhtrIyDyC*~xV<|LM+#sl>wrxq8-#K&jm oWtPOp>lIYq;;_lhPbtkwwJTx;8qWyC#URE None: + def __init__(self, Training_Root, Generator_Root, Labels, Image_Size, Class_Count) -> None: self._validation = validation_the_enter_data() self.stop = 0 self.Labels = Labels + self.Training_Root = Training_Root self.Generator_Root = Generator_Root self.Image_Size = Image_Size - self.Class_Count = 904 + self.Class_Count = Class_Count pass - def Processing_Main(self, Training_Dict_Data_Root): + def Processing_Main(self): data_size = 2712 + File = Process_File() + Prepare = Load_Data_Prepare() + Load_Tool = Load_Data_Tools() - # 製作標準資料增強 - ''' - 這裡我想要做的是依照paper上的資料強化IMAGE DATA COLLECTION AND IMPLEMENTATION OF DEEP LEARNING-BASED MODEL IN DETECTING MONKEYPOX DISEASE USING MODIFIED VGG16 - 產生出資料強化後的影像 - ''' - for i in range(1, 5, 1): - print("\nAugmentation one Generator image") - data_size = self.get_processing_Augmentation(Training_Dict_Data_Root, i, data_size) - self.stop += data_size + if not File.Judge_File_Exist(self.Generator_Root): # 檔案若不存在 + # 確定我要多少個List + Prepare.Set_Data_Content([], len(self.Labels)) - print() + # 製作讀檔字典並回傳檔案路徑 + Prepare.Set_Label_List(self.Labels) + Prepare.Set_Data_Dictionary(Prepare.Get_Label_List(), Prepare.Get_Data_Content(), len(self.Labels)) + Original_Dict_Data_Root = Prepare.Get_Data_Dict() + get_all_original_image_data = Load_Tool.get_data_root(self.Training_Root, Original_Dict_Data_Root, Prepare.Get_Label_List()) + + # 儲存資料強化後資料 + # 製作標準資料增強 + ''' + 這裡我想要做的是依照paper上的資料強化IMAGE DATA COLLECTION AND IMPLEMENTATION OF DEEP LEARNING-BASED MODEL IN DETECTING MONKEYPOX DISEASE USING MODIFIED VGG16 + 產生出資料強化後的影像 + ''' + for i in range(1, 5, 1): + print(f"\nAugmentation {i} Generator image") + data_size = self.get_processing_Augmentation(get_all_original_image_data, i, data_size) + self.stop += data_size + else: # 若檔案存在 + print("standard data and myself data are exist\n") def get_processing_Augmentation(self, original_image_root : dict, Augment_choose, data_size): Prepaer = Load_Data_Prepare() @@ -51,7 +63,6 @@ class Image_generator(): strardand = 要使用哪種Image Augmentation ''' File = Process_File() - image_processing = Read_image_and_Process_image(self.Image_Size) tool = Training_Precesses(self.Image_Size) Classes = [] Transform = self.Generator_Content(stardand) @@ -60,15 +71,15 @@ class Image_generator(): Image_Roots = self.get_data_roots[label] save_root = File.Make_Save_Root(label, save_roots) # 合併路徑 - Classes = image_processing.make_label_list(len(Image_Roots), "1") - Training_Dataset = tool.Setting_DataSet(Image_Roots, Classes) + Classes = make_label_list(len(Image_Roots), "1") + Training_Dataset = tool.Setting_DataSet(Image_Roots, Classes, "Generator") Training_DataLoader = tool.Dataloader_Sampler(Training_Dataset, 1, False) if File.JudgeRoot_MakeDir(save_root): # 判斷要存的資料夾存不存在,不存在則創立 print("The file is exist.This Script is not creating new fold.") for i in range(1, int(self.Class_Count / len(Image_Roots)) + 1, 1): - for batch_idx, (images, labels) in enumerate(Training_DataLoader): + for batch_idx, (images, labels, File_Name, File_Classes) in enumerate(Training_DataLoader): for j, img in enumerate(images): # if i == self.stop: # break @@ -78,7 +89,6 @@ class Image_generator(): # 轉換為 NumPy 陣列並從 BGR 轉為 RGB img_np = img.numpy().transpose(1, 2, 0) # 轉回 HWC 格式 - img_np = cv2.cvtColor(img_np, cv2.COLOR_BGR2RGB) # BGR 轉 RGB img_pil = transforms.ToPILImage()(img_np) File.Save_PIL_File("image_" + label + str(data_size) + ".png", save_root, img_pil) # 存檔 diff --git a/Image_Process/Image_Mask_Ground_Truth_Processing.py b/Image_Process/Image_Mask_Ground_Truth_Processing.py new file mode 100644 index 0000000..1cefe51 --- /dev/null +++ b/Image_Process/Image_Mask_Ground_Truth_Processing.py @@ -0,0 +1,262 @@ +import xml.etree.ElementTree as ET +import cv2 +import os +import numpy as np +from typing import List, Dict, Optional, Tuple +from utils.Stomach_Config import Loading_Config + +class XMLAnnotationProcessor: + """ + XML標註檔案處理器 + 專門處理包含bounding box資訊的XML檔案,並在對應圖片上繪製邊界框 + """ + + def __init__(self, dataset_root: str): + """ + 初始化XML處理器 + + Args: + dataset_root: 圖片資料集根目錄 + output_folder: 輸出資料夾 + """ + self.dataset_root = dataset_root + self.box_color = (0, 255, 0) # 綠色邊界框 + self.text_color = (0, 255, 0) # 綠色文字 + self.box_thickness = 2 + self.font_scale = 0.5 + self.font = cv2.FONT_HERSHEY_SIMPLEX + + def _ensure_output_folder(self, Save_Root: str) -> None: + """確保輸出資料夾存在""" + if not os.path.exists(Save_Root): + os.makedirs(Save_Root) + + def parse_xml(self, xml_file_path: str, Label: str) -> Optional[Dict]: + """ + 解析XML檔案並提取所有相關資訊 + + Args: + xml_file_path: XML檔案路徑 + + Returns: + Dict: 包含檔案資訊和bounding box的字典,解析失敗時返回None + """ + try: + tree = ET.parse(xml_file_path) + root = tree.getroot() + + # 提取基本資訊 + filename_element = root.find('filename') + + if filename_element is None: + print(f"找不到path元素在 {xml_file_path}") + return None + + filename = filename_element.text if filename_element is not None else "Unknown" + Original_Image_Data_Root = os.path.join(self.dataset_root, Label) + Original_Image_Data_Root = os.path.join(Original_Image_Data_Root, filename) + + # 提取圖片尺寸 + size_element = root.find('size') + width = int(size_element.find('width').text) if size_element is not None else 0 + height = int(size_element.find('height').text) if size_element is not None else 0 + depth = int(size_element.find('depth').text) if size_element is not None else 3 + + # 提取所有bounding box + bounding_boxes = [] + objects = root.findall('object') + + for obj in objects: + bndbox = obj.find('bndbox') + if bndbox is not None: + bbox_info = { + 'name': obj.find('name').text if obj.find('name') is not None else "Unknown", + 'pose': obj.find('pose').text if obj.find('pose') is not None else "Unspecified", + 'truncated': int(obj.find('truncated').text) if obj.find('truncated') is not None else 0, + 'difficult': int(obj.find('difficult').text) if obj.find('difficult') is not None else 0, + 'xmin': int(bndbox.find('xmin').text), + 'ymin': int(bndbox.find('ymin').text), + 'xmax': int(bndbox.find('xmax').text), + 'ymax': int(bndbox.find('ymax').text) + } + bounding_boxes.append(bbox_info) + + return { + 'filename': filename, + 'image_path': Original_Image_Data_Root, + 'width': width, + 'height': height, + 'depth': depth, + 'bounding_boxes': bounding_boxes + } + + except Exception as e: + print(f"解析XML檔案 {xml_file_path} 時發生錯誤: {str(e)}") + return None + + def load_image(self, image_path: str) -> Optional[np.ndarray]: + """ + 載入圖片檔案 + + Args: + image_path: 圖片檔案路徑 + + Returns: + np.ndarray: 圖片陣列,載入失敗時返回None + """ + if not os.path.exists(image_path): + print(f"圖片檔案不存在: {image_path}") + return None + + image = cv2.imread(image_path) + if image is None: + print(f"無法讀取圖片: {image_path}") + return None + + return image + + def draw_bounding_boxes(self, image: np.ndarray, bounding_boxes: List[Dict]) -> np.ndarray: + """ + 創建遮罩圖片:bounding box內保持原圖,外部為黑色 + + Args: + image: 圖片陣列 + bounding_boxes: bounding box資訊列表 + + Returns: + np.ndarray: 處理後的遮罩圖片陣列 + """ + # 創建黑色背景圖片 + height, width = image.shape[:2] + result_image = np.zeros((height, width, 3), dtype=np.uint8) + + for i, bbox in enumerate(bounding_boxes): + xmin, ymin = bbox['xmin'], bbox['ymin'] + xmax, ymax = bbox['xmax'], bbox['ymax'] + object_name = bbox['name'] + + # 確保座標在圖片範圍內 + xmin = max(0, min(xmin, width-1)) + ymin = max(0, min(ymin, height-1)) + xmax = max(0, min(xmax, width-1)) + ymax = max(0, min(ymax, height-1)) + + # 將bounding box範圍內的原圖複製到結果圖像中 + result_image[ymin:ymax, xmin:xmax] = image[ymin:ymax, xmin:xmax] + + print(f"Object {i+1}: {object_name} - 座標: ({xmin}, {ymin}, {xmax}, {ymax})") + + return result_image + + def save_annotated_image(self, image: np.ndarray, original_filename: str, Annotation_Root : str, Label : str) -> str: + """ + 儲存標註後的圖片 + + Args: + image: 標註後的圖片陣列 + original_filename: 原始檔案名稱 + + Returns: + str: 儲存的檔案路徑 + """ + output_filename = f"annotated_{original_filename}" + output_path = os.path.join(Annotation_Root, Label) + Save_Image_Roots = os.path.join(output_path, output_filename) + # 確保輸出資料夾存在 + self._ensure_output_folder(output_path) + + cv2.imwrite(Save_Image_Roots, image) + print(f"已儲存標註圖片至: {Save_Image_Roots}") + return Save_Image_Roots + + def process_single_xml(self, xml_file_path: str, Annotation_Root : str, Label : str) -> Optional[Tuple[np.ndarray, str]]: + """ + 處理單一XML檔案 + + Args: + xml_file_path: XML檔案路徑 + + Returns: + Tuple[np.ndarray, str]: (標註後的圖片, 輸出路徑),處理失敗時返回None + """ + # 解析XML + xml_data = self.parse_xml(xml_file_path, Label) + if xml_data is None: + return None + + # 載入圖片 + image = self.load_image(xml_data['image_path']) + if image is None: + return None + + # 繪製bounding box + annotated_image = self.draw_bounding_boxes(image, xml_data['bounding_boxes']) + + # 儲存結果 + output_path = self.save_annotated_image(annotated_image, xml_data['filename'], Annotation_Root, Label) + + return annotated_image, output_path + + def process_multiple_xml(self, xml_folder_path: str, Annotation_Root : str, Label : str) -> List[Tuple[str, bool]]: + """ + 批量處理多個XML檔案 + + Args: + xml_folder_path: 包含XML檔案的資料夾路徑 + + Returns: + List[Tuple[str, bool]]: [(檔案名稱, 處理成功與否), ...] + """ + if not os.path.exists(xml_folder_path): + print(f"XML資料夾不存在: {xml_folder_path}") + return [] + + xml_files = [f for f in os.listdir(xml_folder_path) if f.endswith('.xml')] + + if not xml_files: + print(f"在 {xml_folder_path} 中找不到XML檔案") + return [] + + print(f"找到 {len(xml_files)} 個XML檔案") + for xml_file in xml_files: + try: + Read_XML_File = os.path.join(xml_folder_path, xml_file) + self.process_single_xml(Read_XML_File, Annotation_Root, Label) + print(f"\n處理檔案: {xml_file}") + except Exception as e: + print(f"處理 {xml_file} 時發生錯誤: {str(e)}") + return + + def get_bounding_boxes_info(self, xml_file_path: str) -> Optional[Dict]: + """ + 僅提取XML中的bounding box資訊,不進行圖片處理 + + Args: + xml_file_path: XML檔案路徑 + + Returns: + Dict: 包含檔案資訊和bounding box座標的字典 + """ + return self.parse_xml(xml_file_path) + + def set_drawing_style(self, box_color: Tuple[int, int, int] = None, + text_color: Tuple[int, int, int] = None, + box_thickness: int = None, + font_scale: float = None) -> None: + """ + 設定繪圖樣式 + + Args: + box_color: 邊界框顏色 (B, G, R) + text_color: 文字顏色 (B, G, R) + box_thickness: 邊界框粗細 + font_scale: 字體大小 + """ + if box_color is not None: + self.box_color = box_color + if text_color is not None: + self.text_color = text_color + if box_thickness is not None: + self.box_thickness = box_thickness + if font_scale is not None: + self.font_scale = font_scale diff --git a/Image_Process/__pycache__/Image_Generator.cpython-311.pyc b/Image_Process/__pycache__/Image_Generator.cpython-311.pyc index aed1412b78dfa9de5a61677676a2218896193e83..6e9158b0283d3fccba7138fe6dd4a186e05e86d5 100644 GIT binary patch delta 3456 zcmZ`+eQX;^6`%F4*SpU8BZ=dDwsG@e$LY0cFUP6*YOm=xq@^^u2+}sbt-W!a`Xh|D zy=$;9{R5#O1(a$|ca;!#MnEs9hd8OI^!}oPf6yI>byyT@rJza(L=Xa(yMk09;LSRA z&Y?`!Z|BXtdGGDad%rh%Z{qEX&UYOSJAyW2{B-vB{#(u_CVnf>Kba7w1O`P=#2Ob9 z_9?sB=i@aAX-Z;{1)V|>+gDLUxMM-+F8oSu$`KLAQP93g*&t)M67p3g6qm0k@lZUL zR&QD(0Q!P%UCg7+d~tnR6Gr9>n5-qOU9B>Dil`IX@!p3RV*jd zGbx-%le5g%y!@7B`l4>I@cZ~C*<=RC*$fI%)@&IDIIhB3fU{OO4!DY1wmTkJ_czNW+>fi^pnip`3HQGy^xUb^kmW_Bwv+qpo_)hvo4TjG2%!jNRGL9=X{v%mQpp*b=IYERWC-sEwgHFL8s0;uen;pYj?co;_HP zsZLA-5z|mG+@HM`i7KI!vA7aCL1oOqHQeKhTFT91siX?V4K}VMX*^#=hLcW?ndv+R zD~$Sz@bOrfIw|8DhVxXlkel*mwwE8U#70s!1 zY(X(N>aAfbqlRdr1_cbG@$)zqjV0xHh^j1^qv>h1Qsr_y9!ix3%$+ms8B8oKfQeFO z`h3_+?YYk56vZ3ju?82Z2kB)vlbfjEX<8CDT&-V!efjkzZlkUk5Pko?_cPfi)?xYFqC)yw-C#-}92*^U}k> z`smc!=v036l0JIrx6`tAWk$b}$WJHr>119?=~7CQQU(9Mb^p+se<<%C(fuQu)LH25 zU++D-)_e3}mp(e7O(wL|^?xEX&z!XUz4UraU#Bgfn6E_(uzSx?4yYytiUR9!KM|0( z_4dKra<2B)^c&Mf#5w{dSz$KZ4Vrgol>t(E^6p{XJ*>Hh3vIsjw&At5VQu7#+SEnu z@=U%hs<%Z~#Dd$iBEBKs{!-rUr=1nCXxq}*5_n=qjykPwBrhG-rNdhJ!A;~R)<0Qs zJDd;s5$`=h6E0{qBL*L!$LQQjo=|u;l}anPhYprPN5N^D4Cb+$XO07evmIcbC!euR zv^Bw0xKb*Bq4m*3&igF+Gqaog+}0~ZQI-c_Fj4ZDr8=RrHo(M+g5zj~x%_5UfU)h0 zBQ%4~Qp<{fVmt+yF9-lH0M6U>G;3E~WjTaYT3)tVMy$3O*}0O>SW9r*EN1wKWe054 zz^ol?dc6@g!tI!pG8~|CBY7aYCa_E0b`{{U+A4$8*0M(cp{%-Vn}hGI_+ITf`9R#W z$S#0rgsnDx99{k}>-aQSW~6G1Ao1W5>`~Tv33fQ^%DS_)*}AF~uK!u_wz;A{>&bX> zTYE^}6`Thme8jfXg{;Sd0Ovi`O3bBo<;p{D*}Z<)I9Oiof40Gb)Zq3W%r%g{n#P8P z9m>3L;$EuE9uYDE-3Yah+^A_6McU8UGcZ|G-^kKhl4Y0QS^i-8qZMZPc7~;wEAmmz zhYmxmlmgsB-jXIAO(lS*c!ulAf26kE&qLR6o~2i?arwFuqIigDAmiOY$O*@Q+fTV} zD#yl>D)x|XI)WA~l66NH+lU*;za1?iO&m-=ioD>Inf>HVXM4YBmW^|ALNO$>dn_)~ z8=Aq)fu=;%;DLma^M;MS=VS47Bl)$nStvm)?k9h9c6tXvXZl|zwmxwpcUuWq$syN% zzF7=BM$IJd@;~|H&X z@95V%`in?v03nHd*?pF*xyPHDDbK>9$1GLrL+)lxXu?hRMrvQHV_L}l&Y1%P@EMyw z1`@PHXUz7;BY2t)(!Ji?SDN|NFKPP=%#g9JUHmIBie-}OYHp>XQTRdAjzs&-_M0Q; zf&!ewce`F~HjAKjj#le5y@qbpDLh2_yZub~-cm;T`gkL%XyThSs|9Ys`4JgwFvMN}b!ytVluS48jv zvdg4p;ttSWgN)b4L##2 gphH^q^9Xfl)lZSTY++nQ^lbXr9RKA1%$h#`7ZLhq0{{R3 delta 2795 zcmZt|TWlN0aqmI$_`N>fYH- zjbkJrMZpC8kg^48pbzMya9yM=QltT#APLf+q9{;+blI9XR7KFDZ3Hv`1vh9Bv_)r+ z6cZ|$+nd{Y?9T4&?9Bb(t3SEm`jOLVLjYI)_#o{c+H!@N^43Uvok0?kOj#jkU9lQ{ zbJmu#uh@;gCF@vmf?UYDa_$v(i|1MK0MC;3u6S8AizMqekz~8gBJ?V}O<3_smSq&P z?@}_x=)Fs_C?zvFF)b&>yp&wTg_Nu)$qY|fTd$3tWpwXC0d!_WRRpoTCSn-|+Egs& zmDK{yDM0xyU@?==!Jj@@J-pVaflP zo>5LiNfT9}AhAH1n|+`VteZ<;)P2P~-!oP@4k) zA1B6c6!2ALO-#vS%W5GfrYR+f?1X%S2;7&Ht;rqK^od-$(E^WlF>Mgy$!mrw)KnPjpvywZCYb*I;rhsn^T@tIkLxx zAE)5}&N3x3w;-~1sexVU)tiI1GuP5NIj@RprjQ>fxLIO`z;mCo!qycOTcs$;z77_T_S>*3z};fZ_UiOS?+Wofx` z@oUv^vKCI3=IahmX}&yvD^hhtX{R**SHby`rEDn~52l87KN+?CWlnc3%W85#d``|L z7cz=!M1}5Z?>3o(cs1fBW-|7Qqja#V<)38ga-pEexSu5KA#)dq@I&OP{WvpBzGuI{ zgvg#f!bW+B-Z@sakWt5Bt2vE|7C1nj9^f?Fd9+1ALs!~?J%cuxOLvP_;I+eBvqr#5 z6N)yC-?q?sLRO9Gyud}fX4)1&7GPCB*>H9f-sv@2H1oF27+}*Z2L?DmW~Z`23pcFjHn6AY?a=moM*AH@&sX$o{%x8DT0p*QvK^O9lKJ2g zihdSpg68j>$QbUYekSj`+)RM>PJ{nof&(55s7Lp0KoSq`_qBj}WWNvm5LxGgzG8qy z>Z6}xN60U^U{DJjFx~~H(oIc1D_Jxvb(}i>$taEMR5u(eP^{UtuFmB_QsE>cRTR1M zyX8NWKiFi-Z)qIl2P^rN`!_6(knek*^7UdGo|q;RBY9%s6>sm6As}_vIq|BTTo$j( zN#pXnbCk{+cPk5bOXsq3o}BVddV1+-8Z|nX$*b5;Ui8KWbS`!Mgf676tJ8&S0qf4` zCl{VvN}iovIAyhD@0X2P*4)Cz_aqv(R7idcf8glTN){1ch1tb3ZJYOPtO zpx}^ydqrk|toZuLE4~O%-A{h*>kL7fSq2 z&-h*bZFjY2uGTYG5yHgmA2oMdNA^%RIprTd{(f-ye(>bI;K?_XyN^}JXKUlLzxG#y z=W4-orP+G_q5J*ud;Rg(zWiRO+CN|GpC@Ji+LYTl(m;SVnVtCQ%HxaG`1xA=d;__> zzz0+fjBUs!1izKJ9EGxQ6xh#t~#^R?zfS;i%v}*32F!a)Z0X~2!;M1ZiQ|Y(?zneB5kNmiMjCIPo}F?ja=@!-fHvAso$syiy$#l4ayC#W@;OZ&@Z~=0Gn*ps@eKqY zK;)-KU7i^2w$W1zsU8hZHqbOndHho8gr%Ia)>P3IQp7qFF5CPN8NLf_aJUZXu)xQrctES%02q-$CE zil?;DxIy492>?{ eN45>)Y4D3I<8GkO!NVZfGX($qJTXX(?foA$L80OR diff --git a/Image_Process/__pycache__/Image_Generator.cpython-312.pyc b/Image_Process/__pycache__/Image_Generator.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cb08e7b27f33d42553cd9dcf7121e7b84b4cb134 GIT binary patch literal 11000 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 literal 0 HcmV?d00001 diff --git a/Image_Process/__pycache__/Image_Mask_Ground_Truth_Processing.cpython-311.pyc b/Image_Process/__pycache__/Image_Mask_Ground_Truth_Processing.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..76c939d9ecb72f7c0c6a51d96e2ca3665a84e9a9 GIT binary patch literal 13420 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 H9?|~+G_K9~ literal 0 HcmV?d00001 diff --git a/Image_Process/__pycache__/image_enhancement.cpython-311.pyc b/Image_Process/__pycache__/image_enhancement.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2d9cabe8e4afd51a62b333f213386ef3e00e386 GIT binary patch literal 13260 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 literal 0 HcmV?d00001 diff --git a/Image_Process/__pycache__/image_enhancement.cpython-312.pyc b/Image_Process/__pycache__/image_enhancement.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e58aa362d2c54fdb6f325484ceba21bc452bfa0d GIT binary patch literal 10607 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 chp72$D={Auwhkk*KMLReqW}N^ literal 0 HcmV?d00001 diff --git a/Image_Process/image_enhancement.py b/Image_Process/image_enhancement.py index ce3cc4e..35a2ea6 100644 --- a/Image_Process/image_enhancement.py +++ b/Image_Process/image_enhancement.py @@ -1,87 +1,309 @@ import cv2 import numpy as np +import torch +from PIL import Image +import torchvision +import functools +import inspect -def shapen(image): # 銳化處理 - sigma = 100 - blur_img = cv2.GaussianBlur(image, (0, 0), sigma) - usm = cv2.addWeighted(image, 1.5, blur_img, -0.5, 0) - - return usm - -def increase_contrast(image): # 增加資料對比度 - output = image # 建立 output 變數 - alpha = 2 - beta = 10 - cv2.convertScaleAbs(image, output, alpha, beta) # 套用 convertScaleAbs - - return output - -def adaptive_histogram_equalization(image): - ycrcb = cv2.cvtColor(image, cv2.COLOR_BGR2YCR_CB) - channels = cv2.split(ycrcb) - clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8)) - clahe.apply(channels[0], channels[0]) - - ycrcb = cv2.merge(channels) - Change_image = cv2.cvtColor(ycrcb, cv2.COLOR_YCR_CB2BGR) +# 套用裝飾器到現有函數 +def unsharp_mask(image, kernel_size=(5, 5), sigma=1.0, amount=1.0, threshold=0): + """使用OpenCV實現的Unsharp Mask銳化處理 + 參數: + image: PIL.Image對象(RGB格式) + kernel_size: 高斯模糊的核大小,必須是奇數 + sigma: 高斯模糊的標準差 + amount: 銳化程度,值越大效果越強 + threshold: 邊緣檢測閾值,僅在邊緣處進行銳化 + 返回: + 銳化後的PIL.Image對象 + """ + # 轉換PIL圖像為numpy數組 + numpy_img = np.array(image, dtype=np.uint8) - return Change_image + # 對原圖進行高斯模糊 + blurred = cv2.GaussianBlur(numpy_img, kernel_size, sigma) + + # 計算銳化後的圖像 + sharpened = cv2.addWeighted(numpy_img, 1 + amount, blurred, -amount, 0) + + # 如果設置了threshold,只在邊緣處應用銳化 + if threshold > 0: + low_contrast_mask = np.absolute(numpy_img - blurred) < threshold + np.copyto(sharpened, numpy_img, where=low_contrast_mask) + + # 確保像素值在有效範圍內 + sharpened = np.clip(sharpened, 0, 255).astype(np.uint8) + + # 轉回PIL圖像 + return Image.fromarray(sharpened) -def Remove_Background(image, Matrix_Size): - skinCrCbHist = np.zeros((256,256), dtype= np.uint8) - cv2.ellipse(skinCrCbHist, (113,155),(23,25), 43, 0, 360, (255, 255, 255), -1) #繪製橢圓弧線 +def histogram_equalization(image): + """GPU加速的一般直方圖等化 + 參數: + image: PIL.Image對象(RGB格式) + 返回: + 直方圖等化後的PIL.Image對象 + """ + # 轉換為numpy數組並轉為PyTorch張量 + numpy_img = np.array(image) + tensor_img = torch.from_numpy(numpy_img).float().to('cuda') + + # 分離通道並進行直方圖等化 + result = torch.zeros_like(tensor_img) + for i in range(3): # 對RGB三個通道分別處理 + channel = tensor_img[..., i] + + # 計算直方圖 + hist = torch.histc(channel, bins=256, min=0, max=255) + + # 計算累積分布函數(CDF) + cdf = torch.cumsum(hist, dim=0) + cdf_normalized = ((cdf - cdf.min()) * 255) / (cdf.max() - cdf.min()) + + # 應用直方圖等化 + result[..., i] = cdf_normalized[channel.long()] + + # 轉回CPU和numpy數組 + result = torch.clamp(result, 0, 255).byte() + result_np = result.cpu().numpy() + return Image.fromarray(result_np) - img_ycrcb = cv2.cvtColor(image, cv2.COLOR_BGR2YCR_CB) - y,cr,cb = cv2.split(img_ycrcb) #拆分出Y,Cr,Cb值 +def Contrast_Limited_Adaptive_Histogram_Equalization(image, clip_limit=3.0, tile_size=(8, 8)): + """使用OpenCV實現的對比度限制自適應直方圖均衡化(CLAHE) + + 參數: + image: PIL.Image對象(RGB格式) + clip_limit: 剪切限制,用於限制對比度增強的程度,較大的值會產生更強的對比度 + tile_size: 圖像分塊大小的元組(height, width),較小的值會產生更局部的增強效果 + + 返回: + CLAHE處理後的PIL.Image對象 + """ + # 將PIL圖像轉換為OpenCV格式(BGR) + numpy_img = np.array(image) + bgr_img = cv2.cvtColor(numpy_img, cv2.COLOR_RGB2BGR) + + # 轉換到LAB色彩空間 + lab_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2LAB) + + # 創建CLAHE對象 + clahe = cv2.createCLAHE(clipLimit=clip_limit, tileGridSize=tile_size) + + # 分離LAB通道 + l, a, b = cv2.split(lab_img) + + # 對L通道應用CLAHE + l_clahe = clahe.apply(l) + + # 合併處理後的L通道與原始的a和b通道 + lab_output = cv2.merge([l_clahe, a, b]) + + # 將LAB轉回BGR,然後轉換為RGB + bgr_output = cv2.cvtColor(lab_output, cv2.COLOR_LAB2BGR) + rgb_output = cv2.cvtColor(bgr_output, cv2.COLOR_BGR2RGB) + + # 轉換為PIL圖像並返回 + return Image.fromarray(rgb_output) - skin = np.zeros(cr.shape, dtype = np.uint8) #掩膜 - (x,y) = cr.shape +def adaptive_histogram_equalization_without_limit(image, tile_size=(8, 8)): + """使用OpenCV實現的自適應直方圖均衡化(AHE) + + 參數: + image: PIL.Image對象(RGB格式) + tile_size: 圖像分塊大小的元組(height, width),較小的值會產生更局部的增強效果 + + 返回: + AHE處理後的PIL.Image對象 + """ + # 將PIL圖像轉換為OpenCV格式(BGR) + numpy_img = np.array(image) + bgr_img = cv2.cvtColor(numpy_img, cv2.COLOR_RGB2BGR) + + # 轉換到LAB色彩空間 + lab_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2LAB) + + # 分離LAB通道 + l, a, b = cv2.split(lab_img) + + # 創建AHE對象(不設置clip limit) + clahe = cv2.createCLAHE(clipLimit=None, tileGridSize=tile_size) + + # 對L通道應用AHE + l_ahe = clahe.apply(l) + + # 合併處理後的L通道與原始的a和b通道 + lab_output = cv2.merge([l_ahe, a, b]) + + # 將LAB轉回BGR,然後轉換為RGB + bgr_output = cv2.cvtColor(lab_output, cv2.COLOR_LAB2BGR) + rgb_output = cv2.cvtColor(bgr_output, cv2.COLOR_BGR2RGB) + + # 轉換為PIL圖像並返回 + return Image.fromarray(rgb_output) - # 依序取出圖片中每個像素 - for i in range(x): - for j in range(y): - if skinCrCbHist [cr[i][j], cb[i][j]] > 0: #若不在橢圓區間中 - skin[i][j] = 255 - # 如果該像素的灰階度大於 200,調整該像素的透明度 - # 使用 255 - gray[y, x] 可以將一些邊緣的像素變成半透明,避免太過鋸齒的邊緣 - # img_change = cv2.cvtColor(img_change, cv2.COLOR_BGRA2BGR) - img = cv2.bitwise_and(image, image, mask = skin) - img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) +def laplacian_sharpen(image): + """ + GPU加速的拉普拉斯銳化處理函數 + 參數: + image: PIL.Image對象(RGB格式) + 返回: + 銳化後的PIL.Image對象 + """ + # 轉換為numpy數組並轉為PyTorch張量 + numpy_img = np.array(image) + tensor_img = torch.from_numpy(numpy_img).float().to('cuda') + + # 創建拉普拉斯算子 + laplacian_kernel = torch.tensor([ + [0, 1, 0], + [1, -4, 1], + [0, 1, 0] + ], dtype=torch.float32, device='cuda').unsqueeze(0).unsqueeze(0) + + # 對每個通道進行處理 + result = torch.zeros_like(tensor_img) + for i in range(3): # RGB三個通道 + channel = tensor_img[..., i] + # 添加批次和通道維度 + channel = channel.unsqueeze(0).unsqueeze(0) + # 應用拉普拉斯算子 + laplacian = torch.nn.functional.conv2d(channel, laplacian_kernel, padding=1) + # 移除批次和通道維度 + laplacian = laplacian.squeeze() + # 銳化處理:原圖 - 拉普拉斯 + result[..., i] = channel.squeeze() - laplacian + + # 確保像素值在合理範圍內 + result = torch.clamp(result, 0, 255).byte() + + # 轉回CPU和numpy數組 + result_np = result.cpu().numpy() + return Image.fromarray(result_np) - h = image.shape[0] # 取得圖片高度 - w = image.shape[1] # 取得圖片寬度 +def adjust_hsv(image, v_adjustment=0): + """調整圖像的HSV色彩空間中的H和V通道 + + 參數: + image: PIL.Image對象(RGB格式) + v_adjustment: V通道的調整值,範圍建議在[-255, 255]之間 + + 返回: + HSV調整後的PIL.Image對象 + """ + # 將PIL圖像轉換為OpenCV格式(BGR) + numpy_img = np.array(image) + bgr_img = cv2.cvtColor(numpy_img, cv2.COLOR_RGB2BGR) + + # 轉換到HSV色彩空間 + hsv_img = cv2.cvtColor(bgr_img, cv2.COLOR_BGR2HSV) + + # 調整V通道 + hsv_img[..., 2] = np.clip(hsv_img[..., 2] + v_adjustment, 0, 255) + + # 將HSV轉回BGR,然後轉換為RGB + bgr_output = cv2.cvtColor(hsv_img, cv2.COLOR_HSV2BGR) + rgb_output = cv2.cvtColor(bgr_output, cv2.COLOR_BGR2RGB) + + # 轉換為PIL圖像並返回 + return Image.fromarray(rgb_output) - for x in range(w): - for y in range(h): - if img_gray[y, x] == 0: - # if x == 0 and y == 0: # 當X Y都在左上角時 - # image[y, x] = Add(1, Matrix_Size, image[y, x]) / Matrix_Size - # if x == w - 1 and y == 0: # 當X Y都在右上角時 - # image[y, x] = Add(w - Matrix_Size, w, image[y, x]) / Matrix_Size - # if x == 0 and y == h - 1: # 當X Y都在左下角時 - # image[y, x] = (image[y - 1, x] + image[y - 1, x + 1] + image[y, x + 1]) / 3 - # if x == w - 1 and y == h - 1: # 當X Y都在右下角時 - # image[y, x] = (image[y, x - 1] + image[y - 1, x - 1] + image[y - 1, x]) / 3 +def gamma_correction(image, gamma=1.0): + """對圖像進行伽馬校正 + + 參數: + image: PIL.Image對象(RGB格式) + gamma: 伽馬值,gamma > 1 時圖像變暗,gamma < 1 時圖像變亮,gamma = 1 時保持不變 + + 返回: + 伽馬校正後的PIL.Image對象 + """ + # 將PIL圖像轉換為numpy數組 + numpy_img = np.array(image) + + # 將像素值歸一化到[0, 1]範圍 + normalized = numpy_img.astype(float) / 255.0 + + # 應用伽馬校正 + corrected = np.power(normalized, gamma) + + # 將值縮放回[0, 255]範圍 + output = np.clip(corrected * 255.0, 0, 255).astype(np.uint8) + + # 轉換回PIL圖像並返回 + return Image.fromarray(output) - # if (x > 0 and x < w - 1) and y == 0: # 當上面的X Y從左到右 - # image[y, x] = (image[y, x - 1] + image[y + 1, x - 1] + image[y + 1, x] + image[y, x + 1] + image[y + 1, x + 1]) / 5 - # if (x > 0 and x < w - 1) and y == h - 1: # 當下面的X Y從左到右 - # image[y, x] = (image[y, x - 1] + image[y - 1, x - 1] + image[y - 1, x] + image[y, x + 1] + image[y - 1, x + 1]) / 5 - # if x == 0 and (y > 0 and y < h - 1): # 當左邊的X Y從上到下 - # image[y, x] = (image[y - 1, x] + image[y - 1, x + 1] + image[y, x + 1] + image[y + 1, x + 1] + image[y + 1, x]) / 5 - # if x == w - 1 and (y > 0 and y < h - 1): # 當右邊X Y從上到下 - # image[y, x] = (image[y - 1, x] + image[y - 1, x - 1] + image[y, x - 1] + image[y + 1, x - 1] + image[y + 1, x]) / 5 +def Hight_Light(image, Threshold): + image = np.array(image) - if (x >= 1 and x < w - 1) and (y >= 1 and y < h - 1): # 當y >= 2 且 X >= 2 - image[y, x] = Add(x, y, image, Matrix_Size) / Matrix_Size - # BGRA_image[y, x, 3] = 255 - gray[y, x] - return image + gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY) + # 使用閾值檢測高光點(白色液滴) + _, thresh = cv2.threshold(gray, Threshold, 255, cv2.THRESH_BINARY) + # 使用形態學操作(膨脹)來擴大遮罩區域 + kernel = np.ones((5, 5), np.uint8) + dilated = cv2.dilate(thresh, kernel, iterations=1) + # 使用 inpaint 修復高光點 + image_inpaint = cv2.inpaint(image, dilated, 3, cv2.INPAINT_TELEA) + return Image.fromarray(image_inpaint) -def Add(width_Center, Height_Center, image, Mask_Size): - total = 0 - for i in range(Mask_Size): - for j in range(Mask_Size): - total += image[width_Center - ((Mask_Size - 1) / 2) + j, Height_Center - ((Mask_Size - 1) / 2) + i] +def median_filter(image: Image.Image, kernel_size: int = 3): + """ + 中值濾波(Median Filter)實現 + + 參數: + image: PIL.Image對象(RGB格式) + kernel_size: 濾波核大小,必須是奇數 + + 返回: + 濾波後的PIL.Image對象 + """ + # 確保kernel_size是奇數 + if kernel_size % 2 == 0: + kernel_size += 1 + + # 轉換PIL圖像為numpy數組 + numpy_img = np.array(image, dtype=np.uint8) + + # 對每個通道應用中值濾波 + result = np.zeros_like(numpy_img) + for i in range(3): # 對RGB三個通道分別處理 + result[:, :, i] = cv2.medianBlur(numpy_img[:, :, i], kernel_size) + + # 確保像素值在有效範圍內 + result = np.clip(result, 0, 255).astype(np.uint8) + + # 轉回PIL圖像 + return Image.fromarray(result) - return total \ No newline at end of file +def mean_filter(image: Image.Image, kernel_size: int = 3): + """ + 均質濾波(Mean Filter)實現 + + 參數: + image: PIL.Image對象(RGB格式) + kernel_size: 濾波核大小,必須是奇數 + + 返回: + 濾波後的PIL.Image對象 + """ + # 確保kernel_size是奇數 + if kernel_size % 2 == 0: + kernel_size += 1 + + # 轉換PIL圖像為numpy數組 + numpy_img = np.array(image, dtype=np.uint8) + + # 創建均質濾波核(所有元素都是1/(kernel_size*kernel_size)) + kernel = np.ones((kernel_size, kernel_size), np.float32) / (kernel_size * kernel_size) + + # 對每個通道應用均質濾波 + result = np.zeros_like(numpy_img) + for i in range(3): # 對RGB三個通道分別處理 + result[:, :, i] = cv2.filter2D(numpy_img[:, :, i], -1, kernel) + + # 確保像素值在有效範圍內 + result = np.clip(result, 0, 255).astype(np.uint8) + + # 轉回PIL圖像 + return Image.fromarray(result) \ No newline at end of file diff --git a/Image_Process/load_and_ImageGenerator.py b/Image_Process/load_and_ImageGenerator.py deleted file mode 100644 index f879a4e..0000000 --- a/Image_Process/load_and_ImageGenerator.py +++ /dev/null @@ -1,58 +0,0 @@ -from Load_process.LoadData import Loding_Data_Root -from Image_Process.Image_Generator import Image_generator -from Load_process.file_processing import Process_File -from model_data_processing.processing_for_cut_image import Cut_Indepentend_Data -from Load_process.Loading_Tools import Load_Data_Prepare, Load_Data_Tools - -class Load_ImageGenerator(): - ''' - 這是一個拿來進行資料強化的物件,最主要結合了學姊給的資料強化與我自行設定的資料強化。 -藉由此物件先將資料讀取出來,並將資料分別進行資料強化,利用資料強化來迷部資料的不平衡 -這只是其中一個實驗 - -Parmeter - standard_root: 做跟學姊給的資料強化同一種的資料強化 - myself_root: 資料強化的內容參數是我自己設定的 - IndependentDataRoot: 要存回去的資料夾路徑 - Herpeslabels: 皰疹的類別 - MonKeyPoxlabels: 猴痘的類別(猴痘、水痘、正常) - herpes_data: 合併herpes Dataset的資料成一個List - MonkeyPox_data: 合併MonkeyPox DataSet 的資料成一個List - ''' - def __init__(self, Training_Root,Test_Root, Generator_Root, Labels, Image_Size) -> None: - self.Training_Root = Training_Root - self.TestRoot = Test_Root - self.GeneratoRoot = Generator_Root - self.Labels = Labels - self.Image_Size = Image_Size - pass - - def process_main(self, Data_Length : int): - File = Process_File() - Prepare = Load_Data_Prepare() - load = Loding_Data_Root(self.Labels, self.Training_Root, self.GeneratoRoot) - Indepentend = Cut_Indepentend_Data(self.Training_Root, self.Labels) - Load_Tool = Load_Data_Tools() - Generator = Image_generator(self.GeneratoRoot, self.Labels, self.Image_Size) - - # 將測試資料獨立出來 - test_size = 0.2 - Indepentend.IndependentData_main(self.TestRoot, test_size) - - if not File.Judge_File_Exist(self.GeneratoRoot): # 檔案若不存在 - # 確定我要多少個List - Prepare.Set_Data_Content([], Data_Length) - - # 製作讀檔字典並回傳檔案路徑 - Prepare.Set_Label_List(self.Labels) - Prepare.Set_Data_Dictionary(Prepare.Get_Label_List(), Prepare.Get_Data_Content(), Data_Length) - Original_Dict_Data_Root = Prepare.Get_Data_Dict() - get_all_original_image_data = Load_Tool.get_data_root(self.Training_Root, Original_Dict_Data_Root, Prepare.Get_Label_List()) - - # 儲存資料強化後資料 - Generator.Processing_Main(get_all_original_image_data) # 執行資料強化 - else: # 若檔案存在 - print("standard data and myself data are exist\n") - - # 執行讀檔 - return load.process_main() \ No newline at end of file diff --git a/Load_process/LoadData.py b/Load_process/LoadData.py index 9d57b25..3acfd46 100644 --- a/Load_process/LoadData.py +++ b/Load_process/LoadData.py @@ -11,15 +11,16 @@ class Loding_Data_Root(Process_File): super().__init__() pass - def process_main(self): + def process_main(self, status): '''處理讀Training、Image Generator檔資料''' Merge = merge() get_Image_Data = self.get_Image_data_roots(self.Train_Root) - Get_ImageGenerator_Image_Data = self.get_Image_data_roots(self.Generator_Root) - # Get_Total_Image_Data_Root = Merge.merge_dict_to_dict(get_Image_Data, Get_ImageGenerator_Image_Data) - # Get_Total_Image_Data_Root = Merge.merge_data_main(get_Image_Data, 0, len(self.Label_List)) + if status: + Get_ImageGenerator_Image_Data = self.get_Image_data_roots(self.Generator_Root) + Get_Total_Image_Data_Root = Merge.merge_dict_to_dict(get_Image_Data, Get_ImageGenerator_Image_Data) + return Get_Total_Image_Data_Root return get_Image_Data diff --git a/Load_process/Load_Indepentend.py b/Load_process/Load_Indepentend.py index 5cdc158..9971c35 100644 --- a/Load_process/Load_Indepentend.py +++ b/Load_process/Load_Indepentend.py @@ -1,11 +1,10 @@ -from Read_and_process_image.ReadAndProcess import Read_image_and_Process_image from merge_class.merge import merge -from Read_and_process_image.ReadAndProcess import Read_image_and_Process_image from Load_process.LoadData import Load_Data_Prepare, Load_Data_Tools -from model_data_processing.processing import Balance_Process +from model_data_processing.processing import make_label_list +from utils.Stomach_Config import Loading_Config class Load_Indepentend_Data(): - def __init__(self, Labels, OneHot_Encording): + def __init__(self, OneHot_Encording): ''' 影像切割物件 label有2類,會將其轉成one-hot-encoding的形式 @@ -13,33 +12,33 @@ class Load_Indepentend_Data(): [1, 0] = NPC_positive ''' self.merge = merge() - self.Labels = Labels self.OneHot_Encording = OneHot_Encording pass - def process_main(self, Test_data_root): - self.test, self.test_label = self.get_Independent_image(Test_data_root) + def process_main(self, Test_data_root, Test_mask_root): + self.test, self.test_label, self.test_mask = self.get_Independent_image(Test_data_root, Test_mask_root) print("\ntest_labels有" + str(len(self.test_label)) + "筆資料\n") - # self.validation, self.validation_label = self.get_Independent_image(Validation_data_root) - # print("validation_labels有 " + str(len(self.validation_label)) + " 筆資料\n") - - def get_Independent_image(self, independent_DataRoot): - image_processing = Read_image_and_Process_image(123) - - classify_image = [] + def get_Independent_image(self, independent_DataRoot, independent_MaskRoot): Total_Size_List = [] - Total_Dict_Data_Root = self.Get_Independent_data_Root(independent_DataRoot) # 讀取測試資料集的資料 + Total_Dict_Data_Root = self.Get_Independent_data_Root(independent_DataRoot, Loading_Config["Training_Labels"], len(Loading_Config["Training_Labels"])) # 讀取測試資料集的資料 + Total_Dict_Mask_Root = self.Get_Independent_data_Root(independent_MaskRoot, Loading_Config["XML_Loading_Label"], len(Loading_Config["XML_Loading_Label"])) # 讀取測試資料集的mask資料 + # 將測試資料字典轉成列表,並且將其排序 Total_List_Data_Root = [] - for Label in self.Labels: + for Label in Loading_Config["Training_Labels"]: Total_List_Data_Root.append(Total_Dict_Data_Root[Label]) + + # 將測試資料字典轉成列表,並且將其排序 + Total_List_Mask_Data_Root = [] + for Label in Loading_Config["XML_Loading_Label"]: + Total_List_Mask_Data_Root.append(Total_Dict_Mask_Root[Label]) - test_label, Classify_Label = [], [] + classify_image, Classify_Label = [], [] i = 0 # 計算classify_image的counter,且計算總共有幾筆資料 for test_title in Total_List_Data_Root: # 藉由讀取所有路徑來進行讀檔 - test_label = image_processing.make_label_list(len(test_title), self.OneHot_Encording[i]) # 製作對應圖片數量的label出來+ - print(self.Labels[i] + " 有 " + str(len(test_label)) + " 筆資料 ") + test_label = make_label_list(len(test_title), self.OneHot_Encording[i]) # 製作對應圖片數量的label出來+ + print(Loading_Config["Training_Labels"][i] + " 有 " + str(len(test_label)) + " 筆資料 ") Total_Size_List.append(len(test_label)) @@ -47,28 +46,28 @@ class Load_Indepentend_Data(): Classify_Label.append(test_label) i += 1 - test = self.merge.merge_data_main(classify_image, 0, len(self.Labels)) - test_label = self.merge.merge_data_main(Classify_Label, 0, len(self.Labels)) + classify_Mask_image = [] + i = 0 # 計算classify_image的counter,且計算總共有幾筆資料 + for test_title in Total_List_Mask_Data_Root: # 藉由讀取所有路徑來進行讀檔 + print(Loading_Config["XML_Loading_Label"][i] + " 有 " + str(len(test_title)) + " 筆資料 ") - # test = [] - # test = image_processing.Data_Augmentation_Image(original_test_root) - # test, test_label = image_processing.image_data_processing(test, original_test_label) + classify_Mask_image.append(test_title) + i += 1 - # Balance_Data = list(zip(test, test_label)) - # test, test_label = Balance_Process(Balance_Data, Total_Size_List) # 打亂並取出指定資料筆數的資料 - # test = image_processing.normalization(test) - - - return test, test_label + test = self.merge.merge_data_main(classify_image, 0, len(Loading_Config["Training_Labels"])) + test_label = self.merge.merge_data_main(Classify_Label, 0, len(Loading_Config["Training_Labels"])) + test_Mask = self.merge.merge_data_main(classify_Mask_image, 0, len(Loading_Config["XML_Loading_Label"])) + + return test, test_label, test_Mask - def Get_Independent_data_Root(self, load_data_root): + def Get_Independent_data_Root(self, load_data_root, Dictory_Keys, Length): Prepare = Load_Data_Prepare() Load_Tool = Load_Data_Tools() - Prepare.Set_Data_Content([], len(self.Labels)) - Prepare.Set_Data_Dictionary(self.Labels, Prepare.Get_Data_Content(), 2) + Prepare.Set_Data_Content([], Length) + Prepare.Set_Data_Dictionary(Dictory_Keys, Prepare.Get_Data_Content(), Length) Get_Data_Dict_Content = Prepare.Get_Data_Dict() - Total_Data_Roots = Load_Tool.get_data_root(load_data_root, Get_Data_Dict_Content, self.Labels) + Total_Data_Roots = Load_Tool.get_data_root(load_data_root, Get_Data_Dict_Content, Dictory_Keys) - return Total_Data_Roots \ No newline at end of file + return Total_Data_Roots diff --git a/Load_process/__pycache__/LoadData.cpython-311.pyc b/Load_process/__pycache__/LoadData.cpython-311.pyc index 5f87c98713b5904aa11300509770ae3f45689cc5..9b874327cf062790d4fbba1d51411fb385584e7a 100644 GIT binary patch delta 417 zcmdlXa#oagIWI340}yyU=gkP;$ji@U?5&@XpPQ;*o{?FSnw?pcnTO0QF3HbLOwNc; zPRvVAEz%FDEXglQ&Y0}QR3pX&G6o7*fHX4@f8ICw4wJ%U17?}Y63h~;%r%TfMw1Ph zjagZ0m=>^1W@HwXWUgUZ2GqJ5uDzDEhBcU>hIw*2vl%1n9`(9x#AXiQ77t(PSgb+%^MoJ z*EJk2X*e8^yAYUnQ6v9~M*amJ)f>V(7kG3Y@XKy)U}0otlwRD#&d4Y?xtSw_pPNrxMesD>CZensqymMk+a%z!& zKv8~rQDSaxoh%6CIwc;8ioaolNs4WCrdL+ zO=e`4nS6~^oTZkzhH3HwW-~^X$=8`x*)>^;1b|v5%d?oV7PEj@3oP&{3da?v(20s_8+y@3Y jAu+k1b33E)WOpuqb0tQg3??z5<|9b-3l^y&QJ_lzOJz)1 diff --git a/Load_process/__pycache__/LoadData.cpython-312.pyc b/Load_process/__pycache__/LoadData.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5759b87da3c2212852990147546e204b4b8f633f GIT binary patch literal 2413 zcma)8U1$_n6uz@FvpXic$tF?kuFblTM6`{VVTA5bB3NSMu=XY#E+ZAGoQ@1m<~Vu|=^=xcc|(u|M)SI8 zgyk@YLTDVR!V*$Nja%k@8**emoQeENi45mOj}a@c*)~2@)U`~=>zS|=6(3L>1s@~Y ztU@%ed;RLTW$89(iH1fBTHZJ4@1X{vmS(&8#IUJ(RJ=9IPaKHPHQ@zDB6zKahxbc6Vnj9u5r!Oh~ikp zr$u{iRwJH-anUR~7=x-{Yx=YoW(I68#+2#rp!y^Rp1chh=XC{AjBQ%RG_1vcj~p01 z1*tC(#Q^D3wqqGe{tV75W?mx!2OpaU*KmDQ`|uR2!mM8{M$jUS%+8Z;FnTu8p1zSF zM*8#Z?XW#wMD=94EPUEsPi|+QRJJUvN?Yzqu?rDbdTCWk)}`ngh@yNmeL&Dcu;l*) zhs(%mCOSyu0;GS2O0+GwZ7pJhyWG%U;7c6Y@xPkQvaK6!Y6_*$%!c**-~@#imK%{T zh$S(HN<4szo6Ca4gDaQrU;O03_lrS^?ks+M#83)ax>@9V-+l4m=kxczypjmLs+ zH@!C;F?NEok6VtSx7;#J*)%YUp>&#Tq>iEuOke|Gd$#{69JI2#K*64bZ4up#Z~8n^ z7H=o|Yl&TMV%N&6zwG^SZ#A*M-1SFiPd&S{mObcZ58hB~hfcbOPFAyWC7P)Zzfv3C z=ML|?k*d6HR)?)hbg15!twgi8yZb9rKiNbh3KPwlBjytriU5OQ=pt1A*%)$~2x{Vr zhdKwN4-5ngF!LOAaOm0SC?Kcv#ViCEVwPwRw=J+wo33pIQ3Dr-O#2GBFC0T78xR9O z)7Ned(E%8mq3Ld0fuHBc7(50GLP^LWLLZ(?C!x(sXuiF!9N=$#C=!}DFHSEhJn??Z zbTrfPcwIBSzUK7-=!2qVDrBBc&Q=3noYGI|#tLww23_UFngY}cG$89DiK?(s90{JI zC>?}!!qUgc@2ethV`i&4Vg2SHn<4JALr?Vtb=}_9TR_yl2HPUK**j3}9V$m|Zr)bi zJY0@G45JP4nv`;-)K|{e=dPSvm3Gvn?wXW#rS#R_Z*t#m{9)_$t<|A7R;5wK7;vS5 ztK+r7QFm~(I=JW8LT&7XJ9eTv_TH-eer4)(ZOU+`jH+y|N)}j8ZmT7ByNTT^hpA-F z9m`e6-mOed)g}#h(x^^a)x>PM3k2h-pvy86eTGcM&@lEoFg7f8PN(N6#vjZny3b*c z14+^933N)agm|&Wiur`<4@Y-|MD^NI#{Q_!A`>Vkmoq=7JBV>bmSHqcq9yPsf(q*5qy~Le~ko8(*OVf literal 0 HcmV?d00001 diff --git a/Load_process/__pycache__/Load_Indepentend.cpython-311.pyc b/Load_process/__pycache__/Load_Indepentend.cpython-311.pyc index 2d7ab715a806748c4dc9a56c45283105f399d80b..efad45ccdf6974aca3b1dba9552c67f7dd8f3c32 100644 GIT binary patch literal 5125 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 delta 80 zcmbQF)2hR>oR^o20SGd5g3~whbTFBIbpY~QtYV5w@^cfDGvbpI^O94GVgict(~A;w h6?7F|ENOqScyEkPequ^|K~a8kYH@MQ=4(tg!T|1O97X^D diff --git a/Load_process/__pycache__/Loading_Tools.cpython-312.pyc b/Load_process/__pycache__/Loading_Tools.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..720496a91a62b592492c9673f19c5422062fd1a5 GIT binary patch literal 5215 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 Ssaz!0&&4;m`V|6%S@RDGE#a{M literal 0 HcmV?d00001 diff --git a/Load_process/file_processing.py b/Load_process/file_processing.py index c5c4de7..d09a826 100644 --- a/Load_process/file_processing.py +++ b/Load_process/file_processing.py @@ -35,16 +35,14 @@ class Process_File(): save_root = self.Make_Save_Root(FileName, save_root) np.save(save_root, image) - def Save_CSV_File(self, file_name, data): # 儲存訓練結果 - Save_Root = '../Result/Training_Result/save_the_train_result(' + str(datetime.date.today()) + ")" + def Save_CSV_File(self, Save_Root, file_name, data): # 儲存訓練結果 self.JudgeRoot_MakeDir(Save_Root) modelfiles = self.Make_Save_Root(file_name + ".csv", Save_Root) # 將檔案名稱及路徑字串合併成完整路徑 data.to_csv(modelfiles, mode = "a") - def Save_TXT_File(self, content, File_Name): - model_dir = '../Result/save_the_train_result(' + str(datetime.date.today()) + ")" # 儲存的檔案路徑,由save_the_train_result + 當天日期 - self.JudgeRoot_MakeDir(model_dir) - modelfiles = self.Make_Save_Root(File_Name + ".txt", model_dir) # 將檔案名稱及路徑字串合併成完整路徑 + def Save_TXT_File(self, content, Save_Root, File_Name): + self.JudgeRoot_MakeDir(Save_Root) + modelfiles = self.Make_Save_Root(f"{File_Name}.txt", Save_Root) # 將檔案名稱及路徑字串合併成完整路徑 with open(modelfiles, mode = 'a') as file: file.write(content) diff --git a/Model_Loss/CIOU_Loss.py b/Model_Loss/CIOU_Loss.py new file mode 100644 index 0000000..76db8a6 --- /dev/null +++ b/Model_Loss/CIOU_Loss.py @@ -0,0 +1,315 @@ +import torch +import torch.nn as nn +import math + +class CIOULoss(nn.Module): + """ + Complete Intersection over Union (CIOU) Loss + 適用於目標檢測中的邊界框回歸任務 + + CIOU Loss 考慮了三個幾何因子: + 1. 重疊面積 (Overlap area) + 2. 中心點距離 (Central point distance) + 3. 長寬比一致性 (Aspect ratio consistency) + """ + + def __init__(self, eps=1e-7): + super(CIOULoss, self).__init__() + self.eps = eps + + def forward(self, pred_boxes, target_boxes): + """ + 計算 CIOU Loss + + Args: + pred_boxes: 預測邊界框 [N, 4] (x1, y1, x2, y2) 或 [N, 4] (cx, cy, w, h) 或分割掩碼 [B, 1, H, W] + target_boxes: 真實邊界框 [N, 4] (x1, y1, x2, y2) 或 [N, 4] (cx, cy, w, h) 或分割掩碼 [B, 1, H, W] + + Returns: + CIOU loss value + """ + # 檢查輸入是否為分割掩碼格式 + if len(pred_boxes.shape) == 4 and pred_boxes.shape[1] == 1: + # 將分割掩碼轉換為邊界框格式 + pred_boxes = self._mask_to_boxes(pred_boxes) + target_boxes = self._mask_to_boxes(target_boxes) + + # 如果無法從掩碼中提取有效的邊界框,則返回一個小的損失值 + if pred_boxes is None or target_boxes is None: + return torch.tensor(0.01, device=pred_boxes.device if pred_boxes is not None else target_boxes.device) + + # 確保輸入為浮點數 + pred_boxes = pred_boxes.float() + target_boxes = target_boxes.float() + + # 檢查邊界框維度是否正確 + if pred_boxes.dim() == 1: + # 如果是單個邊界框,擴展為批次大小為1的張量 + pred_boxes = pred_boxes.unsqueeze(0) + if target_boxes.dim() == 1: + target_boxes = target_boxes.unsqueeze(0) + + # 確保邊界框有4個坐標 + if pred_boxes.shape[1] != 4 or target_boxes.shape[1] != 4: + # 如果坐標數量不正確,返回一個小的損失值 + return torch.tensor(0.01, device=pred_boxes.device) + + # 如果輸入是 (cx, cy, w, h) 格式,轉換為 (x1, y1, x2, y2) + if self._is_center_format(pred_boxes, target_boxes): + pred_boxes = self._center_to_corner(pred_boxes) + target_boxes = self._center_to_corner(target_boxes) + + # 計算交集區域 + intersection = self._calculate_intersection(pred_boxes, target_boxes) + + # 計算各自的面積 + pred_area = (pred_boxes[:, 2] - pred_boxes[:, 0]) * (pred_boxes[:, 3] - pred_boxes[:, 1]) + target_area = (target_boxes[:, 2] - target_boxes[:, 0]) * (target_boxes[:, 3] - target_boxes[:, 1]) + + # 計算聯集面積 + union = pred_area + target_area - intersection + self.eps + + # 計算 IoU + iou = intersection / union + + # 計算最小外接矩形 + enclose_x1 = torch.min(pred_boxes[:, 0], target_boxes[:, 0]) + enclose_y1 = torch.min(pred_boxes[:, 1], target_boxes[:, 1]) + enclose_x2 = torch.max(pred_boxes[:, 2], target_boxes[:, 2]) + enclose_y2 = torch.max(pred_boxes[:, 3], target_boxes[:, 3]) + + # 計算最小外接矩形的對角線距離平方 + enclose_diagonal_sq = (enclose_x2 - enclose_x1) ** 2 + (enclose_y2 - enclose_y1) ** 2 + self.eps + + # 計算兩個邊界框中心點之間的距離平方 + pred_center_x = (pred_boxes[:, 0] + pred_boxes[:, 2]) / 2 + pred_center_y = (pred_boxes[:, 1] + pred_boxes[:, 3]) / 2 + target_center_x = (target_boxes[:, 0] + target_boxes[:, 2]) / 2 + target_center_y = (target_boxes[:, 1] + target_boxes[:, 3]) / 2 + + center_distance_sq = (pred_center_x - target_center_x) ** 2 + (pred_center_y - target_center_y) ** 2 + + # 計算長寬比一致性項 + pred_w = pred_boxes[:, 2] - pred_boxes[:, 0] + pred_h = pred_boxes[:, 3] - pred_boxes[:, 1] + target_w = target_boxes[:, 2] - target_boxes[:, 0] + target_h = target_boxes[:, 3] - target_boxes[:, 1] + + # 避免除零 + pred_w = torch.clamp(pred_w, min=self.eps) + pred_h = torch.clamp(pred_h, min=self.eps) + target_w = torch.clamp(target_w, min=self.eps) + target_h = torch.clamp(target_h, min=self.eps) + + v = (4 / (math.pi ** 2)) * torch.pow(torch.atan(target_w / target_h) - torch.atan(pred_w / pred_h), 2) + + # 計算 alpha 參數 + with torch.no_grad(): + alpha = v / (1 - iou + v + self.eps) + + # 計算 CIOU + ciou = iou - (center_distance_sq / enclose_diagonal_sq) - alpha * v + + # 返回 CIOU Loss (1 - CIOU) + ciou_loss = 1 - ciou + + return ciou_loss.mean() + + def _is_center_format(self, pred_boxes, target_boxes): + """ + 判斷輸入格式是否為中心點格式 (cx, cy, w, h) + 簡單的啟發式判斷:如果第三、四列的值都是正數且相對較小,可能是寬高 + """ + # 這裡使用簡單的判斷邏輯,實際使用時可能需要更精確的判斷 + return False # 預設假設輸入為 (x1, y1, x2, y2) 格式 + + def _center_to_corner(self, boxes): + """ + 將中心點格式 (cx, cy, w, h) 轉換為角點格式 (x1, y1, x2, y2) + """ + cx, cy, w, h = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3] + x1 = cx - w / 2 + y1 = cy - h / 2 + x2 = cx + w / 2 + y2 = cy + h / 2 + return torch.stack([x1, y1, x2, y2], dim=1) + + def _mask_to_boxes(self, masks): + """ + 將分割掩碼轉換為邊界框格式 [N, 4] (x1, y1, x2, y2) + + Args: + masks: 分割掩碼 [B, 1, H, W] + + Returns: + boxes: 邊界框 [B, 4] (x1, y1, x2, y2) + """ + batch_size = masks.size(0) + device = masks.device + + # 將掩碼轉換為二值掩碼 + binary_masks = (torch.sigmoid(masks) > 0.5).float() + + # 初始化邊界框張量 + boxes = torch.zeros(batch_size, 4, device=device) + + # 對每個批次處理 + for b in range(batch_size): + mask = binary_masks[b, 0] # [H, W] + + # 找出非零元素的索引 + non_zero_indices = torch.nonzero(mask, as_tuple=True) + + # 如果掩碼中沒有非零元素,則使用默認的小邊界框 + if len(non_zero_indices[0]) == 0: + # 返回一個默認的小邊界框 + boxes[b] = torch.tensor([0, 0, 1, 1], device=device) + continue + + # 計算邊界框坐標 + y_min = torch.min(non_zero_indices[0]) + y_max = torch.max(non_zero_indices[0]) + x_min = torch.min(non_zero_indices[1]) + x_max = torch.max(non_zero_indices[1]) + + # 存儲邊界框 [x1, y1, x2, y2] + boxes[b] = torch.tensor([x_min, y_min, x_max, y_max], device=device) + + return boxes + + def _calculate_intersection(self, pred_boxes, target_boxes): + """ + 計算兩個邊界框的交集面積 + """ + x1 = torch.max(pred_boxes[:, 0], target_boxes[:, 0]) + y1 = torch.max(pred_boxes[:, 1], target_boxes[:, 1]) + x2 = torch.min(pred_boxes[:, 2], target_boxes[:, 2]) + y2 = torch.min(pred_boxes[:, 3], target_boxes[:, 3]) + + # 計算交集的寬度和高度 + intersection_w = torch.clamp(x2 - x1, min=0) + intersection_h = torch.clamp(y2 - y1, min=0) + + return intersection_w * intersection_h + + +class DIoULoss(nn.Module): + """ + Distance Intersection over Union (DIoU) Loss + CIOU 的簡化版本,只考慮重疊面積和中心點距離 + """ + + def __init__(self, eps=1e-7): + super(DIoULoss, self).__init__() + self.eps = eps + + def forward(self, pred_boxes, target_boxes): + # 確保輸入為浮點數 + pred_boxes = pred_boxes.float() + target_boxes = target_boxes.float() + + # 計算交集區域 + intersection = self._calculate_intersection(pred_boxes, target_boxes) + + # 計算各自的面積 + pred_area = (pred_boxes[:, 2] - pred_boxes[:, 0]) * (pred_boxes[:, 3] - pred_boxes[:, 1]) + target_area = (target_boxes[:, 2] - target_boxes[:, 0]) * (target_boxes[:, 3] - target_boxes[:, 1]) + + # 計算聯集面積 + union = pred_area + target_area - intersection + self.eps + + # 計算 IoU + iou = intersection / union + + # 計算最小外接矩形的對角線距離平方 + enclose_x1 = torch.min(pred_boxes[:, 0], target_boxes[:, 0]) + enclose_y1 = torch.min(pred_boxes[:, 1], target_boxes[:, 1]) + enclose_x2 = torch.max(pred_boxes[:, 2], target_boxes[:, 2]) + enclose_y2 = torch.max(pred_boxes[:, 3], target_boxes[:, 3]) + + enclose_diagonal_sq = (enclose_x2 - enclose_x1) ** 2 + (enclose_y2 - enclose_y1) ** 2 + self.eps + + # 計算中心點距離平方 + pred_center_x = (pred_boxes[:, 0] + pred_boxes[:, 2]) / 2 + pred_center_y = (pred_boxes[:, 1] + pred_boxes[:, 3]) / 2 + target_center_x = (target_boxes[:, 0] + target_boxes[:, 2]) / 2 + target_center_y = (target_boxes[:, 1] + target_boxes[:, 3]) / 2 + + center_distance_sq = (pred_center_x - target_center_x) ** 2 + (pred_center_y - target_center_y) ** 2 + + # 計算 DIoU + diou = iou - (center_distance_sq / enclose_diagonal_sq) + + # 返回 DIoU Loss + diou_loss = 1 - diou + + return diou_loss.mean() + + def _calculate_intersection(self, pred_boxes, target_boxes): + """計算交集面積""" + x1 = torch.max(pred_boxes[:, 0], target_boxes[:, 0]) + y1 = torch.max(pred_boxes[:, 1], target_boxes[:, 1]) + x2 = torch.min(pred_boxes[:, 2], target_boxes[:, 2]) + y2 = torch.min(pred_boxes[:, 3], target_boxes[:, 3]) + + intersection_w = torch.clamp(x2 - x1, min=0) + intersection_h = torch.clamp(y2 - y1, min=0) + + return intersection_w * intersection_h + + +class GIoULoss(nn.Module): + """ + Generalized Intersection over Union (GIoU) Loss + IoU 的泛化版本,考慮了最小外接矩形 + """ + + def __init__(self, eps=1e-7): + super(GIoULoss, self).__init__() + self.eps = eps + + def forward(self, pred_boxes, target_boxes): + # 確保輸入為浮點數 + pred_boxes = pred_boxes.float() + target_boxes = target_boxes.float() + + # 計算交集 + intersection = self._calculate_intersection(pred_boxes, target_boxes) + + # 計算各自面積 + pred_area = (pred_boxes[:, 2] - pred_boxes[:, 0]) * (pred_boxes[:, 3] - pred_boxes[:, 1]) + target_area = (target_boxes[:, 2] - target_boxes[:, 0]) * (target_boxes[:, 3] - target_boxes[:, 1]) + + # 計算聯集 + union = pred_area + target_area - intersection + self.eps + + # 計算 IoU + iou = intersection / union + + # 計算最小外接矩形面積 + enclose_x1 = torch.min(pred_boxes[:, 0], target_boxes[:, 0]) + enclose_y1 = torch.min(pred_boxes[:, 1], target_boxes[:, 1]) + enclose_x2 = torch.max(pred_boxes[:, 2], target_boxes[:, 2]) + enclose_y2 = torch.max(pred_boxes[:, 3], target_boxes[:, 3]) + + enclose_area = (enclose_x2 - enclose_x1) * (enclose_y2 - enclose_y1) + self.eps + + # 計算 GIoU + giou = iou - (enclose_area - union) / enclose_area + + # 返回 GIoU Loss + giou_loss = 1 - giou + + return giou_loss.mean() + + def _calculate_intersection(self, pred_boxes, target_boxes): + """計算交集面積""" + x1 = torch.max(pred_boxes[:, 0], target_boxes[:, 0]) + y1 = torch.max(pred_boxes[:, 1], target_boxes[:, 1]) + x2 = torch.min(pred_boxes[:, 2], target_boxes[:, 2]) + y2 = torch.min(pred_boxes[:, 3], target_boxes[:, 3]) + + intersection_w = torch.clamp(x2 - x1, min=0) + intersection_h = torch.clamp(y2 - y1, min=0) + + return intersection_w * intersection_h \ No newline at end of file diff --git a/Model_Loss/Loss.py b/Model_Loss/Loss.py index a9c340b..b507f7d 100644 --- a/Model_Loss/Loss.py +++ b/Model_Loss/Loss.py @@ -8,10 +8,20 @@ class Entropy_Loss(nn.Module): super(Entropy_Loss, self).__init__() def forward(self, outputs, labels): - # 範例: 使用均方誤差作為損失計算 - # outputs = torch.argmax(outputs, 1) + # 转换为张量 outputs_New = torch.as_tensor(outputs, dtype=torch.float32) labels_New = torch.as_tensor(labels, dtype=torch.float32) - - loss = functional.cross_entropy(outputs_New, labels_New) + + # 检查输出和标签的维度是否匹配 + if outputs_New.shape[1] != labels_New.shape[1]: + # 如果维度不匹配,使用交叉熵损失函数 + # 对于交叉熵损失,标签需要是类别索引而不是one-hot编码 + # 将one-hot编码转换为类别索引 + _, labels_indices = torch.max(labels_New, dim=1) + loss = functional.cross_entropy(outputs_New, labels_indices) + else: + # 如果维度匹配,始终使用binary_cross_entropy_with_logits + # 它会自动应用sigmoid函数,避免输入值超出[0,1]范围 + loss = functional.binary_cross_entropy_with_logits(outputs_New, labels_New) + return torch.as_tensor(loss, dtype = torch.float32) \ No newline at end of file diff --git a/Model_Loss/Perceptual_Loss.py b/Model_Loss/Perceptual_Loss.py new file mode 100644 index 0000000..d2ac6dd --- /dev/null +++ b/Model_Loss/Perceptual_Loss.py @@ -0,0 +1,116 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +from torchvision import models, transforms + +class VGGPerceptualLoss(nn.Module): + """ + 基於VGG19的感知損失函數 + 使用預訓練的VGG19網絡提取特徵,計算特徵空間中的損失 + """ + def __init__(self, feature_layers=[2, 7, 12, 21, 30], use_normalization=True): + super(VGGPerceptualLoss, self).__init__() + + # 載入預訓練的VGG19模型 + vgg = models.vgg19(pretrained=True).features + + # 凍結VGG參數 + for param in vgg.parameters(): + param.requires_grad = False + + # 將模型移到與輸入相同的設備上(在forward中處理) + self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + # 選擇要使用的特徵層 + self.feature_layers = feature_layers + self.vgg_layers = nn.ModuleList() + + # 分割VGG網絡到指定層 + layer_idx = 0 + current_layer = 0 + + for i, layer in enumerate(vgg): + if layer_idx < len(feature_layers) and i <= feature_layers[layer_idx]: + self.vgg_layers.append(layer) + if i == feature_layers[layer_idx]: + layer_idx += 1 + else: + break + + # 是否使用ImageNet標準化 + self.use_normalization = use_normalization + if use_normalization: + self.normalize = transforms.Normalize( + mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225] + ) + + # 損失權重 + self.weights = [1.0, 1.0, 1.0, 1.0, 1.0] # 可以調整不同層的權重 + + def extract_features(self, x): + """ + 提取VGG特徵 + """ + # 確保輸入在[0,1]範圍內 + if x.min() < 0 or x.max() > 1: + x = torch.clamp(x, 0, 1) + + # 標準化 + if self.use_normalization: + # 確保normalize在與輸入相同的設備上 + if hasattr(self, 'normalize') and not isinstance(self.normalize, torch.nn.Module): + self.normalize = transforms.Normalize( + mean=[0.485, 0.456, 0.406], + std=[0.229, 0.224, 0.225] + ).to(x.device) + x = self.normalize(x) + + features = [] + layer_idx = 0 + + # 確保所有VGG層都在與輸入相同的設備上 + device = x.device + for i, layer in enumerate(self.vgg_layers): + layer = layer.to(device) # 確保層在正確的設備上 + x = layer(x) + + # 檢查是否到達目標特徵層 + if layer_idx < len(self.feature_layers) and i == self.feature_layers[layer_idx]: + features.append(x) + layer_idx += 1 + + return features + + def forward(self, pred, target): + """ + 計算感知損失 + pred: 預測圖像 [B, C, H, W] + target: 目標圖像 [B, C, H, W] + """ + # 確保模型在與輸入相同的設備上 + device = pred.device + self.vgg_layers = nn.ModuleList([layer.to(device) for layer in self.vgg_layers]) + + # 確保輸入尺寸匹配 + if pred.shape != target.shape: + pred = F.interpolate(pred, size=target.shape[2:], mode='bilinear', align_corners=False) + + # 如果是單通道,轉換為三通道 + if pred.shape[1] == 1: + pred = pred.repeat(1, 3, 1, 1) + if target.shape[1] == 1: + target = target.repeat(1, 3, 1, 1) + + # 提取特徵 + pred_features = self.extract_features(pred) + target_features = self.extract_features(target) + + # 計算特徵損失 + perceptual_loss = 0 + for i, (pred_feat, target_feat) in enumerate(zip(pred_features, target_features)): + # 使用MSE計算特徵差異 + feat_loss = F.mse_loss(pred_feat, target_feat) + perceptual_loss += self.weights[i] * feat_loss + + return perceptual_loss diff --git a/Model_Loss/Segmentation_Loss.py b/Model_Loss/Segmentation_Loss.py new file mode 100644 index 0000000..230c33a --- /dev/null +++ b/Model_Loss/Segmentation_Loss.py @@ -0,0 +1,22 @@ +from multiprocessing import Value +import pstats +import torch +import torch.nn as nn +import torch.nn.functional as F +import torchvision.models as models +from torchvision import transforms +from Model_Loss.CIOU_Loss import CIOULoss +from Model_Loss.Perceptual_Loss import VGGPerceptualLoss + +class Segmentation_Loss(nn.Module): + def __init__(self) -> None: + super(Segmentation_Loss, self).__init__() + self.Perceptual_Loss = VGGPerceptualLoss() + self.CIOU = CIOULoss() + pass + + def forward(self, Output_Result, GroundTruth_Result): + Perceptual_Loss = self.Perceptual_Loss(Output_Result, GroundTruth_Result) + CIOU_Loss = self.CIOU(Output_Result, GroundTruth_Result) + + return Perceptual_Loss + CIOU_Loss diff --git a/Model_Loss/__pycache__/CIOU_Loss.cpython-311.pyc b/Model_Loss/__pycache__/CIOU_Loss.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bdf4037a04198b45fc6908d6a52235c5235456d5 GIT binary patch literal 16175 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 ZdEkFhNZf7MjKcGYEDZcFN+gmd{x@A<+35fP literal 0 HcmV?d00001 diff --git a/Model_Loss/__pycache__/Loss.cpython-311.pyc b/Model_Loss/__pycache__/Loss.cpython-311.pyc index 1e8d4c4100e539c8ad60763979eb32340456acd4..1c98ff20b428c54f32ce55e6d55382f268226b7a 100644 GIT binary patch delta 666 zcmbQjeTtWFIWI340}%A39?Mw5vXQTX(b!c#BR@A)zdR$eBsDv;C^HY4SzMBzo0yyt zpPZPNoLZzGP+5{+l$v$r={y;@M!;MfxR- zaHR}cEHHKrOA6B(=4DI_46A_{0%CxyTGm>&5^k6X149-YlX!(79Ls-c!WPZUKl z`{V;m(vs{bR>G~XVV~^9q$U&0pvmH=$#{!3rKGYT^(9Ce$YV~)%+=(Wti>$ta*MS% zBe5X$7ISW5MG?rsw|J9_@{5b(Q}arS@(U_&DI{g)B^Fi2qlm_rXO?8d=j5knmJ|aG zie@&DXNh225UJ=$_;k`rdqOivmVUG@%4i}(u5xFbEb~~z1cwH0@zakvo;qr7cH;X%? z!sK96&as0+U7AtQi$22eLU>ax(&TViFUKrdWOiiGRT& H2{sG>c`90* diff --git a/Model_Loss/__pycache__/Loss.cpython-312.pyc b/Model_Loss/__pycache__/Loss.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d6a51a9ec5453e6888237a8e54fac02d1dbd7bf GIT binary patch literal 1262 zcma)5&r1|h9RI$Vo!Qx6YzHljD1$&&%7f9t)G##aP>UdT7*-zB%&e}=&TQ|^Vk;YZ zSZITyJj8nRm?)GWc?=NeAhJahpTv_bVt?E8dOVS|n=(4{J5k%cOnE?ZIs z^iUNZAzhh(lpMrwxjyj+Z@e25<_cHbh)xd8X{Z=L@!}A!xTGN7{#L7&w zunH{}Y(i9K2sDgyZqCOzB?TdBJJ}$DvFR9;VoZ6Y?#17uW7jj|#G58YKIcwnsPE+s za|WA+Yucn`!Q&<0BTSvP=Q8&^%XUQ78D4r{p+q7q)_mvDhWc8m!^}iaF?O&ByISIz zvplw~^?uSW*O?B?=CrvCA$COHaW)Osb$ceW?XJatf|b$XRA#y7KeUe4nqH6PV zjui5FJA(d)ow8gGwX-V6WK~X@m7zsSGxRBzUn+@S@J9`z4W*Dn4s)j*LEVB#T=-`_ zGG`ELzT>ZVZfbc7I>Fc??5l9*T+LhZR;D*6x286xc2190W4oPaYj_E-+~2&mHM}vr z(|NNR{g&+dob1_7_Pmb0)juXjs-fLv$BTuh3(NlcS$JB^uNUVrpyi>|^98_Rm zLdun2YFHT(S%sZVkOP=-YzCSbexK_$X05VqV0DQ9R-xe|#-$B4D!f51GB=)*Z^3=O^PuMI2>`~)Tn|39!n4`l!V literal 0 HcmV?d00001 diff --git a/Model_Loss/__pycache__/Perceptual_Loss.cpython-311.pyc b/Model_Loss/__pycache__/Perceptual_Loss.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6e719ad9ffce0a714ea06f673df577ada363300 GIT binary patch literal 5618 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 literal 0 HcmV?d00001 diff --git a/Model_Loss/__pycache__/Segmentation_Loss.cpython-311.pyc b/Model_Loss/__pycache__/Segmentation_Loss.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f17d384c6d5d855fb3c334b5cf0bbdd1d623cdf0 GIT binary patch literal 1793 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 jju+Wx7F1G7VvY;I5B;C!2M?8F9^=L 1: # If one-hot encoded labels = np.argmax(labels, axis=1) + # 確保標籤是整數類型 + try: + # 嘗試將標籤轉換為整數 + labels = labels.astype(np.int64) + except ValueError: + # 如果標籤是字符串,先將其映射到整數 + unique_labels = np.unique(labels) + label_to_idx = {label: idx for idx, label in enumerate(unique_labels)} + labels = np.array([label_to_idx[label] for label in labels]) + # Count occurrences of each class class_counts = np.bincount(labels) class_weights = 1.0 / class_counts # Inverse frequency as weight @@ -98,20 +136,28 @@ class Training_Precesses: def Setting_RandomSampler_Content(self, Dataset): return RandomSampler(Dataset, generator = self.generator) - def Setting_DataSet(self, Datas, Labels, transform = None): + def Setting_DataSet(self, Datas, Labels, Mask_List, transform = None): # 資料預處理 if transform == None: transform = transforms.Compose([ - transforms.Resize((256, 256)) + transforms.Resize((self.ImageSize, self.ImageSize)) ]) elif transform == "Transform": - transform = transforms.Compose([ - transforms.Resize((256, 256)), + transform = transforms.Compose([ + transforms.Resize((self.ImageSize, self.ImageSize)), transforms.ToTensor() ]) elif transform == "Generator": transform = "Generator" # Create Dataset - list_dataset = ListDataset(Datas, Labels , transform) - return list_dataset \ No newline at end of file + list_dataset = ListDataset(Datas, Labels, Mask_List, transform) + return list_dataset + + def Setting_SubsetRandomSampler_Content(self, SubDataSet): + # Calculate subset indices (example: using a fraction of the dataset) + dataset_size = len(SubDataSet) + subset_size = int(0.8 * dataset_size) # Use 80% of the dataset as an example + subset_indices = torch.randperm(dataset_size, generator=self.generator)[:subset_size] + + return SubsetRandomSampler(subset_indices, generator=self.generator) \ No newline at end of file diff --git a/Training_Tools/Tools.py b/Training_Tools/Tools.py index b39e469..7f30087 100644 --- a/Training_Tools/Tools.py +++ b/Training_Tools/Tools.py @@ -5,39 +5,9 @@ import torch class Tool: def __init__(self) -> None: - self.__ICG_Training_Root = "" - self.__Normal_Training_Root = "" - self.__Comprehensive_Training_Root = "" - - self.__ICG_Test_Data_Root = "" - self.__Normal_Test_Data_Root = "" - self.__Comprehensive_Testing_Root = "" - - self.__ICG_ImageGenerator_Data_Root = "" - self.__Normal_ImageGenerator_Data_Root = "" - self.__Comprehensive_Generator_Root = "" - - self.__Labels = [] self.__OneHot_Encording = [] pass - def Set_Labels(self): - self.__Labels = ["stomach_cancer_Crop", "Normal_Crop", "Have_Question_Crop"] - # self.__Labels = ["NPC_negative", "NPC_positive"] - - def Set_Save_Roots(self): - self.__ICG_Training_Root = "../Dataset/Training" - self.__Normal_Training_Root = "../Dataset/Training/CA" - self.__Comprehensive_Training_Root = "../Dataset/Training/Mixed" - - self.__ICG_Test_Data_Root = "../Dataset/Testing" - self.__Normal_Test_Data_Root = "../Dataset/Training/Normal_TestData" - self.__Comprehensive_Testing_Root = "../Dataset/Training/Comprehensive_TestData" - - self.__ICG_ImageGenerator_Data_Root = "../Dataset/ImageGenerator" - self.__Normal_ImageGenerator_Data_Root = "../Dataset/Training/Normal_ImageGenerator" - self.__Comprehensive_Generator_Root = "../Dataset/Training/Comprehensive_ImageGenerator" - def Set_OneHotEncording(self, content): Counter = [] for i in range(len(content)): @@ -46,35 +16,6 @@ class Tool: Counter = torch.tensor(Counter) self.__OneHot_Encording = functional.one_hot(Counter, len(content)) pass - - def Get_Data_Label(self): - ''' - 取得所需資料的Labels - ''' - return self.__Labels - - def Get_Save_Roots(self, choose): - '''回傳結果為Train, test, validation - choose = 1 => 取白光 Label - else => 取濾光 Label - - 若choose != 1 || choose != 2 => 會回傳四個結果 - ''' - if choose == 1: - return self.__ICG_Training_Root, self.__ICG_Test_Data_Root - if choose == 2: - return self.__Normal_Training_Root, self.__Normal_Test_Data_Root - else: - return self.__Comprehensive_Training_Root, self.__Comprehensive_Testing_Root - - def Get_Generator_Save_Roots(self, choose): - '''回傳結果為Train, test, validation''' - if choose == 1: - return self.__ICG_ImageGenerator_Data_Root - if choose == 2: - return self.__Normal_ImageGenerator_Data_Root - else: - return self.__Comprehensive_Generator_Root def Get_OneHot_Encording_Label(self): return self.__OneHot_Encording \ No newline at end of file diff --git a/Training_Tools/__pycache__/PreProcess.cpython-311.pyc b/Training_Tools/__pycache__/PreProcess.cpython-311.pyc index c4a7a1a72adfdfcdd9cbcf16766a7ab06eade536..07e2dd70694cff36bb3cac4b1fd7cedceab3fc4c 100644 GIT binary patch literal 8646 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 delta 2674 zcmaJ@YfKy26~6QI6MGymet`{ffOP@^vUw01P$4Nv$~H=qR4PP`*LVhE;s?4jBqTDS zts>PcMOxI0l>A5)exQ+(Dy{WiHVU~^`g-zoDxcP9??qaep{ZQ*;%%cqfqg-{#XjUmV-XnpQ&Mee zEs6IX)#i41xvHW4@bZ-4VgKfT;@*doa5xF|v+F|paW66yYvhJ^-}2FwlONo@e|O#9 zN&~=5<2LIgL&MtgZ#ecxA$r6?4D9Ywkyp7Vp#F4k$T6}g7*btM$SlW3>_L82V4sQ| zXGN9Z^X3qa^sdn$eP%3I)Ryr!!g2lr4^K za+)dagpdu?F>Zjsv43_XmMl+)z|{~E{?N+ALw)61$ywuNhkwK8U!Gk(Q1*3Id|frd zHJtqD=td~|D7<>697e2Ppo8{=#;Y##y+1Fd~^_JwS(zN1wc)Fsrl_apDG%wGW z7T4`9`XC(JhssEdJbq`SQCPFNp}E#5js$FL0Rh`#4%-o{9dnNI!dk*RG9;`GNuxab z!kq{-g9RE!=mGecSl0$zAUEtkAxQBW*#jphMPavfkbP2XjeHwufF&EE$NRwA1EP^h zP9>9YweFEgLA9&GJ#JD|Md(SY1SqQx)doD9DnocW+3y-Ym*cpaC|mMGqZkDAH~{7z zP1W(fS|Nh`X7&e98`sJH>KWw%EanY!KWBs9AIF*uOc1+N+{poSuMd+Ok`#&bA(&PghcnTv&t#X&+aM1$GSnHX8|BE zUHfXJ+2PqzNTj10++PK3X{|5om5Q0_i(4uVk>uo}cvVqxgmx}TenBnQ(p{dd*@)MZl>E2A>8XNnpag6I{+l>dE zXz7*n6qEoK^^ZHT6r>Bex#1tMpEVuyq2;g9Sb{Uf)B-4#n){aArZb~w^15Nw0L)#M z2TWTguV&JkZsiTyf&5MYQv`O-lv8vjms&9GQ<;3aFb~-W(;~%vCG1v?p`)nn(dVah z%}9RJnCVVuQ@WnC#<5(Wy>T2=b(|VP2kfNZH8&>V1@36mzyCG`X@53>#kUs|^epfVD7afj7Sc~Xjmm;xAA#Vp2 zVOND$1*lt&`ZVBexB^AtO^+@@oLKcB!GBF)etHe`O~;jbwWm?&CnUBOX+2}wuN1CW zd7ip0?oM)-&cJtoZp!ajUkW>A!Huzy#191UhK@VLbHHL;Vg7MX3A9X%ESq=ib~F6fT~B&nmbyj$J7~pPRdF-2zic-#lWSw>9fq%Xwu#l`E+8S#6l+VIVk= y=>GtKQp0gow%*pw{@FH>33HI5zYWV>FOa+WS~PHx<6w#Z9bZ`d&Ho{__Vgbj&3VND diff --git a/Training_Tools/__pycache__/PreProcess.cpython-312.pyc b/Training_Tools/__pycache__/PreProcess.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3dacc792852ed2332c22c7d87d26f13bef26df0d GIT binary patch literal 5616 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 D`v7Zx literal 3985 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 literal 0 HcmV?d00001 diff --git a/Training_Tools/__pycache__/__init__.cpython-311.pyc b/Training_Tools/__pycache__/__init__.cpython-311.pyc index 62f65d91504d37ac68c720e00cf03d132f0a0148..f90ae1fea7e7156a4168c79c40d1e5ec75b60534 100644 GIT binary patch delta 76 zcmZ3+xQmfzIWI340}$+6z?m_T$JpeTuYN{;ZmNEHMrKKBc4kp#9x}7IBtJJXIU_zf UF)ul_NI#&mB)=#*V`98J0K@qkJ^%m! delta 56 zcmdnRxQvl!IWI340}y2B1gB5rF;@6$2IT0M=NDxc7bGU9>IW3%rxzvWD(EV_SknGt J@!pBW?f|pU61xBZ diff --git a/Training_Tools/__pycache__/__init__.cpython-312.pyc b/Training_Tools/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c489d7f97e18294756640a133e43d35e7f1c826d GIT binary patch literal 172 zcmX@j%ge<81bY{7W`O9&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd6Ht_&UX+-d znU@|@T#}!gn4A%xoS2uKS_G4c52!53F9HhtrIyEp6eVWn0oBHbXY0Q>@EATtV38G&I4_9!0JD|jjPDp2(aK8m5@R|7(T zVxJOJLqdpRzcQe*0>=OpmIE(6B=!lTZF>M>PBA`jCj&r;U|XoqHi&J3J{ym1-acCt z@r@6BpGG}W8g&1C@P&UCo$>hRrVx9OYZt_dZ}*gh3$1%yF#qb$kd zvQ(4A&oxw$G-Bj8%5t$(aLmukh|2xkSb||V+0f|yc#$M$;RING|yzj3Z zR+Mth4vL~G6-%OcO^Ua{HMu{}va@!SrWW@UsanlZtdXl@k5DBQCtQv!hy;?gs*%&T z+7W`crEif)x`)@Rcukv33AVq( zBlaF1=af;PZZ@}rsx?v*31UM9x5SPWu*VwhzDy2HqwzyDHl+=b)GNi3q=?JKJtwO@ zMDnza#Eb0MgZ(V16stJTOLSPZW6mi_iqbx7lFbg+I&G%QBu%??P*72+Ce@1Nk|WLb zQH8d@s8;vOuWU%Ze}Z?oqu~8eyW^xVdW~|G!}r0D)Ute_ppUhA%pq5$YT@sVmthzS z+|}LF0*`g~w7`eDds<*xcTWpE)7{eoQ@VRzdD)}yo8FY+O<7#@=*gSaJ<$By!q3n0pli&>o9J?U<)RjFloS) z2~#>uS>b3aJkbnK7~x4XJXv3{GSjWhLNl{)v1MfPW+rdI@%qNe{VR443f z8tg-peTb9su@;|g^4YWd2A?YG&i$zY40YVuPCKV$MU20LrAv-RbxSgIAvHDkH6A1-TuExmnZ z&aM8P)?a+7e6*XeUJ2jGbAO=)xZg#QHx7xu>h literal 0 HcmV?d00001 diff --git a/__pycache__/claculate_output_data.cpython-311.pyc b/__pycache__/claculate_output_data.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f463f61820994f80552e87ac6083c4e7e3ee4a40 GIT binary patch literal 5186 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 WrWf-Ai4V+-jEo-`U_=o!Pz(TLJ0y7k literal 0 HcmV?d00001 diff --git a/__pycache__/main.cpython-311.pyc b/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d1dbac89854ada19ba8aceed6d9ea9eec833af9 GIT binary patch literal 8643 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 literal 0 HcmV?d00001 diff --git a/__pycache__/test_bounding_box.cpython-311.pyc b/__pycache__/test_bounding_box.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c56c1466b13335038bb4a9b7bbece8248f048716 GIT binary patch literal 2608 zcmb7GZA=qq9DlC&^o6!qN{i)19O4^w3-XR3!rWZ4selswu<+$lxC#||t=Fr(q)oa_ zClfYVqS!=~ZZW74H)dSc>?QlKFZ*~$E*ZImWXU|BpVq|ei(j_?bETD{ZrR=ce!b`a z_WYjz^M4NR78aTjT*oGV87wY9=npc;Ub>B!r=9R}1F?vuhEZ?km+IBQST{`jaWAG2 zOJ792dar@SLs}GX)giBb9^xKkvmx-JPHT@_pCa0BH>GTUzpL{tjtdAL!5838@qvDC zC=}rPb5ZbOgolRb=^?-yNT8k@^Jj=6f%t7)=d%1^P9gV>(7Bw?f^Hu44{|n^9@irj zrC1!HSUqdFq}xE_S^6+!)$}H|0Q4C&Z_-;>E9f&=xS`+1+TbpN+divji&+EQ4!B`7 zpo{7vD1ozVH~&Vc$QEW%TChC#V4V@_oFO~DiEioUp(YPpgN@5 z+7+Q$n8(1F$Kd&jjrl8u^=rKmHRa7$7BRhaKAf!=?~EAu;)sba%8M({&rTuE zmS?ZnY8M>Y+Q7bO=ah`u9T7Ue9$WUia%&zIoks4R-EKPd2J{FIJ&saj%i;X#Sz#>b zO~r`nZvrfVUjcZs^wcPU#{@`srKSiZ2oS4c5xgOR3G|)w_6w;7qMiY8>lMs-{9Xl* z`hA>&$21)Edq&ASpmkGNL+TlXgq;BDXLIV^Np*Hc{phOt)0bDBu=efr>h0Mr z1{ay`*6q{}pRa%N2qM-VCswZ~QXo@R$h>KaOLw3Ad~0>;gG};2f1Ju>TmR}xE=ky$OQGKRX7&1w@f})8vUwPw%JAM$ zcvz?nas%N;a96*31bNkm@y*p}tNOP%w}mI$tmwF)f&-j4r0BywPB^4ESl%-NlVn(v z*@!L3gHh3k20cNqLWjbB#p2<4&lux9ANC9@bpM40#pv^o@IJxoE>H@B*{`)?)>!!b zo&m4o@CW*bw&u2G7QJ#)UW{@UP}^7;!}W`ivB0W;zg1{sYd>k&MBJtQPYBD5EJI)>Du zeNs`4TvQV~_Ll(_JFmIol@I$C21R?TWN(%2t;yYzy*+k3Z9w}E#EwsdrW+?l;&l9I z+?cS7wrUCQUf$>apN6y!9p9C}O7;&?4?>63s0j5^j}otB6~n4%X7RF5Vb7 zBy@?!gdx67w(O6+v*IYZ){)qA&%D^M*uU74Y)JMeTNXRynztp#QQ2`c)~RLeN=8I; z7l?$rW!x>|Zb;~OEq*>x92XKj2|jTqJ}ws@h@Dum*{3c{4@tIa*;bwKEZO$Q-qTVv z-K!DJK&wf@%`$Elar5s+SA5r!u|hOfB&-07r2s3YLUCKSWI8FEPKuhSrostMGF8f^ zO3_qFs%5%(LM*CXv`V;L#_b|**Cu#V!bfC$M9j)l=oX}y7-&@=$1rXqzn3WVT-YBR zJh>F=zNNbm4{_x>7r-S}&5sL(P=SX(zuO!i%O$SI7%UGofu!D b%S5_t8N)^&lyJR_>&2|3X@twcs8RU`j^XA} literal 0 HcmV?d00001 diff --git a/__pycache__/test_main.cpython-311.pyc b/__pycache__/test_main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..06c08d894cbec0fd10d17361e13d82652f67985d GIT binary patch literal 7102 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 literal 0 HcmV?d00001 diff --git a/__pycache__/test_model_branch.cpython-311.pyc b/__pycache__/test_model_branch.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2c1594a7cbffe26cb8054ba78a28ea267297cf3 GIT binary patch literal 4192 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 literal 0 HcmV?d00001 diff --git a/__pycache__/test_processing_main.cpython-311.pyc b/__pycache__/test_processing_main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e17904aca8985c882c5704d747af0eaff6aaf333 GIT binary patch literal 6539 zcmb7Ie{2+09)B}C`?J&C(ssKov~&vvTcItK0@5Nt!~@ zV?E*CeoteQ$O$6T7m16FeX(BE*TwZlxtJIf!|@pNG*mNNqrqMd`qCXiLFD7mppz4! z>^C)iJQ5EbV0Q7ra16`u61l#RuDnk1-dNy&XN1B#?L?xnnh2R^JAg#oa`s_~{COqO zer=_2g8{@UqCAbANf`Mjv(!COqO7M2Ek@#^%vcE3BL49K z+9bV9T$1G{^H6ZEb!UAnij)i#CJRSPvpuspv!@fN8*p)eewk*SU9-7^#6fh((v1!h z_h|QUo_6IAs@?rYtFP!x;EhZVolRdjmOlRe)X;GHt=}iyQ1{(ef4em@c6;nf`n6N7 z{!n&02%uMg?%;(yfjAT(SQG#(V96syz=BaHK(Q21D{BQTw*RzDM_fK0;sgO>WfU;8 zaXsK?Fd}Sd>5{rSPkA9y1>zChs`Nq`5<=Yp}PrWxW_3j7Lr{DPZ z)#K@N7t-UuZS^Ox_E6S&>90P%b!;%F_U((eKE8TS?bxYXpPkFp*1J?n2={ZURgCkY zeJaHVW2{QCU{I345Cz}f0!C^rYmdCY#SBF zc8*)dyX4AsO659SJz2HrOkj)}3yznJhvceOrK)wJ>w48j;JH#&HD>}hsv53WHON&> zN>vlCoLsp0%z?4maYA0$tSoGXs)AJQ68t*ZuKiv-xmhl%nJn_oAmodX6Pxw7PNlBr zl&;-M*IrX);;@o<dc z2wRfw>P3(_fxsYf6YT+mBRVe<+V0d7JU;9M+}zLOlTNiWOoWTUcC31^?a(?sjD=yC zf!**e7&$Bz`T0sHnqUY!xdubeLdL9HlE|LDptCWf+ zl9883#dH1Ri_g6>;rV*;glEEYt@NJ@q+dU;Z0(kO-BMAvwnh+R^LXj%ZP+Jb!6?Tt zs*7QwaW(6>isXK{`B7Ms}t$hKhZJU-{7Af9fk!0pvT6u+<)uzr&D7PX(VuLYMdIkPo186 z_wv;6Z_?*J!$-#8)mDE!#pB4BF9)JhQ7#x$DQx`p7PZ23KiiQI`x3L4Id!p#wH*!x zrh|_sV(czHA@0*}e5#90M5Bk92xu+f+57#o=u!~HS3O+M3H|l=cd?wN>p+I^Dv&`m zNzVfSEZIRykL*+)c}~w8lqEVaO0vXu43p4GrvRUYPh$p9r~!JjqWMO}+Upf-<%)Gm z#k!$wAXh4WV*KI1H2twjZr-FcZ-OEunckw%TO@i*s-#Myt8_R6O^gTI1YXBG7-cY= zu{j{7LDBSo;o%K2ZZ==ae+-%-I0>*5|`hAD)^1=)?4f$G~iH zXr@=a&~MoT6-}E9p1CoId^s z@BlB55khkV)y8r!g+m-)1U0HPA%-J@c5tZn*??Mg;SBx?!ttt2_eiyBld*B2l)iE8 zuyMPzjZ-~&nyQp|xQ|m^VTj%ZF&GQsSSta?ld5fa=tuE`~c4s&}g{I48IWBf!TK9=i*VL0P4ZeSsT+TA-Em z9pamDqcymZC(eg^!?9pw)-lxuM#a5GrP{za6A@7*!h9p{O>le%yajyO0YA@q^wX$x zF5BgILhDl8Ed~BFh-Rqg39EO~yIS_HRlIA5T$7GM$z3fw{EEXbIs7v=R9vadTQp?T z7!RF%Npe2~Np{pJjylOvH)HcS@c}hAJ^RF&Un!N#mCBaywH80*w7Xl2oNme8Dm&T~ zN1NnmOZjSt2gVjjz6ROXp!gbw=({%Ls~kC?lr6ncw(@$}%JJpbR!YylAeF6@%XTYe zyN3!itsa#f8x+R|$+2O^W_2!{K?W%zos~1lATG3Ei86oLkSDctg|f6$ax9*)`JELv z{mX{7DRfn8Z8v_m+;ySCVyU=QrrQ*{O`_XU-s&6Prt99OaawvdAVm&J-X__5Nbw#T z+5#(7vtqXUGkSNM)_t{1uTkhV61_%)xRsx@jM+X~e{Q{0yb_X3H!F0rL^s16i{_tP z`pFX6Q>S?9K>5P;lht)&WpecjrFz8-qUNpF$nQFa+lR$TU(IOk73*bM_N`WYt7nkK zyMD5~N?N#ci~s`Z3On9%asTE0dg<$3e-G$6x%?TW{2570Y22d~_h^Nb?SV^jd7Dz+ zCTR&UYq;gdNl!Uw;H=0JZAKfvvP`spVY_ORiZ?=%>2`%~m+1BsT`6T!iuT^1tFP15 zGF_w4H4aC>ZAEXuXI26Qpe1=J2Z*ff>9h^FIRL9Wi!4Ck@YP7EmF1<I9ii-|(xc8pCz zWA0aAMyuoTWk6k#+cxtZxX~17n7iak51}{k zAzat><06e<|he&BQjb;R+e=QYnTIbuKI zdB-zKp0i)@eC!!_$o_STf1O;^suZ=#s7*m_5^BReR!FERH$h#)hC#RFsgqGXZt$3d zHsq!h+9R3M3>6> f_Y&E$RBOe@oC?=H8Gi;gRyhYJ^9Xe zzVrM3obSuI)7&f~Xfm}F+s`BP8(CDF;|1~b4Va!Zjb;wUTxShMhfH}SuV$Yi*C|?N6@PG3MVFN_m!h^bdJffbHG`sac4KZtsK{g zndkorGs^#GOotQY(CntUkmGZXIq-VnrRPF}=Z>5(QS)-s7}UpDX!HhR>>NdJA+43f zbffhkWl!GOphMK$)m?;g&PI&Qbe@2$%sW4EMw=kJY-*C4L}!>2Xp;I@ZPNd#Ezo={ z>jL9Tg`1^2mr9qf{$7|VeSWJGJt6*5@xhey~`&_+$C<_k;dW zb}NY2taxQVASxsiEiR+PQ<}v`@#%O3Tb!0wA~B0q!l|f5YiVm+MoCAos>*78QKqw6 zCaYPT8VhHzlQ$!h!@wuDG5oJ!$@YVk1~ zACCdVWIU?HlqO<}6i)%F98ZSFv1++D)7bjL92~8RQCKB^v;JCp-l1VtYp}OBbJp_P z+}C)c>;M=NWA!{-#T2TrKF+h|={GzFOwWOWxF$5~Ej~l=n}S~#{1qO(;Vp;eCXGrS?w z8(Q@qUGX0Mb*JGSF}))N350w-Hzww{-XF1rxOT(}=(`!iGrqr!V z-9@)|rtjIBYfA;u&d!&U4bZoE)ZIT-{_xV&CGv`H%1Jzqem+*$2ZA`b?ou7y62>jzYHDUqEplAk-nais{4cK@t7p z89L%dOKvgfV3v0Hf;6)4=SsGD3Mp*s-Fn&TgVp<*$IPxkJMD+-q$LQHYfa=T?|bo#`yHJv!TC Vuscn5r(PWu2C-XVQ`rM%{{_QFSF!*A literal 0 HcmV?d00001 diff --git a/__pycache__/testing_Labels_Accuracy.cpython-311.pyc b/__pycache__/testing_Labels_Accuracy.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7fa948dfc733f715488fc66f85514cdb0db78e0 GIT binary patch literal 9005 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 literal 0 HcmV?d00001 diff --git a/_validation/__pycache__/ValidationTheEnterData.cpython-311.pyc b/_validation/__pycache__/ValidationTheEnterData.cpython-311.pyc index f3a8bd9d87276abd2a2e8efaf7928c0925bc2e48..5e9ba225c25e63ba3f6ce89f619796ca5535d38c 100644 GIT binary patch delta 91 zcmcb>ahHQp!w+*JMYjLeeM?98IfJY;5ZNq%l(az=b| jVqS7;k$ymBNq$jshJJimVoqjCVo7Fxp8jTOMpI@0)AJzp delta 78 zcmcc1ae;$pIWI340}y2C1gB5rxoz^*1ITf)iYYG1&rM9uh)+(;OHM6{2`I`>FG|c+ f&{cS`r2WO>y)p4+i8+}mi6xo&c`=(c7)_Z0@Ua`T diff --git a/_validation/__pycache__/ValidationTheEnterData.cpython-312.pyc b/_validation/__pycache__/ValidationTheEnterData.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..69ee064510693f8493b5b8df7bdfdf0689dc4799 GIT binary patch literal 961 zcmZ8gy>HV%6o2QBBux_n4N{W@MMzXwNST-rVxg4H>JW8^BAqPTZ48MW?k*rl9Xe!V zVGA3G3B;emh8QA?p%VW<)gU1;@t$2b4mZ4e_rC7;d++XByeGYxYGko({ z^GvjqVrG?-_G@Ppc#aC9kgK83{ZRRWqrtIVM76PWJgo@Y0%EY3{RKs0NPl!JDYWzV zX#dgRP(&xf83*CXK&oi$xI^wbq3es>!w+K>2{haOn*m>6KRCKZ(i{5E2**Cc=uYCK z!g&w|iu2jsb^L#DyLk-tL7FJeU|FfHPyv^a=ZpL)lbfh4;FO(eFYf~g7BlLp-8&GJ zZRw(fTT*r-gc7Qx`ZO9(91+MUl$77;bVQjVZWS;|C6M{-LBX`y)o#I)1ye&MVL`mx zJMUh6-|j4%yXVc8*rMu2FP``t1SlaTa0itIsOvEimHdIooX$ZHhg1z@5K2XJ$a$IR zq{R)au}P;7wJdq+93Z(}vcTk+c&qn+Gy^ptlH1?Lw)_HR`C1YtxN%(3i zLK~kRPBnDKKIci5^Ks-&N2J#{e>HVRnMYKxn5d&j47xy2@pL?Cy|n*=dXWlhgrpxc zhn2?6`lVr*?TeaWwmv`n4Y*}V6mMHB%cD`RYbBM(8IUJ}>ZAo5s9flbu|Ha!wJrfg Gn(z + Processing_Image + a00.jpg + D:\Programing\stomach_cancer\Processing_Image\a00.jpg + + Unknown + + + 1074 + 1074 + 3 + + 0 + + Have_Question + Unspecified + 0 + 0 + + 263 + 740 + 333 + 814 + + + diff --git a/all_models_tools/__pycache__/__init__.cpython-311.pyc b/all_models_tools/__pycache__/__init__.cpython-311.pyc index e397ef7b9b31e2e2f3e1aef1242ed69f2db637ba..8221143c93a8a4deedb8b7b6f3d17b0e09688546 100644 GIT binary patch delta 94 zcmZ3_xQCHvIWI340}w1&#F;UX$Jp(czkWu3ZmNEHMrKKBc4kp#9x}7IBtJJXIU_zf mF)ul_NI#&mB)=#*Lq9PmCq6enB{iowz9c_Cr&xbtg*gE5wjxvj delta 81 zcmdnPxSo+`IWI340}v$W1gB5rF}D0_59GL5#T1w1=O!j+#3v`_C8rj}1Qg|`7bWH@ i=qkKe(*9!c-k8LkocP@Ql+>K!_>%nmoZ^^?t>yp*!W{_! diff --git a/all_models_tools/__pycache__/__init__.cpython-312.pyc b/all_models_tools/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2748b92cc54b93ed510ec287eefb028a6914f68c GIT binary patch literal 174 zcmX@j%ge<81oIbhW`O9&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxdlIYq;;;cqmFA?{6|n+MX9VJ65aS~=BO_xGGmr%UW=bwk literal 0 HcmV?d00001 diff --git a/all_models_tools/__pycache__/all_model_tools.cpython-311.pyc b/all_models_tools/__pycache__/all_model_tools.cpython-311.pyc index f1d58353dc0e272eece3809a3c8a85bba0dae787..6b6689ef794e1d872e9501adebc82e83ffa6574d 100644 GIT binary patch delta 432 zcmbO)c~gRKIWI340}$}^-p>f<*vPkn(Kt*$BR@A)zdR$eBsDv;C^HY4SzMBzo0yyt zpPZPNoLZzGP+5{+l$uldB3+rPfYLRLATos+%w|}|#K5o`h#{bsrGy{G2C896 zVO_(9rh;{{1*fG7dkRMi=NhhMEI{2r4Asq6!&1Xq!s*pd>RlvnsXd7K>YEPU_^HT*@r$ zKr<&lyHeqf?{7lM1$uC ozRBCT-5Jd%|KpZrw45x%W5&obIhe;lMvzhG0|O>eBnUJZ00on3TmS$7 delta 501 zcmca9F<+8zIWI340}xy}d_P@>Ya`zZM!i7&^8BLg;)2BFRQ=$R{M^LkjCkk7yyVm( z{eYtU^rFPv_<+ii{34*RUuyZ}myB+V!kZ14Dw!CiH?Lx`Wn$Et{DSQ=qtN6%?8S^} zlMOf&xl$Nw7^;A_)Ur$t3vV12F{D zvX=0}*g!R`DQs)l(NwTaHs-W+<4EC5;Y#6J!@Z0Zs2_--`q^t(YuIYo)0l%9G zH#u7jIBs!)mBi;I=BD0a&CE+lt+>URUr>^nn^~1wbc@9;Gbi;HCqzw3X3^wEE@cOh zeg!Bf0{P<>XL4drPJB{ga(0mgkZ%CQ#e0E71H)Zz@lLxQy9SpB0tOqbE(+K-c;1+N zldDNWN%@AN(g$t^LFu&}-|f z$e|45EuxbJP9xx7)VN#R0 z)^vKqv~*Y0bi-ENu8djC+d6fFH+0KZ4AZjQkd7x;EI4{na0N>@mS`7vq7Z&UgV0#G zs|@m=t23!Zh}li5uEJL?!kSezv#exP*o-!2l(~{^Qc$P$cNSH{P*zRY-BN7RG_01w z8&4EUZa`78`K+xd<>N=9IMLAi@epUB*(9|A`L^(GxYj=cFR9iy2(M7Be}Ii%8irS- zHhAK;a4&iY_T)$+&<#t(`w(zQ1j(UEn`{oXC5YsjDQKC3jnCnC>N6ZEv9xyb2fH+r z)>>bN?#c|rciAE9TnCwvCfd;VJ9lbw&XS&ioS{qK>o_RN2lVbal zT$SYQfyd{bCcl=ZYT>?z!UvJ}B9D82JNRU&-rM*pdbW1*l?TGF zq6a*QjUV{Q$SWPT--GRkUcNnZZP$u;?{|jJr)JB?Nf}EFQS3pBk*ZUp;-8!6xZ^7XKxc(M!5qL>4T^_oo8d(k4 z&&}=AS;l4Clz}=$#$3RHfFn0# z*{ZE8S~g>QWY`O5VL+pO&^w9@+5@Wc@DadHw83#0SEZrZB+mok`=L9b2j}*CPE~tO zJ?lwqm-YhRL&!|soq8_CE4`TP$j6aStjgq1cF%n=P?>-Gi%8{KuCiiRa>dHAwXdaj zAi>fAOJ6$4zqkml&wB*{w}7JL)m2?l+>nA4Tr{vRDay}^s^QJhC@i2aVS}fCLYOB8 zbcz{e4R)+!(A*-2KEEjcD;5@q4@Y=$o%77m;0SoIycl?98PB%B(}2W=0BPocm4L61 zfi^@(=*Y5SE5%^Z0c09)H`&K-vSTLz<*?A(q;a0cF38H7fUVy|nU|B}fc=6^M__}iNnh)BzuEiITYoM0 z{^Q3lutGiH@UDMJ%|ID2GuICny<*U$L@}do{9;kNsn46Htz1%9^qDMmBiK=(mUIR6 zE^pb?4L}jF1?*v6X==#>)et%o%>qojl0g*<_!`kk-S|9oGWzWN<@}rh%hX~r z=!V#bF)X{$H`fa~1-E%yNdvfDF`L))bvMYoWy|10z<)V6=q=LVeBSyc&{}Sg{p;Yb zjvJ(GFZebK$p?RLn0PcFWMqCr&8*NA%$|bB`Un~*-0uEgOmEKo<=CrFPgGugV>iB= z+C5u|UEaJ<69W6fU{x4=_`^LRQH%HO$4^(|r?-FlyUd@)J{|wV_hiPK z=cgZ>#&4-TSez zYHVyjma4{5wSm#vXrgxNbZzwHL6F3MbV$Vb@y!bd5h5LbP})vby3bUEGps&=)n1-8 zRZS^)Kf4ncipBu=k0q9#fsdn@881ip(exxX2w!44*m {val_loss:.6f}). Saving model to {save_path}") -def call_back(model_name, index, optimizer): +def call_back(Save_Root, index, optimizer): File = Process_File() - model_dir = '../Result/save_the_best_model/' + model_name - File.JudgeRoot_MakeDir(model_dir) - modelfiles = File.Make_Save_Root('best_model( ' + str(datetime.date.today()) + " )-" + index + ".pt", model_dir) + File.JudgeRoot_MakeDir(Save_Root) + modelfiles = File.Make_Save_Root('best_model( ' + str(datetime.date.today()) + " )-" + index + ".pt", Save_Root) # model_mckp = ModelCheckpoint(modelfiles, monitor='val_loss', save_best_only=True, save_weights_only = True, mode='auto') @@ -60,7 +46,6 @@ def call_back(model_name, index, optimizer): optimizer, factor = 0.94, # 學習率降低的量。 new_lr = lr * factor patience = 2, # 沒有改進的時期數,之後學習率將降低 - verbose = 0, min_lr = 0 # 學習率下限 ) diff --git a/all_models_tools/pre_train_model_construction.py b/all_models_tools/pre_train_model_construction.py deleted file mode 100644 index 8b72d80..0000000 --- a/all_models_tools/pre_train_model_construction.py +++ /dev/null @@ -1,116 +0,0 @@ -from all_models_tools.all_model_tools import attention_block -from keras.activations import softmax, sigmoid -from keras.applications import VGG16,VGG19, ResNet50, ResNet50V2, ResNet101, ResNet101V2, ResNet152, ResNet152V2, InceptionV3, InceptionResNetV2, MobileNet, MobileNetV2, DenseNet121, NASNetLarge, Xception -from keras.layers import GlobalAveragePooling2D, Dense, Flatten -from keras import regularizers -from keras.layers import Add -from application.Xception_indepentment import Xception_indepentment - -def Original_VGG19_Model(): - vgg19 = VGG19(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(vgg19.output) - dense = Dense(units = 4096, activation = "relu")(GAP) - dense = Dense(units = 4096, activation = "relu")(dense) - output = Dense(units = 2, activation = "softmax")(dense) - - return vgg19.input, output - -def Original_ResNet50_model(): - xception = ResNet50(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(xception.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return xception.input, dense - -def Original_NASNetLarge_model(): - nasnetlarge = NASNetLarge(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(nasnetlarge.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return nasnetlarge.input, dense - -def Original_DenseNet121_model(): - Densenet201 = DenseNet121(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(Densenet201.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return Densenet201.input, dense - -def Original_Xception_model(): - xception = Xception(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(xception.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return xception.input, dense - -def Original_VGG16_Model(): - vgg16 = VGG16(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - flatten = Flatten()(vgg16.output) - dense = Dense(units = 4096, activation = "relu")(flatten) - dense = Dense(units = 4096, activation = "relu")(dense) - output = Dense(units = 2, activation = "softmax")(dense) - - return vgg16.input, output - -def Original_ResNet50v2_model(): - resnet50v2 = ResNet50V2(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(resnet50v2.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return resnet50v2.input, dense - -def Original_ResNet101_model(): - resnet101 = ResNet101(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(resnet101.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return resnet101.input, dense - -def Original_ResNet101V2_model(): - resnet101v2 = ResNet101V2(include_top = False, weights = "imagenet", input_shape = (512, 512, 3)) - GAP = GlobalAveragePooling2D()(resnet101v2.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return resnet101v2.input, dense - -def Original_ResNet152_model(): - resnet152 = ResNet152(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(resnet152.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return resnet152.input, dense - -def Original_ResNet152V2_model(): - resnet152v2 = ResNet152V2(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(resnet152v2.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return resnet152v2.input, dense - -def Original_InceptionV3_model(): - inceptionv3 = InceptionV3(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(inceptionv3.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return inceptionv3.input, dense - -def Original_InceptionResNetV2_model(): - inceptionResnetv2 = InceptionResNetV2(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(inceptionResnetv2.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return inceptionResnetv2.input, dense - -def Original_MobileNet_model(): - mobilenet = MobileNet(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(mobilenet.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return mobilenet.input, dense - -def Original_MobileNetV2_model(): - mobilenetv2 = MobileNetV2(include_top = False, weights = "imagenet", input_shape = (200, 200, 3)) - GAP = GlobalAveragePooling2D()(mobilenetv2.output) - dense = Dense(units = 2, activation = "softmax")(GAP) - - return mobilenetv2.input, dense \ No newline at end of file diff --git a/annotation_files.txt b/annotation_files.txt new file mode 100644 index 0000000000000000000000000000000000000000..f929d5ea542e4ed497de181bc5c2f2d6d2a551d7 GIT binary patch literal 15738 zcmb8$&C1+H5QX7h8*(ebBh6?u%kW)@F(d@Cu)WCjC+VYuRu1SHj8}fCuAfuYC5`;= zKVQeU`RDuidwiXL{}{iIFXOlIdECaYa>|TpKJy*1{Ohw70T88yxIE&YMcNuo?hBN(bn7?gCa@}jo>~V|N zX2CLh-0HF8xi(vt+2eMu&4Szrl9zB&w{W8SbeqHx&iu2vk?u8nc2}m$)t=?W`h1=9 z!0KUrzRoT(do~YNoCo3bT+81^ckepqf$7iYM(kM}w%4z7zQ|l#aUO&d|Drz0OE}Se zIH_AUPCHjN@sGp1FW})xUgsv{GM}ffqdv*&xI?aNGo<+$(oetMKTbcd6&do*5rwpf zLRv&2EuxSf(RR6IB=!eK6w)G+iJP;Z)1s*}q~(2Qn<3q%MIM`0OWBH&qZivVWxVG7 zb+vu=+$VB7aG90Y)AHk(sh_cewP`gxS*ha5N*%+Bg3FoO!-_7$X*`)6>gV<*tG>pr z=2Wzo__f$i_*Rcyy@gL!^ANjQoc$*6WfJaDy!wT`_{PPHPx=e7RwR`Db~Dt#u8 zTJ*X2WHno{t2zv;`Uy*o91Iv?)ds?N{&sr-?L-c9Z*v0UQ)7DQnJ*2RC?1l*X*JiyLNFmLGx4ZRNpSU zf7$7o4EBU~TD6MmY^qhaX)4L-(n~#EZkm$PbtSFqbf4`uYZcWQTAP+nos9QmhFUda zQ%?8&G+&EYCqL%&eutEKSDO-hNsB$xLF)cEo;~wU|9Ve7*>~((2I{Tlpse&>{dEug zd_P_K`N7Y&UP+5xcelr}yIDlBY3kRxlkc#sPfCiGN=if}CG+_%RQ(KT ze(F||ugh$2Eh#n17pxkQ?gZP>N0xc*j*WjKC~29`{cV2gFA3YxM>3g9nxE+-v#A}I zFAzU0O&`TbeGIJA7`e{a1*Nt literal 0 HcmV?d00001 diff --git a/annotation_question_files.txt b/annotation_question_files.txt new file mode 100644 index 0000000000000000000000000000000000000000..c26511b925f7d660f095b76b6c43127c3ff97b08 GIT binary patch literal 7558 zcmb8zONvxM5QX6!3vNZatL}4HE0GI|;6NR?el<@8PIM4oQ#3Ti&&ha4X8rzkjc@bw zef%8P{QEpUjgRxcm-+cHzK$Q`%XmND&2Rpv9^>`NIeA0P*P-N%?YvEE&7(VO-rt~^ zSn2t9CKo0*CU+zk_Gslet(^IdHFvgie}kr0=ss4A=K*$J(?YGJ>Q1S-kmgTFt4_1C z{OJ|LNw0^ygD>Hh`RSq)ZpFOpc&_I8U_JBWBtJ4I`$>6C+m^}oGp)!IB7K{YPWJko z$b`P8(hGSKuCM;+y^em0hRbY{7#3+~N7G^xvY$DB?NpCcvELqb@&S2XMkcbX_IOpl68B#SRLYXa3Yg_?5@n1SJBn-|yD!8K3qr_kd`Np_-S}GGOcoMALY`MDve%$JB^-Ajc_tGj_HNvLpF8nTc#&{mmjnRqi0hn zoStiWv#ol}s<-&b?^^LUd!dhCW`Ud=PT~?y&y{-4i^A-am-plOLNWW~K3;n2hs?jc zjLcu_qr8kPZ}R(V{9R}Zp4gY+WWIzmKk`18y0^Z}xt2G1T_%2cnTdVjlr)d!Emam; ZMQ [H', W'] grad_cam = F.relu(grad_cam) # Apply ReLU grad_cam = grad_cam / (grad_cam.max() + 1e-8) # Normalize to [0, 1] - return grad_cam.cpu().numpy() + + # Apply Gaussian smoothing to reduce artifacts + grad_cam_np = grad_cam.cpu().numpy() + grad_cam_np = cv2.GaussianBlur(grad_cam_np, (5, 5), 0) + # Re-normalize after blur + grad_cam_np = grad_cam_np / (grad_cam_np.max() + 1e-8) + + return grad_cam_np def overlay_heatmap(self, heatmap, image, alpha=0.5): - # Resize heatmap to match input image spatial dimensions + # Resize heatmap to match input image spatial dimensions using INTER_CUBIC for smoother results heatmap = np.uint8(255 * heatmap) # Scale to [0, 255] - heatmap = Image.fromarray(heatmap).resize((image.shape[1], image.shape[2]), Image.BILINEAR) - heatmap = np.array(heatmap) - heatmap = plt.cm.jet(heatmap)[:, :, :3] # Apply colormap (jet) + heatmap = cv2.resize(heatmap, (image.shape[2], image.shape[1]), interpolation=cv2.INTER_CUBIC) + # Use viridis colormap for better interpretability + heatmap = plt.cm.viridis(heatmap)[:, :, :3] # Apply viridis colormap # Convert image tensor to numpy and denormalize (assuming ImageNet stats) image_np = image.detach().cpu().permute(1, 2, 0).numpy() # [H, W, C] + # Ensure image is in [0, 1] range (if not already) + if image_np.max() > 1.0: + image_np = (image_np - image_np.min()) / (image_np.max() - image_np.min()) - # Overlay - overlay = alpha * heatmap + (1 - alpha) * image_np / 255.0 + # Overlay heatmap on the image + overlay = alpha * heatmap + (1 - alpha) * image_np overlay = np.clip(overlay, 0, 1) * 255 return overlay.astype(np.uint8) # Return uint8 for cv2 \ No newline at end of file diff --git a/draw_tools/Saliency_Map.py b/draw_tools/Saliency_Map.py new file mode 100644 index 0000000..c8a1e60 --- /dev/null +++ b/draw_tools/Saliency_Map.py @@ -0,0 +1,195 @@ +import torch +import torch.nn as nn +import numpy as np +import cv2 +import matplotlib.pyplot as plt +from Load_process.file_processing import Process_File + +class SaliencyMap: + def __init__(self, model): + self.model = model + self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + self.model.to(self.device) + self.model.eval() # 設置為評估模式 + + def Processing_Main(self, Test_Dataloader, File_Path): + """處理測試數據集並生成顯著性圖""" + File = Process_File() + + for batch_idx, (images, labels, File_Name, File_Classes) in enumerate(Test_Dataloader): + # 將數據移至設備 + images = images.to(self.device, dtype=torch.float32) + labels = labels.to(self.device, dtype=torch.float32) + + # 獲取真實類別索引 + label_classes = torch.argmax(labels, dim=1).cpu().numpy() + + # 為批次中的每個圖像生成顯著性圖 + for i in range(images.size(0)): + # 獲取單個圖像和類別 + image = images[i:i+1] # 保持批次維度 + target_class = label_classes[i] + + # 生成顯著性圖 + saliency_map = self.generate_saliency(image, target_class) + + # 將顯著性圖疊加到原始圖像上 + overlaid_image = self.overlay_saliency(saliency_map, image[0]) + + # 創建保存路徑 + path = f"{File_Path}/{File_Classes[i]}" + File.JudgeRoot_MakeDir(path) + + # 保存結果 + File.Save_CV2_File(f"saliency_{batch_idx}_{File_Name[i]}", path, overlaid_image) + + def generate_saliency(self, image, target_class): + """生成單個圖像的顯著性圖""" + # 確保需要梯度 + image.requires_grad_(True) + + # 前向傳播 + output = self.model(image) + + # 清除之前的梯度 + self.model.zero_grad() + + # 創建one-hot編碼的目標 + one_hot = torch.zeros_like(output) + one_hot[0, target_class] = 1 + + # 反向傳播 + output.backward(gradient=one_hot) + + # 獲取梯度 + gradients = image.grad.data + + # 計算顯著性圖 (取絕對值並在通道維度上取最大值) + saliency, _ = torch.max(gradients.abs(), dim=1) + + # 轉換為numpy並歸一化 + saliency_np = saliency.cpu().numpy()[0] + saliency_np = self._normalize(saliency_np) + + # 應用平滑處理以減少噪聲 + saliency_np = cv2.GaussianBlur(saliency_np, (5, 5), 0) + saliency_np = self._normalize(saliency_np) # 再次歸一化 + + return saliency_np + + def _normalize(self, x): + """將數組歸一化到[0,1]範圍""" + # 添加小的epsilon以避免除以零 + return (x - x.min()) / (x.max() - x.min() + 1e-8) + + def overlay_saliency(self, saliency, image, alpha=0.5): + """將顯著性圖疊加到原始圖像上""" + # 將顯著性圖縮放到[0,255]範圍 + saliency_uint8 = np.uint8(255 * saliency) + + # 應用顏色映射 + heatmap = cv2.applyColorMap(saliency_uint8, cv2.COLORMAP_JET) + + # 將圖像張量轉換為numpy數組 + image_np = image.detach().cpu().permute(1, 2, 0).numpy() + + # 確保圖像在[0,1]範圍內 + if image_np.max() > 1.0: + image_np = (image_np - image_np.min()) / (image_np.max() - image_np.min()) + + # 將圖像轉換為uint8 + image_uint8 = np.uint8(255 * image_np) + + # 如果圖像是單通道的,轉換為3通道 + if len(image_uint8.shape) == 2 or image_uint8.shape[2] == 1: + image_uint8 = cv2.cvtColor(image_uint8, cv2.COLOR_GRAY2BGR) + + # 疊加顯著性圖和原始圖像 + overlaid = cv2.addWeighted(heatmap, alpha, image_uint8, 1-alpha, 0) + + return overlaid + + def generate_smooth_saliency(self, image, target_class, n_samples=20, noise_level=0.1): + """使用SmoothGrad技術生成更平滑的顯著性圖""" + # 獲取輸入圖像的標準差 + stdev = noise_level * (torch.max(image) - torch.min(image)).item() + + # 累積梯度 + accumulated_gradients = None + + # 生成多個帶噪聲的樣本並計算梯度 + for _ in range(n_samples): + # 添加高斯噪聲 + noisy_image = image + torch.randn_like(image) * stdev + noisy_image.requires_grad_(True) + + # 前向傳播 + output = self.model(noisy_image) + + # 反向傳播 + self.model.zero_grad() + one_hot = torch.zeros_like(output) + one_hot[0, target_class] = 1 + output.backward(gradient=one_hot) + + # 獲取梯度 + gradients = noisy_image.grad.data + + # 累積梯度 + if accumulated_gradients is None: + accumulated_gradients = gradients + else: + accumulated_gradients += gradients + + # 計算平均梯度 + avg_gradients = accumulated_gradients / n_samples + + # 計算顯著性圖 + saliency, _ = torch.max(avg_gradients.abs(), dim=1) + + # 轉換為numpy並歸一化 + saliency_np = saliency.cpu().numpy()[0] + saliency_np = self._normalize(saliency_np) + + return saliency_np + + def generate_guided_saliency(self, image, target_class): + """使用Guided Backpropagation生成顯著性圖""" + # 保存原始ReLU反向傳播函數 + relu_backward_functions = {} + for module in self.model.modules(): + if isinstance(module, nn.ReLU): + relu_backward_functions[module] = module.backward + module.backward = self._guided_relu_backward + + # 生成顯著性圖 + image.requires_grad_(True) + output = self.model(image) + + self.model.zero_grad() + one_hot = torch.zeros_like(output) + one_hot[0, target_class] = 1 + output.backward(gradient=one_hot) + + # 獲取梯度 + gradients = image.grad.data + + # 恢復原始ReLU反向傳播函數 + for module in relu_backward_functions: + module.backward = relu_backward_functions[module] + + # 計算顯著性圖 (只保留正梯度) + saliency = torch.clamp(gradients, min=0) + saliency, _ = torch.max(saliency, dim=1) + + # 轉換為numpy並歸一化 + saliency_np = saliency.cpu().numpy()[0] + saliency_np = self._normalize(saliency_np) + + return saliency_np + + def _guided_relu_backward(self, grad_output): + """Guided ReLU的反向傳播函數""" + # 只允許正梯度流過 + positive_grad_output = torch.clamp(grad_output, min=0) + return positive_grad_output \ No newline at end of file diff --git a/draw_tools/__pycache__/Grad_cam.cpython-311.pyc b/draw_tools/__pycache__/Grad_cam.cpython-311.pyc index 88a53ae4162f616468262a5be8c38014b24b98cf..ef5b8ce4626dc361f405db38924d2ae4a5b50684 100644 GIT binary patch delta 1950 zcmZ`(YfKbZ6rS06>@NFcm!0Kdh2Fxll`^xNq6=$(O z+5}tDqL&6*HCc^OlA3f;o08O|*qG>#rr9CeLMAb#57YRoOWHs6NA11CBWUcId%r#R zoO92f`}l5p&p)-s>jpyx2Bkq087j2R8KcC$j<$ODAwE3Fvq67o&>a=RLDoCu@v5{=+D+PPOFk}yy!s-Fua zMWbkVHYtuxgeLKcy*}(P=F9*M>b!zK*8Xm#$%)Gp8;A_CPw-tb{SGU@9g=Ym5Y%UJ z6Zlu%YS*^=1DvOe4RW$xQCkCSG|GV{&2})P$)`*(RRQ=&(^BKbG3-6;p(*d|*u>a4 z`LONagRs=rpK9w*V_DjMd{se7zkj?_vhSav7uzbE=cBzl(`~lu2?~~!bNjovZ#Hw69R1W+6BiQ{hIE0Kt2db=3^=Iv82*g zGf_3^98|VaJgCh03f}{M&-mEV1Q*O3AUH{$LHd61zODnWz4g8BS5-kNvS<)xSJTHkk+B^7V0_zAi_|&^f>u+(U8XW)p)kYQShQs05=qaSf)-5b>-xjGOG=$#}u5&AA#W11B0b9N2!zW zj_j889qe#4>SseOfnnZBgJw%%i>yP%Lox+Dp-7a5)3z4+8XS*icfg3&=7W_UZ#Wnk z7C6rk#|l9<(ha@QyI|Tfat0okJ%2iIK5#BH6Q~93bH+%>reGx&5B;qm%XPQjv6Uq|!W)WKB zMmV*Q9)(ZbddSa|anrsX*+=2Y$4HS7@lm(}A0ZNJ(W4Z2)#e~*9|6L)-ZPr6$4}uR z_#On?AV8)Y{2_tkBjErm_`@N-7rD^;H3&PDbdxia?}Ca<4a3Mf{ut6}o{RcNIhl$M zu@O$zb$0a}c*E1$+tS%86On)*tGq#3J>uv6K7W)~$N{f^6DF%893OAPI48ZvA;bfj@(0;LjxT^Z5SU_oC-{unMi0PYbO-o`$?djHmCqcB z4_`eE2|tz?zI}S3>h@T&wEf4vqp3bFX&I0#11ZbExcZUBHdQ)ZdA>4kmn_bd#X0Lx zzV2E0B~*#bgle`dWqBF6>sIL=TE_6Gz@a}!_JMr$=y)mh#SF-nwzXGqeHG5{qxn1$@S=;5Ki886UUb57K zPwjg&E?B!0=ktMN-<8`42fP&lA~Iiw01=4a339Vr%;=?Is7uYJC%BLwr__Q8_>GQcfxE2W>euxg*G-Fb6#{Pc)6eux~iPx%l_MRL-TQ T6F3f&zZh2)```cLRg(S(>edn0 delta 1663 zcmZ`(U2M}<6t*4PvGeP?`DxO?+NNomwrcuATSQqI=_=?ps+NH!+CgR#lcsA(a10%p z1H4Rvscan=jUt4UX^2(Z3sZThrfK4#54>!uD^Eq9s=*{QP1-}MZ4dCU?OsQPf!OiA zpYJ{A9&y9tuwuS;efdzD+k)v?$Cob1NjVA(D2* z3Tgh6`W&H6A+BLbO0itSuA7Q>@H6eh?cfm|iP8!QBXAjr%ymk!E4G^^xEa_hhGVno zIefM&iM@$MSTJF(-C8h56VpOIAJ^%lf(%bYr{d{MDqbMlbH`KQQ}YGf0qU4RpfCXo zTS-kP-vd{eI?@4I!M9AT`v{I<=dg8W?S(V5XU>!Bt=n$J)z%@cb*PNF*a>{YK-CsL zKdgGg^K^;64@TG;u#cT_P2gpWu}|Q0_`N`6pfTJAmK%5#JBJk{v>Xlsss>6MSRcgLf|y zwqJ<4Ao8#X8X@RxL6ov_D72*1gq&eOI^VH&p0Z;O>3xDe<@{ z39{I`c+J_1JG^gaVKGhN?UT$92dgFXG$_`m49l``|Et z5ge&Lwd3a^*Zpl z9Yl#lsthQ^6bc%aB%TTx`N5a2V3^*FKBre)hU(a~DKoISYq%mVbDJ&_yNFKKI2qRE8ev33h7! diff --git a/draw_tools/__pycache__/Grad_cam.cpython-312.pyc b/draw_tools/__pycache__/Grad_cam.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aacbd930ce253ec828b3331dadf8ef2c2db54b12 GIT binary patch literal 6497 zcmcIpU2GFq7M>Z;*yEr4I&l(WN|KTvhY|=BN+ASjoKPxAq2)(-Lq~&Wl8ocO&Wr;| z#)yZm()Q2QuR~YR|O$*W*b)}|ntoC7%_9e3pwKb)?Xt&aeHx??bv@g5o&UoyQ zy0ltpZ=^ft-h1x7bI0d=-#Isbs;F>aP%1rJ$J^>L?C+>y7P25bn+9P4<1h{nV*%rd zM~DD{8?q%r1VN6F0jkhr4cK&TIzYpd2-_o$fTJ+xjJN_71-UX%3FDSjyZzt_@l==iq2)*{3Lv=Q*=}lu^zU!BjHgVS?U2iqO3zSL zNj9b11wn*^Msbd~U3d%FlQMM_EM$u7o}rp`je-c8W!}nM6Ni(8isvfL4!KLRDS>94 zDVLr7?)*OXwTMpG_5ODj!bKFhF11``~sS%UF|uR^0DF^&&wE}0d_c$o>aQ@p4- z*`O>;va%41N}7EPeqw=-%92LOF)=uUL)j~Rxk2n zf+X`IGa3^wu_DKe$6^y&wZu;H%=(o*Ma7G3aH6DHscROu^;tAh;=`jN`re`wDhb(0 zOH0eYkNWqIfR%%4M2L=!NOCN~2FIBo8->?1N0^gS`g=3O{G}02WG^vtEEbkVkm-VI zq$fV5(F`L*1({){t5G*tbdTACtV{Y3s;gMOep8CP=E!@yQsf%llyBaGo{jmY&Cp%> z(9^sSo)6zS^V`6uf!ub#y4}CFedyNS`-54}JD}jq)2{1|S;zH?*@`)CVPbw_jc$8l z#q1S1x=E#*a`XgQMcWQ9W9z&M*i z8)G-HUs;lsiY3&%VLCLGN^?&@CrfDa_cb_LAz?MUVk@pjDwRrwxf_mMJ4b@WTx%vV zz!HZ}H=H~b=N}_``xMtKoDdNa?)}49{m~)BNNhMh&T9A$&3ciQ!9O*e@l}b4CNw)A zO+tx!SsEp>(J>wnLYU^Y zs@Nni0){c;JS#`oxK{I4f*a%CiN$2*1Utd|1yQSb7va#r*!h3kox>cunNoM@4 z%)+i5V4xkbCUcUN$2Ag(n%#JJfxE0(1w^ruW(CmW!vK-G?l2qSHJ2_9gjq=fg$iAP z2^N}k;k6_U7c`ssj+Mqs3ml^_tC4ZoR6-vDAZ~pTkwIxy1zHEdgEI-y=>`+AHVhyt zkQ(8Kxr#lkYX0y_ihSrlaX*&xzo)tmr;e!&hZn7B>#{x5_o%*k;r#shMfv8;(#-GL zzu10v``r0#{o&M5{s%|CvtpauZXRDczU;}ITJye^^Bz#W2eRISIq!h#9mskIQzro2 z8odk2`DFU+@`Y@}fz+EY%hSBL_vV461L^l~^nX>~J%{HvwWWKPw$0h{t?jwiJ!Lj>s-Xf7YHq!GaOvQULn-nB-S~ndpgHIW9FC6p z(+}b!hIJ425#k}3C{{pKIEr`}WX&;#h|@TXQ;v)T**`)IuU?g;GETJO9l}5~83!-UU!Ar3w ztWf5+Eiq%#q7YYi%QkbRP%+*#djL@(SYF30&eDh}nY)M3SKLs{u_Q#qWl!^h7#7FI zfUo6ZT&m#ZxT!4LoI@P{zwD@3fPn~wLgq9|=tfm!yVB7({0_B_XRvZCSUkB^AHUvsEZeZTF>IMyTm-Sm>VbUL48RcBgEQoQpUs?VU1@_$u)GT4PDDM z*@kUj)x45Al6O^Ke{1%woU283wXC_?@-Fw>k-230l-kg_TGy$%x^k{w)z!Nquey5I zT>iXgQ_izZ^=!*}wx^EfU3J&ro_%}q=mXc*Cw8oM`*$v^y7v0z*~^P`wyJfNZZ!~Z zz3UdCVGeo$@ya?=5|Yqz30abmi(ziL&{n}YNEOEj&T@w|!ypKyOLNM?f7D1w1+FCN@B&opPi-J{-Mpq8gupZKVQRrF@8j3DRl|t4KLgWoap&RNs$=`F?flzEQ-l3J;xYQd zB48EfbLkYMQ>qaek`bPbY8ELG(eNRS6!~yMvzQU0;j@n115cs$ob>}<3d@6%453TsuYLBFB&|lZI@cR7gi|5ia>gHW5_?mnF zO0ViZ2>#`+Ti83lcd;w$emOa-SVpH-jkxi6C1Xmtn=e&&eN@W zy0e~FQqG5-rkn@uo1V!GtsKdE`cuwFp4RlwK4ES#+4j9Fb!z)TRqw6Zv`TOKeiVVu zuG8&rbh<62ljVE}5i7EH6SR}~I{zq>F2aQnQI1YIom75c%wo`vOv0P#rQG$)Iv>U5 zVk#Iy`NW1&&R^ ziHBv42u3v9q#z2MAQ>UDo|)R>ycmHnKnEak1TAHOTPe713kz{bVkML(n<#{c9TEbR zMv5&+rga%$2f_d&hy5P@Yy-VgvbQ1A9fd)O1_Hc_eOp_%&^6z+xI5jjbTC`%OW7XQ z*6Yx7E}i&f=GF`(P**aEFJ|t}-0Qu2Wwm2y?di?vxGDf73$WeBa0YId{A2ZqK?qbM76gdq)P(^k&$sdtc7o zue$rQ?!zhik<)#>Z?^Bl{>6bmJGbN;ThjYJ>AThU>wdMdH#7c4_-^>~=)KE-RDQ4g z;flKVjM{KE^(O4#Zd~k~-;qAGTz~6)rc2$rU#;DbPExnfIp4Y1neI)q+1jq<-D+)5 z%9gM4T)#4V<(C(4jxUX8t2$TdP94+4e)udtT-<^l4s^>Gg(RI}GzY^NSsBPKhIv21 zhK&&sWzAwAs!&QMB8L`Hz$GI17twF6H@%3B`*aU{47LHH1HH^ic2N zPxs-}wx?E{>V0Odr`n$OxT)svx~r)!V+}OjS8LE3t>04iM57QmMm4wD>KRQ$;W{=J zg=p1LlEnbp8EvSWuwlEFlgEyW2)DJG2rI|KF*z(;g!@e-X;$MY3TT|>;L1f7;Kssx z946q`QE0#ogMLY49C8wEg+SQ2hM@b557;kWg+3IINjso=V!?6zYs~cx lR{vLQ%PO|zYpnKb%mK}BkX-c*w&!2u1dew-#Zav;_+OcCKBWKv literal 0 HcmV?d00001 diff --git a/draw_tools/__pycache__/Saliency_Map.cpython-311.pyc b/draw_tools/__pycache__/Saliency_Map.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d53aee35ded9e597b67e187c9694b7da02ea350c GIT binary patch literal 9193 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 literal 0 HcmV?d00001 diff --git a/draw_tools/__pycache__/__init__.cpython-311.pyc b/draw_tools/__pycache__/__init__.cpython-311.pyc index 20957044eb5c62c0194d1041c6e303f6e887f1fe..18f9ce6e8b77374877369edadaf369e30d4648f8 100644 GIT binary patch delta 88 zcmZ35fe`1k204dWS5-2_^sZ8?;v z9_hq3Kp8@e1B~cQsP+599 zKodHk1gDYnW~LeE&1OT>q1rbt%cnsu8=j6hoS+iTwoJDGjqXs>F^Pe?RbruTlLFVN zWN4ENmZWVqznoW8eGAc$NMm|2j1*fL%z9?)jFjRDliiJFw{JomyE`Khtaq_M&k;s#O*Sg zX9tQ}2-W8%@&1vT?8$j@;g`yJc9S9xqc4?o&Mna@wKU5W=$}9Lt;w6Qvzw^deg)dM zn>@4|cQgDF`!=n5*WHZx=CZw;kpllcceBZMyN(v!W3*@?{5^Iv)@)Os*8k^jwlvEFd zABA8bpj`W8GO*bOLYoB5zM}2WY-Uc&tjL=Lhc*cSU{cx44J>AIfPsu6&d7=#eos^~ zlBj3YoXt+CnkH*DBj?rh{7QH+pOeNKJ}a*+zu4qdGBC3VITAgl~yTovwXx3{?A4qj|TFm`>Xv z(t!|dF3**4I5G06p&iZ=gU-UBnnun-!dJe1`_#Oel~3KC&*<{a49?^lNljO?VtPK6 z7ISGCpPE|MRh*tbC1LS)N>^1ybI8H`vK=L+P0eSZ2VTZ!VH|SLv|cz7Me13k;};`$ zM~WApqtKo4(k%lWG0_nV9RcDQu&$Qq(y`L0i4I!mpn(oTixX9$qfD=N z7RUbqyw0+4Z>$nEy9cc9fk(92ea75(*4lTrI6<^rUi+Xtym8w==S_6pLg#^aE*va< zc(1p-@S9V=JGC)tb`6-qpd}0z$K4Lo<*tok1HERV*DUlJ5Y7bGmP~ZWLWc}=h=`4^ z-8NB&g*pt>;j~N8C1Ik3g%Usz)|EBIL~#qn4HW+-)MkXbpK+19kj~;Aziy&_3-ueQzbYJfD)c=O`u-H$xbju(Va(_scAv)?Q@Csimt8wwErmVn zxYm+QwBJJejr#Kf&I;v=l87%Qp6|s!0bTw#QPL`-dmbOWKfw&AG)Fb7Y=NmT^{4#KJdnd2n zx#smdo+m~;4+%Xmu^}d=+f<>tVbg%x4szL{sYRRzh)c3It9`gAf(u~8T#kVCY*x2< zC6klWs-j{WrL$t*4v0%OJ%IOtniV0DR&%q98aSv#R@8B3X{G!9fhjCYnY5m8oJ2yM zP3ZG-!okv&&Yuk2z>D%OpOUSPFTw{wugzX^eNj-Ho3mTp#+aD9C2FIUW5k0&n>nYbcg$Y^nTMk|GWzjq!x1MsHUy`?3cOAH&C^=4) zFqxbrFX0n}4idM;0;t1O?7-*}J`G%r95l~2;4?%p>L7i6T2sJ!l}J)>3mQ-zP%I+c z9jLHI_=FigVTDf=$DXycSuKgmKC`9YYUwXts`Ala9sT9e@;;M4Z1IPS7YGnsEwPpT z8~Wp+zrAC8AR9`~K&pvU3#mZ76md3qqyHj2e;s?w{CWH@<8BM;uK{_cEMclRzQs{Y z=#z<$CrVcg;k5gh=!}KV80btDv7cP~_?ppvdM9hZM1vL@G|(XUAtv$^bv!{GWq`0= z3-ucH2M>WIe2_&Brvq6MT)F=QvH&({De$lMSUf3^%8WTm5V%;PmAB7o-m%?*_)ljZeirk@eFPMZ&-K6m%bsu^( zq`8n7E_iTQ*&XgeJ6F2kB~jnG&tAd!Zm_#+FkT?A8~rySdCP9Fs~;wIa?65eot=Q^ zlOxf#Q=}a!jRTCWlQ$r0UBokLGJxLzNjw78N^%NfF+G!;ON@EAcFn=H1b`f{ugl_$ zigV%cN=(dYw;=+D5PebB5-V*r)RUze%L(Z*$zg2flBj49zY^$60|I!3_(}q#FHS=B z88rt-=BL6c-T2E!vuFD>aJT(B^%eYR;y_$7Up_08dF3~%gkodPJ%Hw3^@c$a|DQb-)T^(9f7Jy8N!hJl;8bz zZ%O?0`1)~=g|Bam~v0^Sc)QgGq?ZNj}os&`0rnN(MxvKeh&gbe18LobO-8O@Hl zXq~?4I1Wg4mI=EF(=qYfxQA4|P!Ys-m$i-9c!GR&@H#NNWb?UHnk*Hv1=iKPCu$%6 zZnnZRFaTMFcG8dM&-v)xc6|V^`}a;7M;H;)noXdDm7s2@l>fF82)Dqy+R+@qP*&TdLP}lMS0aL N-88>N?W~+d{0nsZnzBkB`ckPYWu-neQXX1q22BMTDN>|rA5dSAqQ0O$^xPTG z;GaN~cK0$qbLQN0@3}uS-**qc_xpVmlz%S%J#n>$qW(c1tl}&xuO~tIHN{b!L!eTQ zsMA4or{Ibr<4#9uen!+g9NVV=#*hD`*wYm8UpY4jvyv z)F*c2yn~|;T22*p|7X9hx9pd(!gI`?Yd}`nD4cswKacI_;k*ea=X+XHKIe*gd2RpN zJ^QuS+t>s24eo*STiOFB_wIY(-*XMV{XM9wjL+4}P1X)kl)QgOpRKj@g5T0g@8#cK zdB5aK-~vQ0GI_dCSK7|f^HuL7c-C9BrT5Yi=23YhE=Z!3dAQ0wjIrz^5+as;or~@= z6bM)`^Lu{*LCcS8D33(2574b~G~(POooy1V_`;#Pr;`aOnd3JJ{%jI(z(nZG6;YCS zNvHXY7@yJUam*&uy6+|{Bso@2is_s$o5}DvB=FNRK%`3$<2m1m$nipmG}V25@pu-q z@gy(h>P&mlvXJZQ?CiS6OIbngGWt!X6R}GvHo^(jv&%lqwizSKi{m`~E6xnu! zwozv$ozPvZAVl_IG6CI{5oDc#Ib<=fyQSSb-BxBtJbK>P>iq{d*pibo21wA;N|K5!iS;_7#IBQJ5|<}B&nX&{eSnuQ>~6j>)zM}$*!uW8{Rf>}wNC5Zr9 zs93hUyXHiESIV$)z6%H`f!S1SY(W-rd?q%^&vkK_or}q$C`g9dnOV?l$wI_tk`j0= z;4bKm^eFusHhYPBS=0Q}a}Uog4SbE<_lKA7Dd@0@4r}NzC@;ZudD*diWVug8`!%#* zLHmhq=;t?LtzDlH-b&;!S=Oa`|qx=9{O$UQS1+r z8vemo*Z+L*%gJYxYWVVtX*E2q+>EKgkF?-NOT%Q8mzRC^3Yja$tEf>!jf!=>hL?bf z+pGo;gbB&>>)*iFzvnr|RfbChD~wWoj#)&q%^4ImYoARjQF4*aqeAJK%IXqME#(-t z$jBvVKWq06=NklnG{A2@zpWc20SVo;>qr zjw|c0GNPaKRXz#_aMYVQkgH;D@U$5VI^Mojh> z6ExctL5%ATK=iqpB!IVjEQ>RMo)Jc8q>r;KFayn|(*V}4>6EN{g=CtKi-L%C6i=}k z-O0}9PVO+$2rJ{{e36e#SWcNHgN;J(hcJ1AwjCX~5$?HQC@!X_vl4J($aKuL-s%{` zJeQ2iA%k;5;&cc|EoAhTJNT21ah&DfP*r3#+zkEd%te#cTx=qt*P9RhZ2BH6^?{*= z<+zx|cP=R{>Fybxm0>=(4O-(65l4tPO2jcD+Ck`EiI-z0_4$ZeWJNVN4EX#P;4LG_0#6dG6MKYj1ThsteU5z-10RU~Ri1m#uW-1CO#xBhZxeel-W;4O79strcf zz6q^wLJdqPlT&J7>K!4t>C5P|s2cw8#c?$}rd*p)gSWNd?WN%@4@J8_z4FPGUo|X8 zKWqDCn{up24fd$$jE2rA=*$LUJ{|dFMA>&rMco?eR#3NX>QGUqhB_70xy4X)%{ppc zL(MAy=f^a3OtCI}3f8R*zR4G1!1qJ=`2QF9hGfveIiFUfmx~CXxs)a#j9Ivfqb`60 zD%cQjd67FuSANL5!hQ9j8_klL8KqzYx@94E&dqre6<|olGHa)T@6ry4qG6|ZnS9>G zGHcVrn}Plfs-cSQKz9B?5 z(}dj*#jlWOX}|#0ND$I5Rwh}KketE<`i%X9G|zk=vGIz8z^(^(96L>_Gk0gKAgGuMMh6v91lOe#!XTppGi#*9O(0>~d{T h-&e}7Ep))qv_;wCbfcqvi?YSZCWm*6suso^{sWw@zIp%v diff --git a/draw_tools/__pycache__/draw.cpython-312.pyc b/draw_tools/__pycache__/draw.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..abbd4478ff399f013793c937080a76c612f5347d GIT binary patch literal 5064 zcmcgwU2GHC6`ry0jDHd*Hc6JBu$uuAx^77Tl~Q&~S%m=0U!nkk(hzVbp0P7#?D5_i zlf-hQM5@HHt+c6Hsd>z5_aQ5I=tCb`?N)6iq*Ap~ZP_Sj7F49}OCBnrrB6KdocXaQ zsafcD)f@TTbI(2Z+;e~CJLl#vkw}<<^1J2G)VUUh`3E-K;&Yg%6TtkEkr;_pnJhc* zW0Ci%{&8Z}+&E{|d^Rv1aQcGTP!jaA;qewr;#XUon0-_vn|ei$HRascpa>+C}o0U~CZ@x1D_~u@bk{)BYcA z`JZd6)p5a7Nqp1wws}+>RthxLj5g5>N};q*3g2mQSGaCPo0^PhZEE{@yH38AUH5&B zyY7?zyIqeoUGM*U*V`IiNbN?KdoIQ+E|=Nja*aCE-QZo${k~j#c)O)2(mB4wWnOjl z8gJr^oO1STk-y3YMMkYA)dUf(6%Zqb@bS(K{O&E+=)k z^RUb;6Ym^}`_}N{uOWtf%$k9elGc@?yoT7ZhSO6dCVy7bby+t#Ij<$BOm2*dO3n;l z5>-VK4Mocp!-afarh+P`41hMjswIozVNH@%0f(C5!DO;P#iSzZ#Wq{+NM?(B2L|?@ zm-T{b?6vGFxpd-GR!qx#b@7IrFs9&#^Cc7%zAilT32~DZo{@okE^YcnRgG_=xB%0i zR}GVgH59092K2%tLaj+G%26?wmQ8+E6(?oYt-kgpr6QzFiALz`(*P3V}Tj6B@)bFccQYcBOD7(c{X(H%?St~X)0!6!zOe? z%ZkaVL{iKpW$N}MMrRF;f_Oxpo{*?GoiH>_)h%`)KWnz))+DAB7)@vCUa*gI=08lRv$VhIrqWg8rj#>0dFTxTB?!lFXuqH?X?=|c^n_XpzSl4Q-w-W39=)%gj4->!AD}8T%df^XSKe<-v zJ995p=^HCwN>pP%nm>(R;M&5lPIt}nebV_9j)Y0p<2^J&@U!xRBk*-L%@6z@#CSn| zFh>l`H>{Fr67d_THOG}mrXK&@F_=NPs4~YJ5m%mR5(OY*An?aYyc8($cY?Q_nIUTm z88LUHQID*dPFL2bGn*T{%QeOAFrw&OpybbBBC(-(F%vYJ#Da!DCDvV^)PgoWJ@qUL zOj&AZQUKDdENpzn;_0z?3W+upWw0oeD^B$LUTaxU;kuh#AslBVmV+FtSc$v3Mui zwC1UjGZJ=Wiib?zUKaf(j^~t|B+t-qA@9fF!2^hcQ>JflhVH>>`hn>9(Yxp`&;itL zwIJQ~au`JDn*L89b@=`l&$Pte@4wZ*%-6!-m>+r=iLOS3N<>)hs7CtcPdo^ha5!Xf^+tb<3_Rf(u4R>Mu8_@3;rnD4-3KdPhmd%oErdM#6%i8N zGOXmgQ-2rD5x~AWPJ(r(NcEf!zFCsNL)uUzuJOG+2S2?zB*`>+-DKJ~7=@-3kb>zt z{#dg&dBeQSNWk6>*S=9l+)O=tcKaBn8Ipbp_HxaUwdCCqe^Z34`%|i8qJzDSp8DE7 z*vr+impAIUct&Wfz~#JoyGIkhpAALwym0_8+eXG9AuP~IE$*X-K$m_GNHIPNnUn#U zm@rhwE*tj*05T9?ki|)j=EC7(o0!w5Ayj_t6tPJBrUA7xs>#U5sE51pwTI#WF~Ts<&SiH?-d zU93beesutJliGEOUyXD=CP53?;xTvzhz92BsxnCt*Q`T;=Z1Z$sCCW)$jw+oalj5Y zcI@l%$S1|*b$IjW0}hkGco=l0W{XEm-$J9?&uXHS$lL#}0<-XPaT;*5t*4jucAyx6 ztb_WPu^hKgICvQDZ9$cfP!am!X~F1mAW!@(%RXXyKV!N+W7;1vJO9q~mzn-Y%y+&Z UTiC8I4s^1;Pxo}OAnUk^lez literal 0 HcmV?d00001 diff --git a/draw_tools/draw.py b/draw_tools/draw.py index 9c0ef61..06853e3 100644 --- a/draw_tools/draw.py +++ b/draw_tools/draw.py @@ -5,33 +5,51 @@ import matplotlib.figure as figure import matplotlib.backends.backend_agg as agg from Load_process.file_processing import Process_File -def plot_history(Epochs, Losses, Accuracys, file_name, model_name): +def plot_history(Losses, Accuracys, Save_Root, File_Name): File = Process_File() plt.figure(figsize=(16,4)) plt.subplot(1,2,1) - plt.plot(range(1, Epochs + 1), Losses[0]) - plt.plot(range(1, Epochs + 1), Losses[1]) + + # 修正維度不匹配問題 + train_losses = Losses[0] + val_losses = Losses[1] + + # 分別繪製訓練損失和驗證損失 + train_epochs = range(1, len(train_losses) + 1) + plt.plot(train_epochs, train_losses, label='Train') + + val_epochs = range(1, len(val_losses) + 1) + plt.plot(val_epochs, val_losses, label='Validation') + plt.ylabel('Losses') plt.xlabel('epoch') - plt.legend(['Train','Validation'], loc='upper left') + plt.legend(loc='upper left') plt.title('Model Loss') - plt.subplot(1,2,2) - plt.plot(range(1, Epochs + 1), Accuracys[0]) - plt.plot(range(1, Epochs + 1), Accuracys[1]) - plt.ylabel('Accuracies') - plt.xlabel('epoch') - plt.legend(['Train','Validation'], loc='upper left') - plt.title('Model Accuracy') + if Accuracys is not None: + plt.subplot(1,2,2) + train_acc = Accuracys[0] + val_acc = Accuracys[1] + + # 分別繪製訓練準確率和驗證準確率 + train_epochs_acc = range(1, len(train_acc) + 1) + plt.plot(train_epochs_acc, train_acc, label='Train') + + val_epochs_acc = range(1, len(val_acc) + 1) + plt.plot(val_epochs_acc, val_acc, label='Validation') + + plt.ylabel('Accuracies') + plt.xlabel('epoch') + plt.legend(loc='upper left') + plt.title('Model Accuracy') - model_dir = '../Result/Training_Image/save_the_train_image( ' + str(datetime.date.today()) + " )" - File.JudgeRoot_MakeDir(model_dir) - modelfiles = File.Make_Save_Root(str(model_name) + " " + str(file_name) + ".png", model_dir) + File.JudgeRoot_MakeDir(Save_Root) + modelfiles = File.Make_Save_Root(f"{str(File_Name)}.png", Save_Root) plt.savefig(modelfiles) plt.close("all") # 關閉圖表 -def draw_heatmap(matrix, model_name, index): # 二分類以上混淆矩陣做法 +def draw_heatmap(matrix, Save_Root, File_Name, index): # 二分類以上混淆矩陣做法 File = Process_File() # 创建热图 @@ -40,20 +58,19 @@ def draw_heatmap(matrix, model_name, index): # 二分類以上混淆矩陣做法 Ax = fig.add_subplot(111) sns.heatmap(matrix, square = True, annot = True, fmt = 'd', linecolor = 'white', cmap = "Purples", ax = Ax)#画热力图,cmap表示设定的颜色集 - model_dir = '../Result/Matrix_Image/model_matrix_image ( ' + str(datetime.date.today()) + " )" - File.JudgeRoot_MakeDir(model_dir) - modelfiles = File.Make_Save_Root(str(model_name) + "-" + str(index) + ".png", model_dir) + File.JudgeRoot_MakeDir(Save_Root) + modelfiles = File.Make_Save_Root(f"{File_Name}-{str(index)}.png", Save_Root) # confusion.figure.savefig(modelfiles) # 设置图像参数 - Ax.set_title(str(model_name) + " confusion matrix") + Ax.set_title(f"{File_Name} confusion matrix") Ax.set_xlabel("X-Predict label of the model") Ax.set_ylabel("Y-True label of the model") # 保存图像到文件中 canvas.print_figure(modelfiles) -def Confusion_Matrix_of_Two_Classification(Model_Name, Matrix, index): +def Confusion_Matrix_of_Two_Classification(Matrix, Save_Root, File_Name, index): File = Process_File() fx = sns.heatmap(Matrix, annot=True, cmap='turbo') @@ -63,13 +80,20 @@ def Confusion_Matrix_of_Two_Classification(Model_Name, Matrix, index): fx.set_xlabel('answer Values ') fx.set_ylabel('Predicted Values') - # labels the boxes - fx.xaxis.set_ticklabels(['False','True']) - fx.yaxis.set_ticklabels(['False','True']) + # 根据矩阵维度动态设置标签 + n_classes = Matrix.shape[0] + # 如果是2类问题,使用False/True标签 + if n_classes == 2: + labels = ['False', 'True'] + else: + # 对于多类问题,使用数字标签 + labels = [str(i) for i in range(n_classes)] + + fx.xaxis.set_ticklabels(labels) + fx.yaxis.set_ticklabels(labels) - model_dir = '../Result/model_matrix_image ( ' + str(datetime.date.today()) + " )" - File.JudgeRoot_MakeDir(model_dir) - modelfiles = File.Make_Save_Root(str(Model_Name) + "-" + str(index) + ".png", model_dir) + File.JudgeRoot_MakeDir(Save_Root) + modelfiles = File.Make_Save_Root(f"{File_Name}-{str(index)}.png", Save_Root) plt.savefig(modelfiles) plt.close("all") # 關閉圖表 diff --git a/experiments/Model_All_Step.py b/experiments/Model_All_Step.py deleted file mode 100644 index 2e217f0..0000000 --- a/experiments/Model_All_Step.py +++ /dev/null @@ -1,210 +0,0 @@ -from tqdm import tqdm -from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score -from torchmetrics.functional import auroc -from torch.nn import functional - -from all_models_tools.all_model_tools import call_back -from Model_Loss.Loss import Entropy_Loss -from merge_class.merge import merge -from draw_tools.Grad_cam import GradCAM - -import time -import torch.optim as optim -import numpy as np -import torch -import pandas as pd -import datetime - - -class All_Step: - def __init__(self, Model, Epoch, Number_Of_Classes, Model_Name, Experiment_Name): - self.Model = Model - self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') - - self.Epoch = Epoch - self.Number_Of_Classes = Number_Of_Classes - - self.Model_Name = Model_Name - self.Experiment_Name = Experiment_Name - - def Training_Step(self, train_subset, val_subset, train_loader, val_loader, model_name, fold, TargetLayer): - # Reinitialize model and optimizer for each fold - # self.Model = self.Model.__class__(self.Number_Of_Classes).to(self.device) # Reinitialize model - Optimizer = optim.SGD(self.Model.parameters(), lr=0.045, momentum=0.9, weight_decay=0.01) - model_path, early_stopping, scheduler = call_back(model_name, f"_fold{fold}", Optimizer) - - criterion = Entropy_Loss() # Custom loss function - Merge_Function = merge() - - # Lists to store metrics for this fold - train_losses = [] - val_losses = [] - train_accuracies = [] - val_accuracies = [] - epoch = 0 - - # Epoch loop - for epoch in range(self.Epoch): - self.Model.train() # Start training - running_loss = 0.0 - all_train_preds = [] - all_train_labels = [] - processed_samples = 0 - - # Calculate epoch start time - start_time = time.time() - total_samples = len(train_subset) # Total samples in subset, not DataLoader - total_Validation_samples = len(val_subset) - - # Progress bar for training batches - epoch_iterator = tqdm(train_loader, desc=f"Fold {fold + 1}/5, Epoch [{epoch + 1}/{self.Epoch}]") - - for inputs, labels in epoch_iterator: - inputs, labels = inputs.to(self.device), labels.to(self.device) # Already tensors from DataLoader - - Optimizer.zero_grad() - outputs = self.Model(inputs) - loss = criterion(outputs, labels) - loss.backward() - Optimizer.step() - running_loss += loss.item() - - # Collect training predictions and labels - Output_Values, Output_Indexs = torch.max(outputs, dim=1) - True_Indexs = np.argmax(labels.cpu().numpy(), axis=1) - - all_train_preds.append(Output_Indexs.cpu().numpy()) - all_train_labels.append(True_Indexs) - - processed_samples += inputs.size(0) # Use size(0) for batch size - - # Calculate progress and timing - progress = (processed_samples / total_samples) * 100 - elapsed_time = time.time() - start_time - iterations_per_second = processed_samples / elapsed_time if elapsed_time > 0 else 0 - eta = (total_samples - processed_samples) / iterations_per_second if iterations_per_second > 0 else 0 - time_str = f"{int(elapsed_time//60):02d}:{int(elapsed_time%60):02d}<{int(eta//60):02d}:{int(eta%60):02d}" - - # Calculate batch accuracy(正確label數量 / 該batch總共的label數量) - batch_accuracy = (Output_Indexs.cpu().numpy() == True_Indexs).mean() - - # Update progress bar - epoch_iterator.set_postfix_str( - f"{processed_samples}/{total_samples} [{time_str}, {iterations_per_second:.2f}it/s, " - f"acc={batch_accuracy:.3f}, loss={loss.item():.3f}]" - ) - - epoch_iterator.close() - # Merge predictions and labels - all_train_preds = Merge_Function.merge_data_main(all_train_preds, 0, len(all_train_preds)) - all_train_labels = Merge_Function.merge_data_main(all_train_labels, 0, len(all_train_labels)) - - Training_Loss = running_loss / len(train_loader) - train_accuracy = accuracy_score(all_train_labels, all_train_preds) - - train_losses.append(Training_Loss) - train_accuracies.append(train_accuracy) - - # Validation step - self.Model.eval() - val_loss = 0.0 - all_val_preds = [] - all_val_labels = [] - - start_Validation_time = time.time() - epoch_iterator = tqdm(val_loader, desc=f"\tValidation-Fold {fold + 1}/5, Epoch [{epoch + 1}/{self.Epoch}]") - with torch.no_grad(): - for inputs, labels in epoch_iterator: - inputs, labels = inputs.to(self.device), labels.to(self.device) - outputs = self.Model(inputs) - loss = criterion(outputs, labels) - val_loss += loss.item() - - # Collect validation predictions and labels - Output_Values, Output_Indexs = torch.max(outputs, dim=1) - True_Indexs = np.argmax(labels.cpu().numpy(), axis=1) - - all_val_preds.append(Output_Indexs.cpu().numpy()) - all_val_labels.append(True_Indexs) - - processed_samples += inputs.size(0) # Use size(0) for batch size - - # Calculate progress and timing - progress = (processed_samples / total_Validation_samples) * 100 - elapsed_time = time.time() - start_Validation_time - iterations_per_second = processed_samples / elapsed_time if elapsed_time > 0 else 0 - eta = (total_Validation_samples - processed_samples) / iterations_per_second if iterations_per_second > 0 else 0 - time_str = f"{int(elapsed_time//60):02d}:{int(elapsed_time%60):02d}<{int(eta//60):02d}:{int(eta%60):02d}" - - # Calculate batch accuracy - batch_accuracy = (Output_Indexs.cpu().numpy() == True_Indexs).mean() - - # Update progress bar - epoch_iterator.set_postfix_str( - f"{processed_samples}/{total_Validation_samples} [{time_str}, {iterations_per_second:.2f}it/s, " - f"acc={batch_accuracy:.3f}, loss={loss.item():.3f}]" - ) - - epoch_iterator.close() - print("\n") - - # Merge predictions and labels - all_val_preds = Merge_Function.merge_data_main(all_val_preds, 0, len(all_val_preds)) - all_val_labels = Merge_Function.merge_data_main(all_val_labels, 0, len(all_val_labels)) - - val_loss /= len(val_loader) - val_accuracy = accuracy_score(all_val_labels, all_val_preds) - - val_losses.append(val_loss) - val_accuracies.append(val_accuracy) - - print(f"Traini Loss: {Training_Loss:.4f}, Accuracy: {train_accuracy:0.2f}, Validation Loss: {val_loss:.4f}, Accuracy: {val_accuracy:0.2f}\n") - - if epoch % 10 == 0: - Grad = GradCAM(self.Model, TargetLayer) - Grad.Processing_Main(val_loader, f"../Result/GradCAM_Image/Validation/GradCAM_Image({str(datetime.date.today())})/fold-{str(fold)}/") - - # Early stopping - early_stopping(val_loss, self.Model, model_path) - if early_stopping.early_stop: - print(f"Early stopping triggered in Fold {fold + 1} at epoch {epoch + 1}") - break - - # Learning rate adjustment - scheduler.step(val_loss) - - Total_Epoch = epoch + 1 - return self.Model, model_path, train_losses, val_losses, train_accuracies, val_accuracies, Total_Epoch - - def Evaluate_Model(self, cnn_model, Test_Dataloader): - # (Unchanged Evaluate_Model method) - cnn_model.eval() - True_Label, Predict_Label = [], [] - True_Label_OneHot, Predict_Label_OneHot = [], [] - loss = 0.0 - - with torch.no_grad(): - for images, labels in Test_Dataloader: - images, labels = torch.as_tensor(images).to(self.device), torch.as_tensor(labels).to(self.device) - outputs = cnn_model(images) - Output_Values, Output_Indexs = torch.max(outputs, 1) - True_Indexs = np.argmax(labels.cpu().numpy(), 1) - - True_Label.append(Output_Indexs.cpu().numpy()) - Predict_Label.append(True_Indexs) - - Predict_Label_OneHot.append(torch.tensor(functional.one_hot(Output_Indexs, self.Number_Of_Classes), dtype=torch.float32).cpu().numpy()[0]) - True_Label_OneHot.append(torch.tensor(labels, dtype=torch.int).cpu().numpy()[0]) - - loss /= len(Test_Dataloader) - - True_Label_OneHot = torch.as_tensor(True_Label_OneHot, dtype=torch.int) - Predict_Label_OneHot = torch.as_tensor(Predict_Label_OneHot, dtype=torch.float32) - - accuracy = accuracy_score(True_Label, Predict_Label) - precision = precision_score(True_Label, Predict_Label, average="macro") - recall = recall_score(True_Label, Predict_Label, average="macro") - AUC = auroc(Predict_Label_OneHot, True_Label_OneHot, num_labels=self.Number_Of_Classes, task="multilabel", average="macro") - f1 = f1_score(True_Label, Predict_Label, average="macro") - - return True_Label, Predict_Label, loss, accuracy, precision, recall, AUC, f1 \ No newline at end of file diff --git a/experiments/Models/GastroSegNet_Model.py b/experiments/Models/GastroSegNet_Model.py new file mode 100644 index 0000000..2160fa9 --- /dev/null +++ b/experiments/Models/GastroSegNet_Model.py @@ -0,0 +1,91 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Encode_Block(nn.Module): + """基本的卷積塊:Conv2d + BatchNorm + ReLU""" + def __init__(self, in_channels, out_channels): + super(Encode_Block, self).__init__() + self.conv = nn.Sequential( + nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True), + nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1), + nn.BatchNorm2d(out_channels), + nn.ReLU(inplace=True) + ) + + def forward(self, x): + return self.conv(x) + +class GastroSegNet(nn.Module): + """簡單的U-Net實現""" + def __init__(self, in_channels=3, out_channels=3, features=[32, 64, 128, 256]): + super(GastroSegNet, self).__init__() + + # 編碼器(下採樣路徑) + self.encoder = nn.ModuleList() + self.pool = nn.MaxPool2d(kernel_size=2, stride=2) + + # 第一層 + self.encoder.append(Encode_Block(in_channels, features[0])) + + # 其他編碼層 + for i in range(1, len(features)): + self.encoder.append(Encode_Block(features[i-1], features[i])) + + # 瓶頸層(最底層) + self.bottleneck = Encode_Block(features[-1], features[-1] * 2) + + # 解碼器(上採樣路徑) + self.decoder = nn.ModuleList() + self.upconv = nn.ModuleList() + + # 創建上採樣和解碼層 + for i in range(len(features)): + self.upconv.append( + nn.ConvTranspose2d(features[-1-i] * 2, features[-1-i], kernel_size=2, stride=2) + ) + self.decoder.append( + Encode_Block(features[-1-i] * 2, features[-1-i]) + ) + + # 最終輸出層 + self.final_conv = nn.Conv2d(features[0], out_channels, kernel_size=1) + + def forward(self, x): + # 存儲跳躍連接 + skip_connections = [] + + # 編碼器路徑 + for encoder_layer in self.encoder: + x = encoder_layer(x) + skip_connections.append(x) + x = self.pool(x) + + # 瓶頸層 + x = self.bottleneck(x) + + # 反轉跳躍連接列表 + skip_connections = skip_connections[::-1] + + # 解碼器路徑 + for i, (upconv, decoder) in enumerate(zip(self.upconv, self.decoder)): + # 上採樣 + x = upconv(x) + + # 獲取對應的跳躍連接 + skip = skip_connections[i] + + # 如果尺寸不匹配,調整大小 + if x.shape != skip.shape: + x = F.interpolate(x, size=skip.shape[2:], mode='bilinear', align_corners=False) + + # 連接跳躍連接 + x = torch.cat([skip, x], dim=1) + + # 通過解碼塊 + x = decoder(x) + + # 最終輸出 + return self.final_conv(x) \ No newline at end of file diff --git a/experiments/Models/Xception_Model_Modification.py b/experiments/Models/Xception_Model_Modification.py new file mode 100644 index 0000000..f956f88 --- /dev/null +++ b/experiments/Models/Xception_Model_Modification.py @@ -0,0 +1,148 @@ +import torch.nn as nn +import torch.nn.functional as F +import torch + +class SeparableConv2d(nn.Module): + def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True): + super(SeparableConv2d, self).__init__() + self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size=kernel_size, stride=stride, + padding=padding, groups=in_channels, bias=bias) + self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, + padding=0, bias=bias) + + def forward(self, x): + x = self.depthwise(x) + x = self.pointwise(x) + return x + +class EntryFlow(nn.Module): + def __init__(self, in_channels=3): + super(EntryFlow, self).__init__() + self.conv1 = nn.Conv2d(in_channels, 32, 3, stride=2, padding=1, bias=False, dilation = 2) + self.bn1 = nn.BatchNorm2d(32) + self.conv2 = nn.Conv2d(32, 64, 3, padding=1, bias=False, dilation = 2) + self.bn2 = nn.BatchNorm2d(64) + + self.conv3_residual = nn.Sequential( + SeparableConv2d(64, 128, 3, padding=1), + nn.BatchNorm2d(128), + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(128, 128, 3, padding=1), + nn.BatchNorm2d(128), + nn.MaxPool2d(3, stride=2, padding=1) + ) + self.conv3_shortcut = nn.Conv2d(64, 128, 1, stride=2, bias=False) + self.bn3 = nn.BatchNorm2d(128) + + self.conv4_residual = nn.Sequential( + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(128, 256, 3, padding=1), + nn.BatchNorm2d(256), + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(256, 256, 3, padding=1), + nn.BatchNorm2d(256), + nn.MaxPool2d(3, stride=2, padding=1) + ) + self.conv4_shortcut = nn.Conv2d(128, 256, 1, stride=2, bias=False) + self.bn4 = nn.BatchNorm2d(256) + + self.conv5_residual = nn.Sequential( + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(256, 728, 3, padding=1), + nn.BatchNorm2d(728), + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(728, 728, 3, padding=1), + nn.BatchNorm2d(728), + nn.MaxPool2d(3, stride=2, padding=1) + ) + self.conv5_shortcut = nn.Conv2d(256, 728, 1, stride=2, bias=False) + self.bn5 = nn.BatchNorm2d(728) + + def forward(self, x): + x = F.relu(self.bn1(self.conv1(x))) + x = F.relu(self.bn2(self.conv2(x))) + + residual = self.conv3_residual(x) + shortcut = self.conv3_shortcut(x) + x = F.relu(self.bn3(residual + shortcut)) + + residual = self.conv4_residual(x) + shortcut = self.conv4_shortcut(x) + x = F.relu(self.bn4(residual + shortcut)) + + residual = self.conv5_residual(x) + shortcut = self.conv5_shortcut(x) + x = F.relu(self.bn5(residual + shortcut)) + return x + +class MiddleFlow(nn.Module): + def __init__(self): + super(MiddleFlow, self).__init__() + self.conv_residual = nn.Sequential( + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(728, 728, 3, padding=1), + nn.BatchNorm2d(728), + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(728, 728, 3, padding=1), + nn.BatchNorm2d(728), + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(728, 728, 3, padding=1), + nn.BatchNorm2d(728) + ) + + def forward(self, x): + return self.conv_residual(x) + x + +class ExitFlow(nn.Module): + def __init__(self, num_classes=2): + super(ExitFlow, self).__init__() + self.conv1_residual = nn.Sequential( + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(728, 1024, 3, padding=1), + nn.BatchNorm2d(1024), + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(1024, 1024, 3, padding=1), + nn.BatchNorm2d(1024), + nn.MaxPool2d(3, stride=2, padding=1) + ) + self.conv1_shortcut = nn.Conv2d(728, 1024, 1, stride=2, bias=False) + self.bn1 = nn.BatchNorm2d(1024) + + self.conv2 = nn.Sequential( + SeparableConv2d(1024, 1536, 3, padding=1), + nn.BatchNorm2d(1536), + nn.ReLU(inplace=False), # 修改這裡 + SeparableConv2d(1536, 2048, 3, padding=1), + nn.BatchNorm2d(2048), + nn.ReLU(inplace=False) # 修改這裡 + ) + self.avgpool = nn.AdaptiveAvgPool2d((1, 1)) + self.Hidden = nn.Linear(2048, 1025) + self.fc = nn.Linear(1025, num_classes) + + def forward(self, x): + residual = self.conv1_residual(x) + shortcut = self.conv1_shortcut(x) + x = F.relu(self.bn1(residual + shortcut)) + + x = self.conv2(x) + x = self.avgpool(x) + x = x.view(x.size(0), -1) + x = self.Hidden(x) + x = self.fc(x) + return x + +class Xception(nn.Module): + def __init__(self, num_classes=2): + super(Xception, self).__init__() + self.entry_flow = EntryFlow(in_channels=3) # 默认输入通道为3 + self.middle_flow = nn.Sequential(*[MiddleFlow() for _ in range(8)]) + self.exit_flow = ExitFlow(num_classes) + + def forward(self, x): + # 正常的前向傳播 + x = self.entry_flow(x) + x = self.middle_flow(x) + x = self.exit_flow(x) + + return x \ No newline at end of file diff --git a/experiments/Models/__init__.py b/experiments/Models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/experiments/Models/__pycache__/GastroSegNet_Model.cpython-311.pyc b/experiments/Models/__pycache__/GastroSegNet_Model.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..60dce155e3df3eab2fe6b79393eba9965cc56086 GIT binary patch literal 5059 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 literal 0 HcmV?d00001 diff --git a/experiments/Models/__pycache__/Xception_Model_Modification.cpython-311.pyc b/experiments/Models/__pycache__/Xception_Model_Modification.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..186c9c7789ef32b99202b1fe54e1842bc2d28fed GIT binary patch literal 11162 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 L{8^EkM2Y_c@Dv-0 literal 0 HcmV?d00001 diff --git a/experiments/Models/__pycache__/__init__.cpython-311.pyc b/experiments/Models/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1c5e11fc9c6d9569ece859d7fd813c7501933b7e GIT binary patch literal 190 zcmZ3^%ge<81b3FN%>dDlK?DpiLK&agfQ;!3DGb33nv8xc8H$*I{LdiCUxE4=`MIh3 z};*$K_#N>?l)FS^6#WwZ|5Mj%-WX1+ChuETF55MX4*0tU@<{@il&>v0Mm@Wqg~AHt2h zEF&rEtF117hR{6k&l`7KM)QHa)aKhXtPJ*U@Pga*VjVKD5o7^8=xB)}1kwNz!8z~Z zG~h>eJ_Mr_99U&B5MUzDR*DEG%ik-tYXO$C!k==^8Pd^ zWFlVF6h$rg!kS4<=UTpEr&|_2Bu3GI)t6;UP4v=;St_c8u!^9(BxwcBk|fGmT0T#O zEK$Kq%CpKOtYB#Sb=j;5XsA%2d?Om{-&1JUtZrPF zbxB^Bm5LyuQO_qT%()Iry1b+kDu7E6Q;p*;tLbUV5mhhI*p!j8^70~$nf{~}0*xtN zEKu*9sp>h}Q7Gl5tS+0TYSK2zn@W<&To=Wa*Q4qp1gqu2W%H_=Wbd`m{PYV-LSn2RIM@Ts5D)$u9k z{VVqHv@<+i;T%4`6(4$(daPGZedHWH|6Hg}&pQ`Cx8u4K*O`7G&|h?prk=^f61TwMGC9OZFOWot#Nk2lqRB!MMKa9TSk53{%0ww2Z2FVc zGzY=V)Pby^mqPd5$y<{T$8BNA5r!%l1TO?}QxMmBY+=+9MqSa})UDJ#k2(Kv?r9>sRz{wejBO4q^zP SncO3*OMfu=pDmQGC;tL`CjajM literal 0 HcmV?d00001 diff --git a/experiments/Models/pytorch_Model.py b/experiments/Models/pytorch_Model.py new file mode 100644 index 0000000..be79e6d --- /dev/null +++ b/experiments/Models/pytorch_Model.py @@ -0,0 +1,30 @@ +import torch.nn as nn +import timm + +from utils.Stomach_Config import Model_Config + +class ModifiedXception(nn.Module): + def __init__(self, num_classes): + super(ModifiedXception, self).__init__() + + # 加載 Xception 預訓練模型,去掉最後一層 (fc 層) + self.base_model = timm.create_model(Model_Config["Model Name"], pretrained=True) + self.base_model.fc = nn.Identity() # 移除原來的 fully connected 層 + + # 新增全局平均池化層、隱藏層和輸出層 + self.global_avg_pool = nn.AdaptiveAvgPool1d(Model_Config["GPA Output Nodes"]) # 全局平均池化 + self.hidden_layer = nn.Linear(Model_Config["GPA Output Nodes"], Model_Config["Linear Hidden Nodes"]) # 隱藏層,輸入大小取決於 Xception 的輸出大小 + self.output_layer = nn.Linear(Model_Config["Linear Hidden Nodes"], Model_Config["Output Linear Nodes"]) # 輸出層,依據分類數目設定 + + # 激活函數與 dropout + self.relu = nn.ReLU() + self.softmax = nn.Softmax(1) + self.dropout = nn.Dropout(Model_Config["Dropout Rate"]) + + def forward(self, x): + x = self.base_model(x) # Xception 主體 + x = self.global_avg_pool(x) # 全局平均池化 + x = self.relu(self.hidden_layer(x)) # 隱藏層 + ReLU + x = self.dropout(x) # Dropout + x = self.output_layer(x) # 輸出層 + return x \ No newline at end of file diff --git a/experiments/Training/Identification_Block_Training.py b/experiments/Training/Identification_Block_Training.py new file mode 100644 index 0000000..6e467db --- /dev/null +++ b/experiments/Training/Identification_Block_Training.py @@ -0,0 +1,461 @@ +from tqdm import tqdm +from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score +from torchmetrics.functional import auroc +from torch.nn import functional +from torch import nn +import torch +from sklearn.model_selection import KFold +from torchinfo import summary +from sklearn.metrics import confusion_matrix + +from all_models_tools.all_model_tools import call_back +from Model_Loss.Loss import Entropy_Loss +from Model_Loss.binary_cross_entropy import BinaryCrossEntropy +from merge_class.merge import merge +from draw_tools.Saliency_Map import SaliencyMap +from utils.Stomach_Config import Training_Config, Loading_Config, Save_Result_File_Config +from experiments.Models.Xception_Model_Modification import Xception +from Load_process.LoadData import Loding_Data_Root +from Training_Tools.PreProcess import Training_Precesses +from Calculate_Process.Calculate import Calculate +from Load_process.file_processing import Process_File +from draw_tools.draw import plot_history, draw_heatmap +from Load_process.file_processing import Process_File + +import time +import torch.optim as optim +import numpy as np +import torch +import pandas as pd +import datetime +import argparse +import os + +class Identification_Block_Training_Step(Loding_Data_Root, Training_Precesses): + def __init__(self, Experiment_Name, Best_Model_Save_Root): + self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + + self.Model = self.Construct_Identification_Model_CUDA() # 模型變數 + self.train_subset = None # Training Dataset 的子集 + self.val_subset = None # Validation Dataset 的子集 + self.train_loader = None # Training DataLoader 的讀檔器 + self.val_loader = None # Validation DataLoader 的讀檔器 + self.Mask = None # 遮罩變數,接收GastroSegNet產出來的Mask + self.Grad = None # 梯度變數,後面用來執行Grad CAM + + self.model_name = Training_Config["Model_Name"] # 取名,使用哪個模型(可能是預處理模型/自己設計的模型) + self.Epoch = Training_Config["Epoch"] # 訓練該模型的次數 + self.train_batch_size = Training_Config["Train_Batch_Size"] # 訓練模型的Batch Size + self.Experiment_Name = Experiment_Name + self.Number_Of_Classes = Loading_Config["Identification_Label_Length"] + self.Best_Model_Save_Root = Best_Model_Save_Root + + # 初始化多個繼承物件 + Training_Precesses.__init__(self, Training_Config["Image_Size"]) + Loding_Data_Root.__init__(self, Loading_Config["Training_Labels"], Loading_Config["Train_Data_Root"], Loading_Config["Test_Data_Root"]) + + pass + + def Processing_Main(self, training_dataset, Test_Dataloader=None): + # Lists to store metrics across all folds + all_fold_train_losses = [] + all_fold_val_losses = [] + all_fold_train_accuracies = [] + all_fold_val_accuracies = [] + Calculate_Process = Calculate() + File = Process_File() + Calculate_Tool = [Calculate() for i in range(3)] + Best_Model_Path = None + Best_Validation_Loss = 100000000 + + # K-Fold loop + kf = KFold(n_splits=5, shuffle=True, random_state=42) + for fold, (train_idx, val_idx) in enumerate(kf.split(range(len(training_dataset)))): # K-Fold 交叉驗證迴圈 + print(f"\nStarting Fold {fold + 1}/5") + + # Create training and validation subsets for this fold + self.train_subset = torch.utils.data.Subset(training_dataset, train_idx) + self.val_subset = torch.utils.data.Subset(training_dataset, val_idx) + + # Wrap subsets in DataLoaders (use same batch size as original) + self.train_loader = self.Dataloader_Sampler(self.train_subset , self.train_batch_size, True) + self.val_loader = self.Dataloader_Sampler(self.val_subset, self.train_batch_size, True) + + # 模型訓練與驗證 + model_path, train_losses, Validation_losses, train_accuracies, Validation_accuracies, Total_Epoch, best_val_loss = self.Training_And_Validation(fold) + + # Store fold results + all_fold_train_losses.append(train_losses) + all_fold_val_losses.append(Validation_losses) + all_fold_train_accuracies.append(train_accuracies) + all_fold_val_accuracies.append(Validation_accuracies) + + # 确保张量在CPU上,以便可以转换为NumPy数组 + if torch.is_tensor(train_losses): + train_losses = train_losses.cpu().detach().numpy() + if torch.is_tensor(Validation_losses): + Validation_losses = Validation_losses.cpu().detach().numpy() + if torch.is_tensor(train_accuracies): + train_accuracies = train_accuracies.cpu().detach().numpy() + if torch.is_tensor(Validation_accuracies): + Validation_accuracies = Validation_accuracies.cpu().detach().numpy() + + Losses = [train_losses, Validation_losses] + Accuracies = [train_accuracies, Validation_accuracies] + plot_history(Losses, Accuracies, f"{Save_Result_File_Config['Identification_Plot_Image']}/{self.Experiment_Name}", f"train-{str(fold)}") # 將訓練結果化成圖,並將化出來的圖丟出去儲存 + + # 驗證結果 + True_Label, Predict_Label, loss, accuracy, precision, recall, AUC, f1 = self.Evaluate_Model(self.Model, Test_Dataloader, fold) + + # 紀錄該次訓練結果 + Calculate_Process.Append_numbers(loss, accuracy, precision, recall, AUC, f1) + self.record_matrix_image(True_Label, Predict_Label, fold) + print(self.record_everyTime_test_result(loss, accuracy, precision, recall, AUC, f1, fold, self.Experiment_Name)) # 紀錄當前訓練完之後的預測結果,並輸出成csv檔 + + # 使用識別模型進行各類別評估 + Calculate_Tool = self.Evaluate_Per_Class_Metrics(self.Model, Test_Dataloader, Loading_Config["Training_Labels"], Calculate_Tool) + + if best_val_loss < Best_Validation_Loss: + Best_Validation_Loss = best_val_loss + Best_Model_Path = model_path + + Calculate_Process.Calculate_Mean() + Calculate_Process.Calculate_Std() + + File.Save_CSV_File(f"../Result/Experiment_Result/{self.Experiment_Name}/Total/{str(datetime.date.today())}", f"Total_Training_Result-{fold}", Calculate_Process.Output_Style()) + + for Calculate_Every_Class in Calculate_Tool: + Calculate_Every_Class.Calculate_Mean() + Calculate_Every_Class.Calculate_Std() + + # Aggregate results across folds + avg_train_losses = np.mean([losses[-1] for losses in all_fold_train_losses]) + avg_val_losses = np.mean([losses[-1] for losses in all_fold_val_losses]) + avg_train_accuracies = np.mean([acc[-1] for acc in all_fold_train_accuracies]) + avg_val_accuracies = np.mean([acc[-1] for acc in all_fold_val_accuracies]) + + print(f"\nCross-Validation Results:") + print(f"Avg Train Loss: {avg_train_losses:.4f}, Avg Val Loss: {avg_val_losses:.4f}") + print(f"Avg Train Acc: {avg_train_accuracies:.4f}, Avg Val Acc: {avg_val_accuracies:.4f}") + + File.Save_TXT_File(content = f"\nCross-Validation Results:\nAvg Train Loss: {avg_train_losses:.4f}, Avg Val Loss: {avg_val_losses:.4f}\nAvg Train Acc: {avg_train_accuracies:.4f}, Avg Val Acc: {avg_val_accuracies:.4f}\n", Save_Root = Save_Result_File_Config["Identification_Average_Result"], File_Name = "Training_Average_Result") + + # 返回最後一個fold的模型路徑和平均指標 + return Best_Model_Path, Calculate_Process, Calculate_Tool + + def Training_And_Validation(self, Fold): + # Reinitialize model and optimizer for each fold + # self.Model = self.Model.__class__(self.Number_Of_Classes).to(self.device) # Reinitialize model + self.Model = self.Construct_Identification_Model_CUDA() # 模型初始化 + Optimizer = optim.SGD(self.Model.parameters(), lr=0.045, momentum=0.9, weight_decay = Training_Config["weight_decay"]) + model_path, early_stopping, scheduler = call_back(self.Best_Model_Save_Root, f"fold{Fold}", Optimizer) + + # Lists to store metrics for this fold + train_losses = [] + Validation_losses = [] + train_accuracies = [] + Validation_accuracies = [] + + # Epoch loop + for epoch in range(self.Epoch): + self.Model.train() # Start training + Training_Loss = 0.0 + All_Predict_List, All_Label_List = [], [] + + # Progress bar for training batches + epoch_iterator = tqdm(self.train_loader, desc=f"Fold {Fold + 1}/5, Epoch [{epoch + 1}/{self.Epoch}]") + Start_Time = time.time() + + for inputs, labels, File_Name, File_Classes in epoch_iterator: + Optimizer.zero_grad() # 清零梯度,防止梯度累積 + Total_Losses, Training_Loss, All_Predict_List, All_Label_List, Predict_Indexs, Truth_Indexs = self.Model_Branch(inputs, labels, All_Predict_List, All_Label_List, Training_Loss) + Total_Losses.backward() + + Optimizer.step() + self.Calculate_Progress_And_Timing(inputs, Predict_Indexs, Truth_Indexs, self.train_subset, Total_Losses, epoch_iterator, Start_Time) + + train_losses, train_accuracies, Training_Loss, Train_accuracy = self.Calculate_Average_Scores(self.train_loader, Training_Loss, All_Predict_List, All_Label_List, train_losses, train_accuracies) + + # Validation step + self.Model.eval() + val_loss = 0.0 + all_val_preds = [] + all_val_labels = [] + + start_Validation_time = time.time() + epoch_iterator = tqdm(self.val_loader, desc=f"\tValidation-Fold {Fold + 1}/5, Epoch [{epoch + 1}/{self.Epoch}]") + with torch.no_grad(): + for inputs, labels, File_Name, File_Classes in epoch_iterator: + Validation_Total_Loss, val_loss, all_val_preds, all_val_labels, Predict_Indexs, Truth_Indexs = self.Model_Branch(inputs, labels, all_val_preds, all_val_labels, val_loss) + self.Calculate_Progress_And_Timing(inputs, Predict_Indexs, Truth_Indexs, self.val_subset, Validation_Total_Loss, epoch_iterator, start_Validation_time) + + Validation_losses, Validation_accuracies, val_loss, val_accuracy = self.Calculate_Average_Scores(self.val_loader, val_loss, all_val_preds, all_val_labels, Validation_losses, Validation_accuracies) + print(f"Traini Loss: {Training_Loss:.4f}, Accuracy: {Train_accuracy:0.2f}, Validation Loss: {val_loss:.4f}, Accuracy: {val_accuracy:0.2f}\n") + + # if epoch % 5 == 0: + # # Grad = GradCAM(self.Model, TargetLayer) + # # Grad.Processing_Main(val_loader, f"../Result/GradCAM_Image/Validation/GradCAM_Image({str(datetime.date.today())})/{self.Experiment_Name}/fold-{str(fold)}/") + + # # 創建SaliencyMap實例 + # saliency_map = SaliencyMap(self.Model) + # # 處理測試數據集 + # saliency_map.Processing_Main(self.val_loader, f"../Result/Saliency_Image/Validation/Saliency_Image({str(datetime.date.today())})/{self.Experiment_Name}/fold-{str(Fold)}/") + + # Early stopping + early_stopping(val_loss, self.Model, model_path) + best_val_loss = early_stopping.best_loss + if early_stopping.early_stop: + print(f"Early stopping triggered in Fold {Fold + 1} at epoch {epoch + 1}") + break + + # Learning rate adjustment + scheduler.step(val_loss) + + Total_Epoch = epoch + 1 + # 確保返回模型路徑 + return model_path, train_losses, Validation_losses, train_accuracies, Validation_accuracies, Total_Epoch, best_val_loss + + def Construct_Identification_Model_CUDA(self): + # 从Model_Config中获取输出节点数量 + Model = Xception(num_classes=Loading_Config["Identification_Label_Length"]) + + # 注释掉summary调用,避免Mask参数问题 + # 直接打印模型结构 + print(f"Model structure: {Model}") + + # 打印模型参数 + for name, parameters in Model.named_parameters(): + print(f"Layer Name: {name}, Parameters: {parameters.size()}") + + return self.Convert_Model_To_CUDA(Model) + + def Convert_Model_To_CUDA(self, model): + if torch.cuda.device_count() > 1: + model = nn.DataParallel(model) + + model = model.to(self.device) + + return model + + def Model_Branch(self, Input_Images, Labels, All_Predict_List : list, All_Label_List : list, running_loss): + # 直接將張量移到設備上,不需要重新創建 + Input_Images.requires_grad = False + Input_Images, Labels = Input_Images.to(self.device), Labels.to(self.device) + + # 確保輸入圖像在有效範圍內 + Input_Images = torch.clamp(Input_Images, 0.0, 1.0) + + Predict = self.Model(Input_Images) + + # Collect training predictions and labels + Output_Values, Output_Indexs = torch.max(Predict, dim=1) + True_Indexs = np.argmax(Labels.cpu().numpy(), axis=1) + + All_Predict_List.append(Output_Indexs.cpu().numpy()) + All_Label_List.append(True_Indexs) + + # 不需要對Predict進行clamp,因為我們已經修改了損失函數使用binary_cross_entropy_with_logits + Losses = self.Losses(Predict, Labels) + running_loss += Losses.item() + + return Losses, running_loss, All_Predict_List, All_Label_List, Output_Indexs, True_Indexs + + def Losses(self, Predicts, Labels): + criterion = BinaryCrossEntropy() + Loss = criterion(Predicts, Labels) + return Loss + + def Evaluate_Model(self, cnn_model, Test_Dataloader, index, identification_model_path=None): + # 載入識別模型權重(如果提供了路徑) + if identification_model_path is not None: + cnn_model.load_state_dict(torch.load(identification_model_path)) + else: + assert identification_model_path is None, "No identification model path provided for evaluation." + + # 評估模型 + cnn_model.eval() + True_Label, Predict_Label = [], [] + True_Label_OneHot, Predict_Label_OneHot = [], [] + loss = 0.0 + + with torch.no_grad(): + for images, labels, File_Name, File_Classes in Test_Dataloader: + Total_Loss, Running_Loss, Predict_Label, True_Label, Output_Indexs, Truth_Index = self.Model_Branch(images, labels, Predict_Label, True_Label, 0) + + Predict_Label_OneHot.append(torch.tensor(functional.one_hot(Output_Indexs, self.Number_Of_Classes), dtype=torch.float32).cpu().numpy()[0]) + True_Label_OneHot.append(torch.tensor(labels, dtype=torch.int).cpu().numpy()[0]) + + loss /= len(Test_Dataloader) + + True_Label_OneHot = torch.as_tensor(True_Label_OneHot, dtype=torch.int) + Predict_Label_OneHot = torch.as_tensor(Predict_Label_OneHot, dtype=torch.float32) + + accuracy = accuracy_score(True_Label, Predict_Label) + precision = precision_score(True_Label, Predict_Label, average="macro") + recall = recall_score(True_Label, Predict_Label, average="macro") + AUC = auroc(Predict_Label_OneHot, True_Label_OneHot, num_labels=self.Number_Of_Classes, task="multilabel", average="macro") + f1 = f1_score(True_Label, Predict_Label, average="macro") + + # 計算混淆矩陣 + matrix = confusion_matrix(True_Label, Predict_Label) + draw_heatmap(matrix, f"{Save_Result_File_Config['Identification_Marix_Image']}/{self.Experiment_Name}/Identification_Test_Marix_Image", f"confusion_matrix", index) # 呼叫畫出confusion matrix的function + + return True_Label, Predict_Label, loss, accuracy, precision, recall, AUC, f1 + + def Evaluate_Per_Class_Metrics(self, cnn_model, Test_Dataloader, Labels, Calculate_Tool, identification_model_path=None): + """ + Evaluate the model on the test dataloader and compute binary classification metrics for each class. + + Parameters: + - cnn_model: The trained model to evaluate. + - Test_Dataloader: DataLoader for the test dataset. + - Labels: List of class names for better readability. + - Calculate_Tool: Tool for recording metrics. + - identification_model_path: Path to the trained model weights (optional). + + Returns: + - Calculate_Tool: Updated with binary classification metrics for each class. + """ + # 載入識別模型權重(如果提供了路徑) + if identification_model_path is not None: + cnn_model.load_state_dict(torch.load(identification_model_path)) + + # 测试GPU是否可用 + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + print(f"使用设备: {device}") + + # 设置为评估模式 + cnn_model.eval() + + all_results = [] + all_labels = [] + # 使用PyTorch的预测方式 + with torch.no_grad(): # 不计算梯度 + for inputs, labels, _, _ in Test_Dataloader: + inputs = inputs.to(device) + labels = labels.to(device) + + outputs = cnn_model(inputs) + _, predicted = torch.max(outputs, 1) + all_results.append(predicted.cpu().numpy()) + all_labels.append(np.argmax(labels.cpu().numpy(), axis=1)) + + # 将所有批次的结果合并为一个数组 + Predict = np.concatenate(all_results) + y_test = np.concatenate(all_labels) + + print(f"预测结果: {Predict}\n") + # 计算整体评估指标 + accuracy = accuracy_score(y_test, Predict) + + # 打印整体准确率 + print(f"整体准确率 (Accuracy): {accuracy:.4f}") + + # 假设只有两个类别:0和1 + # 计算类别0的二分类评估指标(将类别0视为正类,类别1视为负类) + print(f"类别 {Labels[0]} 的二分类评估指标:") + y_binary_0 = (y_test == 0).astype(int) + predict_binary_0 = (Predict == 0).astype(int) + + # 计算二分类指标 + binary_accuracy_0 = accuracy_score(y_binary_0, predict_binary_0) + binary_precision_0 = precision_score(y_binary_0, predict_binary_0, zero_division=0) + binary_recall_0 = recall_score(y_binary_0, predict_binary_0, zero_division=0) + binary_f1_0 = f1_score(y_binary_0, predict_binary_0, zero_division=0) + + # 打印二分类指标 + print(f" 准确率 (Accuracy): {binary_accuracy_0:.4f}") + print(f" 精确率 (Precision): {binary_precision_0:.4f}") + print(f" 召回率 (Recall): {binary_recall_0:.4f}") + print(f" F1值: {binary_f1_0:.4f}\n") + + # 记录类别0的指标 + Calculate_Tool[0].Append_numbers(0, binary_accuracy_0, binary_precision_0, binary_recall_0, 0, binary_f1_0) + + # 计算类别1的二分类评估指标(将类别1视为正类,类别0视为负类) + print(f"类别 {Labels[1]} 的二分类评估指标:") + y_binary_1 = (y_test == 1).astype(int) + predict_binary_1 = (Predict == 1).astype(int) + + # 计算二分类指标 + binary_accuracy_1 = accuracy_score(y_binary_1, predict_binary_1) + binary_precision_1 = precision_score(y_binary_1, predict_binary_1, zero_division=0) + binary_recall_1 = recall_score(y_binary_1, predict_binary_1, zero_division=0) + binary_f1_1 = f1_score(y_binary_1, predict_binary_1, zero_division=0) + + # 打印二分类指标 + print(f" 准确率 (Accuracy): {binary_accuracy_1:.4f}") + print(f" 精确率 (Precision): {binary_precision_1:.4f}") + print(f" 召回率 (Recall): {binary_recall_1:.4f}") + print(f" F1值: {binary_f1_1:.4f}\n") + + # 记录类别1的指标 + Calculate_Tool[1].Append_numbers(0, binary_accuracy_1, binary_precision_1, binary_recall_1, 0, binary_f1_1) + + return Calculate_Tool + + def Calculate_Progress_And_Timing(self, inputs, Predict_Labels, Truth_Labels, Subset, loss, epoch_iterator, Start_Time): + # Calculate progress and timing + total_samples = len(Subset) + processed_samples = 0 + + processed_samples += inputs.size(0) # Use size(0) for batch size + + # Calculate progress and timing + elapsed_time = time.time() - Start_Time + iterations_per_second = processed_samples / elapsed_time if elapsed_time > 0 else 0 + eta = (total_samples - processed_samples) / iterations_per_second if iterations_per_second > 0 else 0 + time_str = f"{int(elapsed_time//60):02d}:{int(elapsed_time%60):02d}<{int(eta//60):02d}:{int(eta%60):02d}" + + # Calculate batch metrics using PSNR/SSIM loss + # 检查loss是否为张量,如果是则调用item(),否则直接使用浮点数值 + batch_loss = loss.item() if torch.is_tensor(loss) else loss + # Calculate batch accuracy + batch_accuracy = (Predict_Labels.cpu().numpy() == Truth_Labels).mean() + + # Update progress bar + epoch_iterator.set_postfix_str( + f"{processed_samples}/{total_samples} [{time_str}, {iterations_per_second:.2f}it/s, " + f"acc={batch_accuracy:.3f}, loss={batch_loss:.3f}]" + ) + + return epoch_iterator + + def Calculate_Average_Scores(self, Data_Loader, Running_Losses, All_Predict_Labels, All_Truth_Labels, Losses, Accuracies): + Merge_Function = merge() + + All_Predicts = Merge_Function.merge_data_main(All_Predict_Labels, 0, len(All_Predict_Labels)) + All_Truths = Merge_Function.merge_data_main(All_Truth_Labels, 0, len(All_Truth_Labels)) + + Running_Losses /= len(Data_Loader) + Accuracy = accuracy_score(All_Truths, All_Predicts) + + Losses.append(Running_Losses) + Accuracies.append(Accuracy) + + return Losses, Accuracies, Running_Losses, Accuracy + + def record_matrix_image(self, True_Labels, Predict_Labels, index): + '''劃出混淆矩陣(熱力圖)''' + # 計算混淆矩陣 + matrix = confusion_matrix(True_Labels, Predict_Labels) + # Confusion_Matrix_of_Two_Classification(matrix, Save_Result_File_Config["Identification_Marix_Image"], Experiment_Name, index) # 呼叫畫出confusion matrix的function + draw_heatmap(matrix, Save_Result_File_Config["Identification_Marix_Image"], self.Experiment_Name, index) # 呼叫畫出confusion matrix的function + + def record_everyTime_test_result(self, loss, accuracy, precision, recall, auc, f, indexs, model_name): + '''記錄我單次的訓練結果並將它輸出到檔案中''' + File = Process_File() + + Dataframe = pd.DataFrame( + { + "model_name" : str(model_name), + "loss" : "{:.2f}".format(loss), + "precision" : "{:.2f}%".format(precision * 100), + "recall" : "{:.2f}%".format(recall * 100), + "accuracy" : "{:.2f}%".format(accuracy * 100), + "f" : "{:.2f}%".format(f * 100), + "AUC" : "{:.2f}%".format(auc * 100) + }, index = [indexs]) + File.Save_CSV_File(Save_Result_File_Config["Identification_Every_Fold_Training_Result"], "train_result", Dataframe) + + return Dataframe \ No newline at end of file diff --git a/experiments/Training/Segmentation_Block_Training.py b/experiments/Training/Segmentation_Block_Training.py new file mode 100644 index 0000000..80a8d9e --- /dev/null +++ b/experiments/Training/Segmentation_Block_Training.py @@ -0,0 +1,467 @@ +from tqdm import tqdm +from torch import nn +from sklearn.model_selection import KFold +from skimage import measure + +from all_models_tools.all_model_tools import call_back +from utils.Stomach_Config import Training_Config, Loading_Config, Save_Result_File_Config +from Load_process.LoadData import Loding_Data_Root +from Training_Tools.PreProcess import Training_Precesses +from ..Models.GastroSegNet_Model import GastroSegNet +from Model_Loss.Segmentation_Loss import Segmentation_Loss +from draw_tools.draw import plot_history + +import time +import torch.optim as optim +import torch +import torch.nn.functional as F +import numpy as np +import cv2 +import os + +class Segmentation_Block_Training_Step(Loding_Data_Root, Training_Precesses): + def __init__(self, Best_Model_Save_Root): + self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 設置裝置,若有GPU則使用GPU,否則使用CPU + + self.Model = self.Construct_Segment_Model_CUDA() # 模型變數 + self.train_subset = None # Training Dataset 的子集 + self.val_subset = None # Validation Dataset 的子集 + self.train_loader = None # Training DataLoader 的讀檔器 + self.val_loader = None # Validation DataLoader 的讀檔器 + self.Mask = None # 遮罩變數,接收RD Net產出來的Mask + self.Grad = None # 梯度變數,後面用來執行Grad CAM + + self.model_name = Training_Config["Mask_Experiment_Name"] # 取名,使用哪個模型(可能是預處理模型/自己設計的模型) + self.epoch = Training_Config["Epoch"] # 訓練該模型的次數 + self.train_batch_size = Training_Config["Train_Batch_Size"] # 訓練模型的Batch Size + self.Experiment_Name = Training_Config["Mask_Experiment_Name"] # 取名,使用哪個模型(可能是預處理模型/自己設計的模型) + self.Best_Model_Save_Root = Best_Model_Save_Root + + # 初始化繼承物件 + Training_Precesses.__init__(self, Training_Config["Image_Size"]) + Loding_Data_Root.__init__(self, Loading_Config["Training_Labels"], Loading_Config["Train_Data_Root"], Loading_Config["Test_Data_Root"]) + + def Processing_Main(self, training_dataset, return_processed_images=False, test_dataloader=None): + Best_Model_Path = None + Best_Validation_Loss = 100000000 + # K-Fold loop + kf = KFold(n_splits=5, shuffle=True, random_state=42) + Training_Data_Lader = self.Dataloader_Sampler(training_dataset, self.train_batch_size, True) + + for fold, (train_idx, val_idx) in enumerate(kf.split(range(len(training_dataset)))): # K-Fold 交叉驗證迴圈 + print(f"\nStarting Fold {fold + 1}/5") + + # Create training and validation subsets for this fold + self.train_subset = torch.utils.data.Subset(training_dataset, train_idx) + self.val_subset = torch.utils.data.Subset(training_dataset, val_idx) + + # Wrap subsets in DataLoaders (use same batch size as original) + self.train_loader = self.Dataloader_Sampler(self.train_subset , self.train_batch_size, True) + self.val_loader = self.Dataloader_Sampler(self.val_subset, self.train_batch_size, True) + + # 模型訓練與驗證 + model_path, Training_Losses, Validation_Losses, Total_Epoch, best_val_loss = self.Training_And_Validation(fold) + Losses = [Training_Losses, Validation_Losses] + + if best_val_loss < Best_Validation_Loss: + Best_Validation_Loss = best_val_loss + Best_Model_Path = model_path + + # 將訓練結果化成圖,並將化出來的圖丟出去儲存 + plot_history(Losses, None, f"{Save_Result_File_Config['Segument_Plot_Image']}/{self.Experiment_Name}", f"train-{str(fold)}") # 將訓練結果化成圖,並將化出來的圖丟出去儲存 + + # 如果需要返回處理後的圖像(用於後續識別訓練) + if return_processed_images is not None: + # 載入最佳模型 + self.Model = self.Construct_Segment_Model_CUDA() + self.Model.load_state_dict(torch.load(Best_Model_Path)) + self.Model.eval() + + # 處理測試數據 + with torch.no_grad(): + for Input_Images, Mask_Ground_Truth_Image, Labels, File_Name, File_Classes in Training_Data_Lader: + # 使用Model_Branch處理圖像並獲取分割結果,同時傳遞文件名以保存邊界框圖像 + self.Model_Branch(Input_Images, Mask_Ground_Truth_Image, 0.0, Save_Result_File_Config["Segument_Bounding_Box_Image"], return_processed_image=True, file_names=File_Name, Classes=File_Classes) + + avg_test_loss = self.evaluate_on_test(Best_Model_Path, test_dataloader) + + return Best_Model_Path, avg_test_loss + + return Best_Model_Path + + def Training_And_Validation(self, Fold): + self.Model = self.Construct_Segment_Model_CUDA() # 模型初始化 + Optimizer = optim.SGD(self.Model.parameters(), lr=0.045, momentum=0.9, weight_decay=0.01) # 優化器初始化 + model_path, early_stopping, scheduler = call_back(f"{self.Best_Model_Save_Root}/{self.Experiment_Name}", f"fold{Fold}", Optimizer) # 防止過擬合細節函數初始化 + epoch = 0 + Training_Losses, Validation_Losses = [], [] + Training_Running_Losses, Validation_Running_Losses = 0.0, 0.0 + + # Epoch loop + for epoch in range(self.epoch): + self.Model.train() # Start training + + # Progress bar for training batches + epoch_iterator = tqdm(self.train_loader, desc=f"Fold {Fold + 1}/5, Epoch [{epoch + 1}/{self.epoch}]") + Start_Time = time.time() + + for Input_Images, Mask_Ground_Truth_Image, Labels, File_Name, File_Classes in epoch_iterator: + Optimizer.zero_grad() # 清零梯度,防止梯度累積 + + Training_Total_Losses, Training_Running_Losses = self.Model_Branch(Input_Images, Mask_Ground_Truth_Image, Training_Running_Losses) + Training_Total_Losses.backward() + + Optimizer.step() + epoch_iterator = self.Calculate_Progress_And_Timing(Input_Images, self.train_subset, Training_Total_Losses, epoch_iterator, Start_Time) + + Training_Losses, Training_Running_Losses = self.Calculate_Average_Scores(self.train_loader, Training_Running_Losses, Training_Losses) + + # Validation step + self.Model.eval() + epoch_iterator_Validation = tqdm(self.val_loader, desc=f"\tValidation-Fold {Fold + 1}/5, Epoch [{epoch + 1}/{self.epoch}]") + with torch.no_grad(): + for Input_Images, Mask_Ground_Truth_Image, Labels, File_Name, File_Classes in epoch_iterator_Validation: + Validation_Total_Losses, Validation_Running_Losses = self.Model_Branch(Input_Images, Mask_Ground_Truth_Image, Validation_Running_Losses) + + # 添加Start_Time參數 + Start_Time = time.time() + epoch_iterator_Validation = self.Calculate_Progress_And_Timing(Input_Images, self.val_subset, Validation_Total_Losses, epoch_iterator_Validation, Start_Time) + + Validation_Losses, Validation_Running_Losses = self.Calculate_Average_Scores(self.val_loader, Validation_Running_Losses, Validation_Losses) + print(f"Traini Loss: {Training_Running_Losses:.4f}, Validation Loss: {Validation_Running_Losses:.4f}\n") + + # Early stopping + early_stopping(Validation_Running_Losses, self.Model, model_path) + if early_stopping.early_stop: + print(f"Early stopping triggered in Fold {Fold + 1} at epoch {epoch + 1}") + break + + # Scheduler step + scheduler.step(Validation_Running_Losses) + + Total_Epoch = epoch + 1 + best_val_loss = early_stopping.best_loss + return model_path, Training_Losses, Validation_Losses, Total_Epoch, best_val_loss + + def Construct_Segment_Model_CUDA(self): + GaSeg = GastroSegNet() + + # 添加輸出模型摘要的功能 + print("\n==== GastroSegNet 模型摘要 ====\n") + print(f"輸入通道數: {GaSeg.encoder[0].conv[0].in_channels}") + print(f"輸出通道數: {GaSeg.final_conv.out_channels}") + + # 計算總參數量 + total_params = sum(p.numel() for p in GaSeg.parameters() if p.requires_grad) + print(f"可訓練參數總量: {total_params:,}") + + # 顯示模型結構 + print("\n模型結構:") + print(f"- 編碼器層數: {len(GaSeg.encoder)}") + print(f"- 解碼器層數: {len(GaSeg.decoder)}") + + print("\n特徵通道配置:") + features_str = ", ".join([str(GaSeg.encoder[i].conv[0].out_channels) for i in range(len(GaSeg.encoder))]) + print(f" - 編碼器特徵通道: {features_str}") + print(f" - 瓶頸層特徵通道: {GaSeg.bottleneck.conv[0].out_channels}") + + print("\n==== 摘要結束 ====\n") + + return self.Convert_Model_To_CUDA(GaSeg) + + def Convert_Model_To_CUDA(self, model): + if torch.cuda.device_count() > 1: + model = nn.DataParallel(model) + + model = model.to(self.device) + + return model + + def Model_Branch(self, Input_Images, Mask_Ground_Truth_Image, running_loss, Save_Dir = None, return_processed_image=False, file_names=None, Classes=None): + # 直接將張量移到設備上,不需要重新創建 + Input_Images.requires_grad = False + Input_Images = Input_Images.to(self.device) + Segmentation_Output = self.Model(Input_Images) + + # 如果需要返回處理後的圖像(用於推理階段) + if return_processed_image: + # 調整模型產出影像大小 + Segmentation_Output = self.Compare_Image_And_Resize_It(Segmentation_Output, Input_Images) + # 處理分割輸出,選擇候選框並將框外像素變黑,同時保存邊界框圖像 + return self.process_segmentation_output(Input_Images, Segmentation_Output, Save_Dir, save_bbox_images=True, file_names=file_names, Classes=Classes) + + Mask_Ground_Truth_Image = Mask_Ground_Truth_Image.to(self.device) + # 調整模型產出影像大小 + Segmentation_Output = self.Compare_Image_And_Resize_It(Segmentation_Output, Mask_Ground_Truth_Image) + + Losses = self.Losses(Segmentation_Output, Mask_Ground_Truth_Image) + # 計算損失(不需要手動設置requires_grad,因為損失計算會自動處理梯度) + running_loss += Losses.item() + return Losses, running_loss + + def Compare_Image_And_Resize_It(self, Image, Target): # 調整兩張影像大小到一樣 + # 檢查Target的維度 + if Target.dim() < 3: + # 如果Target是2D張量,將其擴展為4D張量 [batch_size, channels, height, width] + Target = Target.unsqueeze(0).unsqueeze(0) + elif Target.dim() == 3: + # 如果Target是3D張量,將其擴展為4D張量 [batch_size, channels, height, width] + Target = Target.unsqueeze(0) + + # 獲取目標尺寸 + target_height = Target.size(-2) # 使用倒數第二維作為高度 + target_width = Target.size(-1) # 使用倒數第一維作為寬度 + + # 調整Image大小 + Image = torch.nn.functional.interpolate(Image, size=(target_height, target_width), mode='nearest') + + # 動態調整通道維度 + if Image.size(1) != Target.size(1) and Target.dim() >= 3: + conv = torch.nn.Conv2d(Image.size(1), Target.size(1), kernel_size=1).to(self.device) + Image = conv(Image) + + return Image + + def Losses(self, Segmentation_Output_Image, Segmentation_Mask_GroundTruth_Image): + criterion = Segmentation_Loss() + Loss = criterion(Segmentation_Output_Image, Segmentation_Mask_GroundTruth_Image) + return Loss + + def Record_Average_Losses(self, DataLoader): + loss = 0.0 + losses = [] + + # Calculate average validation loss + loss /= len(DataLoader) + losses.append(loss) + + return losses + + def Calculate_Progress_And_Timing(self, inputs, Subset, loss, epoch_iterator, Start_Time): + # Calculate progress and timing + total_samples = len(Subset) + processed_samples = 0 + + processed_samples += inputs.size(0) # Use size(0) for batch size + + # Calculate progress and timing + elapsed_time = time.time() - Start_Time + iterations_per_second = processed_samples / elapsed_time if elapsed_time > 0 else 0 + eta = (total_samples - processed_samples) / iterations_per_second if iterations_per_second > 0 else 0 + time_str = f"{int(elapsed_time//60):02d}:{int(elapsed_time%60):02d}<{int(eta//60):02d}:{int(eta%60):02d}" + + # Calculate batch metrics using PSNR/SSIM loss + batch_loss = loss.item() + + # Update progress bar with PSNR/SSIM loss + epoch_iterator.set_postfix_str( + f"{processed_samples}/{total_samples} [{time_str}, {iterations_per_second:.2f}it/s, " + f"loss={batch_loss:.3f}]" + ) + + return epoch_iterator + + def Calculate_Average_Scores(self, Data_Loader, Running_Losses, Losses): + Running_Losses /= len(Data_Loader) + Losses.append(Running_Losses) + + return Losses, Running_Losses + + def process_segmentation_output(self, input_images, segmentation_output, bbox_save_dir = None, save_bbox_images=True, file_names=None, Classes = None): + """處理分割輸出,選擇候選框並將框外像素變黑,同時保存邊界框圖像 + + Args: + input_images: 原始輸入圖像 [B, C, H, W] + segmentation_output: 分割模型輸出 [B, 1, H, W] + save_bbox_images: 是否保存邊界框圖像 + file_names: 圖像文件名列表,用於保存邊界框圖像 + + Returns: + processed_images: 處理後的圖像,框外像素變黑 [B, 3, H, W] (始終確保輸出是3通道) + """ + + # 將輸出轉換為二值掩碼 (閾值為0.5) + Batch_Size_Of_Image = segmentation_output.size(0) + binary_masks = (torch.sigmoid(segmentation_output) > 0.5).float() + + # 創建一個輸出張量,確保始終是3通道 + # 獲取批次大小、高度和寬度 + Batch_Size_Of_Image, _, height, width = input_images.size() + + # 創建3通道的輸出張量,不管輸入是幾個通道,輸出都是3通道 + processed_images = torch.zeros(Batch_Size_Of_Image, 3, height, width, device=input_images.device) + + # 對批次中的每張圖像進行處理 + for Batch_Size in range(Batch_Size_Of_Image): + # 創建保存邊界框圖像的目錄 + new_bbox_save_dir = bbox_save_dir + new_bbox_save_dir = os.path.join(new_bbox_save_dir, Classes[Batch_Size]) + if save_bbox_images and not os.path.exists(new_bbox_save_dir): + os.makedirs(new_bbox_save_dir, exist_ok=True) + print(f"創建邊界框圖像保存目錄: {new_bbox_save_dir}") + + # 獲取當前圖像的二值掩碼並轉換為numpy數組 + mask = binary_masks[Batch_Size, 0].cpu().numpy().astype(np.uint8) + + # 使用連通區域分析找出所有候選區域 + labeled_mask, num_labels = measure.label(mask, return_num=True, connectivity=2) + + if num_labels > 0: + # 計算每個區域的面積 + regions = measure.regionprops(labeled_mask) + + # 根據面積排序區域(從大到小) + regions.sort(key=lambda x: x.area, reverse=True) + + # 選擇最大的區域作為最終掩碼 + if len(regions) > 0: + # 創建一個新的掩碼,只包含最大的區域 + final_mask = np.zeros_like(mask) + for coords in regions[0].coords: + final_mask[coords[0], coords[1]] = 1 + + # 獲取最大區域的邊界框 + bbox = regions[0].bbox # (min_row, min_col, max_row, max_col) + + # 將最終掩碼轉換回PyTorch張量 + final_mask_tensor = torch.from_numpy(final_mask).float().to(self.device) + + # 確保掩碼與輸入圖像的尺寸匹配 + if final_mask_tensor.shape != input_images[Batch_Size, 0].shape: + # 調整掩碼大小以匹配輸入圖像 + final_mask_tensor = torch.nn.functional.interpolate( + final_mask_tensor.unsqueeze(0).unsqueeze(0), + size=input_images[Batch_Size, 0].shape, + mode='nearest' + ).squeeze(0).squeeze(0) + + # 將掩碼應用到原始圖像上(保留框內像素,將框外像素變黑) + # 處理不同通道數的輸入圖像 + if input_images.size(1) == 1: # 單通道輸入 + # 將單通道複製到3個通道 + for Channel in range(3): + processed_images[Batch_Size, Channel] = input_images[Batch_Size, 0] * final_mask_tensor + elif input_images.size(1) == 3: # 三通道輸入 + # 直接複製三個通道 + for Channel in range(3): + processed_images[Batch_Size, Channel] = input_images[Batch_Size, Channel] * final_mask_tensor + else: # 其他通道數(不太可能,但為了健壯性) + # 取前三個通道或複製第一個通道 + for Channel in range(3): + if Channel < input_images.size(1): + processed_images[Batch_Size, Channel] = input_images[Batch_Size, Channel] * final_mask_tensor + else: + processed_images[Batch_Size, Channel] = input_images[Batch_Size, 0] * final_mask_tensor + + # 保存帶有邊界框的圖像 + if save_bbox_images: + # 將輸入圖像轉換為numpy數組並調整為適合顯示的格式 + img_tensor = input_images[Batch_Size].clone().detach().cpu() + img_np = img_tensor.permute(1, 2, 0).numpy() + + # 將圖像從[0,1]範圍轉換為[0,255]範圍 + img_np = (img_np * 255).astype(np.uint8) + + # 確保圖像是連續的內存塊 + img_np = np.ascontiguousarray(img_np) + + # 如果圖像是單通道的,轉換為三通道 + if img_np.shape[2] == 1: + img_np = cv2.cvtColor(img_np, cv2.COLOR_GRAY2BGR) + elif img_np.shape[2] == 3: + # 確保是BGR格式(OpenCV默認格式) + img_np = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR) + + # 繪製邊界框 + min_row, min_col, max_row, max_col = bbox + cv2.rectangle(img_np, (min_col, min_row), (max_col, max_row), (0, 255, 0), 2) + + # 生成保存文件名 + if file_names is not None and Batch_Size < len(file_names): + # 使用提供的文件名 + file_name = os.path.basename(file_names[Batch_Size]) + save_path = os.path.join(new_bbox_save_dir, f"bbox_{file_name}.png") + else: + # 使用索引作為文件名 + save_path = os.path.join(new_bbox_save_dir, file_names) + + # 保存圖像 (已經是BGR格式,直接保存) + cv2.imwrite(save_path, img_np) + print(f"已保存邊界框圖像: {save_path}") + else: + # 如果沒有找到區域,則保留原始圖像,但確保是3通道 + if input_images.size(1) == 1: # 單通道輸入 + # 將單通道複製到3個通道 + for Channel in range(3): + processed_images[Batch_Size, Channel] = input_images[Batch_Size, 0] + elif input_images.size(1) == 3: # 三通道輸入 + # 直接複製三個通道 + processed_images[Batch_Size] = input_images[Batch_Size] + else: # 其他通道數 + # 取前三個通道或複製第一個通道 + for Channel in range(3): + if Channel < input_images.size(1): + processed_images[Batch_Size, Channel] = input_images[Batch_Size, Channel] + else: + processed_images[Batch_Size, Channel] = input_images[Batch_Size, 0] + else: + # 如果沒有找到任何區域,則保留原始圖像,但確保是3通道 + if input_images.size(1) == 1: # 單通道輸入 + # 將單通道複製到3個通道 + for Channel in range(3): + processed_images[Batch_Size, Channel] = input_images[Batch_Size, 0] + elif input_images.size(1) == 3: # 三通道輸入 + # 直接複製三個通道 + for Channel in range(3): + processed_images[Batch_Size, Channel] = input_images[Batch_Size, Channel] + else: # 其他通道數 + # 取前三個通道或複製第一個通道 + for Channel in range(3): + if Channel < input_images.size(1): + processed_images[Batch_Size, Channel] = input_images[Batch_Size, Channel] + else: + processed_images[Batch_Size, Channel] = input_images[Batch_Size, 0] + + # 在沒有候選區域的情況下也保存處理後的圖像 + if save_bbox_images: + # 轉換為可保存的numpy格式(與上方保存邊界框圖像一致的流程) + img_tensor = processed_images[Batch_Size].clone().detach().cpu() + img_np = img_tensor.permute(1, 2, 0).numpy() + img_np = (img_np * 255).astype(np.uint8) + img_np = np.ascontiguousarray(img_np) + + # 保證三通道BGR格式 + if img_np.shape[2] == 1: + img_np = cv2.cvtColor(img_np, cv2.COLOR_GRAY2BGR) + elif img_np.shape[2] == 3: + img_np = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR) + + # 生成保存文件名(使用提供的檔名或索引),並標記為無邊界框 + if file_names is not None and isinstance(file_names, (list, tuple)) and Batch_Size < len(file_names): + file_name = os.path.basename(file_names[Batch_Size]) + save_path = os.path.join(new_bbox_save_dir, f"no_bbox_{file_name}.png") + else: + base_name = file_names if isinstance(file_names, str) and len(file_names) > 0 else f"no_bbox_{Batch_Size}.png" + save_path = os.path.join(new_bbox_save_dir, base_name) + + cv2.imwrite(save_path, img_np) + print(f"已保存無邊界框圖像: {save_path}") + + def evaluate_on_test(self, model_path, test_dataloader): + if test_dataloader is None: + raise ValueError("Test dataloader is required for evaluation.") + + self.Model = self.Construct_Segment_Model_CUDA() + self.Model.load_state_dict(torch.load(model_path)) + self.Model.eval() + Test_Losses = [] + + test_loss = 0.0 + with torch.no_grad(): + for Input_Images, Mask_Ground_Truth_Image, _, _, _ in test_dataloader: + losses, test_loss = self.Model_Branch(Input_Images, Mask_Ground_Truth_Image, test_loss) + + losses, test_loss = self.Calculate_Average_Scores(test_dataloader, test_loss, Test_Losses) + + print(f"Average Test Loss: {test_loss}") + return test_loss \ No newline at end of file diff --git a/experiments/Training/__init__.py b/experiments/Training/__init__.py new file mode 100644 index 0000000..13fa926 --- /dev/null +++ b/experiments/Training/__init__.py @@ -0,0 +1,2 @@ +from ..Models.GastroSegNet_Model import GastroSegNet +from ..Models.Xception_Model_Modification import Xception \ No newline at end of file diff --git a/experiments/Training/__pycache__/Identification_Block_Training.cpython-311.pyc b/experiments/Training/__pycache__/Identification_Block_Training.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..10e85ce22e77fca78a41a6c100d20b76a92f1de4 GIT binary patch literal 29242 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 literal 0 HcmV?d00001 diff --git a/experiments/Training/__pycache__/Segmentation_Block_Training.cpython-311.pyc b/experiments/Training/__pycache__/Segmentation_Block_Training.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..87d59ce1d4f6a452b0581252ba1046d50afe116c GIT binary patch literal 27038 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 Hkbe0;q}pX9 literal 0 HcmV?d00001 diff --git a/experiments/Training/__pycache__/__init__.cpython-311.pyc b/experiments/Training/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b01b9c50eeb2bfbab4f59a41c7845861db1da628 GIT binary patch literal 351 zcmZ3^%ge<81Z`LMXXFFv#~=<2FhLog<$#Ro3@HpLj5!Rsj8Tk?AU0DDQ!aB9Gmy<3 z%%I8g5~Ny_@fMGJVsS}PesF5KUup@E&k>QFT2PXipXaB^a!b-TKP5G%SPxlEJXoxV z8L0i15>y_h2OcjWWcUmu8GZ%pXXNLm>X&C^mZWB97G>rkGmA^| za}$#@;*%5el2eQH11d}Mi;^?+Q!5Hmi!yUl^Gb^KLy8hJ^D^_&_2c7#bV+=?UP0wA s4x8Nkl+v73yCP7~FamM0K9Kmp%*e=igTdqiD!Rd7c>x;M1& literal 0 HcmV?d00001 diff --git a/experiments/__pycache__/Model_All_Step.cpython-311.pyc b/experiments/__pycache__/Model_All_Step.cpython-311.pyc index 2f0ba02a886cd71b496fc65029e63eaed8a5f8ae..44c7c715a77c2c5535b8fe7495098bdc3e3bd1dc 100644 GIT binary patch delta 8292 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 OSShRh9fneIivI-@r+fVX literal 0 HcmV?d00001 diff --git a/experiments/__pycache__/__init__.cpython-311.pyc b/experiments/__pycache__/__init__.cpython-311.pyc index d2d209603266122c16834fcceb26343e40c8038e..82a2d91ac9887328a6def6801583b2d2001deb17 100644 GIT binary patch delta 89 zcmZ3*xSf$_IWI340}$+6z?m_T$Jp_gmwrZmZmNEHMrKKBc4kp#9x}7IBtJJXIU_zf hF)ul_NI#&mB)=#*LqD~mAhjqnH#M)MSbt)%IRH#5AYT9g delta 76 zcmdnaxQdZyIWI340}y2C1gB5rF*f;X1?0F`#T1w1=O!j+#3v`_C8rj}1Qg|`7bWH@ d=qkKe(*9!c-k8*ig4CkS+|<01;+TmI<^Xu;8v+0T diff --git a/experiments/__pycache__/__init__.cpython-312.pyc b/experiments/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c5515cf2d292e4a21f5b588cea211a922bb5a295 GIT binary patch literal 169 zcmX@j%ge<81bY{7W`O9&AOanHW&w&!XQ*V*Wb|9fP{ah}eFmxd<>6u#6Ht_&UX+-d znU@|@T#}!gn4A%xoS2uKS_G4c52!53F9HhtrIyE}RurTbW#*>ll@!Os$7kkcmc+;F j6;$5hu*uC&Da}c>D`Ev2%m~EAAjU^#Mn=XWW*`dyZ>cP9 literal 0 HcmV?d00001 diff --git a/experiments/__pycache__/__init__.cpython-313.pyc b/experiments/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f5b3a893bcd00990e2a3adb669490b66c70ce1c GIT binary patch literal 169 zcmey&%ge<81bY{7W`O9&AOZ#$p^VQgK*m&tbOudEzm*I{OhDdekkl;?7ps_nqWtut z#N5oh^qAt3{M^LkjQHflyyVm(m`r>?Wl4S!P}ncEJSMfGAhjqnH#M)MI3_+mGcU6w lK3=b&@)n0pZhlH>PO4oIE6`w&#l;}TM`lJw#v*1Q3jlLfEMouw literal 0 HcmV?d00001 diff --git a/experiments/__pycache__/experiment.cpython-311.pyc b/experiments/__pycache__/experiment.cpython-311.pyc index 722d63f79be8a78935a8c0ed15cd66d298258578..ab0e9edd5a9357873a44d38d9a997beec3b94fc8 100644 GIT binary patch literal 23799 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 a=Y8jD^hB%zkBP{aucWxIpOA#G{{I4^*cRmg literal 13205 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 OzY){_vP`Zxef|$Nx)UY< diff --git a/experiments/__pycache__/experiment.cpython-312.pyc b/experiments/__pycache__/experiment.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82deb95fc5ca807378af190904e8a7071df26a5b GIT binary patch literal 13669 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 literal 0 HcmV?d00001 diff --git a/experiments/__pycache__/experiment.cpython-313.pyc b/experiments/__pycache__/experiment.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a970e78f9a39ab564b68381e044bc65a62c8e524 GIT binary patch literal 12811 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®38iQ}gj55%aQk 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 literal 3406 zcma)8-%r~{96u*cV!#ww35AqG7;RZVf&SNAZk&2@P6{VLfdmWujd6t7u(MHS^qSrWeyq@*sZieQgIhNR&kYubHFA@no#80qk~ zn_gnMfZVHGEz#Nb2(3YP!(l0;2OI`Xk-4lUQljUX*FD|>;_RJ8dbMqd(3CTRd+Y@? z<=AtKZ7P??Eos=*p$7(VhCo8hfaVD+HiG;}tSmJewOQ@n0H!CN2&F*^? z#bgFWNzr9}&h$(QW?jF?LuSrM{WGyqRgL$GW=$-vPVjM#pNVlv5SjiVSPYL%_LeMy zFBj+MB;eF(JvprxIQp72bi<^v6rVN&W9p=y;AhQ%W_K=PH3{}+K+Ja{v`K4HeA28^ zrW2eH=QT~z%*uiOQEtQ<)~w+2Vvf^Dkl}E6>D}d?J1V}dC3!*W8PnASFWllT@QNVe zo>8pEFrVN?=X4c=cv!mABhA7V$q9&7>q!>ma3Q65cXAGs1e|Z$dq2DFt^5eo+Mht) zE}?Cv`maMRt8|t*VK66NFx{I>ca}M2FsCxislWZ`XsZ$GTEG1K<4ovMHgw4dT}sgp zYPOHHu6*~)&6S&kF_=)!j~YU$%I(%RqxJOf7qhKrjn=a%+F+Wun_E@}SH<;<+2&rO zxtGYAY}wb@<}*g~8A}FJ1&^c$mIu>=FlNQ}k*4(gYTNQ+dJ$MQ&$ch$P2VMK3Vyq= ze&i}Sa-sKH0lIy}QQef#^-%|U1E%z-?FoIKn-#5ZOGdsoWeSX#& zowD>FmQduMQo|8HCiMZ6%ZiT>QcuWHLV`dd9^4EslbY2?NZ~LJ6E-lZ;yXMR=Nrq? zr=a;1%(OU=CA7uXJ{-9}@}xh@wis+niUPq4HoVD(SL?EDyTP_wqKAX`2Oo(q8ag%` zI@YOdL#NTunPs~Swkxk5xEP9YhC6-h=T10 zUdRuRmFDXpb>r%kV@Hq>9`7@H4H9g_NiskhCxJ^5xx~{a`Va7QQv3i<|AC&){4P%? zq05kp#Ar2_{eg&G#A%m(5u*cuR1kOZTgZjd&aS~%frHXzYbql2|Fd_{S365uj<3?~C%6Da6 zckQ`1Gj=^Q&S!!X+2Di`oG9wXo*&L!zmef5GC?656pWxibg$|g_8`RaLVAG!!mGy6 z3cGq0ic4ds(bx&1>Q{$@>9fn{(&vC-wo92UhE37d1$Ds(IaTXkk>n%a-(v{3L-(mu zDt)p79|fi5(ke6a^{&k*l*v(W)kwxdnRF%`j`;9NkYQ49Fu~zswZi>`Z6hR1NS95% zgpSq+#4b!rDCc2))j8yl5JlK>k{^zYL~5t?_0X*-R@z{a>82l+4mC7i2(202t9ZwJ zmar^7$6tXx*(2>PkervIs4W!Cxc^(IYRUTLE>leu)W~x32&d;>6ZxB>@{<}0mS0X@ M6WN=66jogS0%4!Np#T5? diff --git a/experiments/__pycache__/pytorch_Model.cpython-312.pyc b/experiments/__pycache__/pytorch_Model.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0845c4289d55c06a7b9e74639e7183f38006c3ea GIT binary patch literal 2211 zcma)7%}*Og6rZuz_5w=`ZTJiy8&VOuB&aPtRZ$w$G{h zB2^AZHEN?IiYkbD2!|X}kz)`2ABZYeMx~n2Q`JLmm7rDBQ{U_d-cl-cWX=1W-@NyB z-t$&tV?BcP)7CrlFJcJ&%7kEn?5_Qffvh0~DOg8&oWa=RBbkV+i)NxgBRZFlWnvgb z&dB}Ag4 z3|3GkQb9Sa;1wS3kF1~!S3yfS6PrY-C~X2XEvKo6br{<*~Fd=;((026+&nabTxVuAtc9K#9C&J!Kwd^=puv= z<3|ur9D~>s=xVf9E9tP3p&0sVo&l#MLX~(e(1y zI40-S8}Od%3q-YvtQo3OZW@^w7RQTrp=gU^@XW39>!V$0t;T4>BF7F0smJEpuOX@+J?66I_ypQl2WsNf~#Sw9i>%xV2i+42=M zVi=T9!=<)nmuMuHrOm^N3_Y@_4lmA4n5O==LX&g4c~jOUd2voEfQrVwn5Z!C1}y1v zNhMT(kRT^t;;yTsQ zPV!huvRLS%c;~Ncm*1P6Am$vA^O`X?YuRRA&dy6&*~qFSut*an+a#bKQ*X_xOHdsx z4>?-11z+!eoxwthutqI+9Gwq?K^0kVTU)Tbx`X!k#+?&A8=S)r?(lCN#L=nV-Od50 zbKu$N4_(f=E8CNw>~v07xUZ9Y-Mx=z9?g9FX@$F&Tutuqo!~9@?e-2iy+hxRZVyj7 z@7}2PPF1)azH6_m=W+T``iZ_h^r6##<+-puwcuR+tlFhBb4SR0)#*<^zpy=>cRn(z zU8ZXW;Fh+vkq09W({OX$UR%dn`9XQ(^uyaA3cmQ{+|w_dzKhki_bc38VIR^#$4|f? z!Lo*6-uN?uc?N442mNvzg9rN_N7fOK;2$I81?LXuW=&l?_m3M6=i70fZVZR>>pwg& zOn*FHErV>shDu>{DEAeX}YIc!tr{ z(e>u9#{E;>j?ld>R|OH|WK)GFBH*Xutgj82CD7OP5^Lt7&UitRJ}=6;XK~*$IRpN* z(eInAs_T-J!h}ssi+$8fZgTFda5wfjEH-0bt)PQQGIk07*%yyByVtr7DW39fFAW+7 zVUC1VopKA7Y0#5JThpzJ$#^6=cc@)x}DFOu^B#A32e!}fa= fWBdzhd4U?>_ZvEYz_sJ%`(&;3p!5d<)`j>R((T!n literal 0 HcmV?d00001 diff --git a/experiments/experiment.py b/experiments/experiment.py index 878d080..d3319d8 100644 --- a/experiments/experiment.py +++ b/experiments/experiment.py @@ -1,26 +1,23 @@ -from torchinfo import summary -from sklearn.model_selection import KFold -from sklearn.metrics import confusion_matrix - from Training_Tools.PreProcess import Training_Precesses -from experiments.pytorch_Model import ModifiedXception -from experiments.Model_All_Step import All_Step from Load_process.Load_Indepentend import Load_Indepentend_Data from _validation.ValidationTheEnterData import validation_the_enter_data -from Load_process.file_processing import Process_File -from draw_tools.Grad_cam import GradCAM -from draw_tools.draw import plot_history, draw_heatmap -from Calculate_Process.Calculate import Calculate +from Load_process.LoadData import Loding_Data_Root +from utils.Stomach_Config import Training_Config, Loading_Config, Save_Result_File_Config +from experiments.Training.Identification_Block_Training import Identification_Block_Training_Step +from experiments.Training.Segmentation_Block_Training import Segmentation_Block_Training_Step +from Load_process.LoadData import Load_Data_Prepare +from merge_class.merge import merge +from model_data_processing.processing import make_label_list +from sklearn.metrics import accuracy_score import numpy as np import torch import torch.nn as nn import time import pandas as pd -import datetime class experiments(): - def __init__(self, Image_Size, Model_Name, Experiment_Name, Epoch, Train_Batch_Size, tools, Number_Of_Classes, status): + def __init__(self, Xception_Training_Data, Xception_Training_Label, Xception_Training_Mask_Data, tools, Number_Of_Classes, status): ''' # 實驗物件 @@ -48,155 +45,404 @@ class experiments(): * record_matrix_image: 劃出混淆矩陣(熱力圖) * record_everyTime_test_result: 記錄我單次的訓練結果並將它輸出到檔案中 ''' + self.model_name = Training_Config["Model_Name"] # 取名,告訴我我是用哪個模型(可能是預處理模型/自己設計的模型) + self.epoch = Training_Config["Epoch"] + self.train_batch_size = Training_Config["Train_Batch_Size"] + self.Image_Size = Training_Config["Image_Size"] - self.Topic_Tool = tools - - self.validation_obj = validation_the_enter_data() # 呼叫驗證物件 - self.cut_image = Load_Indepentend_Data(self.Topic_Tool.Get_Data_Label(), self.Topic_Tool.Get_OneHot_Encording_Label()) # 呼叫切割影像物件 - - self.model_name = Model_Name # 取名,告訴我我是用哪個模型(可能是預處理模型/自己設計的模型) - self.experiment_name = Experiment_Name - self.epoch = Epoch - self.train_batch_size = Train_Batch_Size self.Number_Of_Classes = Number_Of_Classes - self.Image_Size = Image_Size - - self.Grad = "" + self.Xception_Training_Data = Xception_Training_Data + self.Xception_Training_Label = Xception_Training_Label + self.Xception_Training_Mask_Data = Xception_Training_Mask_Data + self.Topic_Tool = tools self.Status = status + self.Grad = None + self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + self.validation_obj = validation_the_enter_data() # 呼叫驗證物件 + self.cut_image = Load_Indepentend_Data(self.Topic_Tool.Get_OneHot_Encording_Label()) # 呼叫切割影像物件 pass - def processing_main(self, Training_Data, Training_Label): - Train, Test = self.Topic_Tool.Get_Save_Roots(self.Status) - Calculate_Process = Calculate() - - print(f"Training Data Content: {Training_Data[0]}") + def processing_main(self): + print(f"Testing Data Prepring!!!!") start = time.time() - self.cut_image.process_main(Test) # 呼叫處理test Data與Validation Data的function + self.cut_image.process_main(Loading_Config["Test_Data_Root"], Loading_Config["Annotation_Testing_Root"]) # 呼叫處理test Data與Validation Data的function end = time.time() print("讀取testing與validation資料(154)執行時間:%f 秒\n" % (end - start)) # 將處理好的test Data 與 Validation Data 丟給這個物件的變數 - self.test, self.test_label = self.cut_image.test, self.cut_image.test_label - # self.test = self.test.permute(0, 3, 1, 2) - # Training_Data = Training_Data.permute(0, 3, 1, 2) + print("Testing Data is Prepared finish!!!!") PreProcess = Training_Precesses(self.Image_Size) - File = Process_File() - # print(f"Dataset_Data: \n{self.test}\nLabel: \n{self.test_label}\n") - Testing_Dataset = PreProcess.Setting_DataSet(self.test, self.test_label, "Transform") - self.Test_Dataloader = PreProcess.Dataloader_Sampler(Testing_Dataset, 1, False) - # for images, labels in self.Test_Dataloader: - # print(images.shape) - - # Lists to store metrics across all folds - all_fold_train_losses = [] - all_fold_val_losses = [] - all_fold_train_accuracies = [] - all_fold_val_accuracies = [] - - # Define K-fold cross-validator - K_Fold = KFold(n_splits = 5, shuffle = True, random_state = 42) - # Get the underlying dataset from PreProcess_Classes_Data - training_dataset = PreProcess.Setting_DataSet(Training_Data, Training_Label, "Transform") - # K-Fold loop - for fold, (train_idx, val_idx) in enumerate(K_Fold.split(training_dataset)): - - cnn_model = self.construct_model() # 呼叫讀取模型的function - print(summary(cnn_model, input_size=(int(self.train_batch_size / 2), 3, self.Image_Size, self.Image_Size))) - for name, parameters in cnn_model.named_parameters(): - print(f"Layer Name: {name}, Parameters: {parameters.size()}") - - TargetLayer = cnn_model.base_model.conv4.pointwise - Grad = GradCAM(cnn_model, TargetLayer) - - step = All_Step(cnn_model, self.epoch, self.Number_Of_Classes, self.model_name, self.experiment_name) - print("\n\n\n讀取訓練資料執行時間:%f 秒\n\n" % (end - start)) - print(f"\nStarting Fold {fold + 1}/5") - - # Create training and validation subsets for this fold - train_subset = torch.utils.data.Subset(training_dataset, train_idx) - val_subset = torch.utils.data.Subset(training_dataset, val_idx) - - # print(f"Dataset_Data: \n{train_subset.dataset.data}\nLabel: \n{train_subset.dataset.labels}\n") - - # Wrap subsets in DataLoaders (use same batch size as original) - train_loader = PreProcess.Dataloader_Sampler(train_subset , self.train_batch_size, False) - val_loader = PreProcess.Dataloader_Sampler(val_subset, self.train_batch_size, False) - - cnn_model, model_path, train_losses, val_losses, train_accuracies, val_accuracies, Total_Epoch = step.Training_Step(train_subset, val_subset, train_loader, val_loader, self.model_name, fold, TargetLayer) - - # Store fold results - all_fold_train_losses.append(train_losses) - all_fold_val_losses.append(val_losses) - all_fold_train_accuracies.append(train_accuracies) - all_fold_val_accuracies.append(val_accuracies) - - Losses = [train_losses, val_losses] - Accuracies = [train_accuracies, val_accuracies] - plot_history(Total_Epoch, Losses, Accuracies, "train" + str(fold), self.experiment_name) # 將訓練結果化成圖,並將化出來的圖丟出去儲存 - - cnn_model.load_state_dict(torch.load(model_path)) - True_Label, Predict_Label, loss, accuracy, precision, recall, AUC, f1 = step.Evaluate_Model(cnn_model, self.Test_Dataloader) - - Grad.Processing_Main(self.Test_Dataloader, f"../Result/GradCAM_Image/Testing/GradCAM_Image({str(datetime.date.today())})/fold-{str(fold)}") - Calculate_Process.Append_numbers(loss, accuracy, precision, recall, AUC, f1) - - self.record_matrix_image(True_Label, Predict_Label, self.experiment_name, fold) - print(self.record_everyTime_test_result(loss, accuracy, precision, recall, AUC, f1, fold, self.experiment_name)) # 紀錄當前訓練完之後的預測結果,並輸出成csv檔 + # 分類正常跟其他資料集的測試資料 + Normal_And_Other_Test_Data = self.cut_image.test.copy() + normal_vs_others_Test_labels = [] - # Aggregate results across folds - avg_train_losses = np.mean([losses[-1] for losses in all_fold_train_losses]) - avg_val_losses = np.mean([losses[-1] for losses in all_fold_val_losses]) - avg_train_accuracies = np.mean([acc[-1] for acc in all_fold_train_accuracies]) - avg_val_accuracies = np.mean([acc[-1] for acc in all_fold_val_accuracies]) + # 將標籤轉換為二分類:Normal(1) vs Others(0) + for label in self.cut_image.test_label: + if np.argmax(label) == 1: # Normal_Crop + # Normal類別標籤為[0, 1] + normal_vs_others_Test_labels.append(np.array([0, 1])) + else: + # 其他類別標籤為[1, 0] + normal_vs_others_Test_labels.append(np.array([1, 0])) + + # 創建Normal vs Others的測試數據集 + normal_vs_others_test_dataset = PreProcess.Setting_DataSet( + Normal_And_Other_Test_Data, + normal_vs_others_Test_labels, + None, + "Transform" + ) + normal_vs_others_test_dataloader = PreProcess.Dataloader_Sampler(normal_vs_others_test_dataset, 1, False) - print(f"\nCross-Validation Results:") - print(f"Avg Train Loss: {avg_train_losses:.4f}, Avg Val Loss: {avg_val_losses:.4f}") - print(f"Avg Train Acc: {avg_train_accuracies:.4f}, Avg Val Acc: {avg_val_accuracies:.4f}") + # ========================================================================================================================================================================================= - Calculate_Process.Calculate_Mean() - Calculate_Process.Calculate_Std() + # 分類分割模型的測試資料 + # 使用CA資料和Have_Question資料訓練分割模型 + ca_have_question_test_data = [] + ca_have_question_test_labels = [] + + # 篩選CA和Have_Question資料 + for i, label in enumerate(self.cut_image.test_label): + # 檢查是否為CA或Have_Question類別 + if np.argmax(label) == 0 or np.argmax(label) == 2: # stomach_cancer_Crop或Have_Question_Crop + ca_have_question_test_data.append(self.cut_image.test[i]) + ca_have_question_test_labels.append(self.cut_image.test_label[i]) - print(Calculate_Process.Output_Style()) + print(f"CA and Have_Question Test Data Count: {len(ca_have_question_test_data)}") + print(f"CA and Have_Question Test Mask Count: {len(self.cut_image.test_mask)}") + + # 創建CA和Have_Question的訓練數據集 + segumentation_test_dataset = PreProcess.Setting_DataSet( + ca_have_question_test_data, + ca_have_question_test_labels, + self.cut_image.test_mask, + "Transform" + ) + Segumentation_test_dataloader = PreProcess.Dataloader_Sampler(segumentation_test_dataset, 1, False) - File.Save_TXT_File(content = f"\nCross-Validation Results:\nAvg Train Loss: {avg_train_losses:.4f}, Avg Val Loss: {avg_val_losses:.4f}\nAvg Train Acc: {avg_train_accuracies:.4f}, Avg Val Acc: {avg_val_accuracies:.4f}\n", File_Name = "Training_Average_Result") + # ========================================================================================================================================================================================= - pass + # 非胃癌有病與胃癌資料的分類測試資料 + # 準備CA vs Have_Question的訓練數據 + ca_vs_have_question_test_data = [] + ca_vs_have_question_test_labels = [] + + # 篩選CA和Have_Question資料 + for i, label in enumerate(self.cut_image.test_label): + if np.argmax(label) == 0: # stomach_cancer_Crop + ca_vs_have_question_test_data.append(self.cut_image.test[i]) + ca_vs_have_question_test_labels.append(np.array([1, 0])) # CA類別標籤為[1, 0] + elif np.argmax(label) == 2: # Have_Question_Crop + ca_vs_have_question_test_data.append(self.cut_image.test[i]) + ca_vs_have_question_test_labels.append(np.array([0, 1])) # Have_Question類別標籤為[0, 1] + + # 創建CA vs Have_Question的測試數據集 + ca_vs_have_question_test_dataset = PreProcess.Setting_DataSet( + ca_vs_have_question_test_data, + ca_vs_have_question_test_labels, + None, + "Transform" + ) + ca_vs_have_question_test_dataloader = PreProcess.Dataloader_Sampler(ca_vs_have_question_test_dataset, 1, False) - def construct_model(self): - '''決定我這次訓練要用哪個model''' - cnn_model = ModifiedXception(self.Number_Of_Classes) + # ========================================================================================================================================================================================= - if torch.cuda.device_count() > 1: - cnn_model = nn.DataParallel(cnn_model) + # 建立最終測試資料(不含遮罩) + Testing_Data, Testing_Label = self.cut_image.test.copy(), self.cut_image.test_label.copy() + Test_Dataset = PreProcess.Setting_DataSet( + Testing_Data, + Testing_Label, + None, + "Transform" + ) + self.Test_Dataloader = PreProcess.Dataloader_Sampler(Test_Dataset, 1, False) - cnn_model = cnn_model.to(self.device) - return cnn_model + # ========================================================================================================================================================================================= + + print("Training is started!!\n") + + # 創建訓練步驟物件 + identification_Normal_step = Identification_Block_Training_Step(Training_Config["Normal_Experiment_Name"], Save_Result_File_Config["Normal_Identification_Best_Model"]) + identification_CA_step = Identification_Block_Training_Step(Training_Config["CA_Experiment_Name"], Save_Result_File_Config["CA_Identification_Best_Model"]) + segmentation_step = Segmentation_Block_Training_Step(Save_Result_File_Config["Segmentation_Best_Model"]) + + print("\n=== 第一階段:訓練正常資料分類模型 ===\n") + # 第一組:訓練Normal資料和其他資料的分類模型 + print("\n--- Normal vs Others分類模型 ---\n") + + # 準備Normal vs Others的訓練數據 + # 分類testing的資料 + normal_vs_others_data = self.Xception_Training_Data.copy() + normal_vs_others_labels = [] + + # 將標籤轉換為二分類:Normal(1) vs Others(0) + for label in self.Xception_Training_Label: + if np.argmax(label) == 1: # Normal_Crop + # Normal類別標籤為[0, 1] + normal_vs_others_labels.append(np.array([0, 1])) + else: + # 其他類別標籤為[1, 0] + normal_vs_others_labels.append(np.array([1, 0])) + + # 創建Normal vs Others的訓練數據集 + normal_vs_others_dataset = PreProcess.Setting_DataSet( + normal_vs_others_data, + normal_vs_others_labels, + None, + "Transform" + ) + + # 訓練Normal vs Others分類模型 + Best_Normal_Model_Path, Normal_Calculate_Process, Normal_Calculate_Tool = identification_Normal_step.Processing_Main(normal_vs_others_dataset, normal_vs_others_test_dataloader) + + + # 訓練流程:先訓練分割模型,再訓練分類模型 + print("\n=== 第二階段:訓練分割模型 ===\n") + # 使用CA資料和Have_Question資料訓練分割模型 + ca_have_question_data = [] + ca_have_question_labels = [] + + # 篩選CA和Have_Question資料 + for i, label in enumerate(self.Xception_Training_Label): + # 檢查是否為CA或Have_Question類別 + if np.argmax(label) == 0 or np.argmax(label) == 2: # stomach_cancer_Crop或Have_Question_Crop + ca_have_question_data.append(self.Xception_Training_Data[i]) + ca_have_question_labels.append(self.Xception_Training_Label[i]) + + # 創建CA和Have_Question的訓練數據集 + ca_have_question_dataset = PreProcess.Setting_DataSet( + ca_have_question_data, + ca_have_question_labels, + self.Xception_Training_Mask_Data, + "Transform" + ) + + # 執行分割模型訓練,並獲取處理後的圖像 + segmentation_best_model_path, avg_test_loss = segmentation_step.Processing_Main( + ca_have_question_dataset, + return_processed_images=True, + test_dataloader=Segumentation_test_dataloader + ) + + print(f"分割模型訓練完成,模型路徑: {segmentation_best_model_path}") + + # 將處理後的圖像保存起來,用於後續分析或可視化 + # 這裡可以添加保存處理後圖像的代碼,例如使用torchvision.utils.save_image + + print("\n=== 第三階段:訓練CA資料分類模型 ===\n") + # 第二組:訓練CA資料和Have_Question資料的分類模型 + print("\n--- 訓練CA vs Have_Question分類模型 ---\n") + + Load = Loding_Data_Root(Loading_Config["XML_Loading_Label"], Save_Result_File_Config["Segument_Bounding_Box_Image"], None) + CA_Laod_Data_Dict = Load.process_main(False) + + Total_Size_List = [] + Train_Size = 0 + + print("前處理後資料集總數") + for label in Loading_Config["XML_Loading_Label"]: + Train_Size += len(CA_Laod_Data_Dict[label]) + Total_Size_List.append(len(CA_Laod_Data_Dict[label])) + print(f"Labels: {label}, 總數為: {len(CA_Laod_Data_Dict[label])}") + + print("總共有 " + str(Train_Size) + " 筆資料") + + # 做出跟資料相同數量的Label + Classes = [] + Encording_Label = np.array([[1, 0], [0, 1]]) + i = 0 + for encording in Encording_Label: + Classes.append(make_label_list(Total_Size_List[i], encording)) + i += 1 + + # 將資料做成Dict的資料型態 + Prepare = Load_Data_Prepare() + Merge = merge() + Label_Length = len(Loading_Config["XML_Loading_Label"]) + + Prepare.Set_Final_Dict_Data(Loading_Config["XML_Loading_Label"], CA_Laod_Data_Dict, Classes, Label_Length) + Final_Dict_Data = Prepare.Get_Final_Data_Dict() + keys = list(Final_Dict_Data.keys()) + + Training_Data = Merge.merge_all_image_data(Final_Dict_Data[keys[0]], Final_Dict_Data[keys[1]]) # 將訓練資料合併成一個list + for i in range(2, Label_Length): + Training_Data = Merge.merge_all_image_data(Training_Data, Final_Dict_Data[keys[i]]) # 將訓練資料合併成一個list + + Training_Label = Merge.merge_all_image_data(Final_Dict_Data[keys[Label_Length]], Final_Dict_Data[keys[Label_Length + 1]]) #將訓練資料的label合併成一個label的list + for i in range(Label_Length + 2, 2 * Label_Length): + Training_Label = Merge.merge_all_image_data(Training_Label, Final_Dict_Data[keys[i]]) # 將訓練資料合併成一個list + + # 創建CA vs Have_Question的訓練數據集 + ca_vs_have_question_dataset = PreProcess.Setting_DataSet( + Training_Data, + Training_Label, + None, + "Transform" + ) + + # 訓練CA vs Have_Question分類模型 + Best_CA_Model_Path, CA_Calculate_Process, CA_Calculate_Tool = identification_CA_step.Processing_Main(ca_vs_have_question_dataset, ca_vs_have_question_test_dataloader) + + # 顯示訓練完成的指標平均值 + print("\n=== Normal and another的指標平均值 ===\n") + print(f"Normal and another identification result is \n {Normal_Calculate_Process.Output_Style()}\n") + + print("\n=== Normal and another各類別的指標平均值 ===\n") + for Calculate_Every_Class in Normal_Calculate_Tool: + print(f"\nNormal and another identification result is \n {Calculate_Every_Class.Output_Style()}\n") + print("\n\n") + + # 顯示訓練完成的指標平均值 + print("\n=== CA and Have Question的指標平均值 ===\n") + print(f"CA and Have Question identification result is \n {CA_Calculate_Process.Output_Style()}\n") + + print("\n=== CA and Have Question各類別的指標平均值 ===\n") + for Calculate_Every_Class in CA_Calculate_Tool: + print(f"\nCA vs Have_Question identification result is \n {Calculate_Every_Class.Output_Style()}\n") + print("\n") + + # return Best_Normal_Model_Path, Best_CA_Model_Path, segmentation_best_model_path - def record_matrix_image(self, True_Labels, Predict_Labels, model_name, index): - '''劃出混淆矩陣(熱力圖)''' - # 計算混淆矩陣 - matrix = confusion_matrix(True_Labels, Predict_Labels) - draw_heatmap(matrix, model_name, index) # 呼叫畫出confusion matrix的function - - def record_everyTime_test_result(self, loss, accuracy, precision, recall, auc, f, indexs, model_name): - '''記錄我單次的訓練結果並將它輸出到檔案中''' - File = Process_File() + def test_workflow(self, identification_Normal_step, identification_CA_step, segmentation_step, normal_vs_others_model_path, ca_vs_have_question_model_path, segmentation_model_path): + """測試流程: + 1. 先用Normal vs Others模型辨識是Normal資料還是其他資料 + 2. 若辨識為其他資料,或辨識為Normal但F1 score不到50%,進入下一階段 + 3. 將進入下一階段的資料丟到分割模型產生mask並選擇候選框,將框外像素變黑 + 4. 再丟到CA vs Have_Question模型中辨識為CA或Have_Question + """ + print("\n=== 開始測試流程 ===\n") - Dataframe = pd.DataFrame( - { - "model_name" : str(model_name), - "loss" : "{:.2f}".format(loss), - "precision" : "{:.2f}%".format(precision * 100), - "recall" : "{:.2f}%".format(recall * 100), - "accuracy" : "{:.2f}%".format(accuracy * 100), - "f" : "{:.2f}%".format(f * 100), - "AUC" : "{:.2f}%".format(auc * 100) - }, index = [indexs]) - File.Save_CSV_File("train_result", Dataframe) + identification_Normal_step = Identification_Block_Training_Step(Training_Config["Normal_Experiment_Name"], Save_Result_File_Config["Normal_Identification_Best_Model"]) + identification_CA_step = Identification_Block_Training_Step(Training_Config["CA_Experiment_Name"], Save_Result_File_Config["CA_Identification_Best_Model"]) + segmentation_step = Segmentation_Block_Training_Step(Save_Result_File_Config["Segmentation_Best_Model"]) + + # 準備測試結果記錄 + results = [] + PreProcess = Training_Precesses(self.Image_Size) + + # 第一階段:使用Normal vs Others模型進行辨識 + print("\n--- 第一階段:Normal vs Others辨識 ---\n") + + # 載入Normal vs Others模型 + identification_Normal_step.Model.load_state_dict(torch.load(normal_vs_others_model_path)) + identification_Normal_step.Model.eval() + + # 記錄需要進入第二階段的樣本 + second_stage_samples = [] + second_stage_prepare = [] + second_save_classes = [] + second_load_Classes = [] + + with torch.no_grad(): + for i, (images, labels, file_names, file_classes) in enumerate(self.Test_Dataloader): + # 將數據移到設備上 + images = images.to(identification_Normal_step.device) + + # 進行預測 + outputs = identification_Normal_step.Model(images) + Output_Values, predicted = torch.max(outputs, dim=1) + labels = np.argmax(labels.cpu().numpy(), axis=1) + + # 計算F1 score (這裡簡化為判斷是否需要進入第二階段) + # 如果預測為Others(0)或預測為Normal(1)但置信度不高,進入第二階段 + if predicted.item() == 0 or outputs[0][1].item() < 0.5: # Others或Normal但置信度低 + second_stage_samples.append((images, labels, file_names, file_classes)) + second_stage_indices.append(i) + print(f"樣本 {file_names[0]} 需要進入第二階段 (預測={predicted.item()}, 置信度={outputs[0][predicted.item()].item():.4f})") + second_save_classes.append(file_classes[0]) - return Dataframe \ No newline at end of file + # Labels = torch.argmax(labels, dim=1) + Normal_Accuracy = accuracy_score(labels, predicted.cpu().numpy()) + print(f"Normal vs Others 辨識準確率: {Normal_Accuracy:.2f}") + + second_stage_prepare.append((images, labels, file_names, file_classes)) + + for Classes in second_save_classes: + if Classes not in second_load_Classes: + second_load_Classes.append(Classes) + + # 第二階段:使用分割模型產生mask,再使用CA vs Have_Question模型進行辨識 + if second_stage_samples: + print(f"\n--- 第二階段:分割模型產生mask並進行CA vs Have_Question辨識 ---\n") + print(f"共有 {len(second_stage_samples)} 個樣本進入第二階段") + + # 載入分割模型 + segmentation_step.Model.load_state_dict(torch.load(segmentation_model_path)) + segmentation_step.Model.eval() + + # 載入CA vs Have_Question模型 + identification_CA_step.Model.load_state_dict(torch.load(ca_vs_have_question_model_path)) + identification_CA_step.Model.eval() + + with torch.no_grad(): + for i, (images, labels, file_names, file_classes) in enumerate(second_stage_samples): + # 將數據移到設備上 + images = images.to(segmentation_step.device) + + # 產生mask並處理圖像 + segmentation_step.Model_Branch(Input_Images = images, Mask_Ground_Truth_Image = None, running_loss = 0, Save_Dir = Save_Result_File_Config["Segument_Test_Bounding_Box_Image"], return_processed_image=True, file_names=f"bbox_image_{file_names}.png", Classes = second_save_classes) + + Load = Loding_Data_Root(second_load_Classes, Save_Result_File_Config["Segument_Test_Bounding_Box_Image"], None) + CA_Test_Laod_Data_Dict = Load.process_main(False) + + Total_Size_List = [] + Train_Size = 0 + + print("前處理後資料集總數") + for labels in second_load_Classes: + Train_Size += len(CA_Test_Laod_Data_Dict[labels]) + Total_Size_List.append(len(CA_Test_Laod_Data_Dict[labels])) + print(f"Labels: {labels}, 總數為: {len(CA_Test_Laod_Data_Dict[labels])}") + + print("總共有 " + str(Train_Size) + " 筆資料") + + # 做出跟資料相同數量的Label + Classes = [] + Encording_Label = np.array([[1, 0], [0, 1]]) + i = 0 + for encording in Encording_Label: + Classes.append(make_label_list(Total_Size_List[i], encording)) + i += 1 + + # 將資料做成Dict的資料型態 + Prepare = Load_Data_Prepare() + Merge = merge() + Label_Length = len(second_load_Classes) + + Prepare.Set_Final_Dict_Data(second_load_Classes, CA_Test_Laod_Data_Dict, Classes, Label_Length) + Final_Dict_Data = Prepare.Get_Final_Data_Dict() + keys = list(Final_Dict_Data.keys()) + + Testing_Data = Merge.merge_all_image_data(Final_Dict_Data[keys[0]], Final_Dict_Data[keys[1]]) # 將訓練資料合併成一個list + for i in range(2, Label_Length): + Testing_Data = Merge.merge_all_image_data(Testing_Data, Final_Dict_Data[keys[i]]) # 將訓練資料合併成一個list + + Testing_Label = Merge.merge_all_image_data(Final_Dict_Data[keys[Label_Length]], Final_Dict_Data[keys[Label_Length + 1]]) #將訓練資料的label合併成一個label的list + for i in range(Label_Length + 2, 2 * Label_Length): + Testing_Label = Merge.merge_all_image_data(Testing_Label, Final_Dict_Data[keys[i]]) # 將訓練資料合併成一個list + + # 創建CA vs Have_Question的訓練數據集 + ca_vs_have_question_test_dataset = PreProcess.Setting_DataSet( + Testing_Data, + Testing_Label, + None, + "Transform" + ) + + Evalution_DataLoad = PreProcess.Dataloader_Sampler(ca_vs_have_question_test_dataset, 1, False) + + Running_Loss = 0.0 + Losses, Accuracies = [], [] + All_Predict_List, All_Label_List = [], [] + # 使用處理後的圖像進行CA vs Have_Question模型辨識 + with torch.no_grad(): + for i, (inputs, labels, File_Name, File_Classes) in enumerate(Evalution_DataLoad): + Evalution_Total_Loss, Running_Loss, All_Predict_List, All_Label_List, Predict_Indexs, Truth_Indexs = identification_CA_step.Model_Branch(inputs, labels, All_Predict_List, All_Label_List, Running_Loss) + + Losses, Accuracies, val_loss, val_accuracy = identification_CA_step.Calculate_Average_Scores(Evalution_DataLoad, Running_Loss, All_Predict_List, All_Label_List, Losses, Accuracies) + print(f"CA vs Have Question 辨識準確率: {Accuracies:0.2f}\n") diff --git a/experiments/pytorch_Model.py b/experiments/pytorch_Model.py deleted file mode 100644 index e66b7ec..0000000 --- a/experiments/pytorch_Model.py +++ /dev/null @@ -1,81 +0,0 @@ -import torch.nn as nn -import timm - - -# class ModifiedXception(nn.Module): -# def __init__(self, num_classes): -# super(ModifiedXception, self).__init__() - -# # Load Xception pre-trained model (full model, not just features) -# self.base_model = timm.create_model( -# 'xception', -# pretrained=True -# ) - -# # Replace the default global pooling with AdaptiveAvgPool2d -# self.base_model.global_pool = nn.AdaptiveAvgPool2d(output_size=1) # Output size of 1x1 spatially - -# # Replace the final fully connected layer with Identity to get features -# self.base_model.fc = nn.Identity() # Output will be 2048 (Xception's default feature size) - -# # Custom head: Linear from 2048 to 1370, additional 1370 layer, then to num_classes -# self.custom_head = nn.Sequential( -# nn.Linear(2048, 1025), # From Xception’s 2048 features to 1370 -# nn.ReLU(), # Activation -# nn.Dropout(0.6), # Dropout for regularization -# nn.Linear(1025, num_classes) # Final output layer -# # nn.Softmax(dim = 1) # Sigmoid for binary/multi-label classification -# ) - -# def forward(self, x): -# # Pass through the base Xception model (up to global pooling) -# x = self.base_model.forward_features(x) # Get feature maps -# x = self.base_model.global_pool(x) # Apply AdaptiveAvgPool2d (output: [B, 2048, 1, 1]) -# x = x.flatten(1) # Flatten to [B, 2048] -# # x = self.base_model.fc(x) # Identity layer (still [B, 2048]) -# output = self.custom_head(x) # Custom head processing -# return output - -class ModifiedXception(nn.Module): - def __init__(self, num_classes): - super(ModifiedXception, self).__init__() - - # 加載 Xception 預訓練模型,去掉最後一層 (fc 層) - self.base_model = timm.create_model('xception', pretrained=True) - self.base_model.fc = nn.Identity() # 移除原來的 fully connected 層 - - # 新增全局平均池化層、隱藏層和輸出層 - GAP_Output = 2048 - self.global_avg_pool = nn.AdaptiveAvgPool1d(2048) # 全局平均池化 - self.hidden_layer = nn.Linear(2048, 1025) # 隱藏層,輸入大小取決於 Xception 的輸出大小 - self.output_layer = nn.Linear(1025, num_classes) # 輸出層,依據分類數目設定 - - # 激活函數與 dropout - self.relu = nn.ReLU() - self.softmax = nn.Softmax(1) - self.dropout = nn.Dropout(0.6) - - def forward(self, x): - x = self.base_model(x) # Xception 主體 - x = self.global_avg_pool(x) # 全局平均池化 - x = self.relu(self.hidden_layer(x)) # 隱藏層 + ReLU - x = self.dropout(x) # Dropout - x = self.output_layer(x) # 輸出層 - return x - -class Model_module(): - def __init__(self): - self.conv1 = nn.Conv2d(in_channels = 3, out_channels = 32, kernel_size = 3, padding = 1) - self.conv2 = nn.Conv2d(in_channels = 64, out_channels = 128, kernel_size = 3, padding = 1) - self.conv3 = nn.Conv2d(in_channels = 128, out_channels = 128, kernel_size = 3, padding = 1) - - self.relu = nn.ReLU() - self.sigmoid = nn.Sigmoid() - - self.max_Pool = nn.MaxPool2d(2, 2) - - self.fc1 = nn.Linear() - self.fc2 = nn.Linear() - pass - def forward(self, input): - pass \ No newline at end of file diff --git a/main.py b/main.py index 2d1f89b..3048cce 100644 --- a/main.py +++ b/main.py @@ -1,15 +1,19 @@ from experiments.experiment import experiments -from Image_Process.load_and_ImageGenerator import Load_ImageGenerator -from Read_and_process_image.ReadAndProcess import Read_image_and_Process_image +from Image_Process.Image_Generator import Image_generator from Training_Tools.Tools import Tool -from model_data_processing.processing import Balance_Process +from model_data_processing.processing import make_label_list, Read_Image_Root_And_Image_Enhance from Load_process.LoadData import Load_Data_Prepare from Calculate_Process.Calculate import Calculate from merge_class.merge import merge +from model_data_processing.processing_for_cut_image import Cut_Indepentend_Data +from Load_process.LoadData import Loding_Data_Root +from Load_process.file_processing import Process_File +from utils.Stomach_Config import Training_Config, Loading_Config +from Image_Process.Image_Mask_Ground_Truth_Processing import XMLAnnotationProcessor import time import torch - + if __name__ == "__main__": # 測試GPU是否可用 flag = torch.cuda.is_available() @@ -18,60 +22,117 @@ if __name__ == "__main__": else: print(f"CUDA可用,數量為{torch.cuda.device_count()}\n") - # 參數設定 - tool = Tool() - tool.Set_Labels() - tool.Set_Save_Roots() + # 测试GPU是否可用 + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + print(f"使用设备: {device}") + print(f"GPU: {torch.cuda.get_device_name(0)}") - Status = 1 # 決定要使用什麼資料集 - Labels = tool.Get_Data_Label() - Trainig_Root, Testing_Root = tool.Get_Save_Roots(Status) # 一般的 - Generator_Root = tool.Get_Generator_Save_Roots(Status) + tool = Tool() + Status = 1 # 取得One-hot encording 的資料 - tool.Set_OneHotEncording(Labels) + tool.Set_OneHotEncording(Loading_Config["Training_Labels"]) Encording_Label = tool.Get_OneHot_Encording_Label() - Label_Length = len(Labels) - - Model_Name = "Xception" # 取名,告訴我我是用哪個模型(可能是預處理模型/自己設計的模型) - Experiment_Name = "Xception Skin trains Stomach Cancer Dataset with original images" - Epoch = 10000 - Train_Batch_Size = 64 - Image_Size = 256 + Label_Length = len(Loading_Config["Training_Labels"]) Prepare = Load_Data_Prepare() - loading_data = Load_ImageGenerator(Trainig_Root, Testing_Root, Generator_Root, Labels, Image_Size) - experiment = experiments(Image_Size, Model_Name, Experiment_Name, Epoch, Train_Batch_Size, tool, Label_Length, Status) - image_processing = Read_image_and_Process_image(Image_Size) + Indepentend = Cut_Indepentend_Data(Loading_Config["Train_Data_Root"], Loading_Config["Training_Labels"]) Merge = merge() Calculate_Tool = Calculate() - - counter = 1 - Train_Size = 0 + file = Process_File() - # 讀取資料 - Data_Dict_Data = loading_data.process_main(Label_Length) - Total_Size_List = [] + Train_Size = 0 - for label in Labels: + # 讀取資料 + # 將測試資料獨立出來 + test_size = 0.2 + Indepentend.IndependentData_main(Loading_Config["Test_Data_Root"], test_size) + + # 創建處理切割的部分 + if not file.JudgeRoot_MakeDir(Loading_Config['Annotation_Training_Root']) and not file.JudgeRoot_MakeDir(Loading_Config['Annotation_Testing_Root']): + processor_train = XMLAnnotationProcessor( + dataset_root = Loading_Config["Train_Data_Root"], + ) + processor_test = XMLAnnotationProcessor( + dataset_root = Loading_Config["Test_Data_Root"], + ) + + # 設定自訂樣式(可選) + processor_train.set_drawing_style( + box_color=(0, 0, 255), # 紅色邊界框 + text_color=(255, 255, 255), # 白色文字 + box_thickness=3, + font_scale=0.7 + ) + processor_test.set_drawing_style( + box_color=(0, 0, 255), # 紅色邊界框 + text_color=(255, 255, 255), # 白色文字 + box_thickness=3, + font_scale=0.7 + ) + + print("XML標註處理器已準備就绪") + for Label_Iamge_List in Loading_Config["Label_Image_Labels"]: + if Label_Iamge_List == "CA": + Label = "stomach_cancer_Crop" + else: + Label = "Have_Question_Crop" + training_results = processor_train.process_multiple_xml(f"../Label_Image/{Label_Iamge_List}", Loading_Config['Annotation_Training_Root'], Label) + testing_results = processor_test.process_multiple_xml(f"../Label_Image/{Label_Iamge_List}", Loading_Config['Annotation_Testing_Root'], Label) + + + else: + print("Training and Testing annoation is exist!!!!") + + # 讀取切割完成後的檔案 + print("Mask Ground truth is Finished\n") + Mask_load = Loding_Data_Root(Loading_Config["XML_Loading_Label"], Loading_Config['Annotation_Training_Root'], "") + Mask_Data_Dict_Data = Mask_load.process_main(False) + + Total_Size_Lists = [] + print("Mask資料集總數") + for label in Loading_Config["XML_Loading_Label"]: + Train_Size += len(Mask_Data_Dict_Data[label]) + Total_Size_Lists.append(len(Mask_Data_Dict_Data[label])) + print(f"Labels: {label}, 總數為: {len(Mask_Data_Dict_Data[label])}") + + print("總共有 " + str(Train_Size) + " 筆資料") + + # 讀取原始資料集 + load = Loding_Data_Root(Loading_Config["Training_Labels"], Loading_Config["Train_Data_Root"], Loading_Config["ImageGenerator_Data_Root"]) + Data_Dict_Data = load.process_main(False) + + # 製作資料增強資料 + if not file.Judge_File_Exist(Loading_Config['Image enhance processing save root']): + for label in Loading_Config["Training_Labels"]: + Read_Image_Root_And_Image_Enhance(Data_Dict_Data[label], f"{Loading_Config['Image enhance processing save root']}/{label}") + + tmp_load = Loding_Data_Root(Loading_Config["Training_Labels"], Loading_Config['Image enhance processing save root'], Loading_Config["ImageGenerator_Data_Root"]) + Data_Dict_Data = tmp_load.process_main(False) + + Total_Size_List = [] + print("前處理後資料集總數") + for label in Loading_Config["Training_Labels"]: Train_Size += len(Data_Dict_Data[label]) Total_Size_List.append(len(Data_Dict_Data[label])) print(f"Labels: {label}, 總數為: {len(Data_Dict_Data[label])}") print("總共有 " + str(Train_Size) + " 筆資料") + print(f"要被Mask的資料共有{int(Total_Size_List[0]) + int(Total_Size_List[2])}筆") # 做出跟資料相同數量的Label Classes = [] i = 0 for encording in Encording_Label: - Classes.append(image_processing.make_label_list(Total_Size_List[i], encording)) + Classes.append(make_label_list(Total_Size_List[i], encording)) i += 1 # 將資料做成Dict的資料型態 - Prepare.Set_Final_Dict_Data(Labels, Data_Dict_Data, Classes, Label_Length) + Prepare.Set_Final_Dict_Data(Loading_Config["Training_Labels"], Data_Dict_Data, Classes, Label_Length) Final_Dict_Data = Prepare.Get_Final_Data_Dict() keys = list(Final_Dict_Data.keys()) + Mask_Keys = list(Mask_Data_Dict_Data.keys()) Training_Data = Merge.merge_all_image_data(Final_Dict_Data[keys[0]], Final_Dict_Data[keys[1]]) # 將訓練資料合併成一個list for i in range(2, Label_Length): @@ -81,18 +142,19 @@ if __name__ == "__main__": for i in range(Label_Length + 2, 2 * Label_Length): Training_Label = Merge.merge_all_image_data(Training_Label, Final_Dict_Data[keys[i]]) # 將訓練資料合併成一個list + Training_Mask_Data = Merge.merge_all_image_data(Mask_Data_Dict_Data[Mask_Keys[0]], Mask_Data_Dict_Data[Mask_Keys[1]]) # 將訓練資料合併成一個list + for i in range(2, len(Mask_Keys)): + Training_Mask_Data = Merge.merge_all_image_data(Training_Mask_Data, Mask_Data_Dict_Data[Mask_Keys[i]]) # 將訓練資料合併成一個list + + experiment = experiments( + Xception_Training_Data=Training_Data, + Xception_Training_Label=Training_Label, + Xception_Training_Mask_Data=Training_Mask_Data, + tools=tool, + Number_Of_Classes=Label_Length, + status=Status + ) start = time.time() - # trains_Data_Image = image_processing.Data_Augmentation_Image(training_data) # 讀檔 - # Training_Data, Training_Label = image_processing.image_data_processing(trains_Data_Image, training_label) # 將讀出來的檔做正規化。降label轉成numpy array 格式 - # Training_Data = image_processing.normalization(Training_Data) - - - # Balance_Data = list(zip(Training_Data, Training_Label)) - # Training_Data, Training_Label = Balance_Process(Balance_Data, Total_Size_List) - # training_data = training_data.permute(0, 3, 1, 2) - + experiment.processing_main() # 執行訓練方法 end = time.time() - print("\n\n\n讀取訓練資料(70000)執行時間:%f 秒\n\n" % (end - start)) - - experiment.processing_main(Training_Data, Training_Label) # 執行訓練方法 - \ No newline at end of file + print(f"\n\n\n訓練時間:{end - start} 秒\n\n") \ No newline at end of file diff --git a/merge_class/__pycache__/merge.cpython-311.pyc b/merge_class/__pycache__/merge.cpython-311.pyc index 005151959871d59423478182d0b5a674235bd024..fd04b0052e3f0719f2b1ca73b33d12fe18abb124 100644 GIT binary patch delta 78 zcmeyY_Ct+lIWI340}w1(#F?>?Cza9IT|Xl~H&wqpBeNtmJF_S=51Cn9lAoKHoDrX# Wn3tSdq#saOl3$dZv3Wk@6+r+H${bDr delta 73 zcmeyN_F0W*IWI340}%X~crSe;Pb#CHlYV)AQFd`bVsff}a7lh{Vsb{jb7Ed{YLR|G aQGR++Vs3muWl4S!P}ncEeDe~rWfm6~AN8m;u|2jlmEg!331VNlIRHxw#Ws`{bl+<9Oe zqo#W$?%aFMJ$KHW$L}2TSHHiG!1&FlwO2Dh8-VKWxA`yv6kr8H)VTg;I zCX#E4NbUufd1}x#&PKUa+(a2;+x0{$DJ8UICM{}LWl>IRvLXT@F=QS$XG@l>e;@WU zL?(lbL1O>x+V7%8Du3EW=`T@_DCL>Ya~IcnPLWciHBXS6p(6RS0~lU-YYK2 z3z9yd`GDq!ryrj6<4iPYa3iuZEXRkKG8Iq*H~g*dq#9@rZ^1g0C89$cC-Y1^>QYd^ zsN49&dB$K>Idw(FlaYU)?2lbOuVjXm#7Htdd|A~pBZ;A_;!q+zBr7&YJU^~w6d=dt z_b*e$#GzC|Rn2wJ=(xd)Vlti7L~){?@_Xz(`b8CBxusIRvJ#VZFW`9?7f93h zSlfp=lDsm0$Z(d2jbMCiCZ?AZsweDBGEa4OHAdf6ms9%_;R zm|!a>U9*e;XPuE{G{>|y$|_x8O3d1dk!2Pv12Y%~=;n%%b%CkTx-c$m5h`0~K`R8x z+48Tb1?G9h*sKMhvTN)G9I2z;fobKz&6Vk?)lYuClKbuRKi&M|mmjZ8=bk=!v~qv$ z>Eey&j~+WGySgIh6M(QX6qcAn#e4QfHi9P>dH%Z}KmT;Wyye-irp!yLo`-x?G=N-5 z{vZ}H1#|mHufOhiWYHZ1Ks;PaeX%ofm)ci^bKO zcO2Pxv_?UAG=z;ZB5LEKvcV#tDM92lTOWc5r)9)cQq^dz8Z0htHYJy{qbyApC4hGX z%{$6I&Svi9lEb$wr3rM${@KQ2=V86`aIy1sz4P@#=NpCg*b;wq8Bc82`R(@-OMK+BVAHfz4DZ&%yXV+H zdgr|WsQR8$diZo9cqZp51)F9%?sm+E^U+xTSiBHCm-8$OO*ub}27}Ki$>C%=ks5Nm z3|cs~s05oCveDXQnQA~+>Fr5(l0fBh_ml6vMaU$V<%UU;ne=4YYj|_T$a-v#L3A)# z4t)qY!tdSnIef21xmEmgoPuNJ2H+Pt3r>m*xng#2oj^FF9WT5S~GY}9vSVYbU7{2 zP6Y9R4zr9lSjb?70m9ZqOSJ$&PA|Mv{QxHDS%uK_nVEsR13y1k5V~`0NeJfH&qK|* zzEX4Ry>Crl%bf-=xO4W_*?TohzQ}S*WH$7%fA;#^&?i62Hy_EJDK&(0eajBa@JqgE zsinQx(yO=hK6rc4U1&L$>z@w&^sTiZX>3_*B!R}9)!J2!j|os~E8O_Ma++qZ?M<4w z)%?9FbIq>jHP8T1nr7$|0C4QW2fGITc?j0sSa-6ecSbt0h`~&l`F;RtO%2 z{DPM5!&@KTyPn_u)qL!m1z{l154_yU;MY*3eF}?B8Re1~v?7*we1g?1OGEa&3)zDm zV7cw#3=TWzB<4N%Y$XaUkCR&R?z@m( z40O(4ffq$NgHsaeVOeR1-3F>sD76|>`<|Bcy1)xzEg1$DU zq~lRWp~1+kqPwC3{t8V)mnDiuohXiEq_GsPeWLiou|&$`DELFl#2H$5Xc$vlbs+bb_b{&fP6^@y8`GykjuvUxw=8jre-o#IBn)pN=DC&k69@=5#` z1p*%Zc~8|)PNPCteNDvUkC_H|Q$fFBsZ|?cT5~fD^AB?7U+e(GgkKPxsnmY~bD!Lu literal 0 HcmV?d00001 diff --git a/model_data_processing/__pycache__/__init__.cpython-311.pyc b/model_data_processing/__pycache__/__init__.cpython-311.pyc index 58b90c4ba1ad51f9bffafe145ecc6eaf4abe5d73..ce5b212e74e6c6a1ec325c64ae3cf7396bbbb4b1 100644 GIT binary patch delta 101 zcmdnVe2kfAIWI340}w1)#F?>?M~~6_SBQQ_er~FMc}8YQYIbH(W*#!LxFkO}F*zeX tIWaFewMajpvLwGKIYU1;KP5FMJ|(dvF}|QEKRLCyI5RI@e{uz*BLLy9B%1&L delta 72 zcmX@cypx${IWI340}v$W1gCH0(PPy3>H_4sSj7~V54QV$+iyYk}rM?0DSJ1eS+se!piHMA3`w>!0qM2$lmIr(mVoy0fqfi%VTo$Q&MxlevC(iT}*s@W?p7V qe7s&kvWvV!C|UlCJ3&0$rW-dr2AyZ6FxcQf;@gWF)z1 zi#_~9*_;um2VIkn4m>uxj>0H|vi-2aVEqH^V2C+p2yCY5FTd>)6k6ID zx4|B%*fyBn`1bi<&mSt{6Ao#%=*yOEmPA2 zp`nN-$%HZ?7Fqa=!@!bgy{kKUrr5qU{n6t5 z(tH_FOrOP4RDs*N#<^EH_saep*PG{hv({T^6SB1M8kA9s_Z=``d4C0B0{4Jw_5LH6 zenONi0>2|4N>lR(6Eu%ZqF1GB^@zsl)(B*pP&G7yTh@w7FecwLYj@W>amM889VF3> znMYvrN!>22(AI=wTGzL34clUaZLAdEgibI^J6o`h|HH=Z84{Uy=-s<$k|xylG>5U(grMvg7O5(YwX{JtskL?#vevFx*7>S6u?IdaZv!W7{UqQ)3m_08` zVNu2GOh|;}zVM2ajTrG`>F1v|9(?&S{i(<5dP=`OD?Pmba`7{7r%v))Cl?pf8faN{ z;D)T5I$2XEIfJ{-#H651w&6byx#|n+*rpknj*3t>xGSO|t71gP9c0o!Bi@kx1dC|{ zM9fdz49HP4tf`oZLe(&_-7s~p6Sr0BB!L>3udC@UYcE%!m||xGf>}#8Fm(-gX?i#q zRz<~6P{g*rhbU39K~77mRfTj255oH{%A(|NEagA0*1FXqtsej!!5Y)xGblM6pFCb{ z+p##lG@kSow(lz=ff@aWu#~fG>*9r?uPAGTPUD!ThKH}me{r`vPxvAlaM z&8FERtT2`r-hVus6GrpGXlioZwPnrKyXxxA9L~80@~(lbYoO%m{m!xG8D8}aKi!q{ z9Lsx-WnDdm?j390{j1&m+5Ka`cyrype77&%h;$y03U!%nU2W;7s+eb3#+EhJ%$GOX`jl&mWN9Nn{e&x7;!K6~z>J zTpxxmNen{)21lZ(0^*a_Q$Rwt^(~--+19s!2D7binP#Z%WmIP!yD7em-euNq{sW(> B64(F$ literal 3080 zcmaJ@>u=lE6~81!iIOGTbSo!z;#r&Fhg>YOonTl7H(MS}F{3rwdS4o(5IB)m)an(I zLKcGpR4;9qO+}T}S(Gl@gwF7kdB~D=MS^0>-yj+SA`mlRV38l6CM*~*^wZA0k}R>F zc1a$R_uTWi=brPs_xB!;3qf04GQ(du5c&uHX*Rm?@%$Kk+(sf2sVKUD-*l9U(HCe6 ziOe;0fe{@ddyTqa6YcQFiqrz~b9-2L-cOlqOp?P=sHqHhv+ywRJkJ6F#neR`LTNh9 zq-|+drJ%FXR6MHDG_(es^?k1O?;Lt(IBnOEW*=w@pfEW48TB5qEca+sM;_%wS)a&& z+qTpZ5Z^88JNIutd%U)DYrT5?%k4*xwjX`C^V@rScYY^hZGI+PH&XllPScumjDP}{O1J9Lm__&cy}BaIfDOQwcl2_Yqz&MBc$Yp@{e`^jZZ z3P>hAxkh_;->Sx1$5BXQA%VUN3B(j26%RJeF4C>UIv{Q9C`EOa%AV91&9+D{AdPC* z9!3!g=G@itLZnnr>ksB^Ed)yhNFg|29yqHGG$;Z`%Oh;bs*8d`&?wL`p5~yKxYk(k zm74{99U=(7%^iX$&0kZQs37{ovkC@&2>NA60W%7_fIYv;AaTuNUH<$v;m1;RSHJ$lm=KnHZzU2cSg2-x{#ry) ziQ1W_+TBNgsy?~dP+Qjn3fp`C`Pb~;^0nM$LOix2FSm*8k*2l1FLKUK>i@XSE$lX{cOQNAT;k%APK;<6HaX0m0gpt1mT{sVw zL$Hh)RO?2ZTfe+~HFLEx?k~>d(z>VG`{J#Iytlv_-m$WG%;+62_m1oACfA+q&ZP`) zsLTzOxS_4VVZagR6e0Rt#Xa!U?b~qs3WLSdt3!r6P<97O?m(x0U~Tmr&BsbTFO|5L zYIfx8)`cvWo2fDMfJ^uMn?rqva+iNSl9%pG-kmh~(K0_;LzHud5dCyZ@o14+ohZIl z7&hF~W%qQ6+*{s3?AbIS`YV-@iK2IPR)0M|YPfxy?!N4N{^g>#d?aAFr^@cB61l;n z5_eSQAwZVR4lf(Qw|^0QgUt@=6>oMJ+X%wht()E&2&}_XZ)t~R6SN=&;0DuHbru{* z)9sZi+SE2Y_&S1!%o=#OzK@Sk|A*6@#V!rV(O%(Svy~kns4)hp(FqF?APD`z|3guT ziAHPm669E#&W>x2LK}KF@A24D0)(3H9N+3KMRKfQtNF5*Z&@b5c%ygj=IUjBJoz0%ZG7a4>>s1H}{wjiThn9 zdk*SQF`WyMB`Jup%5?om238Pvn5+Ut3S9)$>TEmtR!n=n#7*{fd>Ct#eVvETfBR+M zsQaEXLKGi5f^g=*hYEQL27MbIPq~2&ZXiEeV2iGjZ>BtW+~7`> zxf3PsM5T97XJJV0U4!!xX}VbL`h}u` zq8uaNWUa}Wi(n~<>ODkc3EqCi%>s<4qS7h(IB0-SBjp_+HHM<73i4#gRY4;q>s_<6 a6dcUNg4WB-%@ diff --git a/model_data_processing/__pycache__/processing.cpython-312.pyc b/model_data_processing/__pycache__/processing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dfd00956be25a3d8e50117a3ba634e708ae7d535 GIT binary patch literal 3449 zcmZ`*TWl2989sB{oxK^a&0uUCVeHhfA-G(URM0>K*bd=h5ujCB8I7hpgLj>o-DPH$ zi#1zqXbNj#g+&lBfmBQT;uI+&rB$n{L>1~orM|GWsjU;EBEf=rv!GI{^rinfv%9{O z{Hr~4F8}=J%zwV`JLm7AkRO5lqia|EOCLgyNTX_OrSjq=RIVTusf>=IP zik(O$@j69S(stswCcoT4K9R8Fsf;b_2_s?SU?yqB6*DaxiuC~w>q=TzVhJTF(_Sr! z{fau6v1~bR9mn+pieV^nEM=NnjLZfL3hp;kG0n2%-h{42SiIzrsU(t#gY0XR+TGFm`#j4pQU*~~82mcp;h2jbtfM1r&vNi)vYBm|A<{*c;S$X$nWjxE< zLUnwQ#9CwyU-e{=!*`=2uOXBb9Ci?Pe6cx#$}~ggyf?V-@M9PHjl9kyhjqB4>_HUa zGN&PkzYVOTqiyC_H=kY_d;Haz@`szrjk@s2KHL<%+aH|hCNC;ttC|em5?Cl!h%j> z<50yxc6)10cT})bwxVM{eaNa}D;CK=`Rul~Zx3~E=?7#Gd;%8w0jh=)i_0-38Pm+_ zh`j%loid@jPdm|Xq*P6(apbfMDe~f6wJUuJ2dgV0)0wR>od|zRgCd7!{pi)sqFLCQ z+xIwFf2pzXqtTx6aQk?$BiA#{`_J}$*jIRSf^UAbY(?HbB}$WGYe{S!jgB!_k4%Vb z7xmm1*Uk#4sdZLF!RFC*_X4Z$@vC3JL}&qgz0g77dj=8>Lc#Py*0XGu0~qrZ%$}?; z2j-h309e*L57vxI;p8wXM`2ZgIFO(QZI!plOw@n`74WOv%?ddH*kOn&&Wp-Aj3X|L zH_`|&Wx)3p;_L7)1vhdyhi#cp0{9vLH#-y}UpBH5Vt5Aw)z!>B9bRSUt+GbE>Ke0r zjetH!crITnD|&iT5-VIrMOOYl)X~y9>fp zxG}eTN@^Ny$oJ-Yr-R{h@8)_QhnE%(j~=_wU)((Q{*AZC!|QXqr$Y^e4VPl0k&DTq z^3TwkJTomVA8jcf9y@lUe_Yx)?4RXOUF3xa)ivdrDY0QvY%Yn-qu(nEWBz+BnDj1>|i1640co?wb*c(eF zZ8*2EpSr`5Y1!uM;AoLWlKrb}pP_u9$@6?R!ti?H7l8t{k8B#*kheZQGC$X=?~CnZ z7gjtBNcVW@|8r4OmyavzGCvnJE#Vvl*|-SV;C*OL0S3t;7uno#I9St@ITw|!G7mJX zc0jtSHfp>RcZ%;B#NR54m;-+TBQ@T3D zccqg9eJ1(B3=x9zAAUP?^^>QCGi|ilR{rzv%hxYI9X=Zgm_%Z!WMDo8=QBm)am}<% zl1Uuiolyrga_r0d0DavF6W5W7d{BYAAL+-u1y$_pIT_R7MhJI9A#ElA%^aXOBI1Cn zS;UpdTlF;xaLgZt>s(dVh>J;}jQO+zykInoV1W>Tm`j3H2Q)>M=VHp+lhtM=5oQm( z^aJ=?e}MvMA^LLLrvpvrw&l9NUbZUlpJf9+Xl@b?D^ZC(w3i$ONaBl4} zyd&IwM}T@nG8p0`@|#(o3i$Jhtx e&3~bt&-prL&GWWpOw0520<-Kzoy7QP)c*knUTH=E literal 0 HcmV?d00001 diff --git a/model_data_processing/__pycache__/processing_for_cut_image.cpython-311.pyc b/model_data_processing/__pycache__/processing_for_cut_image.cpython-311.pyc index 08a73ba927f5989c26b28cf0ce4075333ca0263f..834b3838d5f446e83ca339addbaede0165d2a7fc 100644 GIT binary patch delta 1191 zcmZWoO=whC6u$TU&6`Q)uW6mJK^X;chWYz$05QO9OWj>aD<}vp3!y{8|MlUHlnE;quc^NB2ZtciJ9pn_SELqmgiYM7X*fsp z9p-Dkw2a)K<+Orup30cDFjr z*L`^z)vdM_*1~?+lC~IFL#h_>lI;+7CEW7;2$ITPUff-o9hWIY!M; z;AH2K1A=OOLuH&ZB7$}@NQ})|Q?@zklx*|N4ZKw%4i7u`_L3s8ix~R%vz|GU_ws?} z7H2)D6e#8DHQVUG(9^^Jp|ndD@+ha(3T2%X-&}3akCJ_zTF*H zQyXk2h%Pu9f219uh{NzIo{cv%^i!YU01PKi3~nxej7Er|!=ZMpCyF=iSR(UjB7c$B(ro$vKwOfp-tPl{2TpaXOtAZ*B-^K~{{-~O+&!TR=p q9cGd#m`iGd>nu9o{5F)m91GnE|Ipamt%*|{o+ne04JPxUrlb!w+!6Qy delta 2015 zcmah~OKclO7@pae*Rf+Kj#Il$>R3tB#Gtf^NFP=nA}?qvk+dn4DuG&C?~=OpBaAmC zb=OS`74(oxG%W}&1c6#r?Ewx*GXl>MNbf)UTh0Ha1y2PBwidG+u1mwDQYZ{ zQl_<-l2&6!NG7gjv!#~BrC4V>(BDHEn#3xa>8E{o1V`vwcvn|7(1`~i%L9bN;oo0?@7^~uEuKPy|^0+0BoANka6<_T3L06o)FBcgq_H?To)0I0A zQt=IFyN&7lTpJeX*W5T@E#JZmOA@^-)zQPe*ROInfPQ<^B}Rro7x}h&bVew<8b+_4 z%1Z{nB-^wTyoa_q8k_hV95CT6mApf*E7xK3>S?1RIBz(Ne@sw{sXQ<*8?wr8FPjJ~ zVauB44AGE!p?4u}h_F@S*xCiKh@SzQc@6#$MO=i%PuS9vdIsAVzy^*W5@6LJK(X$5 zO^*#Lx)K{s#Pvibt&sCYZ%R3<#gfV?Eg4HDvU*XlQ68Etjg2^om+EqJ7um^t)RaUw zQxaSvJxxNk>(R8T&1h*|12qn1*jJ}t$l(Fe_FUxk)J)b1BSA~0LTVVVX;4Wj>9`hS z(~Z9t+i;@--HtTZ4a%$^`kztkZ?o$Fm(WVXfxCR6q1S5YHRa%nuchE?wS28t9rRtX zXZ|rYEr(hkhN2Hb(L$)l3iX(B!=sL_J5%e3cTV6En(oN5f7e5Q_XB_T=f}+Gar0%} ziq01HowN3xGw041{5i{?yE?Ms+jf1<4ELG+Q&#vD^JLuA(uF|A3SE80R2pQOLY)P|{16fq*+o{+77t?SWd}Yq%tBk70lK^55h4VNKT zPKMD!(2!I<2gg=kTA-?M46!#N(q+dpoohK@*~vm$p*B{|76%x`n!~dy9HP%9l3HwJ z4)jkvv`Y@nw=s^LMG-bk%ATIp6Um~G%AC_8Zo-y@JjHtI9+ND~t%*!Vw^M~Y&AJ8V zxrh^_!?pq$`mIy-uyZrQ5f^;MA`W_>s&y~h zAkxgBlR*Q(EkxKrJ2weiaU0k|WlzwztM;|K#g=un35_*kU>!XPpk=G-rqstA?4g%k zqh6Nmgsr3v`{@s^p6EtMgRFH3AmS>v+V>i}(KZg4(v7xpaGI8I75h&ob&ZE1!QGGhw2whyLZ>(cXdK V_n(AcSle$~9Vh8Pbx2^r{SAd+>&pND diff --git a/model_data_processing/__pycache__/processing_for_cut_image.cpython-312.pyc b/model_data_processing/__pycache__/processing_for_cut_image.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..59d62d0fdc1325810e980c336891c67bcb040511 GIT binary patch literal 3030 zcma)8U2Gdw7QW+|vByb_-PBoklNuQ%rFF=LEoxdo<+p)u8XB4=AmOH+PCZlC&DhS~ znLr)csGtapC{pr5_}P`R2tlh<0s#`QydroQ%R#m-MO%r#?Hg=XTEx?ybI0SRStD^J zAK#yI&pG$Z_uX^92!%QbwAFWl=YCNL`4$IWlbW54Y3QsFo#=u|azaWFuWUs%6jB{UDH*(hlSzSvbK0z- zn%Wt|RL!hqUlCZurdl?y+JgOUXx>)G z^13l+bAkAM+Q z+Je(bmSLWyA<(C{fw0hSB9Zv@%;^0yaLNqTaM`B zFrJ&q6?90Xj(M7M(}NptcGa^5s;1#^*_@U!hUbb*QB{b^R@H@gyF(9q%K;253gRMZ z#0M+Vy3*VD!_JCysk5PUZNNOaB|WIl)AJIfVTIVOWUQeow6bWo(%G7mO5%ChUEeG- z#729(mB@L3>(;i`wC{mUAYiF;s}>>ccY`h_e@pYC`rW>p=i$D?Ta3Zbvsac&()n%w zzYei=x0#jO$Gq0`R`$bsPn&&yfTYjU5=fEIF3?JLQa}7r%pr?R8MaHRLj}aS%|z44 za}2WWt+ml?+Rhg88ZENO;jJ4&tr=8fp$sT+_)&m3hct^JuAV&W@ks|i+-WjEF-xpx zE74qf1gG%=n942~EZ}iI$XSjAXFaz#R=opsV*r|Ix&Y^)Scn~<6E+$_kI|+_429n* zIpF0&vMv7GsUonfzk|3)u66gt2 zuHJ5-o*yhUFXD0lbb>e6yk05b`4EWRqOaW|CqUZ&M^N^(bfINYv0Ie$v`R`z^axN6 zmV&wu_d=9AAj%HAMZvbT>ws9A(F){JuS7~vEEXV=vV6&wNKq_`Nojr<41QmE`TJKs z`th~PKd!y{ua95;;q^E77{i(2#M7FY1u6h_zPCn*}eftj30c2LX{iyWEP zGX}3?>SGt62)Ycs?I@PUDeYOqC4|DqqghJv>rmu8QxLNVVdl5a&D&X%Nx8za2C$q{ zE4~T6DiZWowr}6Gj7G35(Vb{l;zd=+vUnOCOc!j;L^^V^AhRvEWHSi|Oy>2QDX0r4 z)|iCS!Vkz<=L*g}+6$8lLv5*slWpz^JgD^^h>PUAaNn!XSENQ)s3KesZ?A_3s$szV zz3buo8hb}R?faz9iTtS%>#N5GtFb}nuD>`(PS#?lmZU}`x)NFry`is1`oG(;`>N;+ zjX6g$)uD5>Jy~bgtnJ7x$=CY&oq|Yjs-cIg$0Hz}MbJ{_*_fx~3r}+tZPC$*#YdJ$z zS%<1ZiJmvH-=(U5o!3lvg(4d19VjqER|q%brVJly6b0Vg7P5MgZ1_Yu^lwFxPY4^) zupD#MQRx=O;|@g2#(of+%W#Qcc_@ijg|#M=XW+jqmF2P@*;$f-uYt4D6iNE#5lb%0 zU3}ko`z1JF(0!rd1>Hrpyk5wumaW+aMT1F&-UEO1&mfqB*x@(1-&JHX=L3__1nYDk zd@hJOxK-Y_ut<3Ta#OJzZKAjne%25O0L9%8eI|WoIL~Mfy|8|Fv8oJJQ>M lg76JF_zl_jPjb9Uj(<%;|CMeRVm}iQ|9Myth5g*h{{YTW`^EqO literal 0 HcmV?d00001 diff --git a/model_data_processing/processing.py b/model_data_processing/processing.py index f7bd7fa..ddaa5a9 100644 --- a/model_data_processing/processing.py +++ b/model_data_processing/processing.py @@ -1,67 +1,40 @@ -import random -from merge_class.merge import merge +import os +from PIL import Image +from Load_process.file_processing import Process_File +from utils.Stomach_Config import Image_Enhance +def make_label_list(length, content): + '''製作label的列表''' + label_list = [] + for i in range(length): + label_list.append(content) + return label_list -def calculate_confusion_matrix(predict, result): - '''計算並畫出混淆矩陣''' - tp, fp, tn, fn = 0 - for i in range(len(predict)): - if predict[i] == [1., 0., 0.] and result[i] == [1., 0., 0.]: - pass +def Read_Image_Root_And_Image_Enhance(Image_Roots, Save_Root): + '''讀取Image Root''' + i = 0 + file = Process_File() + for Image_Root in Image_Roots: + try: + Images = Image.open(Image_Root).convert("RGB") + Images = Image_Enhance["gamma"](Images, Image_Enhance["Gamma_Value"]) + for j in range(5): + Images = Image_Enhance["Median"](Images) + Images = Image_Enhance["Shapen"](Images) -def shuffle_data(image, label, mode = 1): - ''' - ## 被用來做資料打亂的用途 - ### 有兩種不同的需求 - 1. 打亂影像資料(讀完檔後的影像) => 回傳Label與Image Root兩個List - 2. 打亂路徑資料(影像的路徑資料,還沒讀檔前) => 回傳打亂後的Dict - ''' - if mode == 1: - shuffle_image, shuffle_label = [], [] - - total = list(zip(image, label)) - random.shuffle(total) - - for total_data in total: - shuffle_image.append(total_data[0]) - shuffle_label.append(total_data[1]) - - return shuffle_image, shuffle_label - else: - shuffle_image = { - label[0] : [] - } - - for i in range(1, len(label)): - shuffle_image.update({label[i] : []}) + file.JudgeRoot_MakeDir(Save_Root) + # 使用原始檔名而不是索引編號 + original_filename = os.path.basename(Image_Root) + path = file.Make_Save_Root(original_filename, Save_Root) - for Label in label: - shuffle_image[Label] = image[Label] - random.shuffle(shuffle_image[Label]) + Images.save(path) + # Image = cv2.imread(Image_Root, cv2.IMREAD_COLOR) # 讀檔(彩色) + # Image = cv2.cvtColor(Image, cv2.COLOR_BGR2RGB) + except Exception as e: + print(e) - return shuffle_image - -def Balance_Process(Datas, Size_List): - # Data_Dict_Data = shuffle_data(Data_Content, Labels, 2) - Train_Size, start = 0, 0 - Image_List = [] - Images, Labels = [], [] - Merge = merge() + i += 1 + print("已處理 " + str(i) + " 張圖片") - Train_Size = min(Size_List[0], Size_List[1]) - for i in range(2, len(Size_List), 1): - Train_Size = min(Train_Size, Size_List[i]) - - for i in Size_List: - Image_List.append(Datas[start : Train_Size]) - start = Train_Size - Train_Size += Train_Size - - Image_List = Merge.merge_data_main(Image_List, 0, len(Image_List)) - - for Image in Image_List: - Images.append(Image[0]) - Labels.append(Image[1]) - - return Images, Labels \ No newline at end of file + pass \ No newline at end of file diff --git a/model_data_processing/processing_for_cut_image.py b/model_data_processing/processing_for_cut_image.py index 9b29881..19c01f5 100644 --- a/model_data_processing/processing_for_cut_image.py +++ b/model_data_processing/processing_for_cut_image.py @@ -1,6 +1,5 @@ -from Read_and_process_image.ReadAndProcess import Read_image_and_Process_image +from model_data_processing.processing import make_label_list from sklearn.model_selection import train_test_split -from Read_and_process_image.ReadAndProcess import Read_image_and_Process_image from Load_process.LoadData import Load_Data_Prepare, Process_File, Load_Data_Tools import shutil @@ -13,29 +12,14 @@ class Cut_Indepentend_Data(): Prepare = Load_Data_Prepare() Load_Tool = Load_Data_Tools() Prepare.Set_Data_Content([], len(self.Labels)) - Prepare.Set_Data_Dictionary(self.Labels, Prepare.Get_Data_Content(), 2) + Prepare.Set_Data_Dictionary(self.Labels, Prepare.Get_Data_Content(), len(self.Labels)) Get_Data_Dict_Content = Prepare.Get_Data_Dict() get_all_image_data = Load_Tool.get_data_root(self.Training_Root, Get_Data_Dict_Content, self.Labels) self.Cut_Of_Independent_Data(get_all_image_data, Indepentend_Data_Root, Test_Size) - def Balance_Cut_Of_Independent_Data(self, Independent_Dict_Data_Content, Test_Size): - image_processing = Read_image_and_Process_image(123) - Prepare = Load_Data_Prepare() - Prepare.Set_Data_Content([], len(self.Labels)) - Prepare.Set_Data_Dictionary(self.Labels, Prepare.Get_Data_Content(), 2) - Indepentend_Content = Prepare.Get_Data_Dictionary() - - for cut_TotalTestData_roots_label in self.Labels: # 將資料的label一個一個讀出來 - label = image_processing.make_label_list(len(Independent_Dict_Data_Content[cut_TotalTestData_roots_label]), 0) # 製作假的label - tmp = list(Cut_Data(Independent_Dict_Data_Content[cut_TotalTestData_roots_label], label, Test_Size)) # 切割出特定數量的資料 - Indepentend_Content[cut_TotalTestData_roots_label] = [tmp[0], tmp[1]] - - return Indepentend_Content - def Cut_Of_Independent_Data(self, Independent_Dict_Data_Content, IndependentDataRoot, Test_Size): '''切割獨立資料(e.g. Validation、training)''' - image_processing = Read_image_and_Process_image(122) File = Process_File() i = 0 @@ -44,7 +28,7 @@ class Cut_Indepentend_Data(): root = File.Make_Save_Root(cut_TotalTestData_roots_label, IndependentDataRoot) # 合併成一個路徑 File.Make_Dir(root) # 建檔 - label = image_processing.make_label_list(len(Independent_Dict_Data_Content[cut_TotalTestData_roots_label]), 0) # 製作假的label + label = make_label_list(len(Independent_Dict_Data_Content[cut_TotalTestData_roots_label]), 0) # 製作假的label cut_data = Cut_Data(Independent_Dict_Data_Content[cut_TotalTestData_roots_label], label, Test_Size) # 切割出特定數量的資料 for data in cut_data[1]: diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..8436f6c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,21 @@ +[project] +name = "pytorch" +version = "0.1.0" +description = "Add your description here" +readme = "README.md" +requires-python = ">=3.11" +dependencies = [ + "matplotlib>=3.10.6", + "opencv-python-headless>=4.12.0.88", + "pandas>=2.3.2", + "scikit-image>=0.25.2", + "scikit-learn>=1.7.1", + "seaborn>=0.13.2", + "timm>=1.0.19", + "torch>=2.8.0", + "torchcam>=0.3.1", + "torchinfo>=1.8.0", + "torchmetrics>=1.8.2", + "torchvision>=0.23.0", + "tqdm>=4.67.1", +] diff --git a/test.ipynb b/test.ipynb index 48d7027..abe6272 100644 --- a/test.ipynb +++ b/test.ipynb @@ -2330,7 +2330,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -2349,16 +2349,1977 @@ "path = \"../Dataset/Training/stomach_cancer_Crop/A01.jpg\"\n", "\n", "with open(path, \"rb\") as f:\n", - " img = Image.open(f)\n", - " img.convert(\"RGB\")\n", + " image = Image.open(f)\n", + " image.convert(\"RGB\")\n", "\n", - " Image._show(img)" + " Image._show(image)" ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['123456789', '123456789', '123456789']" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "a = \"123456789\"\n", + "\n", + "b = [a for i in range(3)]\n", + "b" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "stomach_cancer_Crop 有 68 筆資料 \n", + "Normal_Crop 有 36 筆資料 \n", + "Have_Question_Crop 有 26 筆資料 \n", + "\n", + "test_labels有130筆資料\n", + "\n" + ] + } + ], + "source": [ + "from draw_tools.Grad_cam import GradCAM\n", + "from Load_process.Load_Indepentend import Load_Indepentend_Data\n", + "from Training_Tools.Tools import Tool\n", + "from experiments.pytorch_Model import ModifiedXception\n", + "from Training_Tools.PreProcess import Training_Precesses\n", + "import torch\n", + "import json\n", + "import torch.nn as nn\n", + "\n", + "model_path = \"../Result/save_the_best_model/Xception Skin trains Stomach Cancer Dataset, and uses WeightRandomSampler apply sharpen/Xception/best_model( 2025-05-13 )-_fold0.pt\"\n", + "device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n", + "\n", + "with open('utils/Stomach_Config.json') as f:\n", + " config = json.load(f)\n", + "Training_Configs = config['Training_Config']\n", + "Loading_Config = config['Loading_Config']\n", + "\n", + "tool = Tool()\n", + "\n", + "tool.Set_OneHotEncording(Loading_Config[\"Training_Labels\"])\n", + "Encording_Label = tool.Get_OneHot_Encording_Label()\n", + "\n", + "cut_image = Load_Indepentend_Data(Loading_Config[\"Training_Labels\"], Encording_Label)\n", + "\n", + "Model = ModifiedXception(3)\n", + "\n", + "if torch.cuda.device_count() > 1:\n", + " Model = nn.DataParallel(Model)\n", + "\n", + "Model = Model.to(device)\n", + "TargetLayer = Model.base_model.conv4.pointwise\n", + "\n", + "Model.load_state_dict(torch.load(model_path))\n", + "\n", + "# 预处理对象\n", + "preprocess = Training_Precesses(256)\n", + "\n", + "cut_image.process_main(Loading_Config[\"Test_Data_Root\"]) # 呼叫處理test Data與Validation Data的function\n", + "test, test_label = cut_image.test, cut_image.test_label\n", + "\n", + "# 只评估目标类别\n", + "# 转换为PyTorch张量并移动到设备\n", + "test_dataset = preprocess.Setting_DataSet(cut_image.test, cut_image.test_label, \"Transform\")\n", + "test_loader = preprocess.Dataloader_Sampler(test_dataset, 1, False)\n", + "\n", + "Grad = GradCAM(Model, TargetLayer)\n", + "Grad.Processing_Main(test_loader, f\"123456\")" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "f1\n" + ] + } + ], + "source": [ + "def f1():\n", + " return 1\n", + "\n", + "import json\n", + "with open('utils/Stomach_Config.json') as f:\n", + " config = json.load(f)\n", + "\n", + "a = config[\"a\"]\n", + "\n", + "print(a[\"Function\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([1, 1000])\n" + ] + } + ], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "\n", + "class SeparableConv2d(nn.Module):\n", + " def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True):\n", + " super(SeparableConv2d, self).__init__()\n", + " self.depthwise = nn.Conv2d(in_channels, in_channels, kernel_size=kernel_size, stride=stride,\n", + " padding=padding, groups=in_channels, bias=bias)\n", + " self.pointwise = nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1,\n", + " padding=0, bias=bias)\n", + " \n", + " def forward(self, x):\n", + " x = self.depthwise(x)\n", + " x = self.pointwise(x)\n", + " return x\n", + "\n", + "class EntryFlow(nn.Module):\n", + " def __init__(self):\n", + " super(EntryFlow, self).__init__()\n", + " self.conv1 = nn.Conv2d(3, 32, 3, stride=2, padding=1, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(32)\n", + " self.conv2 = nn.Conv2d(32, 64, 3, padding=1, bias=False)\n", + " self.bn2 = nn.BatchNorm2d(64)\n", + " \n", + " self.conv3_residual = nn.Sequential(\n", + " SeparableConv2d(64, 128, 3, padding=1),\n", + " nn.BatchNorm2d(128),\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(128, 128, 3, padding=1),\n", + " nn.BatchNorm2d(128),\n", + " nn.MaxPool2d(3, stride=2, padding=1)\n", + " )\n", + " self.conv3_shortcut = nn.Conv2d(64, 128, 1, stride=2, bias=False)\n", + " self.bn3 = nn.BatchNorm2d(128)\n", + " \n", + " self.conv4_residual = nn.Sequential(\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(128, 256, 3, padding=1),\n", + " nn.BatchNorm2d(256),\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(256, 256, 3, padding=1),\n", + " nn.BatchNorm2d(256),\n", + " nn.MaxPool2d(3, stride=2, padding=1)\n", + " )\n", + " self.conv4_shortcut = nn.Conv2d(128, 256, 1, stride=2, bias=False)\n", + " self.bn4 = nn.BatchNorm2d(256)\n", + " \n", + " self.conv5_residual = nn.Sequential(\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(256, 728, 3, padding=1),\n", + " nn.BatchNorm2d(728),\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(728, 728, 3, padding=1),\n", + " nn.BatchNorm2d(728),\n", + " nn.MaxPool2d(3, stride=2, padding=1)\n", + " )\n", + " self.conv5_shortcut = nn.Conv2d(256, 728, 1, stride=2, bias=False)\n", + " self.bn5 = nn.BatchNorm2d(728)\n", + " \n", + " def forward(self, x):\n", + " x = F.relu(self.bn1(self.conv1(x)))\n", + " x = F.relu(self.bn2(self.conv2(x)))\n", + " \n", + " residual = self.conv3_residual(x)\n", + " shortcut = self.conv3_shortcut(x)\n", + " x = F.relu(self.bn3(residual + shortcut))\n", + " \n", + " residual = self.conv4_residual(x)\n", + " shortcut = self.conv4_shortcut(x)\n", + " x = F.relu(self.bn4(residual + shortcut))\n", + " \n", + " residual = self.conv5_residual(x)\n", + " shortcut = self.conv5_shortcut(x)\n", + " x = F.relu(self.bn5(residual + shortcut))\n", + " return x\n", + "\n", + "class MiddleFlow(nn.Module):\n", + " def __init__(self):\n", + " super(MiddleFlow, self).__init__()\n", + " self.conv_residual = nn.Sequential(\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(728, 728, 3, padding=1),\n", + " nn.BatchNorm2d(728),\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(728, 728, 3, padding=1),\n", + " nn.BatchNorm2d(728),\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(728, 728, 3, padding=1),\n", + " nn.BatchNorm2d(728)\n", + " )\n", + " \n", + " def forward(self, x):\n", + " return self.conv_residual(x) + x\n", + "\n", + "class ExitFlow(nn.Module):\n", + " def __init__(self, num_classes=1000):\n", + " super(ExitFlow, self).__init__()\n", + " self.conv1_residual = nn.Sequential(\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(728, 1024, 3, padding=1),\n", + " nn.BatchNorm2d(1024),\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(1024, 1024, 3, padding=1),\n", + " nn.BatchNorm2d(1024),\n", + " nn.MaxPool2d(3, stride=2, padding=1)\n", + " )\n", + " self.conv1_shortcut = nn.Conv2d(728, 1024, 1, stride=2, bias=False)\n", + " self.bn1 = nn.BatchNorm2d(1024)\n", + " \n", + " self.conv2 = nn.Sequential(\n", + " SeparableConv2d(1024, 1536, 3, padding=1),\n", + " nn.BatchNorm2d(1536),\n", + " nn.ReLU(inplace=True),\n", + " SeparableConv2d(1536, 2048, 3, padding=1),\n", + " nn.BatchNorm2d(2048),\n", + " nn.ReLU(inplace=True)\n", + " )\n", + " self.avgpool = nn.AdaptiveAvgPool2d((1, 1))\n", + " self.fc = nn.Linear(2048, num_classes)\n", + " \n", + " def forward(self, x):\n", + " residual = self.conv1_residual(x)\n", + " shortcut = self.conv1_shortcut(x)\n", + " x = F.relu(self.bn1(residual + shortcut))\n", + " \n", + " x = self.conv2(x)\n", + " x = self.avgpool(x)\n", + " x = x.view(x.size(0), -1)\n", + " x = self.fc(x)\n", + " return x\n", + "\n", + "class Xception(nn.Module):\n", + " def __init__(self, num_classes=1000):\n", + " super(Xception, self).__init__()\n", + " self.entry_flow = EntryFlow()\n", + " self.middle_flow = nn.Sequential(*[MiddleFlow() for _ in range(8)])\n", + " self.exit_flow = ExitFlow(num_classes)\n", + " \n", + " def forward(self, x):\n", + " x = self.entry_flow(x)\n", + " x = self.middle_flow(x)\n", + " x = self.exit_flow(x)\n", + " return x\n", + "\n", + "def xception(num_classes=1000):\n", + " return Xception(num_classes)\n", + "\n", + "# Example usage:\n", + "model = xception(num_classes=1000)\n", + "input_tensor = torch.randn(1, 3, 299, 299)\n", + "output = model(input_tensor)\n", + "print(output.shape) # Should be torch.Size([1, 1000])" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "完成了0張\n", + "完成了1張\n", + "完成了2張\n", + "完成了3張\n", + "完成了4張\n", + "完成了5張\n", + "完成了6張\n", + "完成了7張\n", + "完成了8張\n", + "完成了9張\n", + "完成了10張\n", + "完成了11張\n", + "完成了12張\n", + "完成了13張\n", + "完成了14張\n", + "完成了15張\n", + "完成了16張\n", + "完成了17張\n", + "完成了18張\n", + "完成了19張\n", + "完成了20張\n", + "完成了21張\n", + "完成了22張\n", + "完成了23張\n", + "完成了24張\n", + "完成了25張\n", + "完成了26張\n", + "完成了27張\n", + "完成了28張\n", + "完成了29張\n", + "完成了30張\n", + "完成了31張\n", + "完成了32張\n", + "完成了33張\n", + "完成了34張\n", + "完成了35張\n", + "完成了36張\n", + "完成了37張\n", + "完成了38張\n", + "完成了39張\n", + "完成了40張\n", + "完成了41張\n", + "完成了42張\n", + "完成了43張\n", + "完成了44張\n", + "完成了45張\n", + "完成了46張\n", + "完成了47張\n", + "完成了48張\n", + "完成了49張\n", + "完成了50張\n", + "完成了51張\n", + "完成了52張\n", + "完成了53張\n", + "完成了54張\n", + "完成了55張\n", + "完成了56張\n", + "完成了57張\n", + "完成了58張\n", + "完成了59張\n", + "完成了60張\n", + "完成了61張\n", + "完成了62張\n", + "完成了63張\n", + "完成了64張\n", + "完成了65張\n", + "完成了66張\n", + "完成了67張\n", + "完成了68張\n", + "完成了69張\n", + "完成了70張\n", + "完成了71張\n", + "完成了72張\n", + "完成了73張\n", + "完成了74張\n", + "完成了75張\n", + "完成了76張\n", + "完成了77張\n", + "完成了78張\n", + "完成了79張\n", + "完成了80張\n", + "完成了81張\n", + "完成了82張\n", + "完成了83張\n", + "完成了84張\n", + "完成了85張\n", + "完成了86張\n", + "完成了87張\n", + "完成了88張\n", + "完成了89張\n", + "完成了90張\n", + "完成了91張\n", + "完成了92張\n", + "完成了93張\n", + "完成了94張\n", + "完成了95張\n", + "完成了96張\n", + "完成了97張\n", + "完成了98張\n", + "完成了99張\n", + "完成了100張\n", + "完成了101張\n", + "完成了102張\n", + "完成了103張\n", + "完成了104張\n", + "完成了105張\n", + "完成了106張\n", + "完成了107張\n", + "完成了108張\n", + "完成了109張\n", + "完成了110張\n", + "完成了111張\n", + "完成了112張\n", + "完成了113張\n", + "完成了114張\n", + "完成了115張\n", + "完成了116張\n", + "完成了117張\n", + "完成了118張\n", + "完成了119張\n", + "完成了120張\n", + "完成了121張\n", + "完成了122張\n", + "完成了123張\n", + "完成了124張\n", + "完成了125張\n", + "完成了126張\n", + "完成了127張\n", + "完成了128張\n", + "完成了129張\n", + "完成了130張\n", + "完成了131張\n", + "完成了132張\n", + "完成了133張\n", + "完成了134張\n", + "完成了135張\n", + "完成了136張\n", + "完成了137張\n", + "完成了138張\n", + "完成了139張\n", + "完成了140張\n", + "完成了141張\n", + "完成了142張\n", + "完成了143張\n", + "完成了144張\n", + "完成了145張\n", + "完成了146張\n", + "完成了147張\n", + "完成了148張\n", + "完成了149張\n", + "完成了150張\n", + "完成了151張\n", + "完成了152張\n", + "完成了153張\n", + "完成了154張\n", + "完成了155張\n", + "完成了156張\n", + "完成了157張\n", + "完成了158張\n", + "完成了159張\n", + "完成了160張\n", + "完成了161張\n", + "完成了162張\n", + "完成了163張\n", + "完成了164張\n", + "完成了165張\n", + "完成了166張\n", + "完成了167張\n", + "完成了168張\n", + "完成了169張\n", + "完成了170張\n", + "完成了171張\n", + "完成了172張\n", + "完成了173張\n", + "完成了174張\n", + "完成了175張\n", + "完成了176張\n", + "完成了177張\n", + "完成了178張\n", + "完成了179張\n", + "完成了180張\n", + "完成了181張\n", + "完成了182張\n", + "完成了183張\n", + "完成了184張\n", + "完成了185張\n", + "完成了186張\n", + "完成了187張\n", + "完成了188張\n", + "完成了189張\n", + "完成了190張\n", + "完成了191張\n", + "完成了192張\n", + "完成了193張\n", + "完成了194張\n", + "完成了195張\n", + "完成了196張\n", + "完成了197張\n", + "完成了198張\n", + "完成了199張\n", + "完成了200張\n", + "完成了201張\n", + "完成了202張\n", + "完成了203張\n", + "完成了204張\n", + "完成了205張\n", + "完成了206張\n", + "完成了207張\n", + "完成了208張\n", + "完成了209張\n", + "完成了210張\n", + "完成了211張\n", + "完成了212張\n", + "完成了213張\n", + "完成了214張\n", + "完成了215張\n", + "完成了216張\n", + "完成了217張\n", + "完成了218張\n", + "完成了219張\n", + "完成了220張\n", + "完成了221張\n", + "完成了222張\n", + "完成了223張\n", + "完成了224張\n", + "完成了225張\n", + "完成了226張\n", + "完成了227張\n", + "完成了228張\n", + "完成了229張\n", + "完成了230張\n", + "完成了231張\n", + "完成了232張\n", + "完成了233張\n", + "完成了234張\n", + "完成了235張\n", + "完成了236張\n", + "完成了237張\n" + ] + } + ], + "source": [ + "import cv2\n", + "import os\n", + "import glob\n", + "\n", + "from utils.Stomach_Config import Loading_Config\n", + "from Load_process.file_processing import Process_File\n", + "from Load_process.LoadData import Load_Data_Tools\n", + "\n", + "file = Process_File()\n", + "Load_Data_Tools = Load_Data_Tools()\n", + "Data_Dict_Data = {\"TestingProcess_Images\" : []}\n", + "\n", + "path = os.path.join(\"../TestProcess_Image\", \"*\")\n", + "path = glob.glob(path)\n", + "Training_Data = path\n", + "\n", + "i = 0\n", + "file.JudgeRoot_MakeDir(Loading_Config[\"Process_Roots\"])\n", + "for Data in Training_Data:\n", + " image = cv2.imread(Data)\n", + " # 轉換為 HSV 色彩空間\n", + " image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)\n", + " # 方法1:固定閾值二值化\n", + " threshold_value = 100 # 閾值,可以調整\n", + " _, binary = cv2.threshold(image, threshold_value, 255, cv2.THRESH_BINARY)\n", + "\n", + " kernel_ellipse = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (7, 7)) # 橢圓核\n", + " # closing_ellipse = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel_ellipse)\n", + " # closing_ellipse = cv2.erode(closing_ellipse, kernel_ellipse, iterations=1)\n", + "\n", + " path = file.Make_Save_Root(f\"{i}.png\", Loading_Config[\"Process_Roots\"])\n", + " cv2.imwrite(path, closing_ellipse)\n", + " print(f\"完成了{i}張\")\n", + " i += 1" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import xml.etree.ElementTree as ET\n", + "import cv2\n", + "import os\n", + "import numpy as np\n", + "from typing import List, Dict, Optional, Tuple\n", + "from utils.Stomach_Config import Loading_Config\n", + "\n", + "class XMLAnnotationProcessor:\n", + " \"\"\"\n", + " XML標註檔案處理器\n", + " 專門處理包含bounding box資訊的XML檔案,並在對應圖片上繪製邊界框\n", + " \"\"\"\n", + " \n", + " def __init__(self, dataset_root: str = \"../Dataset/Training\"):\n", + " \"\"\"\n", + " 初始化XML處理器\n", + " \n", + " Args:\n", + " dataset_root: 圖片資料集根目錄\n", + " output_folder: 輸出資料夾\n", + " \"\"\"\n", + " self.dataset_root = dataset_root\n", + " self.box_color = (0, 255, 0) # 綠色邊界框\n", + " self.text_color = (0, 255, 0) # 綠色文字\n", + " self.box_thickness = 2\n", + " self.font_scale = 0.5\n", + " self.font = cv2.FONT_HERSHEY_SIMPLEX\n", + " \n", + " def _ensure_output_folder(self, Save_Root: str) -> None:\n", + " \"\"\"確保輸出資料夾存在\"\"\"\n", + " if not os.path.exists(Save_Root):\n", + " os.makedirs(Save_Root)\n", + " \n", + " def parse_xml(self, xml_file_path: str, Label: str) -> Optional[Dict]:\n", + " \"\"\"\n", + " 解析XML檔案並提取所有相關資訊\n", + " \n", + " Args:\n", + " xml_file_path: XML檔案路徑\n", + " \n", + " Returns:\n", + " Dict: 包含檔案資訊和bounding box的字典,解析失敗時返回None\n", + " \"\"\"\n", + " try:\n", + " tree = ET.parse(xml_file_path)\n", + " root = tree.getroot()\n", + " \n", + " # 提取基本資訊\n", + " filename_element = root.find('filename')\n", + " \n", + " if filename_element is None:\n", + " print(f\"找不到path元素在 {xml_file_path}\")\n", + " return None\n", + " \n", + " filename = filename_element.text if filename_element is not None else \"Unknown\"\n", + " Original_Image_Data_Root = os.path.join(self.dataset_root, Label)\n", + " Original_Image_Data_Root = os.path.join(Original_Image_Data_Root, filename)\n", + " \n", + " # 提取圖片尺寸\n", + " size_element = root.find('size')\n", + " width = int(size_element.find('width').text) if size_element is not None else 0\n", + " height = int(size_element.find('height').text) if size_element is not None else 0\n", + " depth = int(size_element.find('depth').text) if size_element is not None else 3\n", + " \n", + " # 提取所有bounding box\n", + " bounding_boxes = []\n", + " objects = root.findall('object')\n", + " \n", + " for obj in objects:\n", + " bndbox = obj.find('bndbox')\n", + " if bndbox is not None:\n", + " bbox_info = {\n", + " 'name': obj.find('name').text if obj.find('name') is not None else \"Unknown\",\n", + " 'pose': obj.find('pose').text if obj.find('pose') is not None else \"Unspecified\",\n", + " 'truncated': int(obj.find('truncated').text) if obj.find('truncated') is not None else 0,\n", + " 'difficult': int(obj.find('difficult').text) if obj.find('difficult') is not None else 0,\n", + " 'xmin': int(bndbox.find('xmin').text),\n", + " 'ymin': int(bndbox.find('ymin').text),\n", + " 'xmax': int(bndbox.find('xmax').text),\n", + " 'ymax': int(bndbox.find('ymax').text)\n", + " }\n", + " bounding_boxes.append(bbox_info)\n", + " \n", + " return {\n", + " 'filename': filename,\n", + " 'image_path': Original_Image_Data_Root,\n", + " 'width': width,\n", + " 'height': height,\n", + " 'depth': depth,\n", + " 'bounding_boxes': bounding_boxes\n", + " }\n", + " \n", + " except Exception as e:\n", + " print(f\"解析XML檔案 {xml_file_path} 時發生錯誤: {str(e)}\")\n", + " return None\n", + " \n", + " def load_image(self, image_path: str) -> Optional[np.ndarray]:\n", + " \"\"\"\n", + " 載入圖片檔案\n", + " \n", + " Args:\n", + " image_path: 圖片檔案路徑\n", + " \n", + " Returns:\n", + " np.ndarray: 圖片陣列,載入失敗時返回None\n", + " \"\"\"\n", + " if not os.path.exists(image_path):\n", + " print(f\"圖片檔案不存在: {image_path}\")\n", + " return None\n", + " \n", + " image = cv2.imread(image_path)\n", + " if image is None:\n", + " print(f\"無法讀取圖片: {image_path}\")\n", + " return None\n", + " \n", + " return image\n", + " \n", + " def draw_bounding_boxes(self, image: np.ndarray, bounding_boxes: List[Dict]) -> np.ndarray:\n", + " \"\"\"\n", + " 創建遮罩圖片:bounding box內為白色,外部為黑色\n", + " \n", + " Args:\n", + " image: 圖片陣列\n", + " bounding_boxes: bounding box資訊列表\n", + " \n", + " Returns:\n", + " np.ndarray: 處理後的遮罩圖片陣列\n", + " \"\"\"\n", + " # 創建黑色背景圖片\n", + " height, width = image.shape[:2]\n", + " result_image = np.zeros((height, width, 3), dtype=np.uint8)\n", + " \n", + " for i, bbox in enumerate(bounding_boxes):\n", + " xmin, ymin = bbox['xmin'], bbox['ymin']\n", + " xmax, ymax = bbox['xmax'], bbox['ymax']\n", + " object_name = bbox['name']\n", + " \n", + " # 確保座標在圖片範圍內\n", + " xmin = max(0, min(xmin, width-1))\n", + " ymin = max(0, min(ymin, height-1))\n", + " xmax = max(0, min(xmax, width-1))\n", + " ymax = max(0, min(ymax, height-1))\n", + " \n", + " # 將bounding box範圍內設為白色 (255, 255, 255)\n", + " result_image[ymin:ymax, xmin:xmax] = [255, 255, 255]\n", + " \n", + " print(f\"Object {i+1}: {object_name} - 座標: ({xmin}, {ymin}, {xmax}, {ymax})\")\n", + " \n", + " return result_image\n", + " \n", + " def save_annotated_image(self, image: np.ndarray, original_filename: str, Label : str) -> str:\n", + " \"\"\"\n", + " 儲存標註後的圖片\n", + " \n", + " Args:\n", + " image: 標註後的圖片陣列\n", + " original_filename: 原始檔案名稱\n", + " \n", + " Returns:\n", + " str: 儲存的檔案路徑\n", + " \"\"\"\n", + " output_filename = f\"annotated_{original_filename}\"\n", + " output_path = os.path.join(Loading_Config[\"Annotation_Root\"], Label)\n", + " Save_Image_Roots = os.path.join(output_path, output_filename)\n", + " # 確保輸出資料夾存在\n", + " self._ensure_output_folder(output_path)\n", + "\n", + " cv2.imwrite(Save_Image_Roots, image)\n", + " print(f\"已儲存標註圖片至: {Save_Image_Roots}\")\n", + " return Save_Image_Roots\n", + " \n", + " def process_single_xml(self, xml_file_path: str, Label : str) -> Optional[Tuple[np.ndarray, str]]:\n", + " \"\"\"\n", + " 處理單一XML檔案\n", + " \n", + " Args:\n", + " xml_file_path: XML檔案路徑\n", + " \n", + " Returns:\n", + " Tuple[np.ndarray, str]: (標註後的圖片, 輸出路徑),處理失敗時返回None\n", + " \"\"\"\n", + " # 解析XML\n", + " xml_data = self.parse_xml(xml_file_path, Label)\n", + " if xml_data is None:\n", + " return None\n", + " \n", + " # 載入圖片\n", + " image = self.load_image(xml_data['image_path'])\n", + " if image is None:\n", + " return None\n", + " \n", + " # 繪製bounding box\n", + " annotated_image = self.draw_bounding_boxes(image, xml_data['bounding_boxes'])\n", + " \n", + " # 儲存結果\n", + " output_path = self.save_annotated_image(annotated_image, xml_data['filename'], Label)\n", + " \n", + " return annotated_image, output_path\n", + " \n", + " def process_multiple_xml(self, xml_folder_path: str, Label : str) -> List[Tuple[str, bool]]:\n", + " \"\"\"\n", + " 批量處理多個XML檔案\n", + " \n", + " Args:\n", + " xml_folder_path: 包含XML檔案的資料夾路徑\n", + " \n", + " Returns:\n", + " List[Tuple[str, bool]]: [(檔案名稱, 處理成功與否), ...]\n", + " \"\"\"\n", + " if not os.path.exists(xml_folder_path):\n", + " print(f\"XML資料夾不存在: {xml_folder_path}\")\n", + " return []\n", + " \n", + " xml_files = [f for f in os.listdir(xml_folder_path) if f.endswith('.xml')]\n", + " \n", + " if not xml_files:\n", + " print(f\"在 {xml_folder_path} 中找不到XML檔案\")\n", + " return []\n", + " \n", + " print(f\"找到 {len(xml_files)} 個XML檔案\")\n", + " for xml_file in xml_files: \n", + " try:\n", + " Read_XML_File = os.path.join(xml_folder_path, xml_file)\n", + " self.process_single_xml(Read_XML_File, Label)\n", + " print(f\"\\n處理檔案: {xml_file}\")\n", + " except Exception as e:\n", + " print(f\"處理 {xml_file} 時發生錯誤: {str(e)}\")\n", + " return\n", + " \n", + " def get_bounding_boxes_info(self, xml_file_path: str) -> Optional[Dict]:\n", + " \"\"\"\n", + " 僅提取XML中的bounding box資訊,不進行圖片處理\n", + " \n", + " Args:\n", + " xml_file_path: XML檔案路徑\n", + " \n", + " Returns:\n", + " Dict: 包含檔案資訊和bounding box座標的字典\n", + " \"\"\"\n", + " return self.parse_xml(xml_file_path)\n", + " \n", + " def set_drawing_style(self, box_color: Tuple[int, int, int] = None, \n", + " text_color: Tuple[int, int, int] = None,\n", + " box_thickness: int = None, \n", + " font_scale: float = None) -> None:\n", + " \"\"\"\n", + " 設定繪圖樣式\n", + " \n", + " Args:\n", + " box_color: 邊界框顏色 (B, G, R)\n", + " text_color: 文字顏色 (B, G, R)\n", + " box_thickness: 邊界框粗細\n", + " font_scale: 字體大小\n", + " \"\"\"\n", + " if box_color is not None:\n", + " self.box_color = box_color\n", + " if text_color is not None:\n", + " self.text_color = text_color\n", + " if box_thickness is not None:\n", + " self.box_thickness = box_thickness\n", + " if font_scale is not None:\n", + " self.font_scale = font_scale" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "XML標註處理器已準備就绪\n", + "找到 232 個XML檔案\n", + "Object 1: Have_Question - 座標: (263, 740, 333, 814)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a00.jpg\n", + "\n", + "處理檔案: a00.xml\n", + "Object 1: Have_Question - 座標: (406, 206, 608, 368)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1000.jpg\n", + "\n", + "處理檔案: A1000.xml\n", + "Object 1: Have_Question - 座標: (740, 330, 819, 401)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1002.jpg\n", + "\n", + "處理檔案: A1002.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A1010.jpg\n", + "\n", + "處理檔案: A1010.xml\n", + "Object 1: Have_Question - 座標: (349, 655, 474, 790)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1012.jpg\n", + "\n", + "處理檔案: A1012.xml\n", + "Object 1: Have_Question - 座標: (707, 89, 1206, 746)\n", + "Object 2: Have_Question - 座標: (100, 199, 410, 816)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1020.jpg\n", + "\n", + "處理檔案: A1020.xml\n", + "Object 1: Have_Question - 座標: (720, 391, 769, 439)\n", + "Object 2: Have_Question - 座標: (833, 621, 969, 733)\n", + "Object 3: Have_Question - 座標: (337, 595, 735, 900)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1021.jpg\n", + "\n", + "處理檔案: A1021.xml\n", + "Object 1: Have_Question - 座標: (227, 103, 518, 213)\n", + "Object 2: Have_Question - 座標: (264, 560, 423, 667)\n", + "Object 3: Have_Question - 座標: (423, 724, 522, 810)\n", + "Object 4: Have_Question - 座標: (686, 652, 903, 967)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1030.jpg\n", + "\n", + "處理檔案: A1030.xml\n", + "Object 1: Have_Question - 座標: (134, 266, 342, 414)\n", + "Object 2: Have_Question - 座標: (308, 539, 486, 676)\n", + "Object 3: Have_Question - 座標: (794, 479, 976, 669)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1031.jpg\n", + "\n", + "處理檔案: A1031.xml\n", + "Object 1: Have_Question - 座標: (396, 213, 905, 977)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A10310.jpg\n", + "\n", + "處理檔案: A10310.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A1032.jpg\n", + "\n", + "處理檔案: A1032.xml\n", + "Object 1: Have_Question - 座標: (126, 440, 190, 522)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1033.jpg\n", + "\n", + "處理檔案: A1033.xml\n", + "Object 1: Have_Question - 座標: (301, 379, 484, 527)\n", + "Object 2: Have_Question - 座標: (642, 484, 771, 615)\n", + "Object 3: Have_Question - 座標: (642, 772, 700, 828)\n", + "Object 4: Have_Question - 座標: (495, 836, 538, 871)\n", + "Object 5: Have_Question - 座標: (754, 866, 858, 943)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1034.jpg\n", + "\n", + "處理檔案: A1034.xml\n", + "Object 1: Have_Question - 座標: (375, 423, 629, 543)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1036.jpg\n", + "\n", + "處理檔案: A1036.xml\n", + "Object 1: Have_Question - 座標: (260, 360, 782, 748)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1037.jpg\n", + "\n", + "處理檔案: A1037.xml\n", + "Object 1: Have_Question - 座標: (764, 305, 901, 433)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1040.jpg\n", + "\n", + "處理檔案: A1040.xml\n", + "Object 1: Have_Question - 座標: (336, 622, 681, 930)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1051.jpg\n", + "\n", + "處理檔案: A1051.xml\n", + "Object 1: Have_Question - 座標: (32, 212, 441, 979)\n", + "Object 2: Have_Question - 座標: (536, 578, 769, 777)\n", + "Object 3: Have_Question - 座標: (981, 819, 1035, 858)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1052.jpg\n", + "\n", + "處理檔案: A1052.xml\n", + "Object 1: Have_Question - 座標: (28, 379, 614, 605)\n", + "Object 2: Have_Question - 座標: (1007, 285, 1190, 503)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1061.jpg\n", + "\n", + "處理檔案: A1061.xml\n", + "Object 1: Have_Question - 座標: (399, 236, 492, 333)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1070.jpg\n", + "\n", + "處理檔案: A1070.xml\n", + "Object 1: Have_Question - 座標: (395, 269, 664, 391)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1071.jpg\n", + "\n", + "處理檔案: A1071.xml\n", + "Object 1: Have_Question - 座標: (207, 330, 777, 726)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1072.jpg\n", + "\n", + "處理檔案: A1072.xml\n", + "Object 1: Have_Question - 座標: (160, 221, 218, 323)\n", + "Object 2: Have_Question - 座標: (140, 567, 221, 654)\n", + "Object 3: Have_Question - 座標: (495, 513, 663, 799)\n", + "Object 4: Have_Question - 座標: (600, 353, 797, 477)\n", + "Object 5: Have_Question - 座標: (735, 117, 793, 168)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1075.jpg\n", + "\n", + "處理檔案: A1075.xml\n", + "Object 1: Have_Question - 座標: (590, 478, 765, 612)\n", + "Object 2: Have_Question - 座標: (198, 607, 522, 845)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1080.jpg\n", + "\n", + "處理檔案: A1080.xml\n", + "Object 1: Have_Question - 座標: (805, 545, 963, 624)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a110.jpg\n", + "\n", + "處理檔案: a110.xml\n", + "Object 1: Have_Question - 座標: (427, 194, 472, 243)\n", + "Object 2: Have_Question - 座標: (863, 42, 970, 257)\n", + "Object 3: Have_Question - 座標: (595, 555, 791, 714)\n", + "Object 4: Have_Question - 座標: (648, 786, 747, 875)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1100.jpg\n", + "\n", + "處理檔案: A1100.xml\n", + "Object 1: Have_Question - 座標: (964, 71, 1131, 187)\n", + "Object 2: Have_Question - 座標: (774, 600, 861, 698)\n", + "Object 3: Have_Question - 座標: (756, 770, 849, 861)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1102.jpg\n", + "\n", + "處理檔案: A1102.xml\n", + "Object 1: Have_Question - 座標: (185, 685, 394, 825)\n", + "Object 2: Have_Question - 座標: (710, 482, 823, 550)\n", + "Object 3: Have_Question - 座標: (872, 657, 938, 725)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1103.jpg\n", + "\n", + "處理檔案: A1103.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A1104.jpg\n", + "\n", + "處理檔案: A1104.xml\n", + "Object 1: Have_Question - 座標: (721, 145, 1116, 581)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A1110.jpg\n", + "\n", + "處理檔案: A1110.xml\n", + "Object 1: Have_Question - 座標: (737, 198, 1036, 776)\n", + "Object 2: Have_Question - 座標: (499, 132, 608, 224)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a113.jpg\n", + "\n", + "處理檔案: a113.xml\n", + "Object 1: Have_Question - 座標: (385, 258, 928, 688)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a120.jpg\n", + "\n", + "處理檔案: a120.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a130.jpg\n", + "\n", + "處理檔案: a130.xml\n", + "Object 1: Have_Question - 座標: (297, 136, 773, 624)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a132.jpg\n", + "\n", + "處理檔案: a132.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a140.jpg\n", + "\n", + "處理檔案: a140.xml\n", + "Object 1: Have_Question - 座標: (855, 281, 1031, 667)\n", + "Object 2: Have_Question - 座標: (650, 664, 928, 900)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a144.jpg\n", + "\n", + "處理檔案: a144.xml\n", + "Object 1: Have_Question - 座標: (480, 290, 775, 513)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a150.jpg\n", + "\n", + "處理檔案: a150.xml\n", + "Object 1: Have_Question - 座標: (329, 180, 610, 435)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a172.jpg\n", + "\n", + "處理檔案: a172.xml\n", + "Object 1: Have_Question - 座標: (340, 399, 553, 563)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a180.jpg\n", + "\n", + "處理檔案: a180.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a181.jpg\n", + "\n", + "處理檔案: a181.xml\n", + "Object 1: Have_Question - 座標: (648, 280, 946, 569)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a182.jpg\n", + "\n", + "處理檔案: a182.xml\n", + "Object 1: Have_Question - 座標: (314, 770, 528, 953)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a184.jpg\n", + "\n", + "處理檔案: a184.xml\n", + "Object 1: Have_Question - 座標: (446, 468, 629, 640)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a190.jpg\n", + "\n", + "處理檔案: a190.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a200.jpg\n", + "\n", + "處理檔案: a200.xml\n", + "Object 1: Have_Question - 座標: (709, 777, 861, 909)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a211.jpg\n", + "\n", + "處理檔案: a211.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a233.jpg\n", + "\n", + "處理檔案: a233.xml\n", + "Object 1: Have_Question - 座標: (68, 108, 571, 624)\n", + "Object 2: Have_Question - 座標: (761, 473, 916, 670)\n", + "Object 3: Have_Question - 座標: (635, 886, 750, 978)\n", + "Object 4: Have_Question - 座標: (897, 960, 968, 1030)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a2410.jpg\n", + "\n", + "處理檔案: a2410.xml\n", + "Object 1: Have_Question - 座標: (916, 89, 1429, 411)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a249.jpg\n", + "\n", + "處理檔案: a249.xml\n", + "Object 1: Have_Question - 座標: (374, 477, 442, 546)\n", + "Object 2: Have_Question - 座標: (529, 431, 599, 505)\n", + "Object 3: Have_Question - 座標: (726, 415, 783, 525)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a2513.jpg\n", + "\n", + "處理檔案: a2513.xml\n", + "Object 1: Have_Question - 座標: (504, 416, 625, 480)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a30.jpg\n", + "\n", + "處理檔案: a30.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a300.jpg\n", + "\n", + "處理檔案: a300.xml\n", + "Object 1: Have_Question - 座標: (764, 487, 1269, 742)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a301.jpg\n", + "\n", + "處理檔案: a301.xml\n", + "Object 1: Have_Question - 座標: (516, 594, 1626, 1047)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a302.jpg\n", + "\n", + "處理檔案: a302.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a303.jpg\n", + "\n", + "處理檔案: a303.xml\n", + "Object 1: Have_Question - 座標: (628, 394, 844, 574)\n", + "Object 2: Have_Question - 座標: (1252, 405, 1327, 487)\n", + "Object 3: Have_Question - 座標: (706, 625, 1272, 980)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a316.jpg\n", + "\n", + "處理檔案: a316.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a360.jpg\n", + "\n", + "處理檔案: a360.xml\n", + "Object 1: Have_Question - 座標: (816, 122, 913, 195)\n", + "Object 2: Have_Question - 座標: (822, 262, 1023, 549)\n", + "Object 3: Have_Question - 座標: (881, 589, 942, 712)\n", + "Object 4: Have_Question - 座標: (738, 778, 796, 826)\n", + "Object 5: Have_Question - 座標: (332, 822, 637, 912)\n", + "Object 6: Have_Question - 座標: (687, 927, 823, 981)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a3611.jpg\n", + "\n", + "處理檔案: a3611.xml\n", + "Object 1: Have_Question - 座標: (962, 457, 1093, 640)\n", + "Object 2: Have_Question - 座標: (918, 796, 1176, 1034)\n", + "Object 3: Have_Question - 座標: (610, 935, 700, 1045)\n", + "Object 4: Have_Question - 座標: (602, 39, 710, 188)\n", + "Object 5: Have_Question - 座標: (385, 196, 476, 319)\n", + "Object 6: Have_Question - 座標: (867, 50, 1104, 343)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a3612.jpg\n", + "\n", + "處理檔案: a3612.xml\n", + "Object 1: Have_Question - 座標: (235, 364, 931, 912)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a3613.jpg\n", + "\n", + "處理檔案: a3613.xml\n", + "Object 1: Have_Question - 座標: (373, 254, 686, 406)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a3615.jpg\n", + "\n", + "處理檔案: a3615.xml\n", + "Object 1: Have_Question - 座標: (414, 246, 673, 388)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a3616.jpg\n", + "\n", + "處理檔案: a3616.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a364.jpg\n", + "\n", + "處理檔案: a364.xml\n", + "Object 1: Have_Question - 座標: (1213, 42, 1341, 150)\n", + "Object 2: Have_Question - 座標: (1174, 171, 1549, 382)\n", + "Object 3: Have_Question - 座標: (1219, 379, 1566, 596)\n", + "Object 4: Have_Question - 座標: (1086, 696, 1404, 826)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a365.jpg\n", + "\n", + "處理檔案: a365.xml\n", + "Object 1: Have_Question - 座標: (1542, 266, 1654, 407)\n", + "Object 2: Have_Question - 座標: (1151, 845, 1224, 922)\n", + "Object 3: Have_Question - 座標: (813, 931, 952, 1011)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a367.jpg\n", + "\n", + "處理檔案: a367.xml\n", + "Object 1: Have_Question - 座標: (1058, 337, 1152, 607)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a368.jpg\n", + "\n", + "處理檔案: a368.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a375.jpg\n", + "\n", + "處理檔案: a375.xml\n", + "Object 1: Have_Question - 座標: (132, 460, 354, 685)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a4710.jpg\n", + "\n", + "處理檔案: a4710.xml\n", + "Object 1: Have_Question - 座標: (90, 560, 328, 797)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a4711.jpg\n", + "\n", + "處理檔案: a4711.xml\n", + "Object 1: Have_Question - 座標: (132, 355, 366, 515)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a4712.jpg\n", + "\n", + "處理檔案: a4712.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a473.jpg\n", + "\n", + "處理檔案: a473.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a474.jpg\n", + "\n", + "處理檔案: a474.xml\n", + "Object 1: Have_Question - 座標: (622, 496, 696, 564)\n", + "Object 2: Have_Question - 座標: (1053, 678, 1162, 759)\n", + "Object 3: Have_Question - 座標: (715, 533, 1004, 761)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a4911.jpg\n", + "\n", + "處理檔案: a4911.xml\n", + "Object 1: Have_Question - 座標: (517, 570, 736, 712)\n", + "Object 2: Have_Question - 座標: (676, 723, 802, 798)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a4912.jpg\n", + "\n", + "處理檔案: a4912.xml\n", + "Object 1: Have_Question - 座標: (809, 234, 1010, 421)\n", + "Object 2: Have_Question - 座標: (383, 678, 448, 743)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a497.jpg\n", + "\n", + "處理檔案: a497.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a50.jpg\n", + "\n", + "處理檔案: a50.xml\n", + "Object 1: Have_Question - 座標: (117, 195, 708, 978)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a509.jpg\n", + "\n", + "處理檔案: a509.xml\n", + "Object 1: Have_Question - 座標: (413, 539, 567, 622)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a511.jpg\n", + "\n", + "處理檔案: a511.xml\n", + "Object 1: Have_Question - 座標: (528, 121, 581, 171)\n", + "Object 2: Have_Question - 座標: (885, 276, 964, 354)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a513.jpg\n", + "\n", + "處理檔案: a513.xml\n", + "Object 1: Have_Question - 座標: (978, 458, 1151, 664)\n", + "Object 2: Have_Question - 座標: (672, 873, 849, 1043)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a516.jpg\n", + "\n", + "處理檔案: a516.xml\n", + "Object 1: Have_Question - 座標: (201, 101, 904, 499)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a520.jpg\n", + "\n", + "處理檔案: a520.xml\n", + "Object 1: Have_Question - 座標: (46, 107, 746, 687)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a521.jpg\n", + "\n", + "處理檔案: a521.xml\n", + "Object 1: Have_Question - 座標: (921, 779, 1014, 860)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a523.jpg\n", + "\n", + "處理檔案: a523.xml\n", + "Object 1: Have_Question - 座標: (386, 101, 745, 377)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a524.jpg\n", + "\n", + "處理檔案: a524.xml\n", + "Object 1: Have_Question - 座標: (89, 619, 357, 827)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a526.jpg\n", + "\n", + "處理檔案: a526.xml\n", + "Object 1: Have_Question - 座標: (164, 110, 757, 294)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a5312.jpg\n", + "\n", + "處理檔案: a5312.xml\n", + "Object 1: Have_Question - 座標: (62, 368, 390, 731)\n", + "Object 2: Have_Question - 座標: (231, 276, 849, 446)\n", + "Object 3: Have_Question - 座標: (735, 337, 1025, 907)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a5314.jpg\n", + "\n", + "處理檔案: a5314.xml\n", + "Object 1: Have_Question - 座標: (260, 242, 478, 469)\n", + "Object 2: Have_Question - 座標: (736, 448, 919, 607)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a536.jpg\n", + "\n", + "處理檔案: a536.xml\n", + "Object 1: Have_Question - 座標: (163, 127, 273, 327)\n", + "Object 2: Have_Question - 座標: (470, 230, 576, 315)\n", + "Object 3: Have_Question - 座標: (827, 134, 925, 213)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a538.jpg\n", + "\n", + "處理檔案: a538.xml\n", + "Object 1: Have_Question - 座標: (176, 401, 455, 689)\n", + "Object 2: Have_Question - 座標: (556, 331, 632, 416)\n", + "Object 3: Have_Question - 座標: (746, 267, 803, 340)\n", + "Object 4: Have_Question - 座標: (567, 459, 632, 519)\n", + "Object 5: Have_Question - 座標: (794, 391, 858, 461)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a539.jpg\n", + "\n", + "處理檔案: a539.xml\n", + "Object 1: Have_Question - 座標: (400, 369, 452, 421)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a551.jpg\n", + "\n", + "處理檔案: a551.xml\n", + "Object 1: Have_Question - 座標: (324, 124, 836, 389)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a5511.jpg\n", + "\n", + "處理檔案: a5511.xml\n", + "Object 1: Have_Question - 座標: (46, 763, 177, 896)\n", + "Object 2: Have_Question - 座標: (392, 662, 587, 971)\n", + "Object 3: Have_Question - 座標: (635, 160, 1000, 972)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a560.jpg\n", + "\n", + "處理檔案: a560.xml\n", + "Object 1: Have_Question - 座標: (36, 399, 435, 712)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a563.jpg\n", + "\n", + "處理檔案: a563.xml\n", + "Object 1: Have_Question - 座標: (306, 617, 342, 675)\n", + "Object 2: Have_Question - 座標: (758, 581, 824, 658)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a571.jpg\n", + "\n", + "處理檔案: a571.xml\n", + "Object 1: Have_Question - 座標: (215, 288, 743, 762)\n", + "Object 2: Have_Question - 座標: (809, 423, 931, 681)\n", + "Object 3: Have_Question - 座標: (734, 830, 815, 972)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a590.jpg\n", + "\n", + "處理檔案: a590.xml\n", + "Object 1: Have_Question - 座標: (353, 93, 788, 428)\n", + "Object 2: Have_Question - 座標: (698, 406, 837, 641)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a591.jpg\n", + "\n", + "處理檔案: a591.xml\n", + "Object 1: Have_Question - 座標: (231, 215, 659, 603)\n", + "Object 2: Have_Question - 座標: (662, 250, 920, 770)\n", + "Object 3: Have_Question - 座標: (425, 775, 920, 984)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a592.jpg\n", + "\n", + "處理檔案: a592.xml\n", + "Object 1: Have_Question - 座標: (400, 509, 597, 800)\n", + "Object 2: Have_Question - 座標: (492, 801, 599, 981)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a593.jpg\n", + "\n", + "處理檔案: a593.xml\n", + "Object 1: Have_Question - 座標: (345, 379, 621, 684)\n", + "Object 2: Have_Question - 座標: (630, 433, 906, 869)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a594.jpg\n", + "\n", + "處理檔案: a594.xml\n", + "Object 1: Have_Question - 座標: (239, 317, 371, 431)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a60.jpg\n", + "\n", + "處理檔案: a60.xml\n", + "Object 1: Have_Question - 座標: (266, 567, 609, 873)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a61.jpg\n", + "\n", + "處理檔案: a61.xml\n", + "Object 1: Have_Question - 座標: (365, 69, 539, 135)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a610.jpg\n", + "\n", + "處理檔案: a610.xml\n", + "Object 1: Have_Question - 座標: (175, 577, 246, 636)\n", + "Object 2: Have_Question - 座標: (613, 54, 698, 140)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a613.jpg\n", + "\n", + "處理檔案: a613.xml\n", + "Object 1: Have_Question - 座標: (439, 325, 584, 441)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a614.jpg\n", + "\n", + "處理檔案: a614.xml\n", + "Object 1: Have_Question - 座標: (94, 560, 200, 675)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a616.jpg\n", + "\n", + "處理檔案: a616.xml\n", + "Object 1: Have_Question - 座標: (461, 489, 674, 640)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a617.jpg\n", + "\n", + "處理檔案: a617.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a62.jpg\n", + "\n", + "處理檔案: a62.xml\n", + "Object 1: Have_Question - 座標: (622, 190, 848, 413)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a622.jpg\n", + "\n", + "處理檔案: a622.xml\n", + "Object 1: Have_Question - 座標: (608, 764, 783, 932)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a625.jpg\n", + "\n", + "處理檔案: a625.xml\n", + "Object 1: Have_Question - 座標: (12, 578, 185, 823)\n", + "Object 2: Have_Question - 座標: (186, 764, 894, 981)\n", + "Object 3: Have_Question - 座標: (458, 287, 839, 767)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a626.jpg\n", + "\n", + "處理檔案: a626.xml\n", + "Object 1: Have_Question - 座標: (52, 461, 174, 626)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a632.jpg\n", + "\n", + "處理檔案: a632.xml\n", + "Object 1: Have_Question - 座標: (201, 230, 693, 507)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a64.jpg\n", + "\n", + "處理檔案: a64.xml\n", + "Object 1: Have_Question - 座標: (418, 559, 534, 768)\n", + "Object 2: Have_Question - 座標: (515, 398, 645, 455)\n", + "Object 3: Have_Question - 座標: (354, 427, 373, 445)\n", + "Object 4: Have_Question - 座標: (206, 599, 229, 625)\n", + "Object 5: Have_Question - 座標: (279, 75, 369, 115)\n", + "Object 6: Have_Question - 座標: (509, 36, 816, 200)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a641.jpg\n", + "\n", + "處理檔案: a641.xml\n", + "Object 1: Have_Question - 座標: (320, 228, 489, 757)\n", + "Object 2: Have_Question - 座標: (490, 43, 1172, 758)\n", + "Object 3: Have_Question - 座標: (49, 387, 315, 814)\n", + "Object 4: Have_Question - 座標: (195, 32, 319, 301)\n", + "Object 5: Have_Question - 座標: (8, 173, 109, 362)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a6410.jpg\n", + "\n", + "處理檔案: a6410.xml\n", + "Object 1: Have_Question - 座標: (37, 560, 1055, 1014)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a6411.jpg\n", + "\n", + "處理檔案: a6411.xml\n", + "Object 1: Have_Question - 座標: (652, 234, 840, 469)\n", + "Object 2: Have_Question - 座標: (1132, 525, 1159, 578)\n", + "Object 3: Have_Question - 座標: (726, 55, 816, 101)\n", + "Object 4: Have_Question - 座標: (505, 159, 523, 181)\n", + "Object 5: Have_Question - 座標: (369, 393, 397, 408)\n", + "Object 6: Have_Question - 座標: (723, 516, 891, 775)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a645.jpg\n", + "\n", + "處理檔案: a645.xml\n", + "Object 1: Have_Question - 座標: (193, 271, 358, 424)\n", + "Object 2: Have_Question - 座標: (411, 646, 524, 768)\n", + "Object 3: Have_Question - 座標: (347, 938, 569, 1036)\n", + "Object 4: Have_Question - 座標: (693, 640, 886, 933)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a647.jpg\n", + "\n", + "處理檔案: a647.xml\n", + "Object 1: Have_Question - 座標: (837, 263, 1081, 477)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a648.jpg\n", + "\n", + "處理檔案: a648.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\a649.jpg\n", + "\n", + "處理檔案: a649.xml\n", + "Object 1: Have_Question - 座標: (96, 176, 710, 463)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a650.jpg\n", + "\n", + "處理檔案: a650.xml\n", + "Object 1: Have_Question - 座標: (278, 464, 393, 673)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a654.jpg\n", + "\n", + "處理檔案: a654.xml\n", + "Object 1: Have_Question - 座標: (277, 197, 377, 266)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a655.jpg\n", + "\n", + "處理檔案: a655.xml\n", + "Object 1: Have_Question - 座標: (213, 599, 427, 700)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A697.jpg\n", + "\n", + "處理檔案: A697.xml\n", + "Object 1: Have_Question - 座標: (443, 260, 784, 872)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A698.jpg\n", + "\n", + "處理檔案: A698.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A700.jpg\n", + "\n", + "處理檔案: A700.xml\n", + "Object 1: Have_Question - 座標: (464, 187, 773, 435)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A702.jpg\n", + "\n", + "處理檔案: A702.xml\n", + "Object 1: Have_Question - 座標: (420, 166, 929, 363)\n", + "Object 2: Have_Question - 座標: (479, 497, 911, 908)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A703.jpg\n", + "\n", + "處理檔案: A703.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A704.jpg\n", + "\n", + "處理檔案: A704.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A705.jpg\n", + "\n", + "處理檔案: A705.xml\n", + "Object 1: Have_Question - 座標: (378, 610, 441, 716)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A706.jpg\n", + "\n", + "處理檔案: A706.xml\n", + "Object 1: Have_Question - 座標: (393, 467, 480, 561)\n", + "Object 2: Have_Question - 座標: (310, 184, 450, 351)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A707.jpg\n", + "\n", + "處理檔案: A707.xml\n", + "Object 1: Have_Question - 座標: (870, 386, 987, 497)\n", + "Object 2: Have_Question - 座標: (208, 300, 532, 533)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A710.jpg\n", + "\n", + "處理檔案: A710.xml\n", + "Object 1: Have_Question - 座標: (364, 326, 427, 405)\n", + "Object 2: Have_Question - 座標: (718, 121, 749, 179)\n", + "Object 3: Have_Question - 座標: (496, 326, 717, 532)\n", + "Object 4: Have_Question - 座標: (312, 408, 566, 652)\n", + "Object 5: Have_Question - 座標: (312, 662, 569, 961)\n", + "Object 6: Have_Question - 座標: (756, 458, 1098, 1003)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A714.jpg\n", + "\n", + "處理檔案: A714.xml\n", + "Object 1: Have_Question - 座標: (626, 221, 1203, 760)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A715.jpg\n", + "\n", + "處理檔案: A715.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A720.jpg\n", + "\n", + "處理檔案: A720.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A721.jpg\n", + "\n", + "處理檔案: A721.xml\n", + "Object 1: Have_Question - 座標: (338, 334, 562, 834)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A722.jpg\n", + "\n", + "處理檔案: A722.xml\n", + "Object 1: Have_Question - 座標: (462, 208, 583, 318)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A730.jpg\n", + "\n", + "處理檔案: A730.xml\n", + "Object 1: Have_Question - 座標: (599, 108, 760, 231)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A731.jpg\n", + "\n", + "處理檔案: A731.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A732.jpg\n", + "\n", + "處理檔案: A732.xml\n", + "Object 1: Have_Question - 座標: (669, 257, 798, 522)\n", + "Object 2: Have_Question - 座標: (639, 901, 737, 1041)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A734.jpg\n", + "\n", + "處理檔案: A734.xml\n", + "Object 1: Have_Question - 座標: (331, 280, 1064, 742)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A750.jpg\n", + "\n", + "處理檔案: A750.xml\n", + "Object 1: Have_Question - 座標: (182, 395, 891, 950)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A751.jpg\n", + "\n", + "處理檔案: A751.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A753.jpg\n", + "\n", + "處理檔案: A753.xml\n", + "Object 1: Have_Question - 座標: (477, 252, 651, 433)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A756.jpg\n", + "\n", + "處理檔案: A756.xml\n", + "Object 1: Have_Question - 座標: (543, 359, 609, 415)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A757.jpg\n", + "\n", + "處理檔案: A757.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A770.jpg\n", + "\n", + "處理檔案: A770.xml\n", + "Object 1: Have_Question - 座標: (147, 780, 188, 837)\n", + "Object 2: Have_Question - 座標: (431, 906, 477, 959)\n", + "Object 3: Have_Question - 座標: (633, 739, 655, 762)\n", + "Object 4: Have_Question - 座標: (755, 545, 784, 572)\n", + "Object 5: Have_Question - 座標: (928, 464, 947, 486)\n", + "Object 6: Have_Question - 座標: (575, 285, 597, 299)\n", + "Object 7: Have_Question - 座標: (702, 278, 719, 300)\n", + "Object 8: Have_Question - 座標: (841, 301, 872, 319)\n", + "Object 9: Have_Question - 座標: (461, 114, 669, 180)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A771.jpg\n", + "\n", + "處理檔案: A771.xml\n", + "Object 1: Have_Question - 座標: (43, 309, 68, 336)\n", + "Object 2: Have_Question - 座標: (35, 634, 62, 667)\n", + "Object 3: Have_Question - 座標: (830, 233, 962, 370)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A775.jpg\n", + "\n", + "處理檔案: A775.xml\n", + "Object 1: Have_Question - 座標: (256, 480, 390, 812)\n", + "Object 2: Have_Question - 座標: (82, 743, 250, 939)\n", + "Object 3: Have_Question - 座標: (58, 103, 888, 234)\n", + "Object 4: Have_Question - 座標: (509, 225, 1049, 480)\n", + "Object 5: Have_Question - 座標: (781, 437, 1009, 671)\n", + "Object 6: Have_Question - 座標: (588, 682, 801, 769)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A776.jpg\n", + "\n", + "處理檔案: A776.xml\n", + "Object 1: Have_Question - 座標: (819, 136, 1004, 500)\n", + "Object 2: Have_Question - 座標: (315, 727, 743, 939)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A777.jpg\n", + "\n", + "處理檔案: A777.xml\n", + "Object 1: Have_Question - 座標: (72, 149, 265, 433)\n", + "Object 2: Have_Question - 座標: (95, 453, 471, 816)\n", + "Object 3: Have_Question - 座標: (429, 270, 627, 779)\n", + "Object 4: Have_Question - 座標: (655, 97, 777, 217)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A778.jpg\n", + "\n", + "處理檔案: A778.xml\n", + "Object 1: Have_Question - 座標: (233, 386, 631, 940)\n", + "Object 2: Have_Question - 座標: (630, 391, 1123, 1027)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A780.jpg\n", + "\n", + "處理檔案: A780.xml\n", + "Object 1: Have_Question - 座標: (408, 467, 545, 797)\n", + "Object 2: Have_Question - 座標: (655, 518, 1161, 1040)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A781.jpg\n", + "\n", + "處理檔案: A781.xml\n", + "Object 1: Have_Question - 座標: (331, 209, 357, 240)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A790.jpg\n", + "\n", + "處理檔案: A790.xml\n", + "Object 1: Have_Question - 座標: (692, 704, 727, 733)\n", + "Object 2: Have_Question - 座標: (819, 960, 850, 984)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A794.jpg\n", + "\n", + "處理檔案: A794.xml\n", + "Object 1: Have_Question - 座標: (152, 313, 494, 767)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_a80.jpg\n", + "\n", + "處理檔案: a80.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A800.jpg\n", + "\n", + "處理檔案: A800.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A803.jpg\n", + "\n", + "處理檔案: A803.xml\n", + "Object 1: Have_Question - 座標: (328, 588, 632, 825)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A806.jpg\n", + "\n", + "處理檔案: A806.xml\n", + "Object 1: Have_Question - 座標: (462, 616, 649, 772)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A807.jpg\n", + "\n", + "處理檔案: A807.xml\n", + "Object 1: Have_Question - 座標: (268, 114, 311, 155)\n", + "Object 2: Have_Question - 座標: (94, 530, 248, 676)\n", + "Object 3: Have_Question - 座標: (502, 590, 824, 733)\n", + "Object 4: Have_Question - 座標: (502, 736, 993, 1044)\n", + "Object 5: Have_Question - 座標: (925, 550, 1195, 900)\n", + "Object 6: Have_Question - 座標: (496, 94, 787, 500)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A810.jpg\n", + "\n", + "處理檔案: A810.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A811.jpg\n", + "\n", + "處理檔案: A811.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A812.jpg\n", + "\n", + "處理檔案: A812.xml\n", + "Object 1: Have_Question - 座標: (523, 372, 562, 409)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A820.jpg\n", + "\n", + "處理檔案: A820.xml\n", + "Object 1: Have_Question - 座標: (603, 480, 761, 619)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A821.jpg\n", + "\n", + "處理檔案: A821.xml\n", + "Object 1: Have_Question - 座標: (631, 364, 692, 426)\n", + "Object 2: Have_Question - 座標: (766, 626, 829, 682)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A822.jpg\n", + "\n", + "處理檔案: A822.xml\n", + "Object 1: Have_Question - 座標: (825, 313, 885, 361)\n", + "Object 2: Have_Question - 座標: (1010, 504, 1054, 559)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A823.jpg\n", + "\n", + "處理檔案: A823.xml\n", + "Object 1: Have_Question - 座標: (357, 830, 454, 908)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A824.jpg\n", + "\n", + "處理檔案: A824.xml\n", + "Object 1: Have_Question - 座標: (550, 227, 593, 269)\n", + "Object 2: Have_Question - 座標: (623, 473, 681, 533)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A825.jpg\n", + "\n", + "處理檔案: A825.xml\n", + "Object 1: Have_Question - 座標: (523, 614, 610, 715)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A829.jpg\n", + "\n", + "處理檔案: A829.xml\n", + "Object 1: Have_Question - 座標: (156, 153, 194, 181)\n", + "Object 2: Have_Question - 座標: (110, 210, 137, 248)\n", + "Object 3: Have_Question - 座標: (327, 215, 347, 252)\n", + "Object 4: Have_Question - 座標: (523, 229, 559, 270)\n", + "Object 5: Have_Question - 座標: (640, 336, 786, 562)\n", + "Object 6: Have_Question - 座標: (730, 694, 754, 720)\n", + "Object 7: Have_Question - 座標: (159, 697, 273, 817)\n", + "Object 8: Have_Question - 座標: (57, 590, 83, 621)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A830.jpg\n", + "\n", + "處理檔案: A830.xml\n", + "Object 1: Have_Question - 座標: (284, 650, 651, 910)\n", + "Object 2: Have_Question - 座標: (579, 519, 887, 819)\n", + "Object 3: Have_Question - 座標: (607, 286, 1010, 551)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A831.jpg\n", + "\n", + "處理檔案: A831.xml\n", + "Object 1: Have_Question - 座標: (40, 102, 697, 632)\n", + "Object 2: Have_Question - 座標: (694, 106, 1040, 389)\n", + "Object 3: Have_Question - 座標: (796, 685, 906, 815)\n", + "Object 4: Have_Question - 座標: (494, 763, 586, 850)\n", + "Object 5: Have_Question - 座標: (220, 803, 330, 904)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A840.jpg\n", + "\n", + "處理檔案: A840.xml\n", + "Object 1: Have_Question - 座標: (118, 97, 284, 481)\n", + "Object 2: Have_Question - 座標: (285, 100, 701, 264)\n", + "Object 3: Have_Question - 座標: (703, 101, 1032, 431)\n", + "Object 4: Have_Question - 座標: (459, 421, 557, 498)\n", + "Object 5: Have_Question - 座標: (47, 786, 390, 928)\n", + "Object 6: Have_Question - 座標: (275, 574, 605, 811)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A841.jpg\n", + "\n", + "處理檔案: A841.xml\n", + "Object 1: Have_Question - 座標: (53, 101, 656, 844)\n", + "Object 2: Have_Question - 座標: (449, 825, 662, 940)\n", + "Object 3: Have_Question - 座標: (657, 98, 1045, 821)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A842.jpg\n", + "\n", + "處理檔案: A842.xml\n", + "Object 1: Have_Question - 座標: (21, 197, 353, 685)\n", + "Object 2: Have_Question - 座標: (15, 687, 357, 1052)\n", + "Object 3: Have_Question - 座標: (348, 580, 701, 1041)\n", + "Object 4: Have_Question - 座標: (698, 689, 1043, 1044)\n", + "Object 5: Have_Question - 座標: (835, 629, 1178, 1042)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A850.jpg\n", + "\n", + "處理檔案: A850.xml\n", + "Object 1: Have_Question - 座標: (165, 259, 511, 910)\n", + "Object 2: Have_Question - 座標: (509, 449, 1167, 948)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A851.jpg\n", + "\n", + "處理檔案: A851.xml\n", + "Object 1: Have_Question - 座標: (141, 304, 1199, 954)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A852.jpg\n", + "\n", + "處理檔案: A852.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A853.jpg\n", + "\n", + "處理檔案: A853.xml\n", + "Object 1: Have_Question - 座標: (32, 244, 440, 625)\n", + "Object 2: Have_Question - 座標: (34, 626, 1201, 1046)\n", + "Object 3: Have_Question - 座標: (720, 442, 1197, 627)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A854.jpg\n", + "\n", + "處理檔案: A854.xml\n", + "Object 1: Have_Question - 座標: (293, 320, 610, 578)\n", + "Object 2: Have_Question - 座標: (94, 466, 1196, 1067)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A855.jpg\n", + "\n", + "處理檔案: A855.xml\n", + "Object 1: Have_Question - 座標: (389, 200, 760, 464)\n", + "Object 2: Have_Question - 座標: (35, 35, 380, 488)\n", + "Object 3: Have_Question - 座標: (250, 487, 600, 795)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A870.jpg\n", + "\n", + "處理檔案: A870.xml\n", + "Object 1: Have_Question - 座標: (696, 34, 1192, 927)\n", + "Object 2: Have_Question - 座標: (26, 412, 699, 752)\n", + "Object 3: Have_Question - 座標: (25, 750, 947, 1043)\n", + "Object 4: Have_Question - 座標: (946, 970, 1100, 1044)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A872.jpg\n", + "\n", + "處理檔案: A872.xml\n", + "Object 1: Have_Question - 座標: (686, 285, 1034, 543)\n", + "Object 2: Have_Question - 座標: (772, 535, 1041, 772)\n", + "Object 3: Have_Question - 座標: (704, 706, 805, 841)\n", + "Object 4: Have_Question - 座標: (441, 718, 703, 849)\n", + "Object 5: Have_Question - 座標: (354, 544, 489, 805)\n", + "Object 6: Have_Question - 座標: (467, 447, 701, 584)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A873.jpg\n", + "\n", + "處理檔案: A873.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A880.jpg\n", + "\n", + "處理檔案: A880.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A881.jpg\n", + "\n", + "處理檔案: A881.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A890.jpg\n", + "\n", + "處理檔案: A890.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A892.jpg\n", + "\n", + "處理檔案: A892.xml\n", + "Object 1: Have_Question - 座標: (38, 43, 870, 632)\n", + "Object 2: Have_Question - 座標: (30, 635, 287, 806)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A900.jpg\n", + "\n", + "處理檔案: A900.xml\n", + "Object 1: Have_Question - 座標: (457, 29, 983, 570)\n", + "Object 2: Have_Question - 座標: (15, 39, 492, 885)\n", + "Object 3: Have_Question - 座標: (482, 669, 713, 950)\n", + "Object 4: Have_Question - 座標: (982, 32, 1182, 273)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A902.jpg\n", + "\n", + "處理檔案: A902.xml\n", + "Object 1: Have_Question - 座標: (174, 180, 1042, 1043)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A903.jpg\n", + "\n", + "處理檔案: A903.xml\n", + "Object 1: Have_Question - 座標: (683, 414, 1044, 972)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A905.jpg\n", + "\n", + "處理檔案: A905.xml\n", + "Object 1: Have_Question - 座標: (802, 278, 970, 512)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A910.jpg\n", + "\n", + "處理檔案: A910.xml\n", + "Object 1: Have_Question - 座標: (484, 518, 580, 618)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A911.jpg\n", + "\n", + "處理檔案: A911.xml\n", + "Object 1: Have_Question - 座標: (639, 570, 714, 642)\n", + "Object 2: Have_Question - 座標: (1023, 381, 1087, 446)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A913.jpg\n", + "\n", + "處理檔案: A913.xml\n", + "Object 1: Have_Question - 座標: (826, 142, 877, 207)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A914.jpg\n", + "\n", + "處理檔案: A914.xml\n", + "Object 1: Have_Question - 座標: (446, 90, 490, 124)\n", + "Object 2: Have_Question - 座標: (633, 98, 663, 124)\n", + "Object 3: Have_Question - 座標: (933, 477, 993, 593)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A915.jpg\n", + "\n", + "處理檔案: A915.xml\n", + "Object 1: Have_Question - 座標: (552, 31, 1102, 808)\n", + "Object 2: Have_Question - 座標: (29, 471, 180, 921)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A916.jpg\n", + "\n", + "處理檔案: A916.xml\n", + "Object 1: Have_Question - 座標: (68, 559, 451, 942)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A920.jpg\n", + "\n", + "處理檔案: A920.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A930.jpg\n", + "\n", + "處理檔案: A930.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A931.jpg\n", + "\n", + "處理檔案: A931.xml\n", + "Object 1: Have_Question - 座標: (893, 545, 1174, 957)\n", + "Object 2: Have_Question - 座標: (808, 29, 1154, 341)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A941.jpg\n", + "\n", + "處理檔案: A941.xml\n", + "Object 1: Have_Question - 座標: (555, 468, 1118, 885)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A942.jpg\n", + "\n", + "處理檔案: A942.xml\n", + "Object 1: Have_Question - 座標: (296, 449, 656, 750)\n", + "Object 2: Have_Question - 座標: (1060, 243, 1107, 309)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A944.jpg\n", + "\n", + "處理檔案: A944.xml\n", + "Object 1: Have_Question - 座標: (246, 396, 590, 674)\n", + "Object 2: Have_Question - 座標: (531, 126, 749, 318)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A946.jpg\n", + "\n", + "處理檔案: A946.xml\n", + "Object 1: Have_Question - 座標: (417, 363, 662, 669)\n", + "Object 2: Have_Question - 座標: (17, 414, 49, 497)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A950.jpg\n", + "\n", + "處理檔案: A950.xml\n", + "Object 1: Have_Question - 座標: (554, 597, 809, 835)\n", + "Object 2: Have_Question - 座標: (449, 872, 543, 972)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A951.jpg\n", + "\n", + "處理檔案: A951.xml\n", + "Object 1: Have_Question - 座標: (213, 98, 519, 476)\n", + "Object 2: Have_Question - 座標: (609, 105, 850, 422)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A952.jpg\n", + "\n", + "處理檔案: A952.xml\n", + "Object 1: Have_Question - 座標: (237, 413, 405, 881)\n", + "Object 2: Have_Question - 座標: (463, 528, 776, 799)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A953.jpg\n", + "\n", + "處理檔案: A953.xml\n", + "Object 1: Have_Question - 座標: (551, 798, 679, 929)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A955.jpg\n", + "\n", + "處理檔案: A955.xml\n", + "Object 1: Have_Question - 座標: (180, 319, 267, 618)\n", + "Object 2: Have_Question - 座標: (326, 233, 451, 631)\n", + "Object 3: Have_Question - 座標: (513, 258, 598, 601)\n", + "Object 4: Have_Question - 座標: (702, 232, 830, 511)\n", + "Object 5: Have_Question - 座標: (371, 832, 652, 979)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A956.jpg\n", + "\n", + "處理檔案: A956.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A957.jpg\n", + "\n", + "處理檔案: A957.xml\n", + "Object 1: Have_Question - 座標: (299, 614, 751, 939)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A960.jpg\n", + "\n", + "處理檔案: A960.xml\n", + "Object 1: Have_Question - 座標: (611, 507, 1014, 818)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A961.jpg\n", + "\n", + "處理檔案: A961.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A9610.jpg\n", + "\n", + "處理檔案: A9610.xml\n", + "Object 1: Have_Question - 座標: (66, 166, 858, 958)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A9611.jpg\n", + "\n", + "處理檔案: A9611.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A9612.jpg\n", + "\n", + "處理檔案: A9612.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A962.jpg\n", + "\n", + "處理檔案: A962.xml\n", + "Object 1: Have_Question - 座標: (75, 324, 454, 914)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A963.jpg\n", + "\n", + "處理檔案: A963.xml\n", + "Object 1: Have_Question - 座標: (103, 613, 704, 957)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A964.jpg\n", + "\n", + "處理檔案: A964.xml\n", + "Object 1: Have_Question - 座標: (24, 363, 643, 986)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A965.jpg\n", + "\n", + "處理檔案: A965.xml\n", + "Object 1: Have_Question - 座標: (28, 119, 377, 388)\n", + "Object 2: Have_Question - 座標: (844, 849, 942, 948)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A966.jpg\n", + "\n", + "處理檔案: A966.xml\n", + "Object 1: Have_Question - 座標: (7, 316, 76, 580)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A967.jpg\n", + "\n", + "處理檔案: A967.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A968.jpg\n", + "\n", + "處理檔案: A968.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A969.jpg\n", + "\n", + "處理檔案: A969.xml\n", + "Object 1: Have_Question - 座標: (218, 349, 514, 609)\n", + "Object 2: Have_Question - 座標: (574, 787, 757, 914)\n", + "Object 3: Have_Question - 座標: (958, 768, 1191, 918)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A970.jpg\n", + "\n", + "處理檔案: A970.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A972.jpg\n", + "\n", + "處理檔案: A972.xml\n", + "Object 1: Have_Question - 座標: (338, 449, 669, 796)\n", + "Object 2: Have_Question - 座標: (123, 197, 359, 458)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A980.jpg\n", + "\n", + "處理檔案: A980.xml\n", + "Object 1: Have_Question - 座標: (540, 125, 666, 219)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A990.jpg\n", + "\n", + "處理檔案: A990.xml\n", + "圖片檔案不存在: ../Dataset/Training\\Have_Question_Crop\\A991.jpg\n", + "\n", + "處理檔案: A991.xml\n", + "Object 1: Have_Question - 座標: (213, 339, 331, 459)\n", + "已儲存標註圖片至: ../Dataset/Annotation\\Have_Question_Crop\\annotated_A994.jpg\n", + "\n", + "處理檔案: A994.xml\n" + ] + } + ], + "source": [ + "# 創建處理器實例\n", + "processor = XMLAnnotationProcessor(\n", + " dataset_root = Loading_Config[\"Train_Data_Root\"],\n", + ")\n", + "\n", + "# 設定自訂樣式(可選)\n", + "processor.set_drawing_style(\n", + " box_color=(0, 0, 255), # 紅色邊界框\n", + " text_color=(255, 255, 255), # 白色文字\n", + " box_thickness=3,\n", + " font_scale=0.7\n", + ")\n", + "\n", + "print(\"XML標註處理器已準備就绪\")\n", + "results = processor.process_multiple_xml(f\"../Label_Image/Have_Question\", \"Have_Question_Crop\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "base", + "display_name": "Stomach_Cancer_Env", "language": "python", "name": "python3" }, @@ -2372,7 +4333,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.11" + "version": "3.11.9" } }, "nbformat": 4, diff --git a/test_binary_cross_entropy.py b/test_binary_cross_entropy.py new file mode 100644 index 0000000..2912f3e --- /dev/null +++ b/test_binary_cross_entropy.py @@ -0,0 +1,68 @@ +import torch +import torch.nn as nn +import sys +import os + +# 添加當前目錄到系統路徑 +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +# 導入自定義的 BinaryCrossEntropy 類 +from Model_Loss.binary_cross_entropy import BinaryCrossEntropy + +def test_binary_cross_entropy(): + print("開始測試 BinaryCrossEntropy 類...") + + # 創建損失函數實例 + criterion = BinaryCrossEntropy() + + # 測試 1: 維度匹配的情況 (二元分類) + print("\n測試 1: 維度匹配的情況 (二元分類)") + predictions_match = torch.tensor([[0.7, 0.3], [0.2, 0.8]], dtype=torch.float32) + targets_match = torch.tensor([[1.0, 0.0], [0.0, 1.0]], dtype=torch.float32) + + try: + loss_match = criterion(predictions_match, targets_match) + print(f"維度匹配的損失值: {loss_match.item()}") + print("測試 1 通過!") + except Exception as e: + print(f"測試 1 失敗: {e}") + + # 測試 2: 維度不匹配的情況 (多類別分類) + print("\n測試 2: 維度不匹配的情況 (多類別分類)") + predictions_mismatch = torch.tensor([[0.7, 0.2, 0.1], [0.1, 0.8, 0.1]], dtype=torch.float32) + targets_mismatch = torch.tensor([[1.0, 0.0], [0.0, 1.0]], dtype=torch.float32) + + try: + loss_mismatch = criterion(predictions_mismatch, targets_mismatch) + print(f"維度不匹配的損失值: {loss_mismatch.item()}") + print("測試 2 通過!") + except Exception as e: + print(f"測試 2 失敗: {e}") + + # 測試 3: 與 PyTorch 內建函數比較 + print("\n測試 3: 與 PyTorch 內建函數比較") + predictions_compare = torch.tensor([[0.7, 0.3], [0.2, 0.8]], dtype=torch.float32) + targets_compare = torch.tensor([[1.0, 0.0], [0.0, 1.0]], dtype=torch.float32) + + try: + # 自定義損失函數 + loss_custom = criterion(predictions_compare, targets_compare) + + # PyTorch 內建損失函數 + loss_pytorch = nn.BCEWithLogitsLoss()(predictions_compare, targets_compare) + + print(f"自定義損失值: {loss_custom.item()}") + print(f"PyTorch 損失值: {loss_pytorch.item()}") + print(f"差異: {abs(loss_custom.item() - loss_pytorch.item())}") + + if abs(loss_custom.item() - loss_pytorch.item()) < 1e-5: + print("測試 3 通過!") + else: + print("測試 3 失敗: 損失值與 PyTorch 內建函數不一致") + except Exception as e: + print(f"測試 3 失敗: {e}") + + print("\n測試完成!") + +if __name__ == "__main__": + test_binary_cross_entropy() \ No newline at end of file diff --git a/test_bounding_box.py b/test_bounding_box.py new file mode 100644 index 0000000..a351317 --- /dev/null +++ b/test_bounding_box.py @@ -0,0 +1,66 @@ +import cv2 +import numpy as np +from Image_Process.Image_Mask_Ground_Truth_Processing import XMLAnnotationProcessor + +def test_bounding_box_processing_with_mock_data(): + # 初始化XML處理器 + processor = XMLAnnotationProcessor() + + # 創建一個測試圖像 (300x300 彩色圖像) + test_image = np.ones((300, 300, 3), dtype=np.uint8) * 128 # 灰色背景 + + # 在圖像中央創建一個彩色區域 + test_image[100:200, 100:200, 0] = 255 # 紅色通道 + test_image[120:180, 120:180, 1] = 255 # 綠色通道 + test_image[140:160, 140:160, 2] = 255 # 藍色通道 + + # 創建模擬的bounding box數據 + mock_bounding_boxes = [ + { + 'name': 'test_object', + 'xmin': 50, + 'ymin': 50, + 'xmax': 150, + 'ymax': 150 + }, + { + 'name': 'test_object2', + 'xmin': 200, + 'ymin': 200, + 'xmax': 250, + 'ymax': 250 + } + ] + + # 調用draw_bounding_boxes方法 + result_image = processor.draw_bounding_boxes(test_image, mock_bounding_boxes) + + # 顯示處理結果 + print(f"原始圖像形狀: {test_image.shape}") + print(f"結果圖像形狀: {result_image.shape}") + + # 檢查圖像是否有非黑色區域(bounding box內的原圖) + non_black_pixels = np.sum(result_image > 0) + print(f"非黑色像素數量: {non_black_pixels}") + + # 檢查第一個bounding box區域是否保留了原圖 + box1 = result_image[50:150, 50:150] + box1_matches = np.array_equal(box1, test_image[50:150, 50:150]) + print(f"第一個bounding box區域是否與原圖相同: {box1_matches}") + + # 檢查框外區域是否為黑色 + outside_box = result_image[0:40, 0:40] # 選擇一個框外區域 + is_black = np.sum(outside_box) == 0 + print(f"框外區域是否為黑色: {is_black}") + + if non_black_pixels > 0 and box1_matches and is_black: + print("測試成功: bounding box內保持原圖,框外變為黑色") + else: + print("測試失敗") + + # 保存結果圖像以便查看 + cv2.imwrite("test_bounding_box_result.png", result_image) + print("已保存結果圖像: test_bounding_box_result.png") + +if __name__ == "__main__": + test_bounding_box_processing_with_mock_data() \ No newline at end of file diff --git a/test_bounding_box_result.png b/test_bounding_box_result.png new file mode 100644 index 0000000000000000000000000000000000000000..baf6e9ba657d15d3de7e1fb745cb5de06aa45e13 GIT binary patch literal 1874 zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4kn<;H+e}V1_pLXPZ!6K3dXkw8#`GH1(+Q* zi^^ZjKe$)K>+8P#@`wSOP&zjosLRz6Ja;hj^miQfbi;uCuP zzBRgm!hF-klXe%tp>Ae%lU)iF?kC*Te>*G&h5XGIDe@WMh?AcChPf9MbpvDA&zmPz zw?Mt{Y4c?745;&-q^nQA0Q1LrKfQ%8H_o3M<0K9BjJ@^F7Bi@?>&l8abD=)^^X7@r zEvVNAqXj_s+2P}}h4vWGas mP4*LZy`x= 2: + print("\n嘗試合併掩碼數據...") + Merge = merge() + Training_Mask_Data = Merge.merge_all_image_data(Mask_Data_Dict_Data[Mask_Keys[0]], Mask_Data_Dict_Data[Mask_Keys[1]]) + print(f"合併後的掩碼數據長度: {len(Training_Mask_Data)}") + else: + print("\n無法合併掩碼數據:Mask_Keys長度小於2") + + except Exception as e: + print(f"\n加載掩碼數據時出錯: {str(e)}") + import traceback + traceback.print_exc() + +if __name__ == "__main__": + test_mask_loading() \ No newline at end of file diff --git a/test_model_branch.py b/test_model_branch.py new file mode 100644 index 0000000..cd721b0 --- /dev/null +++ b/test_model_branch.py @@ -0,0 +1,91 @@ +import torch +import torch.nn.functional as F +import sys +import os + +# 添加項目根目錄到路徑 +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +# 導入必要的模塊 +from experiments.Models.GastroSegNet_Model import GastroSegNet +from experiments.Training.Segmentation_Block_Training import Segmentation_Block_Training_Step + +def test_model_branch(): + # 初始化模型 + try: + model_step = Segmentation_Block_Training_Step() + print("初始化成功") + + # 獲取設備 + device = model_step.device + print(f"使用設備: {device}") + + # 創建一個簡單的測試數據 + batch_size = 2 + input_images = torch.rand(batch_size, 3, 256, 256) + + # 創建符合Model_Branch方法輸入要求的mask_gt + # 創建二值掩碼,形狀為[batch_size, 1, height, width] + mask_gt = torch.zeros(batch_size, 1, 256, 256) + + # 在掩碼中央創建一個矩形區域(模擬分割目標) + for i in range(batch_size): + # 設置矩形區域為1(白色) + mask_gt[i, 0, 50:200, 50:200] = 1.0 + + # 初始化模型 + model_step.Model = model_step.Construct_Segment_Model_CUDA() + print("模型初始化完成") + + # 測試Model_Branch方法 + try: + # 調用Model_Branch方法,設置return_processed_image=True + print("\n開始測試Model_Branch方法...") + processed_images, seg_outputs = model_step.Model_Branch(input_images, mask_gt, return_processed_image=True) + + # 檢查結果 + print("Model_Branch方法測試成功") + print(f"處理後的圖像形狀: {processed_images.shape}") + print(f"分割輸出形狀: {seg_outputs.shape}") + + # 測試Model_Branch方法,設置return_processed_image=False + print("\n開始測試Model_Branch方法 (return_processed_image=False)...") + + # 創建一個自定義的損失計算函數,用於捕獲輸入形狀 + def mock_losses(Segmentation_Output_Image, Segmentation_Mask_GroundTruth_Image): + print(f"Losses方法輸入形狀 - 預測: {Segmentation_Output_Image.shape}, 目標: {Segmentation_Mask_GroundTruth_Image.shape}") + return torch.tensor(0.5, device=model_step.device) + + # 保存原始的Losses方法 + original_losses = model_step.Losses + + try: + # 替換Losses方法 + model_step.Losses = mock_losses + + # 調用Model_Branch方法 + loss = model_step.Model_Branch(input_images, mask_gt, return_processed_image=False) + + print("Model_Branch方法測試成功 (return_processed_image=False)") + print(f"損失值: {loss}") + finally: + # 恢復原始的Losses方法 + model_step.Losses = original_losses + + return True + except Exception as e: + print(f"Model_Branch方法測試失敗: {str(e)}") + import traceback + traceback.print_exc() + return False + + except Exception as e: + print(f"初始化過程中出錯: {str(e)}") + return False + +if __name__ == "__main__": + success = test_model_branch() + if success: + print("\n所有測試通過!") + else: + print("\n測試失敗!") \ No newline at end of file diff --git a/test_processing_main.py b/test_processing_main.py new file mode 100644 index 0000000..a5a298a --- /dev/null +++ b/test_processing_main.py @@ -0,0 +1,117 @@ +import torch +import torch.nn.functional as F +import sys +import os +import time + +# 添加項目根目錄到路徑 +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +# 導入Loading_Config +from utils.Stomach_Config import Loading_Config + +# 設置Segmentation_Plot_Image配置項 +Loading_Config["Segmentation_Plot_Image"] = "./test_plot.png" + +# 導入必要的模塊 +from experiments.Models.GastroSegNet_Model import GastroSegNet +from experiments.Training.Segmentation_Block_Training import Segmentation_Block_Training_Step + +def test_processing_main(): + # 初始化模型 + try: + model_step = Segmentation_Block_Training_Step() + print("初始化成功") + + # 獲取設備 + device = model_step.device + print(f"使用設備: {device}") + + # 創建一個簡單的測試數據集 + class SimpleDataset(torch.utils.data.Dataset): + def __init__(self, size=10): + self.size = size + # 將數據放在CPU上,避免CUDA轉NumPy的問題 + self.data = torch.rand(size, 3, 256, 256) + self.masks = torch.rand(size, 1, 256, 256) > 0.5 + self.masks = self.masks.float() + self.labels = torch.zeros(size, 3) # 假設有3個類別 + self.labels[:, 0] = 1 # 所有樣本都是第一個類別 + print(f"創建了測試數據集,大小: {size},數據形狀: {self.data.shape},掩碼形狀: {self.masks.shape},標籤形狀: {self.labels.shape}") + + def __len__(self): + return self.size + + def __getitem__(self, idx): + return self.data[idx], self.masks[idx], f"sample_{idx}", self.labels[idx] + + # 創建測試數據集 + print("創建測試數據集和數據加載器...") + test_dataset = SimpleDataset(size=10) # 使用10個樣本以滿足KFold的要求 + + # 創建測試數據加載器 + test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=2, shuffle=False) + print("測試數據集和數據加載器創建完成") + + # 創建一個自定義的損失計算函數,用於捕獲輸入形狀 + def mock_losses(Segmentation_Output_Image, Segmentation_Mask_GroundTruth_Image): + print(f"Losses方法輸入形狀 - 預測: {Segmentation_Output_Image.shape}, 目標: {Segmentation_Mask_GroundTruth_Image.shape}") + # 創建一個可以進行反向傳播的損失張量 + dummy_loss = Segmentation_Output_Image.mean() + print(f"創建了虛擬損失,值: {dummy_loss.item()}") + return dummy_loss + + # 創建一個簡化版的Calculate_Progress_And_Timing函數,避免遞歸調用 + def mock_calculate_progress_and_timing(*args): + # 直接返回最後一個參數(epoch_iterator) + return args[-1] + + # 保存原始的方法 + original_losses = model_step.Losses + original_calculate_progress = model_step.Calculate_Progress_And_Timing + + # 測試Processing_Main方法 + try: + # 替換方法 + model_step.Losses = mock_losses + model_step.Calculate_Progress_And_Timing = mock_calculate_progress_and_timing + + # Loading_Config已在全局設置 + + # 調用Processing_Main方法,設置return_processed_images=True並提供test_dataloader + print("\n開始測試Processing_Main方法...") + result = model_step.Processing_Main(test_dataset, return_processed_images=True, test_dataloader=test_loader) + + # 恢復原始的方法 + model_step.Losses = original_losses + model_step.Calculate_Progress_And_Timing = original_calculate_progress + + # 檢查結果 + print("Processing_Main方法測試成功") + print(f"結果類型: {type(result)}") + + # 如果結果是元組,打印每個元素 + if isinstance(result, tuple): + for i, item in enumerate(result): + if isinstance(item, torch.Tensor): + print(f"結果[{i}]: {type(item)} - 形狀: {item.shape}") + else: + print(f"結果[{i}]: {type(item)}") + + return True + except Exception as e: + print(f"Processing_Main方法測試失敗: {str(e)}") + import traceback + traceback.print_exc() + return False + + except Exception as e: + print(f"初始化過程中出錯: {str(e)}") + return False + +if __name__ == "__main__": + success = test_processing_main() + if success: + print("\n所有測試通過!") + else: + print("\n測試失敗!") \ No newline at end of file diff --git a/test_segmentation.py b/test_segmentation.py new file mode 100644 index 0000000..d49386a --- /dev/null +++ b/test_segmentation.py @@ -0,0 +1,48 @@ +import torch +import sys +import os + +# 添加項目根目錄到路徑 +sys.path.append(os.path.dirname(os.path.abspath(__file__))) + +# 導入必要的模塊 +from experiments.Models.GastroSegNet_Model import GastroSegNet +from experiments.Training.Segmentation_Block_Training import Segmentation_Block_Training_Step + +def test_process_segmentation_output(): + # 初始化模型 + try: + model_step = Segmentation_Block_Training_Step() + print("初始化成功") + + # 創建測試數據 + batch_size = 2 + channels = 3 + height = 256 + width = 256 + + # 獲取設備 + device = model_step.device + print(f"使用設備: {device}") + + # 創建隨機輸入圖像並移到正確的設備上 + input_images = torch.rand(batch_size, channels, height, width).to(device) + + # 創建隨機分割輸出 (模擬模型輸出)並移到正確的設備上 + segmentation_output = torch.rand(batch_size, 1, height, width).to(device) + + # 測試處理方法 + try: + processed_images = model_step.process_segmentation_output(input_images, segmentation_output) + print(f"處理後圖像形狀: {processed_images.shape}") + print("處理成功") + return True + except Exception as e: + print(f"處理過程中出錯: {str(e)}") + return False + except Exception as e: + print(f"初始化過程中出錯: {str(e)}") + return False + +if __name__ == "__main__": + test_process_segmentation_output() \ No newline at end of file diff --git a/testing_Labels_Accuracy.py b/testing_Labels_Accuracy.py index b98e2fe..3f64286 100644 --- a/testing_Labels_Accuracy.py +++ b/testing_Labels_Accuracy.py @@ -1,103 +1,141 @@ from experiments.experiment import experiments -from concurrent.futures import ProcessPoolExecutor -from loadData_and_MakeImageGenerator.load_and_ImageGenerator import Load_ImageGenerator -from Read_and_process_image.ReadAndProcess import Read_image_and_Process_image -import tensorflow as tf +import torch import numpy as np -from sklearn.metrics import confusion_matrix, accuracy_score -from draw_tools.draw import draw_heatmap +from sklearn.metrics import confusion_matrix, accuracy_score, precision_score, recall_score, f1_score from Load_process.LoadData import Loding_Data_Root import os import seaborn as sns import datetime -from Load_process.file_processing import judge_file_exist, make_dir, make_save_root -from matplotlib import pyplot as plt +from Load_process.file_processing import Process_File from Load_process.Load_Indepentend import Load_Indepentend_Data - -def draw(matrix, model_name, index): - # Using Seaborn heatmap to create the plot - - fx = sns.heatmap(matrix, annot=True, cmap='turbo') - # labels the title and x, y axis of plot - fx.set_title('Plotting Confusion Matrix using Seaborn\n\n') - fx.set_xlabel('Predicted Values') - fx.set_ylabel('answer Values ') - # labels the boxes - fx.xaxis.set_ticklabels(['False','True']) - fx.yaxis.set_ticklabels(['False','True']) - - model_dir = '../../Model_Confusion_matrix/model_matrix_image ( ' + str(datetime.date.today()) + " )/" + model_name - if not judge_file_exist(model_dir): - make_dir(model_dir) - modelfiles = make_save_root(str(model_name) + "-" + str(index) + ".png", model_dir) - plt.savefig(modelfiles) - plt.close("all") # 關閉圖表 +from Training_Tools.PreProcess import Training_Precesses +from Training_Tools.Tools import Tool +import matplotlib.figure as figure +import matplotlib.backends.backend_agg as agg +from Calculate_Process.Calculate import Calculate +import argparse +import json +from utils.Stomach_Config import Training_Config, Loading_Config +from model_data_processing.processing import shuffle_data if __name__ == "__main__": - with ProcessPoolExecutor() as executor: ## 默认为1 - print('TensorFlow version:', tf.__version__) - physical_devices = tf.config.experimental.list_physical_devices('GPU') - print(physical_devices) - assert len(physical_devices) > 0, "Not enough GPU hardware devices available" - tf.config.experimental.set_memory_growth(physical_devices[0], True) - os.environ["CUDA_VISIBLE_DEVICES"]='0' + # 解析命令行参数 + parser = argparse.ArgumentParser(description='评估单一类别的准确度、精确度、召回率和F1值') + parser.add_argument('--target_class', type=int, default=0, help='要评估的目标类别索引 (0, 1, 2)') + args = parser.parse_args() + + # 测试GPU是否可用 + device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') + print(f"使用设备: {device}") + + # 设置GPU + if torch.cuda.is_available(): + torch.cuda.set_device(0) + print(f"GPU: {torch.cuda.get_device_name(0)}") - load = Loding_Data_Root() - experiment = experiments() - image_processing = Read_image_and_Process_image() - cut_image = Load_Indepentend_Data() + # 初始化对象 + tool = Tool() + Status = 1 # 決定要使用什麼資料集 - model = experiment.construct_model() - model_dir = '../../best_model( 2023-10-17 )-2.h5' # 這是一個儲存模型權重的路徑,每一個模型都有一個自己權重儲存的檔 - if os.path.exists(model_dir): # 如果這個檔案存在 - model.load_weights(model_dir) # 將模型權重讀出來 - print("讀出權重\n") + # 取得One-hot encording 的資料 + tool.Set_OneHotEncording(Loading_Config["Training_Labels"]) + Encording_Label = tool.Get_OneHot_Encording_Label() + + Label_Length = len(Loading_Config["Training_Labels"]) + + # 检查目标类别是否有效 + target_class = args.target_class + training_labels = Loading_Config["Training_Labels"] + if target_class < 0 or target_class >= len(training_labels): + print(f"错误: 目标类别索引 {target_class} 无效,必须在 0 到 {len(training_labels)-1} 之间") + exit(1) + + print(f"正在评估类别: {training_labels[target_class]}") + + load = Loding_Data_Root(Loading_Config["Training_Labels"], Loading_Config["Train_Data_Root"], Loading_Config["ImageGenerator_Data_Root"]) + cut_image = Load_Indepentend_Data(Loading_Config["Training_Labels"], Encording_Label) + + # 创建模型 + experiment = experiments(Training_Config, Loading_Config, tool, 3, "Test") + model = experiment.construct_model() + + # 加载模型权重 + Model_Weight = [ + "../Result/save_the_best_model/Xception Skin trains Stomach Cancer Dataset, and uses WeightRandomSampler Change HSV Channel of V is -150/Xception/best_model( 2025-05-19 )-_fold0.pt", + "../Result/save_the_best_model/Xception Skin trains Stomach Cancer Dataset, and uses WeightRandomSampler Change HSV Channel of V is -150/Xception/best_model( 2025-05-19 )-_fold1.pt", + "../Result/save_the_best_model/Xception Skin trains Stomach Cancer Dataset, and uses WeightRandomSampler Change HSV Channel of V is -150/Xception/best_model( 2025-05-19 )-_fold2.pt", + "../Result/save_the_best_model/Xception Skin trains Stomach Cancer Dataset, and uses WeightRandomSampler Change HSV Channel of V is -150/Xception/best_model( 2025-05-19 )-_fold3.pt", + "../Result/save_the_best_model/Xception Skin trains Stomach Cancer Dataset, and uses WeightRandomSampler Change HSV Channel of V is -150/Xception/best_model( 2025-05-19 )-_fold4.pt" + ] + + Calculate_Tool = [Calculate() for i in range(3)] + i = 0 + for path in Model_Weight: + if os.path.exists(path): + model.load_state_dict(torch.load(path)) + print("读取权重完成\n") + model.eval() # 设置为评估模式 + + # 预处理对象 + preprocess = Training_Precesses(256) + + cut_image.process_main(Loading_Config["Test_Data_Root"]) # 呼叫處理test Data與Validation Data的function + test, test_label = cut_image.test, cut_image.test_label + test, test_label = shuffle_data(test, test_label) - for times in range(5): - name = ["BP", "PF", "PV", "Chickenpox", "Monkeypox", "Normal", "Another"] - cut_image.process_main() # 呼叫處理test Data與Validation Data的function - test, test_label = cut_image.test, cut_image.test_label + # 只评估目标类别 + # 转换为PyTorch张量并移动到设备 + test_dataset = preprocess.Setting_DataSet(cut_image.test, cut_image.test_label, "Transform") + test_loader = preprocess.Dataloader_Sampler(test_dataset, 1, False) + + all_results = [] + all_labels = [] + + # 使用PyTorch的预测方式 + with torch.no_grad(): # 不计算梯度 + for inputs, labels, _, _ in test_loader: + inputs = inputs.to(device) + labels = labels.to(device) - total_data = [[], [], [], [], [], [], []] - total_labels = [[], [], [], [], [], [], []] - start = 0 - end = 22 - for k in range(7): - for i in range(start, end): - total_data[k].append(test[i]) - total_labels[k].append(test_label[i]) - - total_data[k], total_labels[k] = image_processing.image_data_processing(total_data[k], total_labels[k]) - total_data[k] = image_processing.normalization(total_data[k]) + outputs = model(inputs) + _, predicted = torch.max(outputs, 1) + all_results.append(predicted.cpu().numpy()) + all_labels.append(np.argmax(labels.cpu().numpy(), axis=1)) + + # 合并结果 + Predict = np.concatenate(all_results) + y_test = np.concatenate(all_labels) + + print(f"{training_labels[target_class]} 预测结果: {Predict}\n") - start = end - end += 22 - + # 计算评估指标 + accuracy = accuracy_score(y_test, Predict) + precision = precision_score(y_test, Predict, average=None) + recall = recall_score(y_test, Predict, average=None) + F1 = f1_score(y_test, Predict, average=None) + + # 计算每个类别的准确率 + class_accuracies = [] + for class_idx in range(len(training_labels)): + class_mask = (y_test == class_idx) + class_accuracy = accuracy_score(y_test[class_mask], Predict[class_mask]) + class_accuracies.append(class_accuracy) + + print(f"运行 {i+1}:\n") + print(f"整体准确率 (Accuracy): {accuracy:.4f}") + for class_idx in range(len(training_labels)): + print(f"类别 {training_labels[class_idx]} 的评估指标:") + print(f" 准确率 (Accuracy): {class_accuracies[class_idx]:.4f}") + print(f" 精确率 (Precision): {precision[class_idx]:.4f}") + print(f" 召回率 (Recall): {recall[class_idx]:.4f}") + print(f" F1值: {F1[class_idx]:.4f}\n") + Calculate_Tool[class_idx].Append_numbers(0, class_accuracies[class_idx], precision[class_idx], recall[class_idx], 0, F1[class_idx]) + + i += 1 - j = 0 - for total_label in range(7): - result = model.predict(total_data[j]) # 利用predict function來預測結果 - result = np.argmax(result, axis = 1) # 將預測出來的結果從one-hot encoding轉成label-encoding - y_test = np.argmax(total_labels[j], axis = 1) - - print(name[j] + str(result), "\n") - - y_pre = [] - for i in range(len(result)): - if result[i] != j: - result[i] = 0 - else: - result[i] = 1 - - y_test[i] = 1 - - matrix = confusion_matrix(y_test, result, labels = [0, 1]) # 丟入confusion matrix的function中,以形成混淆矩陣 - draw(matrix, name[j], times) # 呼叫畫出confusion matrix的function - tn, fp, fn, tp = matrix.ravel() - - accuracy = (tn + tp) / (tn + fp + fn + tp) - print(name[j] + " 權重為: ", accuracy) - - experiment.record_everyTime_test_result(0, accuracy, 0, 0, 0, 0, times, name[j]) - - j += 1 + # 计算平均值和标准差 + for i in range(3): + Calculate_Tool[i].Calculate_Mean() + Calculate_Tool[i].Calculate_Std() + print(f"\n{training_labels[target_class]} 类别的评估结果:") + print(Calculate_Tool[i].Output_Style()) diff --git a/training_files.txt b/training_files.txt new file mode 100644 index 0000000000000000000000000000000000000000..295545013f43c0d974adac0a2336aa3fd1f5fa2a GIT binary patch literal 8350 zcmaKxyN=XQ5JVj#@hb@1GagTf_CpAfi1_~ixW^?+xT=gc+M{+qs{6Jd^XK=s>FYF4 zU#6eauj$A1dHOU#mLTh(ZnYM>XYuwdc3ZJ~l^AkmX=5eKK z0P|d6t{=>Enah>fT~)>^z0Jj2S}n!fQle&W=jl=Gp2go*S!%MCDze}6^eT4Q+j-hY zhOSihcAm1gFxM*o&t9XZ*M*wiF<9DVFP4!-v-3GwMz7N@&mMN|TGweA%4N>k+hxkL zyiD0|Smu}g#xC>QMwDwGmoWqBFXv(zGmv%c<=UK|Wz0Zcn{&a*@LXU%FEFo-u6Ybt z`pem%yJ?r_l#VyM%q4rijycFWvghmQP}=1jtYr>h?b^(5i}SpWIY|9-Hn7VWx%<~K zFFtE)nFE;nLp{$0=Gw!&Ha2Nq>s$Tf@b=w2p7fdzbeWnh^cw%Py>0>MT0KBB8Z`Yv zyWgwMM0?a|(2NGnXwZxX?a{W&ULl8PjRwtVKHpsb8kX0NpEPUOt1YzKW(L@1y}q}| z!0&Nl?b=l8Jx=Jq`&ZY#3fqk_)z`WHI41pTsa&>M`^mlflY0$t?|@i#2JTwJS}dlh z`Q84*n{Vt}&aNkUvH~(GVyDXbB+}&GD@r)^+HSt7{+lHsH+^5hU)1UmEX|~CvAFg@|$|_JNuSj zd!j&Z_?><01olmJc+Gp>6|=Fpzh*oQ3|G?i?V#qMk#pxr}O zfvs;2`AyZa^{v6q%qbCd9Yj4dQO`^}-Fw_OJ^Q@n&^oUjntt0Umu=?DJfsKFJKnvd zLU`%6sSvi_JMC&eU83Gm(d=lOZ0+u>uFbG)vkGjpiZ;WKW3tl&w(g++`IWRx2&hxlm^9FR?-zUGb&rIY!a}oD$%YXOMeRK~#8PB>OMbj_SnL4$Z zm50oMc}b1hetaIgG^4fI;(KEH6?M%-y*5!ld3>90exd2N?Iylp=IIyp+W6|-qM>g_ zgJu=2LtA|-5>3Bsiu4Q3d|NlSdJo)=)9;-Z^&I%Zn-%jtx6#(2*U`81i>=otTdz&j z=izm9)2k58Xsz?F+GBp7$j*zpUw*e}woM(`dc~q%v8Y!p>gQP0pX~U$-ZE>aMYfq4 zwwYNw7kszRc@Ry%oD1*UUU#2pdT4jh{Ww{fFSe;|N(q)F+j%$jw9BT(Zr4Q?tK}^#iZ~ literal 0 HcmV?d00001 diff --git a/training_question_files.txt b/training_question_files.txt new file mode 100644 index 0000000000000000000000000000000000000000..6f61db7a6a528139f786025b89579611f76f67f8 GIT binary patch literal 3860 zcmZ{mJC58i5JVXp@KubR8GXY!iXsD!eE+~UpBe_Xt7@U_q1gW>_4m&;KIZph{2IT< z&+&bH8}ISBS*FjReT+n((e86vcWl0b@l&GIGYBKD(=M?t`vtcI!P0exAPfX+x=~;HK)vX4CbECkn9lP#1MM43_Xp$h65Ue#hfH<(tdSnqnVUMrY(7^e4ov0nRP z?n7&ePWQ5y=eADm=f0uS4J_t)>@tC+OZL1+`r>l-khz5E<`?TVxaP?|RqvZDXJQm)`Niwi2CB5GX?dgmDzF!!(r+0hlk`J9fUMKhKJ>qrp z-1Pqzzl&|)8F~rRd4ahP-gvFO_mZ=oo4%mL#|x+SV2QeCeY?t{S9*)l=%({}c=i3} LIA`3h(?5oPzPHw^ literal 0 HcmV?d00001 diff --git a/utils/Stomach_Config.py b/utils/Stomach_Config.py new file mode 100644 index 0000000..779a164 --- /dev/null +++ b/utils/Stomach_Config.py @@ -0,0 +1,73 @@ +# 在import部分添加median_filter +from Image_Process.image_enhancement import histogram_equalization, adaptive_histogram_equalization_without_limit, unsharp_mask, laplacian_sharpen, adjust_hsv, gamma_correction, Contrast_Limited_Adaptive_Histogram_Equalization, Hight_Light, mean_filter, median_filter +import datetime + +Image_Enhance = { + "Shapen" : laplacian_sharpen, + "CLAHE": histogram_equalization, + "CLAHE_Adaptive" : adaptive_histogram_equalization_without_limit, + "CLAHE_Adaptive_have_Limit" : Contrast_Limited_Adaptive_Histogram_Equalization, + "HSV" : adjust_hsv, + "gamma" : gamma_correction, + "Hight_Light" : Hight_Light, + "Mean" : mean_filter, + "Median" : median_filter, # 添加中值濾波 + "Gamma_Value" : 1.0 +} + +Loading_Config = { + "Test_Data_Root": "../Dataset/Testing", + "Train_Data_Root": "../Dataset/Training", + "Annotation_Training_Root": "../Dataset/Annotation/Training", + "Annotation_Testing_Root": "../Dataset/Annotation/Testing", + "TestProcess_Image_Root" : "../TestProcess_Image", + "ImageGenerator_Data_Root": "../Dataset/ImageGenerator", + "Process_Roots" : "../Dataset/test_Images", + # "Image enhance processing save root": f'../Dataset/image_enhancement_Result/New_{Image_Enhance["gamma"].__name__}_and_gamma_value_is_{Image_Enhance["Gamma_Value"]}', + "Image enhance processing save root": f'../Dataset/image_enhancement_Result/Resetting the training and testing dataset', + "Training_Labels": ["stomach_cancer_Crop", "Normal_Crop", "Have_Question_Crop"], + "Label_Image_Labels" : ["CA", "Have_Question"], + "XML_Loading_Label" : ["stomach_cancer_Crop", "Have_Question_Crop"], + "Identification_Label_Length" : 2, +} + +Training_Config = { + "Model_Name": "Xception and GastoSegNet", + "CA_Experiment_Name": f"New architecture of Xception to CA and Have Question", + "Normal_Experiment_Name": f"New architecture of Xception to Normal and Others", + "Mask_Experiment_Name" : "New architecture of GastoSegNet", + "Epoch": 10000, + "Train_Batch_Size": 64, + "Image_Size": 256, + "Class_Count": 904, + "Get_Generator": "True", + "weight_decay": 0.01, + "Number_Of_Classes" : len(Loading_Config["Training_Labels"]) +} + +Model_Config = { + "Model Name": "xception", + "GPA Output Nodes": 2048, + "Linear Hidden Nodes": 1025, + "Output Linear Nodes": 2, + "Dropout Rate": 0.6 +} + +Save_Result_File_Config = { + "Identification_Plot_Image" : f"../Result/Training_Image/save_the_train_image({str(datetime.date.today())})", # 分類模型的走勢圖存檔路徑 + "Segument_Plot_Image" : f"../Result/Training_Image/save_the_train_image({str(datetime.date.today())})/Segument_Plot_Image", # 分割模型的走勢圖存檔路徑 + + "Identification_Marix_Image" : f"../Result/Matrix_Image/model_matrix_image({str(datetime.date.today())})/Identification_Plot_Marix_Image", # 分類模型的混淆矩陣存檔路徑 + + "Identification_Every_Fold_Training_Result" : f'../Result/Training_Result/save_the_train_result({str(datetime.date.today())})/Identification_Every_Fold', # 分類模型每折訓練結果存檔路徑 + "Identification_Average_Result" : f'../Result/Training_Average_Result/Average_Result({str(datetime.date.today())})/Identification_Average_Result', # 分類模型平均訓練結果存檔路徑 + + "Segument_Every_Fold_Training_Result" : f'../Result/Training_Result/save_the_train_result({str(datetime.date.today())})/Segument_Every_Fold', # 分割模型每折訓練結果存檔路徑 + "Segument_Average_Result" : f'../Result/Training_Average_Result/Average_Result({str(datetime.date.today())})/Segument_Average_Result', # 分割模型平均訓練結果存檔路徑 + "Segument_Bounding_Box_Image" : f'../Result/Bounding_Box_Image/save_bounding_box_image({str(datetime.date.today())})', # 分割模型邊界框圖像存檔路徑 + "Segument_Test_Bounding_Box_Image" : f'../Result/Test_Bounding_Box_Image/save_bounding_box_image({str(datetime.date.today())})', # 分割模型邊界框圖像存檔路徑 + + "Normal_Identification_Best_Model" : '../Result/save_the_best_model/Identification_Normal', + "CA_Identification_Best_Model" : "../Result/save_the_best_model/Identification_CA", + "Segmentation_Best_Model" : "../Result/save_the_best_model/Segmentation", +} \ No newline at end of file diff --git a/utils/__pycache__/Stomach_Config.cpython-311.pyc b/utils/__pycache__/Stomach_Config.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3708fdb61f7e5f8df7c7f1da9c9a0cd6abcc5f60 GIT binary patch literal 4548 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 literal 0 HcmV?d00001 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..ebd1dc0 --- /dev/null +++ b/uv.lock @@ -0,0 +1,1404 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" +resolution-markers = [ + "python_full_version >= '3.12'", + "python_full_version < '3.12'", +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/b5/991245018615474a60965a7c9cd2b4efbaabd16d582a5547c47ee1c7730b/charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b", size = 204483, upload-time = "2025-08-09T07:55:53.12Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/ae245c41c06299ec18262825c1569c5d3298fc920e4ddf56ab011b417efd/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64", size = 145520, upload-time = "2025-08-09T07:55:54.712Z" }, + { url = "https://files.pythonhosted.org/packages/3a/a4/b3b6c76e7a635748c4421d2b92c7b8f90a432f98bda5082049af37ffc8e3/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91", size = 158876, upload-time = "2025-08-09T07:55:56.024Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e6/63bb0e10f90a8243c5def74b5b105b3bbbfb3e7bb753915fe333fb0c11ea/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f", size = 156083, upload-time = "2025-08-09T07:55:57.582Z" }, + { url = "https://files.pythonhosted.org/packages/87/df/b7737ff046c974b183ea9aa111b74185ac8c3a326c6262d413bd5a1b8c69/charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07", size = 150295, upload-time = "2025-08-09T07:55:59.147Z" }, + { url = "https://files.pythonhosted.org/packages/61/f1/190d9977e0084d3f1dc169acd060d479bbbc71b90bf3e7bf7b9927dec3eb/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30", size = 148379, upload-time = "2025-08-09T07:56:00.364Z" }, + { url = "https://files.pythonhosted.org/packages/4c/92/27dbe365d34c68cfe0ca76f1edd70e8705d82b378cb54ebbaeabc2e3029d/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14", size = 160018, upload-time = "2025-08-09T07:56:01.678Z" }, + { url = "https://files.pythonhosted.org/packages/99/04/baae2a1ea1893a01635d475b9261c889a18fd48393634b6270827869fa34/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c", size = 157430, upload-time = "2025-08-09T07:56:02.87Z" }, + { url = "https://files.pythonhosted.org/packages/2f/36/77da9c6a328c54d17b960c89eccacfab8271fdaaa228305330915b88afa9/charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae", size = 151600, upload-time = "2025-08-09T07:56:04.089Z" }, + { url = "https://files.pythonhosted.org/packages/64/d4/9eb4ff2c167edbbf08cdd28e19078bf195762e9bd63371689cab5ecd3d0d/charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849", size = 99616, upload-time = "2025-08-09T07:56:05.658Z" }, + { url = "https://files.pythonhosted.org/packages/f4/9c/996a4a028222e7761a96634d1820de8a744ff4327a00ada9c8942033089b/charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c", size = 107108, upload-time = "2025-08-09T07:56:07.176Z" }, + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "contourpy" +version = "1.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/2e/c4390a31919d8a78b90e8ecf87cd4b4c4f05a5b48d05ec17db8e5404c6f4/contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1", size = 288773, upload-time = "2025-07-26T12:01:02.277Z" }, + { url = "https://files.pythonhosted.org/packages/0d/44/c4b0b6095fef4dc9c420e041799591e3b63e9619e3044f7f4f6c21c0ab24/contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381", size = 270149, upload-time = "2025-07-26T12:01:04.072Z" }, + { url = "https://files.pythonhosted.org/packages/30/2e/dd4ced42fefac8470661d7cb7e264808425e6c5d56d175291e93890cce09/contourpy-1.3.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:929ddf8c4c7f348e4c0a5a3a714b5c8542ffaa8c22954862a46ca1813b667ee7", size = 329222, upload-time = "2025-07-26T12:01:05.688Z" }, + { url = "https://files.pythonhosted.org/packages/f2/74/cc6ec2548e3d276c71389ea4802a774b7aa3558223b7bade3f25787fafc2/contourpy-1.3.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e999574eddae35f1312c2b4b717b7885d4edd6cb46700e04f7f02db454e67c1", size = 377234, upload-time = "2025-07-26T12:01:07.054Z" }, + { url = "https://files.pythonhosted.org/packages/03/b3/64ef723029f917410f75c09da54254c5f9ea90ef89b143ccadb09df14c15/contourpy-1.3.3-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0bf67e0e3f482cb69779dd3061b534eb35ac9b17f163d851e2a547d56dba0a3a", size = 380555, upload-time = "2025-07-26T12:01:08.801Z" }, + { url = "https://files.pythonhosted.org/packages/5f/4b/6157f24ca425b89fe2eb7e7be642375711ab671135be21e6faa100f7448c/contourpy-1.3.3-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:51e79c1f7470158e838808d4a996fa9bac72c498e93d8ebe5119bc1e6becb0db", size = 355238, upload-time = "2025-07-26T12:01:10.319Z" }, + { url = "https://files.pythonhosted.org/packages/98/56/f914f0dd678480708a04cfd2206e7c382533249bc5001eb9f58aa693e200/contourpy-1.3.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:598c3aaece21c503615fd59c92a3598b428b2f01bfb4b8ca9c4edeecc2438620", size = 1326218, upload-time = "2025-07-26T12:01:12.659Z" }, + { url = "https://files.pythonhosted.org/packages/fb/d7/4a972334a0c971acd5172389671113ae82aa7527073980c38d5868ff1161/contourpy-1.3.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:322ab1c99b008dad206d406bb61d014cf0174df491ae9d9d0fac6a6fda4f977f", size = 1392867, upload-time = "2025-07-26T12:01:15.533Z" }, + { url = "https://files.pythonhosted.org/packages/75/3e/f2cc6cd56dc8cff46b1a56232eabc6feea52720083ea71ab15523daab796/contourpy-1.3.3-cp311-cp311-win32.whl", hash = "sha256:fd907ae12cd483cd83e414b12941c632a969171bf90fc937d0c9f268a31cafff", size = 183677, upload-time = "2025-07-26T12:01:17.088Z" }, + { url = "https://files.pythonhosted.org/packages/98/4b/9bd370b004b5c9d8045c6c33cf65bae018b27aca550a3f657cdc99acdbd8/contourpy-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:3519428f6be58431c56581f1694ba8e50626f2dd550af225f82fb5f5814d2a42", size = 225234, upload-time = "2025-07-26T12:01:18.256Z" }, + { url = "https://files.pythonhosted.org/packages/d9/b6/71771e02c2e004450c12b1120a5f488cad2e4d5b590b1af8bad060360fe4/contourpy-1.3.3-cp311-cp311-win_arm64.whl", hash = "sha256:15ff10bfada4bf92ec8b31c62bf7c1834c244019b4a33095a68000d7075df470", size = 193123, upload-time = "2025-07-26T12:01:19.848Z" }, + { url = "https://files.pythonhosted.org/packages/be/45/adfee365d9ea3d853550b2e735f9d66366701c65db7855cd07621732ccfc/contourpy-1.3.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b08a32ea2f8e42cf1d4be3169a98dd4be32bafe4f22b6c4cb4ba810fa9e5d2cb", size = 293419, upload-time = "2025-07-26T12:01:21.16Z" }, + { url = "https://files.pythonhosted.org/packages/53/3e/405b59cfa13021a56bba395a6b3aca8cec012b45bf177b0eaf7a202cde2c/contourpy-1.3.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:556dba8fb6f5d8742f2923fe9457dbdd51e1049c4a43fd3986a0b14a1d815fc6", size = 273979, upload-time = "2025-07-26T12:01:22.448Z" }, + { url = "https://files.pythonhosted.org/packages/d4/1c/a12359b9b2ca3a845e8f7f9ac08bdf776114eb931392fcad91743e2ea17b/contourpy-1.3.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92d9abc807cf7d0e047b95ca5d957cf4792fcd04e920ca70d48add15c1a90ea7", size = 332653, upload-time = "2025-07-26T12:01:24.155Z" }, + { url = "https://files.pythonhosted.org/packages/63/12/897aeebfb475b7748ea67b61e045accdfcf0d971f8a588b67108ed7f5512/contourpy-1.3.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b2e8faa0ed68cb29af51edd8e24798bb661eac3bd9f65420c1887b6ca89987c8", size = 379536, upload-time = "2025-07-26T12:01:25.91Z" }, + { url = "https://files.pythonhosted.org/packages/43/8a/a8c584b82deb248930ce069e71576fc09bd7174bbd35183b7943fb1064fd/contourpy-1.3.3-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:626d60935cf668e70a5ce6ff184fd713e9683fb458898e4249b63be9e28286ea", size = 384397, upload-time = "2025-07-26T12:01:27.152Z" }, + { url = "https://files.pythonhosted.org/packages/cc/8f/ec6289987824b29529d0dfda0d74a07cec60e54b9c92f3c9da4c0ac732de/contourpy-1.3.3-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4d00e655fcef08aba35ec9610536bfe90267d7ab5ba944f7032549c55a146da1", size = 362601, upload-time = "2025-07-26T12:01:28.808Z" }, + { url = "https://files.pythonhosted.org/packages/05/0a/a3fe3be3ee2dceb3e615ebb4df97ae6f3828aa915d3e10549ce016302bd1/contourpy-1.3.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:451e71b5a7d597379ef572de31eeb909a87246974d960049a9848c3bc6c41bf7", size = 1331288, upload-time = "2025-07-26T12:01:31.198Z" }, + { url = "https://files.pythonhosted.org/packages/33/1d/acad9bd4e97f13f3e2b18a3977fe1b4a37ecf3d38d815333980c6c72e963/contourpy-1.3.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:459c1f020cd59fcfe6650180678a9993932d80d44ccde1fa1868977438f0b411", size = 1403386, upload-time = "2025-07-26T12:01:33.947Z" }, + { url = "https://files.pythonhosted.org/packages/cf/8f/5847f44a7fddf859704217a99a23a4f6417b10e5ab1256a179264561540e/contourpy-1.3.3-cp312-cp312-win32.whl", hash = "sha256:023b44101dfe49d7d53932be418477dba359649246075c996866106da069af69", size = 185018, upload-time = "2025-07-26T12:01:35.64Z" }, + { url = "https://files.pythonhosted.org/packages/19/e8/6026ed58a64563186a9ee3f29f41261fd1828f527dd93d33b60feca63352/contourpy-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:8153b8bfc11e1e4d75bcb0bff1db232f9e10b274e0929de9d608027e0d34ff8b", size = 226567, upload-time = "2025-07-26T12:01:36.804Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e2/f05240d2c39a1ed228d8328a78b6f44cd695f7ef47beb3e684cf93604f86/contourpy-1.3.3-cp312-cp312-win_arm64.whl", hash = "sha256:07ce5ed73ecdc4a03ffe3e1b3e3c1166db35ae7584be76f65dbbe28a7791b0cc", size = 193655, upload-time = "2025-07-26T12:01:37.999Z" }, + { url = "https://files.pythonhosted.org/packages/68/35/0167aad910bbdb9599272bd96d01a9ec6852f36b9455cf2ca67bd4cc2d23/contourpy-1.3.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:177fb367556747a686509d6fef71d221a4b198a3905fe824430e5ea0fda54eb5", size = 293257, upload-time = "2025-07-26T12:01:39.367Z" }, + { url = "https://files.pythonhosted.org/packages/96/e4/7adcd9c8362745b2210728f209bfbcf7d91ba868a2c5f40d8b58f54c509b/contourpy-1.3.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d002b6f00d73d69333dac9d0b8d5e84d9724ff9ef044fd63c5986e62b7c9e1b1", size = 274034, upload-time = "2025-07-26T12:01:40.645Z" }, + { url = "https://files.pythonhosted.org/packages/73/23/90e31ceeed1de63058a02cb04b12f2de4b40e3bef5e082a7c18d9c8ae281/contourpy-1.3.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:348ac1f5d4f1d66d3322420f01d42e43122f43616e0f194fc1c9f5d830c5b286", size = 334672, upload-time = "2025-07-26T12:01:41.942Z" }, + { url = "https://files.pythonhosted.org/packages/ed/93/b43d8acbe67392e659e1d984700e79eb67e2acb2bd7f62012b583a7f1b55/contourpy-1.3.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:655456777ff65c2c548b7c454af9c6f33f16c8884f11083244b5819cc214f1b5", size = 381234, upload-time = "2025-07-26T12:01:43.499Z" }, + { url = "https://files.pythonhosted.org/packages/46/3b/bec82a3ea06f66711520f75a40c8fc0b113b2a75edb36aa633eb11c4f50f/contourpy-1.3.3-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:644a6853d15b2512d67881586bd03f462c7ab755db95f16f14d7e238f2852c67", size = 385169, upload-time = "2025-07-26T12:01:45.219Z" }, + { url = "https://files.pythonhosted.org/packages/4b/32/e0f13a1c5b0f8572d0ec6ae2f6c677b7991fafd95da523159c19eff0696a/contourpy-1.3.3-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4debd64f124ca62069f313a9cb86656ff087786016d76927ae2cf37846b006c9", size = 362859, upload-time = "2025-07-26T12:01:46.519Z" }, + { url = "https://files.pythonhosted.org/packages/33/71/e2a7945b7de4e58af42d708a219f3b2f4cff7386e6b6ab0a0fa0033c49a9/contourpy-1.3.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a15459b0f4615b00bbd1e91f1b9e19b7e63aea7483d03d804186f278c0af2659", size = 1332062, upload-time = "2025-07-26T12:01:48.964Z" }, + { url = "https://files.pythonhosted.org/packages/12/fc/4e87ac754220ccc0e807284f88e943d6d43b43843614f0a8afa469801db0/contourpy-1.3.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ca0fdcd73925568ca027e0b17ab07aad764be4706d0a925b89227e447d9737b7", size = 1403932, upload-time = "2025-07-26T12:01:51.979Z" }, + { url = "https://files.pythonhosted.org/packages/a6/2e/adc197a37443f934594112222ac1aa7dc9a98faf9c3842884df9a9d8751d/contourpy-1.3.3-cp313-cp313-win32.whl", hash = "sha256:b20c7c9a3bf701366556e1b1984ed2d0cedf999903c51311417cf5f591d8c78d", size = 185024, upload-time = "2025-07-26T12:01:53.245Z" }, + { url = "https://files.pythonhosted.org/packages/18/0b/0098c214843213759692cc638fce7de5c289200a830e5035d1791d7a2338/contourpy-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:1cadd8b8969f060ba45ed7c1b714fe69185812ab43bd6b86a9123fe8f99c3263", size = 226578, upload-time = "2025-07-26T12:01:54.422Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9a/2f6024a0c5995243cd63afdeb3651c984f0d2bc727fd98066d40e141ad73/contourpy-1.3.3-cp313-cp313-win_arm64.whl", hash = "sha256:fd914713266421b7536de2bfa8181aa8c699432b6763a0ea64195ebe28bff6a9", size = 193524, upload-time = "2025-07-26T12:01:55.73Z" }, + { url = "https://files.pythonhosted.org/packages/c0/b3/f8a1a86bd3298513f500e5b1f5fd92b69896449f6cab6a146a5d52715479/contourpy-1.3.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:88df9880d507169449d434c293467418b9f6cbe82edd19284aa0409e7fdb933d", size = 306730, upload-time = "2025-07-26T12:01:57.051Z" }, + { url = "https://files.pythonhosted.org/packages/3f/11/4780db94ae62fc0c2053909b65dc3246bd7cecfc4f8a20d957ad43aa4ad8/contourpy-1.3.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d06bb1f751ba5d417047db62bca3c8fde202b8c11fb50742ab3ab962c81e8216", size = 287897, upload-time = "2025-07-26T12:01:58.663Z" }, + { url = "https://files.pythonhosted.org/packages/ae/15/e59f5f3ffdd6f3d4daa3e47114c53daabcb18574a26c21f03dc9e4e42ff0/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e4e6b05a45525357e382909a4c1600444e2a45b4795163d3b22669285591c1ae", size = 326751, upload-time = "2025-07-26T12:02:00.343Z" }, + { url = "https://files.pythonhosted.org/packages/0f/81/03b45cfad088e4770b1dcf72ea78d3802d04200009fb364d18a493857210/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ab3074b48c4e2cf1a960e6bbeb7f04566bf36b1861d5c9d4d8ac04b82e38ba20", size = 375486, upload-time = "2025-07-26T12:02:02.128Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ba/49923366492ffbdd4486e970d421b289a670ae8cf539c1ea9a09822b371a/contourpy-1.3.3-cp313-cp313t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6c3d53c796f8647d6deb1abe867daeb66dcc8a97e8455efa729516b997b8ed99", size = 388106, upload-time = "2025-07-26T12:02:03.615Z" }, + { url = "https://files.pythonhosted.org/packages/9f/52/5b00ea89525f8f143651f9f03a0df371d3cbd2fccd21ca9b768c7a6500c2/contourpy-1.3.3-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:50ed930df7289ff2a8d7afeb9603f8289e5704755c7e5c3bbd929c90c817164b", size = 352548, upload-time = "2025-07-26T12:02:05.165Z" }, + { url = "https://files.pythonhosted.org/packages/32/1d/a209ec1a3a3452d490f6b14dd92e72280c99ae3d1e73da74f8277d4ee08f/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4feffb6537d64b84877da813a5c30f1422ea5739566abf0bd18065ac040e120a", size = 1322297, upload-time = "2025-07-26T12:02:07.379Z" }, + { url = "https://files.pythonhosted.org/packages/bc/9e/46f0e8ebdd884ca0e8877e46a3f4e633f6c9c8c4f3f6e72be3fe075994aa/contourpy-1.3.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2b7e9480ffe2b0cd2e787e4df64270e3a0440d9db8dc823312e2c940c167df7e", size = 1391023, upload-time = "2025-07-26T12:02:10.171Z" }, + { url = "https://files.pythonhosted.org/packages/b9/70/f308384a3ae9cd2209e0849f33c913f658d3326900d0ff5d378d6a1422d2/contourpy-1.3.3-cp313-cp313t-win32.whl", hash = "sha256:283edd842a01e3dcd435b1c5116798d661378d83d36d337b8dde1d16a5fc9ba3", size = 196157, upload-time = "2025-07-26T12:02:11.488Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/880f890a6663b84d9e34a6f88cded89d78f0091e0045a284427cb6b18521/contourpy-1.3.3-cp313-cp313t-win_amd64.whl", hash = "sha256:87acf5963fc2b34825e5b6b048f40e3635dd547f590b04d2ab317c2619ef7ae8", size = 240570, upload-time = "2025-07-26T12:02:12.754Z" }, + { url = "https://files.pythonhosted.org/packages/80/99/2adc7d8ffead633234817ef8e9a87115c8a11927a94478f6bb3d3f4d4f7d/contourpy-1.3.3-cp313-cp313t-win_arm64.whl", hash = "sha256:3c30273eb2a55024ff31ba7d052dde990d7d8e5450f4bbb6e913558b3d6c2301", size = 199713, upload-time = "2025-07-26T12:02:14.4Z" }, + { url = "https://files.pythonhosted.org/packages/72/8b/4546f3ab60f78c514ffb7d01a0bd743f90de36f0019d1be84d0a708a580a/contourpy-1.3.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fde6c716d51c04b1c25d0b90364d0be954624a0ee9d60e23e850e8d48353d07a", size = 292189, upload-time = "2025-07-26T12:02:16.095Z" }, + { url = "https://files.pythonhosted.org/packages/fd/e1/3542a9cb596cadd76fcef413f19c79216e002623158befe6daa03dbfa88c/contourpy-1.3.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:cbedb772ed74ff5be440fa8eee9bd49f64f6e3fc09436d9c7d8f1c287b121d77", size = 273251, upload-time = "2025-07-26T12:02:17.524Z" }, + { url = "https://files.pythonhosted.org/packages/b1/71/f93e1e9471d189f79d0ce2497007731c1e6bf9ef6d1d61b911430c3db4e5/contourpy-1.3.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:22e9b1bd7a9b1d652cd77388465dc358dafcd2e217d35552424aa4f996f524f5", size = 335810, upload-time = "2025-07-26T12:02:18.9Z" }, + { url = "https://files.pythonhosted.org/packages/91/f9/e35f4c1c93f9275d4e38681a80506b5510e9327350c51f8d4a5a724d178c/contourpy-1.3.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a22738912262aa3e254e4f3cb079a95a67132fc5a063890e224393596902f5a4", size = 382871, upload-time = "2025-07-26T12:02:20.418Z" }, + { url = "https://files.pythonhosted.org/packages/b5/71/47b512f936f66a0a900d81c396a7e60d73419868fba959c61efed7a8ab46/contourpy-1.3.3-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:afe5a512f31ee6bd7d0dda52ec9864c984ca3d66664444f2d72e0dc4eb832e36", size = 386264, upload-time = "2025-07-26T12:02:21.916Z" }, + { url = "https://files.pythonhosted.org/packages/04/5f/9ff93450ba96b09c7c2b3f81c94de31c89f92292f1380261bd7195bea4ea/contourpy-1.3.3-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f64836de09927cba6f79dcd00fdd7d5329f3fccc633468507079c829ca4db4e3", size = 363819, upload-time = "2025-07-26T12:02:23.759Z" }, + { url = "https://files.pythonhosted.org/packages/3e/a6/0b185d4cc480ee494945cde102cb0149ae830b5fa17bf855b95f2e70ad13/contourpy-1.3.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1fd43c3be4c8e5fd6e4f2baeae35ae18176cf2e5cced681cca908addf1cdd53b", size = 1333650, upload-time = "2025-07-26T12:02:26.181Z" }, + { url = "https://files.pythonhosted.org/packages/43/d7/afdc95580ca56f30fbcd3060250f66cedbde69b4547028863abd8aa3b47e/contourpy-1.3.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:6afc576f7b33cf00996e5c1102dc2a8f7cc89e39c0b55df93a0b78c1bd992b36", size = 1404833, upload-time = "2025-07-26T12:02:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e2/366af18a6d386f41132a48f033cbd2102e9b0cf6345d35ff0826cd984566/contourpy-1.3.3-cp314-cp314-win32.whl", hash = "sha256:66c8a43a4f7b8df8b71ee1840e4211a3c8d93b214b213f590e18a1beca458f7d", size = 189692, upload-time = "2025-07-26T12:02:30.128Z" }, + { url = "https://files.pythonhosted.org/packages/7d/c2/57f54b03d0f22d4044b8afb9ca0e184f8b1afd57b4f735c2fa70883dc601/contourpy-1.3.3-cp314-cp314-win_amd64.whl", hash = "sha256:cf9022ef053f2694e31d630feaacb21ea24224be1c3ad0520b13d844274614fd", size = 232424, upload-time = "2025-07-26T12:02:31.395Z" }, + { url = "https://files.pythonhosted.org/packages/18/79/a9416650df9b525737ab521aa181ccc42d56016d2123ddcb7b58e926a42c/contourpy-1.3.3-cp314-cp314-win_arm64.whl", hash = "sha256:95b181891b4c71de4bb404c6621e7e2390745f887f2a026b2d99e92c17892339", size = 198300, upload-time = "2025-07-26T12:02:32.956Z" }, + { url = "https://files.pythonhosted.org/packages/1f/42/38c159a7d0f2b7b9c04c64ab317042bb6952b713ba875c1681529a2932fe/contourpy-1.3.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:33c82d0138c0a062380332c861387650c82e4cf1747aaa6938b9b6516762e772", size = 306769, upload-time = "2025-07-26T12:02:34.2Z" }, + { url = "https://files.pythonhosted.org/packages/c3/6c/26a8205f24bca10974e77460de68d3d7c63e282e23782f1239f226fcae6f/contourpy-1.3.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ea37e7b45949df430fe649e5de8351c423430046a2af20b1c1961cae3afcda77", size = 287892, upload-time = "2025-07-26T12:02:35.807Z" }, + { url = "https://files.pythonhosted.org/packages/66/06/8a475c8ab718ebfd7925661747dbb3c3ee9c82ac834ccb3570be49d129f4/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d304906ecc71672e9c89e87c4675dc5c2645e1f4269a5063b99b0bb29f232d13", size = 326748, upload-time = "2025-07-26T12:02:37.193Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a3/c5ca9f010a44c223f098fccd8b158bb1cb287378a31ac141f04730dc49be/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ca658cd1a680a5c9ea96dc61cdbae1e85c8f25849843aa799dfd3cb370ad4fbe", size = 375554, upload-time = "2025-07-26T12:02:38.894Z" }, + { url = "https://files.pythonhosted.org/packages/80/5b/68bd33ae63fac658a4145088c1e894405e07584a316738710b636c6d0333/contourpy-1.3.3-cp314-cp314t-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ab2fd90904c503739a75b7c8c5c01160130ba67944a7b77bbf36ef8054576e7f", size = 388118, upload-time = "2025-07-26T12:02:40.642Z" }, + { url = "https://files.pythonhosted.org/packages/40/52/4c285a6435940ae25d7410a6c36bda5145839bc3f0beb20c707cda18b9d2/contourpy-1.3.3-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b7301b89040075c30e5768810bc96a8e8d78085b47d8be6e4c3f5a0b4ed478a0", size = 352555, upload-time = "2025-07-26T12:02:42.25Z" }, + { url = "https://files.pythonhosted.org/packages/24/ee/3e81e1dd174f5c7fefe50e85d0892de05ca4e26ef1c9a59c2a57e43b865a/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:2a2a8b627d5cc6b7c41a4beff6c5ad5eb848c88255fda4a8745f7e901b32d8e4", size = 1322295, upload-time = "2025-07-26T12:02:44.668Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b2/6d913d4d04e14379de429057cd169e5e00f6c2af3bb13e1710bcbdb5da12/contourpy-1.3.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:fd6ec6be509c787f1caf6b247f0b1ca598bef13f4ddeaa126b7658215529ba0f", size = 1391027, upload-time = "2025-07-26T12:02:47.09Z" }, + { url = "https://files.pythonhosted.org/packages/93/8a/68a4ec5c55a2971213d29a9374913f7e9f18581945a7a31d1a39b5d2dfe5/contourpy-1.3.3-cp314-cp314t-win32.whl", hash = "sha256:e74a9a0f5e3fff48fb5a7f2fd2b9b70a3fe014a67522f79b7cca4c0c7e43c9ae", size = 202428, upload-time = "2025-07-26T12:02:48.691Z" }, + { url = "https://files.pythonhosted.org/packages/fa/96/fd9f641ffedc4fa3ace923af73b9d07e869496c9cc7a459103e6e978992f/contourpy-1.3.3-cp314-cp314t-win_amd64.whl", hash = "sha256:13b68d6a62db8eafaebb8039218921399baf6e47bf85006fd8529f2a08ef33fc", size = 250331, upload-time = "2025-07-26T12:02:50.137Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8c/469afb6465b853afff216f9528ffda78a915ff880ed58813ba4faf4ba0b6/contourpy-1.3.3-cp314-cp314t-win_arm64.whl", hash = "sha256:b7448cb5a725bb1e35ce88771b86fba35ef418952474492cf7c764059933ff8b", size = 203831, upload-time = "2025-07-26T12:02:51.449Z" }, + { url = "https://files.pythonhosted.org/packages/a5/29/8dcfe16f0107943fa92388c23f6e05cff0ba58058c4c95b00280d4c75a14/contourpy-1.3.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:cd5dfcaeb10f7b7f9dc8941717c6c2ade08f587be2226222c12b25f0483ed497", size = 278809, upload-time = "2025-07-26T12:02:52.74Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/8b37ef4f7dafeb335daee3c8254645ef5725be4d9c6aa70b50ec46ef2f7e/contourpy-1.3.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:0c1fc238306b35f246d61a1d416a627348b5cf0648648a031e14bb8705fcdfe8", size = 261593, upload-time = "2025-07-26T12:02:54.037Z" }, + { url = "https://files.pythonhosted.org/packages/0a/59/ebfb8c677c75605cc27f7122c90313fd2f375ff3c8d19a1694bda74aaa63/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70f9aad7de812d6541d29d2bbf8feb22ff7e1c299523db288004e3157ff4674e", size = 302202, upload-time = "2025-07-26T12:02:55.947Z" }, + { url = "https://files.pythonhosted.org/packages/3c/37/21972a15834d90bfbfb009b9d004779bd5a07a0ec0234e5ba8f64d5736f4/contourpy-1.3.3-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5ed3657edf08512fc3fe81b510e35c2012fbd3081d2e26160f27ca28affec989", size = 329207, upload-time = "2025-07-26T12:02:57.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/58/bd257695f39d05594ca4ad60df5bcb7e32247f9951fd09a9b8edb82d1daa/contourpy-1.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:3d1a3799d62d45c18bafd41c5fa05120b96a28079f2393af559b843d1a966a77", size = 225315, upload-time = "2025-07-26T12:02:58.801Z" }, +] + +[[package]] +name = "cycler" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/95/a3dbbb5028f35eafb79008e7522a75244477d2838f38cbb722248dabc2a8/cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c", size = 7615, upload-time = "2023-10-07T05:32:18.335Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30", size = 8321, upload-time = "2023-10-07T05:32:16.783Z" }, +] + +[[package]] +name = "filelock" +version = "3.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, +] + +[[package]] +name = "fonttools" +version = "4.59.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0d/a5/fba25f9fbdab96e26dedcaeeba125e5f05a09043bf888e0305326e55685b/fonttools-4.59.2.tar.gz", hash = "sha256:e72c0749b06113f50bcb80332364c6be83a9582d6e3db3fe0b280f996dc2ef22", size = 3540889, upload-time = "2025-08-27T16:40:30.97Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/53/742fcd750ae0bdc74de4c0ff923111199cc2f90a4ee87aaddad505b6f477/fonttools-4.59.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:511946e8d7ea5c0d6c7a53c4cb3ee48eda9ab9797cd9bf5d95829a398400354f", size = 2774961, upload-time = "2025-08-27T16:38:47.536Z" }, + { url = "https://files.pythonhosted.org/packages/57/2a/976f5f9fa3b4dd911dc58d07358467bec20e813d933bc5d3db1a955dd456/fonttools-4.59.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8e5e2682cf7be766d84f462ba8828d01e00c8751a8e8e7ce12d7784ccb69a30d", size = 2344690, upload-time = "2025-08-27T16:38:49.723Z" }, + { url = "https://files.pythonhosted.org/packages/c1/8f/b7eefc274fcf370911e292e95565c8253b0b87c82a53919ab3c795a4f50e/fonttools-4.59.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5729e12a982dba3eeae650de48b06f3b9ddb51e9aee2fcaf195b7d09a96250e2", size = 5026910, upload-time = "2025-08-27T16:38:51.904Z" }, + { url = "https://files.pythonhosted.org/packages/69/95/864726eaa8f9d4e053d0c462e64d5830ec7c599cbdf1db9e40f25ca3972e/fonttools-4.59.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c52694eae5d652361d59ecdb5a2246bff7cff13b6367a12da8499e9df56d148d", size = 4971031, upload-time = "2025-08-27T16:38:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/24/4c/b8c4735ebdea20696277c70c79e0de615dbe477834e5a7c2569aa1db4033/fonttools-4.59.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f1f1bbc23ba1312bd8959896f46f667753b90216852d2a8cfa2d07e0cb234144", size = 5006112, upload-time = "2025-08-27T16:38:55.69Z" }, + { url = "https://files.pythonhosted.org/packages/3b/23/f9ea29c292aa2fc1ea381b2e5621ac436d5e3e0a5dee24ffe5404e58eae8/fonttools-4.59.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1a1bfe5378962825dabe741720885e8b9ae9745ec7ecc4a5ec1f1ce59a6062bf", size = 5117671, upload-time = "2025-08-27T16:38:58.984Z" }, + { url = "https://files.pythonhosted.org/packages/ba/07/cfea304c555bf06e86071ff2a3916bc90f7c07ec85b23bab758d4908c33d/fonttools-4.59.2-cp311-cp311-win32.whl", hash = "sha256:e937790f3c2c18a1cbc7da101550a84319eb48023a715914477d2e7faeaba570", size = 2218157, upload-time = "2025-08-27T16:39:00.75Z" }, + { url = "https://files.pythonhosted.org/packages/d7/de/35d839aa69db737a3f9f3a45000ca24721834d40118652a5775d5eca8ebb/fonttools-4.59.2-cp311-cp311-win_amd64.whl", hash = "sha256:9836394e2f4ce5f9c0a7690ee93bd90aa1adc6b054f1a57b562c5d242c903104", size = 2265846, upload-time = "2025-08-27T16:39:02.453Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3d/1f45db2df51e7bfa55492e8f23f383d372200be3a0ded4bf56a92753dd1f/fonttools-4.59.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:82906d002c349cad647a7634b004825a7335f8159d0d035ae89253b4abf6f3ea", size = 2769711, upload-time = "2025-08-27T16:39:04.423Z" }, + { url = "https://files.pythonhosted.org/packages/29/df/cd236ab32a8abfd11558f296e064424258db5edefd1279ffdbcfd4fd8b76/fonttools-4.59.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a10c1bd7644dc58f8862d8ba0cf9fb7fef0af01ea184ba6ce3f50ab7dfe74d5a", size = 2340225, upload-time = "2025-08-27T16:39:06.143Z" }, + { url = "https://files.pythonhosted.org/packages/98/12/b6f9f964fe6d4b4dd4406bcbd3328821c3de1f909ffc3ffa558fe72af48c/fonttools-4.59.2-cp312-cp312-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:738f31f23e0339785fd67652a94bc69ea49e413dfdb14dcb8c8ff383d249464e", size = 4912766, upload-time = "2025-08-27T16:39:08.138Z" }, + { url = "https://files.pythonhosted.org/packages/73/78/82bde2f2d2c306ef3909b927363170b83df96171f74e0ccb47ad344563cd/fonttools-4.59.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ec99f9bdfee9cdb4a9172f9e8fd578cce5feb231f598909e0aecf5418da4f25", size = 4955178, upload-time = "2025-08-27T16:39:10.094Z" }, + { url = "https://files.pythonhosted.org/packages/92/77/7de766afe2d31dda8ee46d7e479f35c7d48747e558961489a2d6e3a02bd4/fonttools-4.59.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0476ea74161322e08c7a982f83558a2b81b491509984523a1a540baf8611cc31", size = 4897898, upload-time = "2025-08-27T16:39:12.087Z" }, + { url = "https://files.pythonhosted.org/packages/c5/77/ce0e0b905d62a06415fda9f2b2e109a24a5db54a59502b769e9e297d2242/fonttools-4.59.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:95922a922daa1f77cc72611747c156cfb38030ead72436a2c551d30ecef519b9", size = 5049144, upload-time = "2025-08-27T16:39:13.84Z" }, + { url = "https://files.pythonhosted.org/packages/d9/ea/870d93aefd23fff2e07cbeebdc332527868422a433c64062c09d4d5e7fe6/fonttools-4.59.2-cp312-cp312-win32.whl", hash = "sha256:39ad9612c6a622726a6a130e8ab15794558591f999673f1ee7d2f3d30f6a3e1c", size = 2206473, upload-time = "2025-08-27T16:39:15.854Z" }, + { url = "https://files.pythonhosted.org/packages/61/c4/e44bad000c4a4bb2e9ca11491d266e857df98ab6d7428441b173f0fe2517/fonttools-4.59.2-cp312-cp312-win_amd64.whl", hash = "sha256:980fd7388e461b19a881d35013fec32c713ffea1fc37aef2f77d11f332dfd7da", size = 2254706, upload-time = "2025-08-27T16:39:17.893Z" }, + { url = "https://files.pythonhosted.org/packages/13/7b/d0d3b9431642947b5805201fbbbe938a47b70c76685ef1f0cb5f5d7140d6/fonttools-4.59.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:381bde13216ba09489864467f6bc0c57997bd729abfbb1ce6f807ba42c06cceb", size = 2761563, upload-time = "2025-08-27T16:39:20.286Z" }, + { url = "https://files.pythonhosted.org/packages/76/be/fc5fe58dd76af7127b769b68071dbc32d4b95adc8b58d1d28d42d93c90f2/fonttools-4.59.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f33839aa091f7eef4e9078f5b7ab1b8ea4b1d8a50aeaef9fdb3611bba80869ec", size = 2335671, upload-time = "2025-08-27T16:39:22.027Z" }, + { url = "https://files.pythonhosted.org/packages/f2/9f/bf231c2a3fac99d1d7f1d89c76594f158693f981a4aa02be406e9f036832/fonttools-4.59.2-cp313-cp313-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:6235fc06bcbdb40186f483ba9d5d68f888ea68aa3c8dac347e05a7c54346fbc8", size = 4893967, upload-time = "2025-08-27T16:39:23.664Z" }, + { url = "https://files.pythonhosted.org/packages/26/a9/d46d2ad4fcb915198504d6727f83aa07f46764c64f425a861aa38756c9fd/fonttools-4.59.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:83ad6e5d06ef3a2884c4fa6384a20d6367b5cfe560e3b53b07c9dc65a7020e73", size = 4951986, upload-time = "2025-08-27T16:39:25.379Z" }, + { url = "https://files.pythonhosted.org/packages/07/90/1cc8d7dd8f707dfeeca472b82b898d3add0ebe85b1f645690dcd128ee63f/fonttools-4.59.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d029804c70fddf90be46ed5305c136cae15800a2300cb0f6bba96d48e770dde0", size = 4891630, upload-time = "2025-08-27T16:39:27.494Z" }, + { url = "https://files.pythonhosted.org/packages/d8/04/f0345b0d9fe67d65aa8d3f2d4cbf91d06f111bc7b8d802e65914eb06194d/fonttools-4.59.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:95807a3b5e78f2714acaa26a33bc2143005cc05c0217b322361a772e59f32b89", size = 5035116, upload-time = "2025-08-27T16:39:29.406Z" }, + { url = "https://files.pythonhosted.org/packages/d7/7d/5ba5eefffd243182fbd067cdbfeb12addd4e5aec45011b724c98a344ea33/fonttools-4.59.2-cp313-cp313-win32.whl", hash = "sha256:b3ebda00c3bb8f32a740b72ec38537d54c7c09f383a4cfefb0b315860f825b08", size = 2204907, upload-time = "2025-08-27T16:39:31.42Z" }, + { url = "https://files.pythonhosted.org/packages/ea/a9/be7219fc64a6026cc0aded17fa3720f9277001c185434230bd351bf678e6/fonttools-4.59.2-cp313-cp313-win_amd64.whl", hash = "sha256:a72155928d7053bbde499d32a9c77d3f0f3d29ae72b5a121752481bcbd71e50f", size = 2253742, upload-time = "2025-08-27T16:39:33.079Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c7/486580d00be6fa5d45e41682e5ffa5c809f3d25773c6f39628d60f333521/fonttools-4.59.2-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:d09e487d6bfbe21195801323ba95c91cb3523f0fcc34016454d4d9ae9eaa57fe", size = 2762444, upload-time = "2025-08-27T16:39:34.759Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9b/950ea9b7b764ceb8d18645c62191e14ce62124d8e05cb32a4dc5e65fde0b/fonttools-4.59.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:dec2f22486d7781087b173799567cffdcc75e9fb2f1c045f05f8317ccce76a3e", size = 2333256, upload-time = "2025-08-27T16:39:40.777Z" }, + { url = "https://files.pythonhosted.org/packages/9b/4d/8ee9d563126de9002eede950cde0051be86cc4e8c07c63eca0c9fc95734a/fonttools-4.59.2-cp314-cp314-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1647201af10993090120da2e66e9526c4e20e88859f3e34aa05b8c24ded2a564", size = 4834846, upload-time = "2025-08-27T16:39:42.885Z" }, + { url = "https://files.pythonhosted.org/packages/03/26/f26d947b0712dce3d118e92ce30ca88f98938b066498f60d0ee000a892ae/fonttools-4.59.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47742c33fe65f41eabed36eec2d7313a8082704b7b808752406452f766c573fc", size = 4930871, upload-time = "2025-08-27T16:39:44.818Z" }, + { url = "https://files.pythonhosted.org/packages/fc/7f/ebe878061a5a5e6b6502f0548489e01100f7e6c0049846e6546ba19a3ab4/fonttools-4.59.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:92ac2d45794f95d1ad4cb43fa07e7e3776d86c83dc4b9918cf82831518165b4b", size = 4876971, upload-time = "2025-08-27T16:39:47.027Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0d/0d22e3a20ac566836098d30718092351935487e3271fd57385db1adb2fde/fonttools-4.59.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fa9ecaf2dcef8941fb5719e16322345d730f4c40599bbf47c9753de40eb03882", size = 4987478, upload-time = "2025-08-27T16:39:48.774Z" }, + { url = "https://files.pythonhosted.org/packages/3b/a3/960cc83182a408ffacc795e61b5f698c6f7b0cfccf23da4451c39973f3c8/fonttools-4.59.2-cp314-cp314-win32.whl", hash = "sha256:a8d40594982ed858780e18a7e4c80415af65af0f22efa7de26bdd30bf24e1e14", size = 2208640, upload-time = "2025-08-27T16:39:50.592Z" }, + { url = "https://files.pythonhosted.org/packages/d8/74/55e5c57c414fa3965fee5fc036ed23f26a5c4e9e10f7f078a54ff9c7dfb7/fonttools-4.59.2-cp314-cp314-win_amd64.whl", hash = "sha256:9cde8b6a6b05f68516573523f2013a3574cb2c75299d7d500f44de82ba947b80", size = 2258457, upload-time = "2025-08-27T16:39:52.611Z" }, + { url = "https://files.pythonhosted.org/packages/e1/dc/8e4261dc591c5cfee68fecff3ffee2a9b29e1edc4c4d9cbafdc5aefe74ee/fonttools-4.59.2-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:036cd87a2dbd7ef72f7b68df8314ced00b8d9973aee296f2464d06a836aeb9a9", size = 2829901, upload-time = "2025-08-27T16:39:55.014Z" }, + { url = "https://files.pythonhosted.org/packages/fb/05/331538dcf21fd6331579cd628268150e85210d0d2bdae20f7598c2b36c05/fonttools-4.59.2-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:14870930181493b1d740b6f25483e20185e5aea58aec7d266d16da7be822b4bb", size = 2362717, upload-time = "2025-08-27T16:39:56.843Z" }, + { url = "https://files.pythonhosted.org/packages/60/ae/d26428ca9ede809c0a93f0af91f44c87433dc0251e2aec333da5ed00d38f/fonttools-4.59.2-cp314-cp314t-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7ff58ea1eb8fc7e05e9a949419f031890023f8785c925b44d6da17a6a7d6e85d", size = 4835120, upload-time = "2025-08-27T16:39:59.06Z" }, + { url = "https://files.pythonhosted.org/packages/07/c4/0f6ac15895de509e07688cb1d45f1ae583adbaa0fa5a5699d73f3bd58ca0/fonttools-4.59.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6dee142b8b3096514c96ad9e2106bf039e2fe34a704c587585b569a36df08c3c", size = 5071115, upload-time = "2025-08-27T16:40:01.009Z" }, + { url = "https://files.pythonhosted.org/packages/b2/b6/147a711b7ecf7ea39f9da9422a55866f6dd5747c2f36b3b0a7a7e0c6820b/fonttools-4.59.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8991bdbae39cf78bcc9cd3d81f6528df1f83f2e7c23ccf6f990fa1f0b6e19708", size = 4943905, upload-time = "2025-08-27T16:40:03.179Z" }, + { url = "https://files.pythonhosted.org/packages/5b/4e/2ab19006646b753855e2b02200fa1cabb75faa4eeca4ef289f269a936974/fonttools-4.59.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:53c1a411b7690042535a4f0edf2120096a39a506adeb6c51484a232e59f2aa0c", size = 4960313, upload-time = "2025-08-27T16:40:05.45Z" }, + { url = "https://files.pythonhosted.org/packages/98/3d/df77907e5be88adcca93cc2cee00646d039da220164be12bee028401e1cf/fonttools-4.59.2-cp314-cp314t-win32.whl", hash = "sha256:59d85088e29fa7a8f87d19e97a1beae2a35821ee48d8ef6d2c4f965f26cb9f8a", size = 2269719, upload-time = "2025-08-27T16:40:07.553Z" }, + { url = "https://files.pythonhosted.org/packages/2d/a0/d4c4bc5b50275449a9a908283b567caa032a94505fe1976e17f994faa6be/fonttools-4.59.2-cp314-cp314t-win_amd64.whl", hash = "sha256:7ad5d8d8cc9e43cb438b3eb4a0094dd6d4088daa767b0a24d52529361fd4c199", size = 2333169, upload-time = "2025-08-27T16:40:09.656Z" }, + { url = "https://files.pythonhosted.org/packages/65/a4/d2f7be3c86708912c02571db0b550121caab8cd88a3c0aacb9cfa15ea66e/fonttools-4.59.2-py3-none-any.whl", hash = "sha256:8bd0f759020e87bb5d323e6283914d9bf4ae35a7307dafb2cbd1e379e720ad37", size = 1132315, upload-time = "2025-08-27T16:40:28.984Z" }, +] + +[[package]] +name = "fsspec" +version = "2025.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/e0/bab50af11c2d75c9c4a2a26a5254573c0bd97cea152254401510950486fa/fsspec-2025.9.0.tar.gz", hash = "sha256:19fd429483d25d28b65ec68f9f4adc16c17ea2c7c7bf54ec61360d478fb19c19", size = 304847, upload-time = "2025-09-02T19:10:49.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/71/70db47e4f6ce3e5c37a607355f80da8860a33226be640226ac52cb05ef2e/fsspec-2025.9.0-py3-none-any.whl", hash = "sha256:530dc2a2af60a414a832059574df4a6e10cce927f6f4a78209390fe38955cfb7", size = 199289, upload-time = "2025-09-02T19:10:47.708Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.1.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/0f/5b60fc28ee7f8cc17a5114a584fd6b86e11c3e0a6e142a7f97a161e9640a/hf_xet-1.1.9.tar.gz", hash = "sha256:c99073ce404462e909f1d5839b2d14a3827b8fe75ed8aed551ba6609c026c803", size = 484242, upload-time = "2025-08-27T23:05:19.441Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/12/56e1abb9a44cdef59a411fe8a8673313195711b5ecce27880eb9c8fa90bd/hf_xet-1.1.9-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:a3b6215f88638dd7a6ff82cb4e738dcbf3d863bf667997c093a3c990337d1160", size = 2762553, upload-time = "2025-08-27T23:05:15.153Z" }, + { url = "https://files.pythonhosted.org/packages/3a/e6/2d0d16890c5f21b862f5df3146519c182e7f0ae49b4b4bf2bd8a40d0b05e/hf_xet-1.1.9-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:9b486de7a64a66f9a172f4b3e0dfe79c9f0a93257c501296a2521a13495a698a", size = 2623216, upload-time = "2025-08-27T23:05:13.778Z" }, + { url = "https://files.pythonhosted.org/packages/81/42/7e6955cf0621e87491a1fb8cad755d5c2517803cea174229b0ec00ff0166/hf_xet-1.1.9-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a4c5a840c2c4e6ec875ed13703a60e3523bc7f48031dfd750923b2a4d1a5fc3c", size = 3186789, upload-time = "2025-08-27T23:05:12.368Z" }, + { url = "https://files.pythonhosted.org/packages/df/8b/759233bce05457f5f7ec062d63bbfd2d0c740b816279eaaa54be92aa452a/hf_xet-1.1.9-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:96a6139c9e44dad1c52c52520db0fffe948f6bce487cfb9d69c125f254bb3790", size = 3088747, upload-time = "2025-08-27T23:05:10.439Z" }, + { url = "https://files.pythonhosted.org/packages/6c/3c/28cc4db153a7601a996985bcb564f7b8f5b9e1a706c7537aad4b4809f358/hf_xet-1.1.9-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ad1022e9a998e784c97b2173965d07fe33ee26e4594770b7785a8cc8f922cd95", size = 3251429, upload-time = "2025-08-27T23:05:16.471Z" }, + { url = "https://files.pythonhosted.org/packages/84/17/7caf27a1d101bfcb05be85850d4aa0a265b2e1acc2d4d52a48026ef1d299/hf_xet-1.1.9-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86754c2d6d5afb11b0a435e6e18911a4199262fe77553f8c50d75e21242193ea", size = 3354643, upload-time = "2025-08-27T23:05:17.828Z" }, + { url = "https://files.pythonhosted.org/packages/cd/50/0c39c9eed3411deadcc98749a6699d871b822473f55fe472fad7c01ec588/hf_xet-1.1.9-cp37-abi3-win_amd64.whl", hash = "sha256:5aad3933de6b725d61d51034e04174ed1dce7a57c63d530df0014dea15a40127", size = 2804797, upload-time = "2025-08-27T23:05:20.77Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.34.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/c9/bdbe19339f76d12985bc03572f330a01a93c04dffecaaea3061bdd7fb892/huggingface_hub-0.34.4.tar.gz", hash = "sha256:a4228daa6fb001be3f4f4bdaf9a0db00e1739235702848df00885c9b5742c85c", size = 459768, upload-time = "2025-08-08T09:14:52.365Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl", hash = "sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a", size = 561452, upload-time = "2025-08-08T09:14:50.159Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "imageio" +version = "2.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pillow" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0c/47/57e897fb7094afb2d26e8b2e4af9a45c7cf1a405acdeeca001fdf2c98501/imageio-2.37.0.tar.gz", hash = "sha256:71b57b3669666272c818497aebba2b4c5f20d5b37c81720e5e1a56d59c492996", size = 389963, upload-time = "2025-01-20T02:42:37.089Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/bd/b394387b598ed84d8d0fa90611a90bee0adc2021820ad5729f7ced74a8e2/imageio-2.37.0-py3-none-any.whl", hash = "sha256:11efa15b87bc7871b61590326b2d635439acc321cf7f8ce996f812543ce10eed", size = 315796, upload-time = "2025-01-20T02:42:34.931Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "joblib" +version = "1.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e8/5d/447af5ea094b9e4c4054f82e223ada074c552335b9b4b2d14bd9b35a67c4/joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55", size = 331077, upload-time = "2025-08-27T12:15:46.575Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/e8/685f47e0d754320684db4425a0967f7d3fa70126bffd76110b7009a0090f/joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241", size = 308396, upload-time = "2025-08-27T12:15:45.188Z" }, +] + +[[package]] +name = "kiwisolver" +version = "1.4.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5c/3c/85844f1b0feb11ee581ac23fe5fce65cd049a200c1446708cc1b7f922875/kiwisolver-1.4.9.tar.gz", hash = "sha256:c3b22c26c6fd6811b0ae8363b95ca8ce4ea3c202d3d0975b2914310ceb1bcc4d", size = 97564, upload-time = "2025-08-10T21:27:49.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/ab/c80b0d5a9d8a1a65f4f815f2afff9798b12c3b9f31f1d304dd233dd920e2/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:eb14a5da6dc7642b0f3a18f13654847cd8b7a2550e2645a5bda677862b03ba16", size = 124167, upload-time = "2025-08-10T21:25:53.403Z" }, + { url = "https://files.pythonhosted.org/packages/a0/c0/27fe1a68a39cf62472a300e2879ffc13c0538546c359b86f149cc19f6ac3/kiwisolver-1.4.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:39a219e1c81ae3b103643d2aedb90f1ef22650deb266ff12a19e7773f3e5f089", size = 66579, upload-time = "2025-08-10T21:25:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/31/a2/a12a503ac1fd4943c50f9822678e8015a790a13b5490354c68afb8489814/kiwisolver-1.4.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2405a7d98604b87f3fc28b1716783534b1b4b8510d8142adca34ee0bc3c87543", size = 65309, upload-time = "2025-08-10T21:25:55.76Z" }, + { url = "https://files.pythonhosted.org/packages/66/e1/e533435c0be77c3f64040d68d7a657771194a63c279f55573188161e81ca/kiwisolver-1.4.9-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:dc1ae486f9abcef254b5618dfb4113dd49f94c68e3e027d03cf0143f3f772b61", size = 1435596, upload-time = "2025-08-10T21:25:56.861Z" }, + { url = "https://files.pythonhosted.org/packages/67/1e/51b73c7347f9aabdc7215aa79e8b15299097dc2f8e67dee2b095faca9cb0/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8a1f570ce4d62d718dce3f179ee78dac3b545ac16c0c04bb363b7607a949c0d1", size = 1246548, upload-time = "2025-08-10T21:25:58.246Z" }, + { url = "https://files.pythonhosted.org/packages/21/aa/72a1c5d1e430294f2d32adb9542719cfb441b5da368d09d268c7757af46c/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb27e7b78d716c591e88e0a09a2139c6577865d7f2e152488c2cc6257f460872", size = 1263618, upload-time = "2025-08-10T21:25:59.857Z" }, + { url = "https://files.pythonhosted.org/packages/a3/af/db1509a9e79dbf4c260ce0cfa3903ea8945f6240e9e59d1e4deb731b1a40/kiwisolver-1.4.9-cp311-cp311-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:15163165efc2f627eb9687ea5f3a28137217d217ac4024893d753f46bce9de26", size = 1317437, upload-time = "2025-08-10T21:26:01.105Z" }, + { url = "https://files.pythonhosted.org/packages/e0/f2/3ea5ee5d52abacdd12013a94130436e19969fa183faa1e7c7fbc89e9a42f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bdee92c56a71d2b24c33a7d4c2856bd6419d017e08caa7802d2963870e315028", size = 2195742, upload-time = "2025-08-10T21:26:02.675Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9b/1efdd3013c2d9a2566aa6a337e9923a00590c516add9a1e89a768a3eb2fc/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:412f287c55a6f54b0650bd9b6dce5aceddb95864a1a90c87af16979d37c89771", size = 2290810, upload-time = "2025-08-10T21:26:04.009Z" }, + { url = "https://files.pythonhosted.org/packages/fb/e5/cfdc36109ae4e67361f9bc5b41323648cb24a01b9ade18784657e022e65f/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2c93f00dcba2eea70af2be5f11a830a742fe6b579a1d4e00f47760ef13be247a", size = 2461579, upload-time = "2025-08-10T21:26:05.317Z" }, + { url = "https://files.pythonhosted.org/packages/62/86/b589e5e86c7610842213994cdea5add00960076bef4ae290c5fa68589cac/kiwisolver-1.4.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f117e1a089d9411663a3207ba874f31be9ac8eaa5b533787024dc07aeb74f464", size = 2268071, upload-time = "2025-08-10T21:26:06.686Z" }, + { url = "https://files.pythonhosted.org/packages/3b/c6/f8df8509fd1eee6c622febe54384a96cfaf4d43bf2ccec7a0cc17e4715c9/kiwisolver-1.4.9-cp311-cp311-win_amd64.whl", hash = "sha256:be6a04e6c79819c9a8c2373317d19a96048e5a3f90bec587787e86a1153883c2", size = 73840, upload-time = "2025-08-10T21:26:07.94Z" }, + { url = "https://files.pythonhosted.org/packages/e2/2d/16e0581daafd147bc11ac53f032a2b45eabac897f42a338d0a13c1e5c436/kiwisolver-1.4.9-cp311-cp311-win_arm64.whl", hash = "sha256:0ae37737256ba2de764ddc12aed4956460277f00c4996d51a197e72f62f5eec7", size = 65159, upload-time = "2025-08-10T21:26:09.048Z" }, + { url = "https://files.pythonhosted.org/packages/86/c9/13573a747838aeb1c76e3267620daa054f4152444d1f3d1a2324b78255b5/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ac5a486ac389dddcc5bef4f365b6ae3ffff2c433324fb38dd35e3fab7c957999", size = 123686, upload-time = "2025-08-10T21:26:10.034Z" }, + { url = "https://files.pythonhosted.org/packages/51/ea/2ecf727927f103ffd1739271ca19c424d0e65ea473fbaeea1c014aea93f6/kiwisolver-1.4.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2ba92255faa7309d06fe44c3a4a97efe1c8d640c2a79a5ef728b685762a6fd2", size = 66460, upload-time = "2025-08-10T21:26:11.083Z" }, + { url = "https://files.pythonhosted.org/packages/5b/5a/51f5464373ce2aeb5194508298a508b6f21d3867f499556263c64c621914/kiwisolver-1.4.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a2899935e724dd1074cb568ce7ac0dce28b2cd6ab539c8e001a8578eb106d14", size = 64952, upload-time = "2025-08-10T21:26:12.058Z" }, + { url = "https://files.pythonhosted.org/packages/70/90/6d240beb0f24b74371762873e9b7f499f1e02166a2d9c5801f4dbf8fa12e/kiwisolver-1.4.9-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f6008a4919fdbc0b0097089f67a1eb55d950ed7e90ce2cc3e640abadd2757a04", size = 1474756, upload-time = "2025-08-10T21:26:13.096Z" }, + { url = "https://files.pythonhosted.org/packages/12/42/f36816eaf465220f683fb711efdd1bbf7a7005a2473d0e4ed421389bd26c/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:67bb8b474b4181770f926f7b7d2f8c0248cbcb78b660fdd41a47054b28d2a752", size = 1276404, upload-time = "2025-08-10T21:26:14.457Z" }, + { url = "https://files.pythonhosted.org/packages/2e/64/bc2de94800adc830c476dce44e9b40fd0809cddeef1fde9fcf0f73da301f/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2327a4a30d3ee07d2fbe2e7933e8a37c591663b96ce42a00bc67461a87d7df77", size = 1294410, upload-time = "2025-08-10T21:26:15.73Z" }, + { url = "https://files.pythonhosted.org/packages/5f/42/2dc82330a70aa8e55b6d395b11018045e58d0bb00834502bf11509f79091/kiwisolver-1.4.9-cp312-cp312-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7a08b491ec91b1d5053ac177afe5290adacf1f0f6307d771ccac5de30592d198", size = 1343631, upload-time = "2025-08-10T21:26:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/22/fd/f4c67a6ed1aab149ec5a8a401c323cee7a1cbe364381bb6c9c0d564e0e20/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d8fc5c867c22b828001b6a38d2eaeb88160bf5783c6cb4a5e440efc981ce286d", size = 2224963, upload-time = "2025-08-10T21:26:18.737Z" }, + { url = "https://files.pythonhosted.org/packages/45/aa/76720bd4cb3713314677d9ec94dcc21ced3f1baf4830adde5bb9b2430a5f/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:3b3115b2581ea35bb6d1f24a4c90af37e5d9b49dcff267eeed14c3893c5b86ab", size = 2321295, upload-time = "2025-08-10T21:26:20.11Z" }, + { url = "https://files.pythonhosted.org/packages/80/19/d3ec0d9ab711242f56ae0dc2fc5d70e298bb4a1f9dfab44c027668c673a1/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:858e4c22fb075920b96a291928cb7dea5644e94c0ee4fcd5af7e865655e4ccf2", size = 2487987, upload-time = "2025-08-10T21:26:21.49Z" }, + { url = "https://files.pythonhosted.org/packages/39/e9/61e4813b2c97e86b6fdbd4dd824bf72d28bcd8d4849b8084a357bc0dd64d/kiwisolver-1.4.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ed0fecd28cc62c54b262e3736f8bb2512d8dcfdc2bcf08be5f47f96bf405b145", size = 2291817, upload-time = "2025-08-10T21:26:22.812Z" }, + { url = "https://files.pythonhosted.org/packages/a0/41/85d82b0291db7504da3c2defe35c9a8a5c9803a730f297bd823d11d5fb77/kiwisolver-1.4.9-cp312-cp312-win_amd64.whl", hash = "sha256:f68208a520c3d86ea51acf688a3e3002615a7f0238002cccc17affecc86a8a54", size = 73895, upload-time = "2025-08-10T21:26:24.37Z" }, + { url = "https://files.pythonhosted.org/packages/e2/92/5f3068cf15ee5cb624a0c7596e67e2a0bb2adee33f71c379054a491d07da/kiwisolver-1.4.9-cp312-cp312-win_arm64.whl", hash = "sha256:2c1a4f57df73965f3f14df20b80ee29e6a7930a57d2d9e8491a25f676e197c60", size = 64992, upload-time = "2025-08-10T21:26:25.732Z" }, + { url = "https://files.pythonhosted.org/packages/31/c1/c2686cda909742ab66c7388e9a1a8521a59eb89f8bcfbee28fc980d07e24/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a5d0432ccf1c7ab14f9949eec60c5d1f924f17c037e9f8b33352fa05799359b8", size = 123681, upload-time = "2025-08-10T21:26:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f0/f44f50c9f5b1a1860261092e3bc91ecdc9acda848a8b8c6abfda4a24dd5c/kiwisolver-1.4.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efb3a45b35622bb6c16dbfab491a8f5a391fe0e9d45ef32f4df85658232ca0e2", size = 66464, upload-time = "2025-08-10T21:26:27.733Z" }, + { url = "https://files.pythonhosted.org/packages/2d/7a/9d90a151f558e29c3936b8a47ac770235f436f2120aca41a6d5f3d62ae8d/kiwisolver-1.4.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a12cf6398e8a0a001a059747a1cbf24705e18fe413bc22de7b3d15c67cffe3f", size = 64961, upload-time = "2025-08-10T21:26:28.729Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e9/f218a2cb3a9ffbe324ca29a9e399fa2d2866d7f348ec3a88df87fc248fc5/kiwisolver-1.4.9-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b67e6efbf68e077dd71d1a6b37e43e1a99d0bff1a3d51867d45ee8908b931098", size = 1474607, upload-time = "2025-08-10T21:26:29.798Z" }, + { url = "https://files.pythonhosted.org/packages/d9/28/aac26d4c882f14de59041636292bc838db8961373825df23b8eeb807e198/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5656aa670507437af0207645273ccdfee4f14bacd7f7c67a4306d0dcaeaf6eed", size = 1276546, upload-time = "2025-08-10T21:26:31.401Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ad/8bfc1c93d4cc565e5069162f610ba2f48ff39b7de4b5b8d93f69f30c4bed/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bfc08add558155345129c7803b3671cf195e6a56e7a12f3dde7c57d9b417f525", size = 1294482, upload-time = "2025-08-10T21:26:32.721Z" }, + { url = "https://files.pythonhosted.org/packages/da/f1/6aca55ff798901d8ce403206d00e033191f63d82dd708a186e0ed2067e9c/kiwisolver-1.4.9-cp313-cp313-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:40092754720b174e6ccf9e845d0d8c7d8e12c3d71e7fc35f55f3813e96376f78", size = 1343720, upload-time = "2025-08-10T21:26:34.032Z" }, + { url = "https://files.pythonhosted.org/packages/d1/91/eed031876c595c81d90d0f6fc681ece250e14bf6998c3d7c419466b523b7/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:497d05f29a1300d14e02e6441cf0f5ee81c1ff5a304b0d9fb77423974684e08b", size = 2224907, upload-time = "2025-08-10T21:26:35.824Z" }, + { url = "https://files.pythonhosted.org/packages/e9/ec/4d1925f2e49617b9cca9c34bfa11adefad49d00db038e692a559454dfb2e/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:bdd1a81a1860476eb41ac4bc1e07b3f07259e6d55bbf739b79c8aaedcf512799", size = 2321334, upload-time = "2025-08-10T21:26:37.534Z" }, + { url = "https://files.pythonhosted.org/packages/43/cb/450cd4499356f68802750c6ddc18647b8ea01ffa28f50d20598e0befe6e9/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:e6b93f13371d341afee3be9f7c5964e3fe61d5fa30f6a30eb49856935dfe4fc3", size = 2488313, upload-time = "2025-08-10T21:26:39.191Z" }, + { url = "https://files.pythonhosted.org/packages/71/67/fc76242bd99f885651128a5d4fa6083e5524694b7c88b489b1b55fdc491d/kiwisolver-1.4.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d75aa530ccfaa593da12834b86a0724f58bff12706659baa9227c2ccaa06264c", size = 2291970, upload-time = "2025-08-10T21:26:40.828Z" }, + { url = "https://files.pythonhosted.org/packages/75/bd/f1a5d894000941739f2ae1b65a32892349423ad49c2e6d0771d0bad3fae4/kiwisolver-1.4.9-cp313-cp313-win_amd64.whl", hash = "sha256:dd0a578400839256df88c16abddf9ba14813ec5f21362e1fe65022e00c883d4d", size = 73894, upload-time = "2025-08-10T21:26:42.33Z" }, + { url = "https://files.pythonhosted.org/packages/95/38/dce480814d25b99a391abbddadc78f7c117c6da34be68ca8b02d5848b424/kiwisolver-1.4.9-cp313-cp313-win_arm64.whl", hash = "sha256:d4188e73af84ca82468f09cadc5ac4db578109e52acb4518d8154698d3a87ca2", size = 64995, upload-time = "2025-08-10T21:26:43.889Z" }, + { url = "https://files.pythonhosted.org/packages/e2/37/7d218ce5d92dadc5ebdd9070d903e0c7cf7edfe03f179433ac4d13ce659c/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:5a0f2724dfd4e3b3ac5a82436a8e6fd16baa7d507117e4279b660fe8ca38a3a1", size = 126510, upload-time = "2025-08-10T21:26:44.915Z" }, + { url = "https://files.pythonhosted.org/packages/23/b0/e85a2b48233daef4b648fb657ebbb6f8367696a2d9548a00b4ee0eb67803/kiwisolver-1.4.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1b11d6a633e4ed84fc0ddafd4ebfd8ea49b3f25082c04ad12b8315c11d504dc1", size = 67903, upload-time = "2025-08-10T21:26:45.934Z" }, + { url = "https://files.pythonhosted.org/packages/44/98/f2425bc0113ad7de24da6bb4dae1343476e95e1d738be7c04d31a5d037fd/kiwisolver-1.4.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61874cdb0a36016354853593cffc38e56fc9ca5aa97d2c05d3dcf6922cd55a11", size = 66402, upload-time = "2025-08-10T21:26:47.101Z" }, + { url = "https://files.pythonhosted.org/packages/98/d8/594657886df9f34c4177cc353cc28ca7e6e5eb562d37ccc233bff43bbe2a/kiwisolver-1.4.9-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:60c439763a969a6af93b4881db0eed8fadf93ee98e18cbc35bc8da868d0c4f0c", size = 1582135, upload-time = "2025-08-10T21:26:48.665Z" }, + { url = "https://files.pythonhosted.org/packages/5c/c6/38a115b7170f8b306fc929e166340c24958347308ea3012c2b44e7e295db/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92a2f997387a1b79a75e7803aa7ded2cfbe2823852ccf1ba3bcf613b62ae3197", size = 1389409, upload-time = "2025-08-10T21:26:50.335Z" }, + { url = "https://files.pythonhosted.org/packages/bf/3b/e04883dace81f24a568bcee6eb3001da4ba05114afa622ec9b6fafdc1f5e/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a31d512c812daea6d8b3be3b2bfcbeb091dbb09177706569bcfc6240dcf8b41c", size = 1401763, upload-time = "2025-08-10T21:26:51.867Z" }, + { url = "https://files.pythonhosted.org/packages/9f/80/20ace48e33408947af49d7d15c341eaee69e4e0304aab4b7660e234d6288/kiwisolver-1.4.9-cp313-cp313t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:52a15b0f35dad39862d376df10c5230155243a2c1a436e39eb55623ccbd68185", size = 1453643, upload-time = "2025-08-10T21:26:53.592Z" }, + { url = "https://files.pythonhosted.org/packages/64/31/6ce4380a4cd1f515bdda976a1e90e547ccd47b67a1546d63884463c92ca9/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a30fd6fdef1430fd9e1ba7b3398b5ee4e2887783917a687d86ba69985fb08748", size = 2330818, upload-time = "2025-08-10T21:26:55.051Z" }, + { url = "https://files.pythonhosted.org/packages/fa/e9/3f3fcba3bcc7432c795b82646306e822f3fd74df0ee81f0fa067a1f95668/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cc9617b46837c6468197b5945e196ee9ca43057bb7d9d1ae688101e4e1dddf64", size = 2419963, upload-time = "2025-08-10T21:26:56.421Z" }, + { url = "https://files.pythonhosted.org/packages/99/43/7320c50e4133575c66e9f7dadead35ab22d7c012a3b09bb35647792b2a6d/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:0ab74e19f6a2b027ea4f845a78827969af45ce790e6cb3e1ebab71bdf9f215ff", size = 2594639, upload-time = "2025-08-10T21:26:57.882Z" }, + { url = "https://files.pythonhosted.org/packages/65/d6/17ae4a270d4a987ef8a385b906d2bdfc9fce502d6dc0d3aea865b47f548c/kiwisolver-1.4.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:dba5ee5d3981160c28d5490f0d1b7ed730c22470ff7f6cc26cfcfaacb9896a07", size = 2391741, upload-time = "2025-08-10T21:26:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8f/8f6f491d595a9e5912971f3f863d81baddccc8a4d0c3749d6a0dd9ffc9df/kiwisolver-1.4.9-cp313-cp313t-win_arm64.whl", hash = "sha256:0749fd8f4218ad2e851e11cc4dc05c7cbc0cbc4267bdfdb31782e65aace4ee9c", size = 68646, upload-time = "2025-08-10T21:27:00.52Z" }, + { url = "https://files.pythonhosted.org/packages/6b/32/6cc0fbc9c54d06c2969faa9c1d29f5751a2e51809dd55c69055e62d9b426/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:9928fe1eb816d11ae170885a74d074f57af3a0d65777ca47e9aeb854a1fba386", size = 123806, upload-time = "2025-08-10T21:27:01.537Z" }, + { url = "https://files.pythonhosted.org/packages/b2/dd/2bfb1d4a4823d92e8cbb420fe024b8d2167f72079b3bb941207c42570bdf/kiwisolver-1.4.9-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d0005b053977e7b43388ddec89fa567f43d4f6d5c2c0affe57de5ebf290dc552", size = 66605, upload-time = "2025-08-10T21:27:03.335Z" }, + { url = "https://files.pythonhosted.org/packages/f7/69/00aafdb4e4509c2ca6064646cba9cd4b37933898f426756adb2cb92ebbed/kiwisolver-1.4.9-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:2635d352d67458b66fd0667c14cb1d4145e9560d503219034a18a87e971ce4f3", size = 64925, upload-time = "2025-08-10T21:27:04.339Z" }, + { url = "https://files.pythonhosted.org/packages/43/dc/51acc6791aa14e5cb6d8a2e28cefb0dc2886d8862795449d021334c0df20/kiwisolver-1.4.9-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:767c23ad1c58c9e827b649a9ab7809fd5fd9db266a9cf02b0e926ddc2c680d58", size = 1472414, upload-time = "2025-08-10T21:27:05.437Z" }, + { url = "https://files.pythonhosted.org/packages/3d/bb/93fa64a81db304ac8a246f834d5094fae4b13baf53c839d6bb6e81177129/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72d0eb9fba308b8311685c2268cf7d0a0639a6cd027d8128659f72bdd8a024b4", size = 1281272, upload-time = "2025-08-10T21:27:07.063Z" }, + { url = "https://files.pythonhosted.org/packages/70/e6/6df102916960fb8d05069d4bd92d6d9a8202d5a3e2444494e7cd50f65b7a/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f68e4f3eeca8fb22cc3d731f9715a13b652795ef657a13df1ad0c7dc0e9731df", size = 1298578, upload-time = "2025-08-10T21:27:08.452Z" }, + { url = "https://files.pythonhosted.org/packages/7c/47/e142aaa612f5343736b087864dbaebc53ea8831453fb47e7521fa8658f30/kiwisolver-1.4.9-cp314-cp314-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d84cd4061ae292d8ac367b2c3fa3aad11cb8625a95d135fe93f286f914f3f5a6", size = 1345607, upload-time = "2025-08-10T21:27:10.125Z" }, + { url = "https://files.pythonhosted.org/packages/54/89/d641a746194a0f4d1a3670fb900d0dbaa786fb98341056814bc3f058fa52/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a60ea74330b91bd22a29638940d115df9dc00af5035a9a2a6ad9399ffb4ceca5", size = 2230150, upload-time = "2025-08-10T21:27:11.484Z" }, + { url = "https://files.pythonhosted.org/packages/aa/6b/5ee1207198febdf16ac11f78c5ae40861b809cbe0e6d2a8d5b0b3044b199/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:ce6a3a4e106cf35c2d9c4fa17c05ce0b180db622736845d4315519397a77beaf", size = 2325979, upload-time = "2025-08-10T21:27:12.917Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ff/b269eefd90f4ae14dcc74973d5a0f6d28d3b9bb1afd8c0340513afe6b39a/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:77937e5e2a38a7b48eef0585114fe7930346993a88060d0bf886086d2aa49ef5", size = 2491456, upload-time = "2025-08-10T21:27:14.353Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d4/10303190bd4d30de547534601e259a4fbf014eed94aae3e5521129215086/kiwisolver-1.4.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:24c175051354f4a28c5d6a31c93906dc653e2bf234e8a4bbfb964892078898ce", size = 2294621, upload-time = "2025-08-10T21:27:15.808Z" }, + { url = "https://files.pythonhosted.org/packages/28/e0/a9a90416fce5c0be25742729c2ea52105d62eda6c4be4d803c2a7be1fa50/kiwisolver-1.4.9-cp314-cp314-win_amd64.whl", hash = "sha256:0763515d4df10edf6d06a3c19734e2566368980d21ebec439f33f9eb936c07b7", size = 75417, upload-time = "2025-08-10T21:27:17.436Z" }, + { url = "https://files.pythonhosted.org/packages/1f/10/6949958215b7a9a264299a7db195564e87900f709db9245e4ebdd3c70779/kiwisolver-1.4.9-cp314-cp314-win_arm64.whl", hash = "sha256:0e4e2bf29574a6a7b7f6cb5fa69293b9f96c928949ac4a53ba3f525dffb87f9c", size = 66582, upload-time = "2025-08-10T21:27:18.436Z" }, + { url = "https://files.pythonhosted.org/packages/ec/79/60e53067903d3bc5469b369fe0dfc6b3482e2133e85dae9daa9527535991/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d976bbb382b202f71c67f77b0ac11244021cfa3f7dfd9e562eefcea2df711548", size = 126514, upload-time = "2025-08-10T21:27:19.465Z" }, + { url = "https://files.pythonhosted.org/packages/25/d1/4843d3e8d46b072c12a38c97c57fab4608d36e13fe47d47ee96b4d61ba6f/kiwisolver-1.4.9-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:2489e4e5d7ef9a1c300a5e0196e43d9c739f066ef23270607d45aba368b91f2d", size = 67905, upload-time = "2025-08-10T21:27:20.51Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ae/29ffcbd239aea8b93108de1278271ae764dfc0d803a5693914975f200596/kiwisolver-1.4.9-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e2ea9f7ab7fbf18fffb1b5434ce7c69a07582f7acc7717720f1d69f3e806f90c", size = 66399, upload-time = "2025-08-10T21:27:21.496Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ae/d7ba902aa604152c2ceba5d352d7b62106bedbccc8e95c3934d94472bfa3/kiwisolver-1.4.9-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b34e51affded8faee0dfdb705416153819d8ea9250bbbf7ea1b249bdeb5f1122", size = 1582197, upload-time = "2025-08-10T21:27:22.604Z" }, + { url = "https://files.pythonhosted.org/packages/f2/41/27c70d427eddb8bc7e4f16420a20fefc6f480312122a59a959fdfe0445ad/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d8aacd3d4b33b772542b2e01beb50187536967b514b00003bdda7589722d2a64", size = 1390125, upload-time = "2025-08-10T21:27:24.036Z" }, + { url = "https://files.pythonhosted.org/packages/41/42/b3799a12bafc76d962ad69083f8b43b12bf4fe78b097b12e105d75c9b8f1/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7cf974dd4e35fa315563ac99d6287a1024e4dc2077b8a7d7cd3d2fb65d283134", size = 1402612, upload-time = "2025-08-10T21:27:25.773Z" }, + { url = "https://files.pythonhosted.org/packages/d2/b5/a210ea073ea1cfaca1bb5c55a62307d8252f531beb364e18aa1e0888b5a0/kiwisolver-1.4.9-cp314-cp314t-manylinux_2_24_s390x.manylinux_2_28_s390x.whl", hash = "sha256:85bd218b5ecfbee8c8a82e121802dcb519a86044c9c3b2e4aef02fa05c6da370", size = 1453990, upload-time = "2025-08-10T21:27:27.089Z" }, + { url = "https://files.pythonhosted.org/packages/5f/ce/a829eb8c033e977d7ea03ed32fb3c1781b4fa0433fbadfff29e39c676f32/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0856e241c2d3df4efef7c04a1e46b1936b6120c9bcf36dd216e3acd84bc4fb21", size = 2331601, upload-time = "2025-08-10T21:27:29.343Z" }, + { url = "https://files.pythonhosted.org/packages/e0/4b/b5e97eb142eb9cd0072dacfcdcd31b1c66dc7352b0f7c7255d339c0edf00/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:9af39d6551f97d31a4deebeac6f45b156f9755ddc59c07b402c148f5dbb6482a", size = 2422041, upload-time = "2025-08-10T21:27:30.754Z" }, + { url = "https://files.pythonhosted.org/packages/40/be/8eb4cd53e1b85ba4edc3a9321666f12b83113a178845593307a3e7891f44/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:bb4ae2b57fc1d8cbd1cf7b1d9913803681ffa903e7488012be5b76dedf49297f", size = 2594897, upload-time = "2025-08-10T21:27:32.803Z" }, + { url = "https://files.pythonhosted.org/packages/99/dd/841e9a66c4715477ea0abc78da039832fbb09dac5c35c58dc4c41a407b8a/kiwisolver-1.4.9-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:aedff62918805fb62d43a4aa2ecd4482c380dc76cd31bd7c8878588a61bd0369", size = 2391835, upload-time = "2025-08-10T21:27:34.23Z" }, + { url = "https://files.pythonhosted.org/packages/0c/28/4b2e5c47a0da96896fdfdb006340ade064afa1e63675d01ea5ac222b6d52/kiwisolver-1.4.9-cp314-cp314t-win_amd64.whl", hash = "sha256:1fa333e8b2ce4d9660f2cda9c0e1b6bafcfb2457a9d259faa82289e73ec24891", size = 79988, upload-time = "2025-08-10T21:27:35.587Z" }, + { url = "https://files.pythonhosted.org/packages/80/be/3578e8afd18c88cdf9cb4cffde75a96d2be38c5a903f1ed0ceec061bd09e/kiwisolver-1.4.9-cp314-cp314t-win_arm64.whl", hash = "sha256:4a48a2ce79d65d363597ef7b567ce3d14d68783d2b2263d98db3d9477805ba32", size = 70260, upload-time = "2025-08-10T21:27:36.606Z" }, + { url = "https://files.pythonhosted.org/packages/a3/0f/36d89194b5a32c054ce93e586d4049b6c2c22887b0eb229c61c68afd3078/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:720e05574713db64c356e86732c0f3c5252818d05f9df320f0ad8380641acea5", size = 60104, upload-time = "2025-08-10T21:27:43.287Z" }, + { url = "https://files.pythonhosted.org/packages/52/ba/4ed75f59e4658fd21fe7dde1fee0ac397c678ec3befba3fe6482d987af87/kiwisolver-1.4.9-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:17680d737d5335b552994a2008fab4c851bcd7de33094a82067ef3a576ff02fa", size = 58592, upload-time = "2025-08-10T21:27:44.314Z" }, + { url = "https://files.pythonhosted.org/packages/33/01/a8ea7c5ea32a9b45ceeaee051a04c8ed4320f5add3c51bfa20879b765b70/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:85b5352f94e490c028926ea567fc569c52ec79ce131dadb968d3853e809518c2", size = 80281, upload-time = "2025-08-10T21:27:45.369Z" }, + { url = "https://files.pythonhosted.org/packages/da/e3/dbd2ecdce306f1d07a1aaf324817ee993aab7aee9db47ceac757deabafbe/kiwisolver-1.4.9-pp311-pypy311_pp73-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:464415881e4801295659462c49461a24fb107c140de781d55518c4b80cb6790f", size = 78009, upload-time = "2025-08-10T21:27:46.376Z" }, + { url = "https://files.pythonhosted.org/packages/da/e9/0d4add7873a73e462aeb45c036a2dead2562b825aa46ba326727b3f31016/kiwisolver-1.4.9-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:fb940820c63a9590d31d88b815e7a3aa5915cad3ce735ab45f0c730b39547de1", size = 73929, upload-time = "2025-08-10T21:27:48.236Z" }, +] + +[[package]] +name = "lazy-loader" +version = "0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/6b/c875b30a1ba490860c93da4cabf479e03f584eba06fe5963f6f6644653d8/lazy_loader-0.4.tar.gz", hash = "sha256:47c75182589b91a4e1a85a136c074285a5ad4d9f39c63e0d7fb76391c4574cd1", size = 15431, upload-time = "2024-04-05T13:03:12.261Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/60/d497a310bde3f01cb805196ac61b7ad6dc5dcf8dce66634dc34364b20b4f/lazy_loader-0.4-py3-none-any.whl", hash = "sha256:342aa8e14d543a154047afb4ba8ef17f5563baad3fc610d7b15b213b0f119efc", size = 12097, upload-time = "2024-04-05T13:03:10.514Z" }, +] + +[[package]] +name = "lightning-utilities" +version = "0.15.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "setuptools" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b8/39/6fc58ca81492db047149b4b8fd385aa1bfb8c28cd7cacb0c7eb0c44d842f/lightning_utilities-0.15.2.tar.gz", hash = "sha256:cdf12f530214a63dacefd713f180d1ecf5d165338101617b4742e8f22c032e24", size = 31090, upload-time = "2025-08-06T13:57:39.242Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/73/3d757cb3fc16f0f9794dd289bcd0c4a031d9cf54d8137d6b984b2d02edf3/lightning_utilities-0.15.2-py3-none-any.whl", hash = "sha256:ad3ab1703775044bbf880dbf7ddaaac899396c96315f3aa1779cec9d618a9841", size = 29431, upload-time = "2025-08-06T13:57:38.046Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "matplotlib" +version = "3.10.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "contourpy" }, + { name = "cycler" }, + { name = "fonttools" }, + { name = "kiwisolver" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "pyparsing" }, + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a0/59/c3e6453a9676ffba145309a73c462bb407f4400de7de3f2b41af70720a3c/matplotlib-3.10.6.tar.gz", hash = "sha256:ec01b645840dd1996df21ee37f208cd8ba57644779fa20464010638013d3203c", size = 34804264, upload-time = "2025-08-30T00:14:25.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/d6/5d3665aa44c49005aaacaa68ddea6fcb27345961cd538a98bb0177934ede/matplotlib-3.10.6-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:905b60d1cb0ee604ce65b297b61cf8be9f4e6cfecf95a3fe1c388b5266bc8f4f", size = 8257527, upload-time = "2025-08-30T00:12:45.31Z" }, + { url = "https://files.pythonhosted.org/packages/8c/af/30ddefe19ca67eebd70047dabf50f899eaff6f3c5e6a1a7edaecaf63f794/matplotlib-3.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7bac38d816637343e53d7185d0c66677ff30ffb131044a81898b5792c956ba76", size = 8119583, upload-time = "2025-08-30T00:12:47.236Z" }, + { url = "https://files.pythonhosted.org/packages/d3/29/4a8650a3dcae97fa4f375d46efcb25920d67b512186f8a6788b896062a81/matplotlib-3.10.6-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:942a8de2b5bfff1de31d95722f702e2966b8a7e31f4e68f7cd963c7cd8861cf6", size = 8692682, upload-time = "2025-08-30T00:12:48.781Z" }, + { url = "https://files.pythonhosted.org/packages/aa/d3/b793b9cb061cfd5d42ff0f69d1822f8d5dbc94e004618e48a97a8373179a/matplotlib-3.10.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3276c85370bc0dfca051ec65c5817d1e0f8f5ce1b7787528ec8ed2d524bbc2f", size = 9521065, upload-time = "2025-08-30T00:12:50.602Z" }, + { url = "https://files.pythonhosted.org/packages/f7/c5/53de5629f223c1c66668d46ac2621961970d21916a4bc3862b174eb2a88f/matplotlib-3.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9df5851b219225731f564e4b9e7f2ac1e13c9e6481f941b5631a0f8e2d9387ce", size = 9576888, upload-time = "2025-08-30T00:12:52.92Z" }, + { url = "https://files.pythonhosted.org/packages/fc/8e/0a18d6d7d2d0a2e66585032a760d13662e5250c784d53ad50434e9560991/matplotlib-3.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:abb5d9478625dd9c9eb51a06d39aae71eda749ae9b3138afb23eb38824026c7e", size = 8115158, upload-time = "2025-08-30T00:12:54.863Z" }, + { url = "https://files.pythonhosted.org/packages/07/b3/1a5107bb66c261e23b9338070702597a2d374e5aa7004b7adfc754fbed02/matplotlib-3.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:886f989ccfae63659183173bb3fced7fd65e9eb793c3cc21c273add368536951", size = 7992444, upload-time = "2025-08-30T00:12:57.067Z" }, + { url = "https://files.pythonhosted.org/packages/ea/1a/7042f7430055d567cc3257ac409fcf608599ab27459457f13772c2d9778b/matplotlib-3.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:31ca662df6a80bd426f871105fdd69db7543e28e73a9f2afe80de7e531eb2347", size = 8272404, upload-time = "2025-08-30T00:12:59.112Z" }, + { url = "https://files.pythonhosted.org/packages/a9/5d/1d5f33f5b43f4f9e69e6a5fe1fb9090936ae7bc8e2ff6158e7a76542633b/matplotlib-3.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1678bb61d897bb4ac4757b5ecfb02bfb3fddf7f808000fb81e09c510712fda75", size = 8128262, upload-time = "2025-08-30T00:13:01.141Z" }, + { url = "https://files.pythonhosted.org/packages/67/c3/135fdbbbf84e0979712df58e5e22b4f257b3f5e52a3c4aacf1b8abec0d09/matplotlib-3.10.6-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:56cd2d20842f58c03d2d6e6c1f1cf5548ad6f66b91e1e48f814e4fb5abd1cb95", size = 8697008, upload-time = "2025-08-30T00:13:03.24Z" }, + { url = "https://files.pythonhosted.org/packages/9c/be/c443ea428fb2488a3ea7608714b1bd85a82738c45da21b447dc49e2f8e5d/matplotlib-3.10.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:662df55604a2f9a45435566d6e2660e41efe83cd94f4288dfbf1e6d1eae4b0bb", size = 9530166, upload-time = "2025-08-30T00:13:05.951Z" }, + { url = "https://files.pythonhosted.org/packages/a9/35/48441422b044d74034aea2a3e0d1a49023f12150ebc58f16600132b9bbaf/matplotlib-3.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:08f141d55148cd1fc870c3387d70ca4df16dee10e909b3b038782bd4bda6ea07", size = 9593105, upload-time = "2025-08-30T00:13:08.356Z" }, + { url = "https://files.pythonhosted.org/packages/45/c3/994ef20eb4154ab84cc08d033834555319e4af970165e6c8894050af0b3c/matplotlib-3.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:590f5925c2d650b5c9d813c5b3b5fc53f2929c3f8ef463e4ecfa7e052044fb2b", size = 8122784, upload-time = "2025-08-30T00:13:10.367Z" }, + { url = "https://files.pythonhosted.org/packages/57/b8/5c85d9ae0e40f04e71bedb053aada5d6bab1f9b5399a0937afb5d6b02d98/matplotlib-3.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:f44c8d264a71609c79a78d50349e724f5d5fc3684ead7c2a473665ee63d868aa", size = 7992823, upload-time = "2025-08-30T00:13:12.24Z" }, + { url = "https://files.pythonhosted.org/packages/a0/db/18380e788bb837e724358287b08e223b32bc8dccb3b0c12fa8ca20bc7f3b/matplotlib-3.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:819e409653c1106c8deaf62e6de6b8611449c2cd9939acb0d7d4e57a3d95cc7a", size = 8273231, upload-time = "2025-08-30T00:13:13.881Z" }, + { url = "https://files.pythonhosted.org/packages/d3/0f/38dd49445b297e0d4f12a322c30779df0d43cb5873c7847df8a82e82ec67/matplotlib-3.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:59c8ac8382fefb9cb71308dde16a7c487432f5255d8f1fd32473523abecfecdf", size = 8128730, upload-time = "2025-08-30T00:13:15.556Z" }, + { url = "https://files.pythonhosted.org/packages/e5/b8/9eea6630198cb303d131d95d285a024b3b8645b1763a2916fddb44ca8760/matplotlib-3.10.6-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:84e82d9e0fd70c70bc55739defbd8055c54300750cbacf4740c9673a24d6933a", size = 8698539, upload-time = "2025-08-30T00:13:17.297Z" }, + { url = "https://files.pythonhosted.org/packages/71/34/44c7b1f075e1ea398f88aeabcc2907c01b9cc99e2afd560c1d49845a1227/matplotlib-3.10.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:25f7a3eb42d6c1c56e89eacd495661fc815ffc08d9da750bca766771c0fd9110", size = 9529702, upload-time = "2025-08-30T00:13:19.248Z" }, + { url = "https://files.pythonhosted.org/packages/b5/7f/e5c2dc9950c7facaf8b461858d1b92c09dd0cf174fe14e21953b3dda06f7/matplotlib-3.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f9c862d91ec0b7842920a4cfdaaec29662195301914ea54c33e01f1a28d014b2", size = 9593742, upload-time = "2025-08-30T00:13:21.181Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1d/70c28528794f6410ee2856cd729fa1f1756498b8d3126443b0a94e1a8695/matplotlib-3.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:1b53bd6337eba483e2e7d29c5ab10eee644bc3a2491ec67cc55f7b44583ffb18", size = 8122753, upload-time = "2025-08-30T00:13:23.44Z" }, + { url = "https://files.pythonhosted.org/packages/e8/74/0e1670501fc7d02d981564caf7c4df42974464625935424ca9654040077c/matplotlib-3.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:cbd5eb50b7058b2892ce45c2f4e92557f395c9991f5c886d1bb74a1582e70fd6", size = 7992973, upload-time = "2025-08-30T00:13:26.632Z" }, + { url = "https://files.pythonhosted.org/packages/b1/4e/60780e631d73b6b02bd7239f89c451a72970e5e7ec34f621eda55cd9a445/matplotlib-3.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:acc86dd6e0e695c095001a7fccff158c49e45e0758fdf5dcdbb0103318b59c9f", size = 8316869, upload-time = "2025-08-30T00:13:28.262Z" }, + { url = "https://files.pythonhosted.org/packages/f8/15/baa662374a579413210fc2115d40c503b7360a08e9cc254aa0d97d34b0c1/matplotlib-3.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e228cd2ffb8f88b7d0b29e37f68ca9aaf83e33821f24a5ccc4f082dd8396bc27", size = 8178240, upload-time = "2025-08-30T00:13:30.007Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3f/3c38e78d2aafdb8829fcd0857d25aaf9e7dd2dfcf7ec742765b585774931/matplotlib-3.10.6-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:658bc91894adeab669cf4bb4a186d049948262987e80f0857216387d7435d833", size = 8711719, upload-time = "2025-08-30T00:13:31.72Z" }, + { url = "https://files.pythonhosted.org/packages/96/4b/2ec2bbf8cefaa53207cc56118d1fa8a0f9b80642713ea9390235d331ede4/matplotlib-3.10.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8913b7474f6dd83ac444c9459c91f7f0f2859e839f41d642691b104e0af056aa", size = 9541422, upload-time = "2025-08-30T00:13:33.611Z" }, + { url = "https://files.pythonhosted.org/packages/83/7d/40255e89b3ef11c7871020563b2dd85f6cb1b4eff17c0f62b6eb14c8fa80/matplotlib-3.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:091cea22e059b89f6d7d1a18e2c33a7376c26eee60e401d92a4d6726c4e12706", size = 9594068, upload-time = "2025-08-30T00:13:35.833Z" }, + { url = "https://files.pythonhosted.org/packages/f0/a9/0213748d69dc842537a113493e1c27daf9f96bd7cc316f933dc8ec4de985/matplotlib-3.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:491e25e02a23d7207629d942c666924a6b61e007a48177fdd231a0097b7f507e", size = 8200100, upload-time = "2025-08-30T00:13:37.668Z" }, + { url = "https://files.pythonhosted.org/packages/be/15/79f9988066ce40b8a6f1759a934ea0cde8dc4adc2262255ee1bc98de6ad0/matplotlib-3.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3d80d60d4e54cda462e2cd9a086d85cd9f20943ead92f575ce86885a43a565d5", size = 8042142, upload-time = "2025-08-30T00:13:39.426Z" }, + { url = "https://files.pythonhosted.org/packages/7c/58/e7b6d292beae6fb4283ca6fb7fa47d7c944a68062d6238c07b497dd35493/matplotlib-3.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:70aaf890ce1d0efd482df969b28a5b30ea0b891224bb315810a3940f67182899", size = 8273802, upload-time = "2025-08-30T00:13:41.006Z" }, + { url = "https://files.pythonhosted.org/packages/9f/f6/7882d05aba16a8cdd594fb9a03a9d3cca751dbb6816adf7b102945522ee9/matplotlib-3.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1565aae810ab79cb72e402b22facfa6501365e73ebab70a0fdfb98488d2c3c0c", size = 8131365, upload-time = "2025-08-30T00:13:42.664Z" }, + { url = "https://files.pythonhosted.org/packages/94/bf/ff32f6ed76e78514e98775a53715eca4804b12bdcf35902cdd1cf759d324/matplotlib-3.10.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3b23315a01981689aa4e1a179dbf6ef9fbd17143c3eea77548c2ecfb0499438", size = 9533961, upload-time = "2025-08-30T00:13:44.372Z" }, + { url = "https://files.pythonhosted.org/packages/fe/c3/6bf88c2fc2da7708a2ff8d2eeb5d68943130f50e636d5d3dcf9d4252e971/matplotlib-3.10.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:30fdd37edf41a4e6785f9b37969de57aea770696cb637d9946eb37470c94a453", size = 9804262, upload-time = "2025-08-30T00:13:46.614Z" }, + { url = "https://files.pythonhosted.org/packages/0f/7a/e05e6d9446d2d577b459427ad060cd2de5742d0e435db3191fea4fcc7e8b/matplotlib-3.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:bc31e693da1c08012c764b053e702c1855378e04102238e6a5ee6a7117c53a47", size = 9595508, upload-time = "2025-08-30T00:13:48.731Z" }, + { url = "https://files.pythonhosted.org/packages/39/fb/af09c463ced80b801629fd73b96f726c9f6124c3603aa2e480a061d6705b/matplotlib-3.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:05be9bdaa8b242bc6ff96330d18c52f1fc59c6fb3a4dd411d953d67e7e1baf98", size = 8252742, upload-time = "2025-08-30T00:13:50.539Z" }, + { url = "https://files.pythonhosted.org/packages/b1/f9/b682f6db9396d9ab8f050c0a3bfbb5f14fb0f6518f08507c04cc02f8f229/matplotlib-3.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:f56a0d1ab05d34c628592435781d185cd99630bdfd76822cd686fb5a0aecd43a", size = 8124237, upload-time = "2025-08-30T00:13:54.3Z" }, + { url = "https://files.pythonhosted.org/packages/b5/d2/b69b4a0923a3c05ab90527c60fdec899ee21ca23ede7f0fb818e6620d6f2/matplotlib-3.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:94f0b4cacb23763b64b5dace50d5b7bfe98710fed5f0cef5c08135a03399d98b", size = 8316956, upload-time = "2025-08-30T00:13:55.932Z" }, + { url = "https://files.pythonhosted.org/packages/28/e9/dc427b6f16457ffaeecb2fc4abf91e5adb8827861b869c7a7a6d1836fa73/matplotlib-3.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cc332891306b9fb39462673d8225d1b824c89783fee82840a709f96714f17a5c", size = 8178260, upload-time = "2025-08-30T00:14:00.942Z" }, + { url = "https://files.pythonhosted.org/packages/c4/89/1fbd5ad611802c34d1c7ad04607e64a1350b7fb9c567c4ec2c19e066ed35/matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee1d607b3fb1590deb04b69f02ea1d53ed0b0bf75b2b1a5745f269afcbd3cdd3", size = 9541422, upload-time = "2025-08-30T00:14:02.664Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/65fec8716025b22c1d72d5a82ea079934c76a547696eaa55be6866bc89b1/matplotlib-3.10.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:376a624a218116461696b27b2bbf7a8945053e6d799f6502fc03226d077807bf", size = 9803678, upload-time = "2025-08-30T00:14:04.741Z" }, + { url = "https://files.pythonhosted.org/packages/c7/b0/40fb2b3a1ab9381bb39a952e8390357c8be3bdadcf6d5055d9c31e1b35ae/matplotlib-3.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:83847b47f6524c34b4f2d3ce726bb0541c48c8e7692729865c3df75bfa0f495a", size = 9594077, upload-time = "2025-08-30T00:14:07.012Z" }, + { url = "https://files.pythonhosted.org/packages/76/34/c4b71b69edf5b06e635eee1ed10bfc73cf8df058b66e63e30e6a55e231d5/matplotlib-3.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:c7e0518e0d223683532a07f4b512e2e0729b62674f1b3a1a69869f98e6b1c7e3", size = 8342822, upload-time = "2025-08-30T00:14:09.041Z" }, + { url = "https://files.pythonhosted.org/packages/e8/62/aeabeef1a842b6226a30d49dd13e8a7a1e81e9ec98212c0b5169f0a12d83/matplotlib-3.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:4dd83e029f5b4801eeb87c64efd80e732452781c16a9cf7415b7b63ec8f374d7", size = 8172588, upload-time = "2025-08-30T00:14:11.166Z" }, + { url = "https://files.pythonhosted.org/packages/12/bb/02c35a51484aae5f49bd29f091286e7af5f3f677a9736c58a92b3c78baeb/matplotlib-3.10.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:f2d684c3204fa62421bbf770ddfebc6b50130f9cad65531eeba19236d73bb488", size = 8252296, upload-time = "2025-08-30T00:14:19.49Z" }, + { url = "https://files.pythonhosted.org/packages/7d/85/41701e3092005aee9a2445f5ee3904d9dbd4a7df7a45905ffef29b7ef098/matplotlib-3.10.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:6f4a69196e663a41d12a728fab8751177215357906436804217d6d9cf0d4d6cf", size = 8116749, upload-time = "2025-08-30T00:14:21.344Z" }, + { url = "https://files.pythonhosted.org/packages/16/53/8d8fa0ea32a8c8239e04d022f6c059ee5e1b77517769feccd50f1df43d6d/matplotlib-3.10.6-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d6ca6ef03dfd269f4ead566ec6f3fb9becf8dab146fb999022ed85ee9f6b3eb", size = 8693933, upload-time = "2025-08-30T00:14:22.942Z" }, +] + +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + +[[package]] +name = "networkx" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, +] + +[[package]] +name = "numpy" +version = "2.2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, + { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, + { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, + { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, + { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, + { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, + { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, + { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, + { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, + { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, + { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, + { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, + { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, + { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, +] + +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12" }, + { name = "nvidia-cusparse-cu12" }, + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/5b/4e4fff7bad39adf89f735f2bc87248c81db71205b62bcc0d5ca5b606b3c3/nvidia_nccl_cu12-2.27.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adf27ccf4238253e0b826bce3ff5fa532d65fc42322c8bfdfaf28024c0fbe039", size = 322364134, upload-time = "2025-06-03T21:58:04.013Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, +] + +[[package]] +name = "opencv-python-headless" +version = "4.12.0.88" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a4/63/6861102ec149c3cd298f4d1ea7ce9d6adbc7529221606ff1dab991a19adb/opencv-python-headless-4.12.0.88.tar.gz", hash = "sha256:cfdc017ddf2e59b6c2f53bc12d74b6b0be7ded4ec59083ea70763921af2b6c09", size = 95379675, upload-time = "2025-07-07T09:21:06.815Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/7d/414e243c5c8216a5277afd104a319cc1291c5e23f5eeef512db5629ee7f4/opencv_python_headless-4.12.0.88-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:1e58d664809b3350c1123484dd441e1667cd7bed3086db1b9ea1b6f6cb20b50e", size = 37877864, upload-time = "2025-07-07T09:14:41.693Z" }, + { url = "https://files.pythonhosted.org/packages/05/14/7e162714beed1cd5e7b5eb66fcbcba2f065c51b1d9da2463024c84d2f7c0/opencv_python_headless-4.12.0.88-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:365bb2e486b50feffc2d07a405b953a8f3e8eaa63865bc650034e5c71e7a5154", size = 57326608, upload-time = "2025-07-07T09:14:51.885Z" }, + { url = "https://files.pythonhosted.org/packages/69/4e/116720df7f1f7f3b59abc608ca30fbec9d2b3ae810afe4e4d26483d9dfa0/opencv_python_headless-4.12.0.88-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:aeb4b13ecb8b4a0beb2668ea07928160ea7c2cd2d9b5ef571bbee6bafe9cc8d0", size = 33145800, upload-time = "2025-07-07T09:15:00.367Z" }, + { url = "https://files.pythonhosted.org/packages/89/53/e19c21e0c4eb1275c3e2c97b081103b6dfb3938172264d283a519bf728b9/opencv_python_headless-4.12.0.88-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:236c8df54a90f4d02076e6f9c1cc763d794542e886c576a6fee46ec8ff75a7a9", size = 54023419, upload-time = "2025-07-07T09:15:10.164Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9c/a76fd5414de6ec9f21f763a600058a0c3e290053cea87e0275692b1375c0/opencv_python_headless-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:fde2cf5c51e4def5f2132d78e0c08f9c14783cd67356922182c6845b9af87dbd", size = 30225230, upload-time = "2025-07-07T09:15:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/f2/35/0858e9e71b36948eafbc5e835874b63e515179dc3b742cbe3d76bc683439/opencv_python_headless-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:86b413bdd6c6bf497832e346cd5371995de148e579b9774f8eba686dee3f5528", size = 38923559, upload-time = "2025-07-07T09:15:25.229Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pandas" +version = "2.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "python-dateutil" }, + { name = "pytz" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/8e/0e90233ac205ad182bd6b422532695d2b9414944a280488105d598c70023/pandas-2.3.2.tar.gz", hash = "sha256:ab7b58f8f82706890924ccdfb5f48002b83d2b5a3845976a9fb705d36c34dcdb", size = 4488684, upload-time = "2025-08-21T10:28:29.257Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7a/59/f3e010879f118c2d400902d2d871c2226cef29b08c09fb8dc41111730400/pandas-2.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1333e9c299adcbb68ee89a9bb568fc3f20f9cbb419f1dd5225071e6cddb2a743", size = 11563308, upload-time = "2025-08-21T10:26:56.656Z" }, + { url = "https://files.pythonhosted.org/packages/38/18/48f10f1cc5c397af59571d638d211f494dba481f449c19adbd282aa8f4ca/pandas-2.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:76972bcbd7de8e91ad5f0ca884a9f2c477a2125354af624e022c49e5bd0dfff4", size = 10820319, upload-time = "2025-08-21T10:26:59.162Z" }, + { url = "https://files.pythonhosted.org/packages/95/3b/1e9b69632898b048e223834cd9702052bcf06b15e1ae716eda3196fb972e/pandas-2.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b98bdd7c456a05eef7cd21fd6b29e3ca243591fe531c62be94a2cc987efb5ac2", size = 11790097, upload-time = "2025-08-21T10:27:02.204Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ef/0e2ffb30b1f7fbc9a588bd01e3c14a0d96854d09a887e15e30cc19961227/pandas-2.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d81573b3f7db40d020983f78721e9bfc425f411e616ef019a10ebf597aedb2e", size = 12397958, upload-time = "2025-08-21T10:27:05.409Z" }, + { url = "https://files.pythonhosted.org/packages/23/82/e6b85f0d92e9afb0e7f705a51d1399b79c7380c19687bfbf3d2837743249/pandas-2.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e190b738675a73b581736cc8ec71ae113d6c3768d0bd18bffa5b9a0927b0b6ea", size = 13225600, upload-time = "2025-08-21T10:27:07.791Z" }, + { url = "https://files.pythonhosted.org/packages/e8/f1/f682015893d9ed51611948bd83683670842286a8edd4f68c2c1c3b231eef/pandas-2.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c253828cb08f47488d60f43c5fc95114c771bbfff085da54bfc79cb4f9e3a372", size = 13879433, upload-time = "2025-08-21T10:27:10.347Z" }, + { url = "https://files.pythonhosted.org/packages/a7/e7/ae86261695b6c8a36d6a4c8d5f9b9ede8248510d689a2f379a18354b37d7/pandas-2.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:9467697b8083f9667b212633ad6aa4ab32436dcbaf4cd57325debb0ddef2012f", size = 11336557, upload-time = "2025-08-21T10:27:12.983Z" }, + { url = "https://files.pythonhosted.org/packages/ec/db/614c20fb7a85a14828edd23f1c02db58a30abf3ce76f38806155d160313c/pandas-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fbb977f802156e7a3f829e9d1d5398f6192375a3e2d1a9ee0803e35fe70a2b9", size = 11587652, upload-time = "2025-08-21T10:27:15.888Z" }, + { url = "https://files.pythonhosted.org/packages/99/b0/756e52f6582cade5e746f19bad0517ff27ba9c73404607c0306585c201b3/pandas-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b9b52693123dd234b7c985c68b709b0b009f4521000d0525f2b95c22f15944b", size = 10717686, upload-time = "2025-08-21T10:27:18.486Z" }, + { url = "https://files.pythonhosted.org/packages/37/4c/dd5ccc1e357abfeee8353123282de17997f90ff67855f86154e5a13b81e5/pandas-2.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bd281310d4f412733f319a5bc552f86d62cddc5f51d2e392c8787335c994175", size = 11278722, upload-time = "2025-08-21T10:27:21.149Z" }, + { url = "https://files.pythonhosted.org/packages/d3/a4/f7edcfa47e0a88cda0be8b068a5bae710bf264f867edfdf7b71584ace362/pandas-2.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96d31a6b4354e3b9b8a2c848af75d31da390657e3ac6f30c05c82068b9ed79b9", size = 11987803, upload-time = "2025-08-21T10:27:23.767Z" }, + { url = "https://files.pythonhosted.org/packages/f6/61/1bce4129f93ab66f1c68b7ed1c12bac6a70b1b56c5dab359c6bbcd480b52/pandas-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:df4df0b9d02bb873a106971bb85d448378ef14b86ba96f035f50bbd3688456b4", size = 12766345, upload-time = "2025-08-21T10:27:26.6Z" }, + { url = "https://files.pythonhosted.org/packages/8e/46/80d53de70fee835531da3a1dae827a1e76e77a43ad22a8cd0f8142b61587/pandas-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:213a5adf93d020b74327cb2c1b842884dbdd37f895f42dcc2f09d451d949f811", size = 13439314, upload-time = "2025-08-21T10:27:29.213Z" }, + { url = "https://files.pythonhosted.org/packages/28/30/8114832daff7489f179971dbc1d854109b7f4365a546e3ea75b6516cea95/pandas-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:8c13b81a9347eb8c7548f53fd9a4f08d4dfe996836543f805c987bafa03317ae", size = 10983326, upload-time = "2025-08-21T10:27:31.901Z" }, + { url = "https://files.pythonhosted.org/packages/27/64/a2f7bf678af502e16b472527735d168b22b7824e45a4d7e96a4fbb634b59/pandas-2.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0c6ecbac99a354a051ef21c5307601093cb9e0f4b1855984a084bfec9302699e", size = 11531061, upload-time = "2025-08-21T10:27:34.647Z" }, + { url = "https://files.pythonhosted.org/packages/54/4c/c3d21b2b7769ef2f4c2b9299fcadd601efa6729f1357a8dbce8dd949ed70/pandas-2.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:c6f048aa0fd080d6a06cc7e7537c09b53be6642d330ac6f54a600c3ace857ee9", size = 10668666, upload-time = "2025-08-21T10:27:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/50/e2/f775ba76ecfb3424d7f5862620841cf0edb592e9abd2d2a5387d305fe7a8/pandas-2.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0064187b80a5be6f2f9c9d6bdde29372468751dfa89f4211a3c5871854cfbf7a", size = 11332835, upload-time = "2025-08-21T10:27:40.188Z" }, + { url = "https://files.pythonhosted.org/packages/8f/52/0634adaace9be2d8cac9ef78f05c47f3a675882e068438b9d7ec7ef0c13f/pandas-2.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ac8c320bded4718b298281339c1a50fb00a6ba78cb2a63521c39bec95b0209b", size = 12057211, upload-time = "2025-08-21T10:27:43.117Z" }, + { url = "https://files.pythonhosted.org/packages/0b/9d/2df913f14b2deb9c748975fdb2491da1a78773debb25abbc7cbc67c6b549/pandas-2.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:114c2fe4f4328cf98ce5716d1532f3ab79c5919f95a9cfee81d9140064a2e4d6", size = 12749277, upload-time = "2025-08-21T10:27:45.474Z" }, + { url = "https://files.pythonhosted.org/packages/87/af/da1a2417026bd14d98c236dba88e39837182459d29dcfcea510b2ac9e8a1/pandas-2.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:48fa91c4dfb3b2b9bfdb5c24cd3567575f4e13f9636810462ffed8925352be5a", size = 13415256, upload-time = "2025-08-21T10:27:49.885Z" }, + { url = "https://files.pythonhosted.org/packages/22/3c/f2af1ce8840ef648584a6156489636b5692c162771918aa95707c165ad2b/pandas-2.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:12d039facec710f7ba305786837d0225a3444af7bbd9c15c32ca2d40d157ed8b", size = 10982579, upload-time = "2025-08-21T10:28:08.435Z" }, + { url = "https://files.pythonhosted.org/packages/f3/98/8df69c4097a6719e357dc249bf437b8efbde808038268e584421696cbddf/pandas-2.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c624b615ce97864eb588779ed4046186f967374185c047070545253a52ab2d57", size = 12028163, upload-time = "2025-08-21T10:27:52.232Z" }, + { url = "https://files.pythonhosted.org/packages/0e/23/f95cbcbea319f349e10ff90db488b905c6883f03cbabd34f6b03cbc3c044/pandas-2.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:0cee69d583b9b128823d9514171cabb6861e09409af805b54459bd0c821a35c2", size = 11391860, upload-time = "2025-08-21T10:27:54.673Z" }, + { url = "https://files.pythonhosted.org/packages/ad/1b/6a984e98c4abee22058aa75bfb8eb90dce58cf8d7296f8bc56c14bc330b0/pandas-2.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2319656ed81124982900b4c37f0e0c58c015af9a7bbc62342ba5ad07ace82ba9", size = 11309830, upload-time = "2025-08-21T10:27:56.957Z" }, + { url = "https://files.pythonhosted.org/packages/15/d5/f0486090eb18dd8710bf60afeaf638ba6817047c0c8ae5c6a25598665609/pandas-2.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b37205ad6f00d52f16b6d09f406434ba928c1a1966e2771006a9033c736d30d2", size = 11883216, upload-time = "2025-08-21T10:27:59.302Z" }, + { url = "https://files.pythonhosted.org/packages/10/86/692050c119696da19e20245bbd650d8dfca6ceb577da027c3a73c62a047e/pandas-2.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:837248b4fc3a9b83b9c6214699a13f069dc13510a6a6d7f9ba33145d2841a012", size = 12699743, upload-time = "2025-08-21T10:28:02.447Z" }, + { url = "https://files.pythonhosted.org/packages/cd/d7/612123674d7b17cf345aad0a10289b2a384bff404e0463a83c4a3a59d205/pandas-2.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d2c3554bd31b731cd6490d94a28f3abb8dd770634a9e06eb6d2911b9827db370", size = 13186141, upload-time = "2025-08-21T10:28:05.377Z" }, +] + +[[package]] +name = "pillow" +version = "11.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/0d/d0d6dea55cd152ce3d6767bb38a8fc10e33796ba4ba210cbab9354b6d238/pillow-11.3.0.tar.gz", hash = "sha256:3828ee7586cd0b2091b6209e5ad53e20d0649bbe87164a459d0676e035e8f523", size = 47113069, upload-time = "2025-07-01T09:16:30.666Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/26/77f8ed17ca4ffd60e1dcd220a6ec6d71210ba398cfa33a13a1cd614c5613/pillow-11.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:1cd110edf822773368b396281a2293aeb91c90a2db00d78ea43e7e861631b722", size = 5316531, upload-time = "2025-07-01T09:13:59.203Z" }, + { url = "https://files.pythonhosted.org/packages/cb/39/ee475903197ce709322a17a866892efb560f57900d9af2e55f86db51b0a5/pillow-11.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9c412fddd1b77a75aa904615ebaa6001f169b26fd467b4be93aded278266b288", size = 4686560, upload-time = "2025-07-01T09:14:01.101Z" }, + { url = "https://files.pythonhosted.org/packages/d5/90/442068a160fd179938ba55ec8c97050a612426fae5ec0a764e345839f76d/pillow-11.3.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7d1aa4de119a0ecac0a34a9c8bde33f34022e2e8f99104e47a3ca392fd60e37d", size = 5870978, upload-time = "2025-07-03T13:09:55.638Z" }, + { url = "https://files.pythonhosted.org/packages/13/92/dcdd147ab02daf405387f0218dcf792dc6dd5b14d2573d40b4caeef01059/pillow-11.3.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:91da1d88226663594e3f6b4b8c3c8d85bd504117d043740a8e0ec449087cc494", size = 7641168, upload-time = "2025-07-03T13:10:00.37Z" }, + { url = "https://files.pythonhosted.org/packages/6e/db/839d6ba7fd38b51af641aa904e2960e7a5644d60ec754c046b7d2aee00e5/pillow-11.3.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:643f189248837533073c405ec2f0bb250ba54598cf80e8c1e043381a60632f58", size = 5973053, upload-time = "2025-07-01T09:14:04.491Z" }, + { url = "https://files.pythonhosted.org/packages/f2/2f/d7675ecae6c43e9f12aa8d58b6012683b20b6edfbdac7abcb4e6af7a3784/pillow-11.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:106064daa23a745510dabce1d84f29137a37224831d88eb4ce94bb187b1d7e5f", size = 6640273, upload-time = "2025-07-01T09:14:06.235Z" }, + { url = "https://files.pythonhosted.org/packages/45/ad/931694675ede172e15b2ff03c8144a0ddaea1d87adb72bb07655eaffb654/pillow-11.3.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd8ff254faf15591e724dc7c4ddb6bf4793efcbe13802a4ae3e863cd300b493e", size = 6082043, upload-time = "2025-07-01T09:14:07.978Z" }, + { url = "https://files.pythonhosted.org/packages/3a/04/ba8f2b11fc80d2dd462d7abec16351b45ec99cbbaea4387648a44190351a/pillow-11.3.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:932c754c2d51ad2b2271fd01c3d121daaa35e27efae2a616f77bf164bc0b3e94", size = 6715516, upload-time = "2025-07-01T09:14:10.233Z" }, + { url = "https://files.pythonhosted.org/packages/48/59/8cd06d7f3944cc7d892e8533c56b0acb68399f640786313275faec1e3b6f/pillow-11.3.0-cp311-cp311-win32.whl", hash = "sha256:b4b8f3efc8d530a1544e5962bd6b403d5f7fe8b9e08227c6b255f98ad82b4ba0", size = 6274768, upload-time = "2025-07-01T09:14:11.921Z" }, + { url = "https://files.pythonhosted.org/packages/f1/cc/29c0f5d64ab8eae20f3232da8f8571660aa0ab4b8f1331da5c2f5f9a938e/pillow-11.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:1a992e86b0dd7aeb1f053cd506508c0999d710a8f07b4c791c63843fc6a807ac", size = 6986055, upload-time = "2025-07-01T09:14:13.623Z" }, + { url = "https://files.pythonhosted.org/packages/c6/df/90bd886fabd544c25addd63e5ca6932c86f2b701d5da6c7839387a076b4a/pillow-11.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:30807c931ff7c095620fe04448e2c2fc673fcbb1ffe2a7da3fb39613489b1ddd", size = 2423079, upload-time = "2025-07-01T09:14:15.268Z" }, + { url = "https://files.pythonhosted.org/packages/40/fe/1bc9b3ee13f68487a99ac9529968035cca2f0a51ec36892060edcc51d06a/pillow-11.3.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdae223722da47b024b867c1ea0be64e0df702c5e0a60e27daad39bf960dd1e4", size = 5278800, upload-time = "2025-07-01T09:14:17.648Z" }, + { url = "https://files.pythonhosted.org/packages/2c/32/7e2ac19b5713657384cec55f89065fb306b06af008cfd87e572035b27119/pillow-11.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:921bd305b10e82b4d1f5e802b6850677f965d8394203d182f078873851dada69", size = 4686296, upload-time = "2025-07-01T09:14:19.828Z" }, + { url = "https://files.pythonhosted.org/packages/8e/1e/b9e12bbe6e4c2220effebc09ea0923a07a6da1e1f1bfbc8d7d29a01ce32b/pillow-11.3.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:eb76541cba2f958032d79d143b98a3a6b3ea87f0959bbe256c0b5e416599fd5d", size = 5871726, upload-time = "2025-07-03T13:10:04.448Z" }, + { url = "https://files.pythonhosted.org/packages/8d/33/e9200d2bd7ba00dc3ddb78df1198a6e80d7669cce6c2bdbeb2530a74ec58/pillow-11.3.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67172f2944ebba3d4a7b54f2e95c786a3a50c21b88456329314caaa28cda70f6", size = 7644652, upload-time = "2025-07-03T13:10:10.391Z" }, + { url = "https://files.pythonhosted.org/packages/41/f1/6f2427a26fc683e00d985bc391bdd76d8dd4e92fac33d841127eb8fb2313/pillow-11.3.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97f07ed9f56a3b9b5f49d3661dc9607484e85c67e27f3e8be2c7d28ca032fec7", size = 5977787, upload-time = "2025-07-01T09:14:21.63Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/06dd4a38974e24f932ff5f98ea3c546ce3f8c995d3f0985f8e5ba48bba19/pillow-11.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:676b2815362456b5b3216b4fd5bd89d362100dc6f4945154ff172e206a22c024", size = 6645236, upload-time = "2025-07-01T09:14:23.321Z" }, + { url = "https://files.pythonhosted.org/packages/40/e7/848f69fb79843b3d91241bad658e9c14f39a32f71a301bcd1d139416d1be/pillow-11.3.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3e184b2f26ff146363dd07bde8b711833d7b0202e27d13540bfe2e35a323a809", size = 6086950, upload-time = "2025-07-01T09:14:25.237Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1a/7cff92e695a2a29ac1958c2a0fe4c0b2393b60aac13b04a4fe2735cad52d/pillow-11.3.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6be31e3fc9a621e071bc17bb7de63b85cbe0bfae91bb0363c893cbe67247780d", size = 6723358, upload-time = "2025-07-01T09:14:27.053Z" }, + { url = "https://files.pythonhosted.org/packages/26/7d/73699ad77895f69edff76b0f332acc3d497f22f5d75e5360f78cbcaff248/pillow-11.3.0-cp312-cp312-win32.whl", hash = "sha256:7b161756381f0918e05e7cb8a371fff367e807770f8fe92ecb20d905d0e1c149", size = 6275079, upload-time = "2025-07-01T09:14:30.104Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ce/e7dfc873bdd9828f3b6e5c2bbb74e47a98ec23cc5c74fc4e54462f0d9204/pillow-11.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:a6444696fce635783440b7f7a9fc24b3ad10a9ea3f0ab66c5905be1c19ccf17d", size = 6986324, upload-time = "2025-07-01T09:14:31.899Z" }, + { url = "https://files.pythonhosted.org/packages/16/8f/b13447d1bf0b1f7467ce7d86f6e6edf66c0ad7cf44cf5c87a37f9bed9936/pillow-11.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:2aceea54f957dd4448264f9bf40875da0415c83eb85f55069d89c0ed436e3542", size = 2423067, upload-time = "2025-07-01T09:14:33.709Z" }, + { url = "https://files.pythonhosted.org/packages/1e/93/0952f2ed8db3a5a4c7a11f91965d6184ebc8cd7cbb7941a260d5f018cd2d/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:1c627742b539bba4309df89171356fcb3cc5a9178355b2727d1b74a6cf155fbd", size = 2128328, upload-time = "2025-07-01T09:14:35.276Z" }, + { url = "https://files.pythonhosted.org/packages/4b/e8/100c3d114b1a0bf4042f27e0f87d2f25e857e838034e98ca98fe7b8c0a9c/pillow-11.3.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:30b7c02f3899d10f13d7a48163c8969e4e653f8b43416d23d13d1bbfdc93b9f8", size = 2170652, upload-time = "2025-07-01T09:14:37.203Z" }, + { url = "https://files.pythonhosted.org/packages/aa/86/3f758a28a6e381758545f7cdb4942e1cb79abd271bea932998fc0db93cb6/pillow-11.3.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7859a4cc7c9295f5838015d8cc0a9c215b77e43d07a25e460f35cf516df8626f", size = 2227443, upload-time = "2025-07-01T09:14:39.344Z" }, + { url = "https://files.pythonhosted.org/packages/01/f4/91d5b3ffa718df2f53b0dc109877993e511f4fd055d7e9508682e8aba092/pillow-11.3.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec1ee50470b0d050984394423d96325b744d55c701a439d2bd66089bff963d3c", size = 5278474, upload-time = "2025-07-01T09:14:41.843Z" }, + { url = "https://files.pythonhosted.org/packages/f9/0e/37d7d3eca6c879fbd9dba21268427dffda1ab00d4eb05b32923d4fbe3b12/pillow-11.3.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7db51d222548ccfd274e4572fdbf3e810a5e66b00608862f947b163e613b67dd", size = 4686038, upload-time = "2025-07-01T09:14:44.008Z" }, + { url = "https://files.pythonhosted.org/packages/ff/b0/3426e5c7f6565e752d81221af9d3676fdbb4f352317ceafd42899aaf5d8a/pillow-11.3.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2d6fcc902a24ac74495df63faad1884282239265c6839a0a6416d33faedfae7e", size = 5864407, upload-time = "2025-07-03T13:10:15.628Z" }, + { url = "https://files.pythonhosted.org/packages/fc/c1/c6c423134229f2a221ee53f838d4be9d82bab86f7e2f8e75e47b6bf6cd77/pillow-11.3.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0f5d8f4a08090c6d6d578351a2b91acf519a54986c055af27e7a93feae6d3f1", size = 7639094, upload-time = "2025-07-03T13:10:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/09e6746630fe6372c67c648ff9deae52a2bc20897d51fa293571977ceb5d/pillow-11.3.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c37d8ba9411d6003bba9e518db0db0c58a680ab9fe5179f040b0463644bc9805", size = 5973503, upload-time = "2025-07-01T09:14:45.698Z" }, + { url = "https://files.pythonhosted.org/packages/d5/1c/a2a29649c0b1983d3ef57ee87a66487fdeb45132df66ab30dd37f7dbe162/pillow-11.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:13f87d581e71d9189ab21fe0efb5a23e9f28552d5be6979e84001d3b8505abe8", size = 6642574, upload-time = "2025-07-01T09:14:47.415Z" }, + { url = "https://files.pythonhosted.org/packages/36/de/d5cc31cc4b055b6c6fd990e3e7f0f8aaf36229a2698501bcb0cdf67c7146/pillow-11.3.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:023f6d2d11784a465f09fd09a34b150ea4672e85fb3d05931d89f373ab14abb2", size = 6084060, upload-time = "2025-07-01T09:14:49.636Z" }, + { url = "https://files.pythonhosted.org/packages/d5/ea/502d938cbaeec836ac28a9b730193716f0114c41325db428e6b280513f09/pillow-11.3.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:45dfc51ac5975b938e9809451c51734124e73b04d0f0ac621649821a63852e7b", size = 6721407, upload-time = "2025-07-01T09:14:51.962Z" }, + { url = "https://files.pythonhosted.org/packages/45/9c/9c5e2a73f125f6cbc59cc7087c8f2d649a7ae453f83bd0362ff7c9e2aee2/pillow-11.3.0-cp313-cp313-win32.whl", hash = "sha256:a4d336baed65d50d37b88ca5b60c0fa9d81e3a87d4a7930d3880d1624d5b31f3", size = 6273841, upload-time = "2025-07-01T09:14:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/23/85/397c73524e0cd212067e0c969aa245b01d50183439550d24d9f55781b776/pillow-11.3.0-cp313-cp313-win_amd64.whl", hash = "sha256:0bce5c4fd0921f99d2e858dc4d4d64193407e1b99478bc5cacecba2311abde51", size = 6978450, upload-time = "2025-07-01T09:14:56.436Z" }, + { url = "https://files.pythonhosted.org/packages/17/d2/622f4547f69cd173955194b78e4d19ca4935a1b0f03a302d655c9f6aae65/pillow-11.3.0-cp313-cp313-win_arm64.whl", hash = "sha256:1904e1264881f682f02b7f8167935cce37bc97db457f8e7849dc3a6a52b99580", size = 2423055, upload-time = "2025-07-01T09:14:58.072Z" }, + { url = "https://files.pythonhosted.org/packages/dd/80/a8a2ac21dda2e82480852978416cfacd439a4b490a501a288ecf4fe2532d/pillow-11.3.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:4c834a3921375c48ee6b9624061076bc0a32a60b5532b322cc0ea64e639dd50e", size = 5281110, upload-time = "2025-07-01T09:14:59.79Z" }, + { url = "https://files.pythonhosted.org/packages/44/d6/b79754ca790f315918732e18f82a8146d33bcd7f4494380457ea89eb883d/pillow-11.3.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:5e05688ccef30ea69b9317a9ead994b93975104a677a36a8ed8106be9260aa6d", size = 4689547, upload-time = "2025-07-01T09:15:01.648Z" }, + { url = "https://files.pythonhosted.org/packages/49/20/716b8717d331150cb00f7fdd78169c01e8e0c219732a78b0e59b6bdb2fd6/pillow-11.3.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1019b04af07fc0163e2810167918cb5add8d74674b6267616021ab558dc98ced", size = 5901554, upload-time = "2025-07-03T13:10:27.018Z" }, + { url = "https://files.pythonhosted.org/packages/74/cf/a9f3a2514a65bb071075063a96f0a5cf949c2f2fce683c15ccc83b1c1cab/pillow-11.3.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f944255db153ebb2b19c51fe85dd99ef0ce494123f21b9db4877ffdfc5590c7c", size = 7669132, upload-time = "2025-07-03T13:10:33.01Z" }, + { url = "https://files.pythonhosted.org/packages/98/3c/da78805cbdbee9cb43efe8261dd7cc0b4b93f2ac79b676c03159e9db2187/pillow-11.3.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f85acb69adf2aaee8b7da124efebbdb959a104db34d3a2cb0f3793dbae422a8", size = 6005001, upload-time = "2025-07-01T09:15:03.365Z" }, + { url = "https://files.pythonhosted.org/packages/6c/fa/ce044b91faecf30e635321351bba32bab5a7e034c60187fe9698191aef4f/pillow-11.3.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05f6ecbeff5005399bb48d198f098a9b4b6bdf27b8487c7f38ca16eeb070cd59", size = 6668814, upload-time = "2025-07-01T09:15:05.655Z" }, + { url = "https://files.pythonhosted.org/packages/7b/51/90f9291406d09bf93686434f9183aba27b831c10c87746ff49f127ee80cb/pillow-11.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a7bc6e6fd0395bc052f16b1a8670859964dbd7003bd0af2ff08342eb6e442cfe", size = 6113124, upload-time = "2025-07-01T09:15:07.358Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5a/6fec59b1dfb619234f7636d4157d11fb4e196caeee220232a8d2ec48488d/pillow-11.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:83e1b0161c9d148125083a35c1c5a89db5b7054834fd4387499e06552035236c", size = 6747186, upload-time = "2025-07-01T09:15:09.317Z" }, + { url = "https://files.pythonhosted.org/packages/49/6b/00187a044f98255225f172de653941e61da37104a9ea60e4f6887717e2b5/pillow-11.3.0-cp313-cp313t-win32.whl", hash = "sha256:2a3117c06b8fb646639dce83694f2f9eac405472713fcb1ae887469c0d4f6788", size = 6277546, upload-time = "2025-07-01T09:15:11.311Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5c/6caaba7e261c0d75bab23be79f1d06b5ad2a2ae49f028ccec801b0e853d6/pillow-11.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:857844335c95bea93fb39e0fa2726b4d9d758850b34075a7e3ff4f4fa3aa3b31", size = 6985102, upload-time = "2025-07-01T09:15:13.164Z" }, + { url = "https://files.pythonhosted.org/packages/f3/7e/b623008460c09a0cb38263c93b828c666493caee2eb34ff67f778b87e58c/pillow-11.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:8797edc41f3e8536ae4b10897ee2f637235c94f27404cac7297f7b607dd0716e", size = 2424803, upload-time = "2025-07-01T09:15:15.695Z" }, + { url = "https://files.pythonhosted.org/packages/73/f4/04905af42837292ed86cb1b1dabe03dce1edc008ef14c473c5c7e1443c5d/pillow-11.3.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:d9da3df5f9ea2a89b81bb6087177fb1f4d1c7146d583a3fe5c672c0d94e55e12", size = 5278520, upload-time = "2025-07-01T09:15:17.429Z" }, + { url = "https://files.pythonhosted.org/packages/41/b0/33d79e377a336247df6348a54e6d2a2b85d644ca202555e3faa0cf811ecc/pillow-11.3.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0b275ff9b04df7b640c59ec5a3cb113eefd3795a8df80bac69646ef699c6981a", size = 4686116, upload-time = "2025-07-01T09:15:19.423Z" }, + { url = "https://files.pythonhosted.org/packages/49/2d/ed8bc0ab219ae8768f529597d9509d184fe8a6c4741a6864fea334d25f3f/pillow-11.3.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0743841cabd3dba6a83f38a92672cccbd69af56e3e91777b0ee7f4dba4385632", size = 5864597, upload-time = "2025-07-03T13:10:38.404Z" }, + { url = "https://files.pythonhosted.org/packages/b5/3d/b932bb4225c80b58dfadaca9d42d08d0b7064d2d1791b6a237f87f661834/pillow-11.3.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2465a69cf967b8b49ee1b96d76718cd98c4e925414ead59fdf75cf0fd07df673", size = 7638246, upload-time = "2025-07-03T13:10:44.987Z" }, + { url = "https://files.pythonhosted.org/packages/09/b5/0487044b7c096f1b48f0d7ad416472c02e0e4bf6919541b111efd3cae690/pillow-11.3.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41742638139424703b4d01665b807c6468e23e699e8e90cffefe291c5832b027", size = 5973336, upload-time = "2025-07-01T09:15:21.237Z" }, + { url = "https://files.pythonhosted.org/packages/a8/2d/524f9318f6cbfcc79fbc004801ea6b607ec3f843977652fdee4857a7568b/pillow-11.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93efb0b4de7e340d99057415c749175e24c8864302369e05914682ba642e5d77", size = 6642699, upload-time = "2025-07-01T09:15:23.186Z" }, + { url = "https://files.pythonhosted.org/packages/6f/d2/a9a4f280c6aefedce1e8f615baaa5474e0701d86dd6f1dede66726462bbd/pillow-11.3.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7966e38dcd0fa11ca390aed7c6f20454443581d758242023cf36fcb319b1a874", size = 6083789, upload-time = "2025-07-01T09:15:25.1Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/86b0cd9dbb683a9d5e960b66c7379e821a19be4ac5810e2e5a715c09a0c0/pillow-11.3.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:98a9afa7b9007c67ed84c57c9e0ad86a6000da96eaa638e4f8abe5b65ff83f0a", size = 6720386, upload-time = "2025-07-01T09:15:27.378Z" }, + { url = "https://files.pythonhosted.org/packages/e7/95/88efcaf384c3588e24259c4203b909cbe3e3c2d887af9e938c2022c9dd48/pillow-11.3.0-cp314-cp314-win32.whl", hash = "sha256:02a723e6bf909e7cea0dac1b0e0310be9d7650cd66222a5f1c571455c0a45214", size = 6370911, upload-time = "2025-07-01T09:15:29.294Z" }, + { url = "https://files.pythonhosted.org/packages/2e/cc/934e5820850ec5eb107e7b1a72dd278140731c669f396110ebc326f2a503/pillow-11.3.0-cp314-cp314-win_amd64.whl", hash = "sha256:a418486160228f64dd9e9efcd132679b7a02a5f22c982c78b6fc7dab3fefb635", size = 7117383, upload-time = "2025-07-01T09:15:31.128Z" }, + { url = "https://files.pythonhosted.org/packages/d6/e9/9c0a616a71da2a5d163aa37405e8aced9a906d574b4a214bede134e731bc/pillow-11.3.0-cp314-cp314-win_arm64.whl", hash = "sha256:155658efb5e044669c08896c0c44231c5e9abcaadbc5cd3648df2f7c0b96b9a6", size = 2511385, upload-time = "2025-07-01T09:15:33.328Z" }, + { url = "https://files.pythonhosted.org/packages/1a/33/c88376898aff369658b225262cd4f2659b13e8178e7534df9e6e1fa289f6/pillow-11.3.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:59a03cdf019efbfeeed910bf79c7c93255c3d54bc45898ac2a4140071b02b4ae", size = 5281129, upload-time = "2025-07-01T09:15:35.194Z" }, + { url = "https://files.pythonhosted.org/packages/1f/70/d376247fb36f1844b42910911c83a02d5544ebd2a8bad9efcc0f707ea774/pillow-11.3.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f8a5827f84d973d8636e9dc5764af4f0cf2318d26744b3d902931701b0d46653", size = 4689580, upload-time = "2025-07-01T09:15:37.114Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/537e930496149fbac69efd2fc4329035bbe2e5475b4165439e3be9cb183b/pillow-11.3.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ee92f2fd10f4adc4b43d07ec5e779932b4eb3dbfbc34790ada5a6669bc095aa6", size = 5902860, upload-time = "2025-07-03T13:10:50.248Z" }, + { url = "https://files.pythonhosted.org/packages/bd/57/80f53264954dcefeebcf9dae6e3eb1daea1b488f0be8b8fef12f79a3eb10/pillow-11.3.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c96d333dcf42d01f47b37e0979b6bd73ec91eae18614864622d9b87bbd5bbf36", size = 7670694, upload-time = "2025-07-03T13:10:56.432Z" }, + { url = "https://files.pythonhosted.org/packages/70/ff/4727d3b71a8578b4587d9c276e90efad2d6fe0335fd76742a6da08132e8c/pillow-11.3.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4c96f993ab8c98460cd0c001447bff6194403e8b1d7e149ade5f00594918128b", size = 6005888, upload-time = "2025-07-01T09:15:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/716592277934f85d3be51d7256f3636672d7b1abfafdc42cf3f8cbd4b4c8/pillow-11.3.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41342b64afeba938edb034d122b2dda5db2139b9a4af999729ba8818e0056477", size = 6670330, upload-time = "2025-07-01T09:15:41.269Z" }, + { url = "https://files.pythonhosted.org/packages/e7/bb/7fe6cddcc8827b01b1a9766f5fdeb7418680744f9082035bdbabecf1d57f/pillow-11.3.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:068d9c39a2d1b358eb9f245ce7ab1b5c3246c7c8c7d9ba58cfa5b43146c06e50", size = 6114089, upload-time = "2025-07-01T09:15:43.13Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f5/06bfaa444c8e80f1a8e4bff98da9c83b37b5be3b1deaa43d27a0db37ef84/pillow-11.3.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a1bc6ba083b145187f648b667e05a2534ecc4b9f2784c2cbe3089e44868f2b9b", size = 6748206, upload-time = "2025-07-01T09:15:44.937Z" }, + { url = "https://files.pythonhosted.org/packages/f0/77/bc6f92a3e8e6e46c0ca78abfffec0037845800ea38c73483760362804c41/pillow-11.3.0-cp314-cp314t-win32.whl", hash = "sha256:118ca10c0d60b06d006be10a501fd6bbdfef559251ed31b794668ed569c87e12", size = 6377370, upload-time = "2025-07-01T09:15:46.673Z" }, + { url = "https://files.pythonhosted.org/packages/4a/82/3a721f7d69dca802befb8af08b7c79ebcab461007ce1c18bd91a5d5896f9/pillow-11.3.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8924748b688aa210d79883357d102cd64690e56b923a186f35a82cbc10f997db", size = 7121500, upload-time = "2025-07-01T09:15:48.512Z" }, + { url = "https://files.pythonhosted.org/packages/89/c7/5572fa4a3f45740eaab6ae86fcdf7195b55beac1371ac8c619d880cfe948/pillow-11.3.0-cp314-cp314t-win_arm64.whl", hash = "sha256:79ea0d14d3ebad43ec77ad5272e6ff9bba5b679ef73375ea760261207fa8e0aa", size = 2512835, upload-time = "2025-07-01T09:15:50.399Z" }, + { url = "https://files.pythonhosted.org/packages/9e/e3/6fa84033758276fb31da12e5fb66ad747ae83b93c67af17f8c6ff4cc8f34/pillow-11.3.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7c8ec7a017ad1bd562f93dbd8505763e688d388cde6e4a010ae1486916e713e6", size = 5270566, upload-time = "2025-07-01T09:16:19.801Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ee/e8d2e1ab4892970b561e1ba96cbd59c0d28cf66737fc44abb2aec3795a4e/pillow-11.3.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:9ab6ae226de48019caa8074894544af5b53a117ccb9d3b3dcb2871464c829438", size = 4654618, upload-time = "2025-07-01T09:16:21.818Z" }, + { url = "https://files.pythonhosted.org/packages/f2/6d/17f80f4e1f0761f02160fc433abd4109fa1548dcfdca46cfdadaf9efa565/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fe27fb049cdcca11f11a7bfda64043c37b30e6b91f10cb5bab275806c32f6ab3", size = 4874248, upload-time = "2025-07-03T13:11:20.738Z" }, + { url = "https://files.pythonhosted.org/packages/de/5f/c22340acd61cef960130585bbe2120e2fd8434c214802f07e8c03596b17e/pillow-11.3.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:465b9e8844e3c3519a983d58b80be3f668e2a7a5db97f2784e7079fbc9f9822c", size = 6583963, upload-time = "2025-07-03T13:11:26.283Z" }, + { url = "https://files.pythonhosted.org/packages/31/5e/03966aedfbfcbb4d5f8aa042452d3361f325b963ebbadddac05b122e47dd/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5418b53c0d59b3824d05e029669efa023bbef0f3e92e75ec8428f3799487f361", size = 4957170, upload-time = "2025-07-01T09:16:23.762Z" }, + { url = "https://files.pythonhosted.org/packages/cc/2d/e082982aacc927fc2cab48e1e731bdb1643a1406acace8bed0900a61464e/pillow-11.3.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:504b6f59505f08ae014f724b6207ff6222662aab5cc9542577fb084ed0676ac7", size = 5581505, upload-time = "2025-07-01T09:16:25.593Z" }, + { url = "https://files.pythonhosted.org/packages/34/e7/ae39f538fd6844e982063c3a5e4598b8ced43b9633baa3a85ef33af8c05c/pillow-11.3.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c84d689db21a1c397d001aa08241044aa2069e7587b398c8cc63020390b1c1b8", size = 6984598, upload-time = "2025-07-01T09:16:27.732Z" }, +] + +[[package]] +name = "pyparsing" +version = "3.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/22/f1129e69d94ffff626bdb5c835506b3a5b4f3d070f17ea295e12c2c6f60f/pyparsing-3.2.3.tar.gz", hash = "sha256:b9c13f1ab8b3b542f72e28f634bad4de758ab3ce4546e4301970ad6fa77c38be", size = 1088608, upload-time = "2025-03-25T05:01:28.114Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl", hash = "sha256:a749938e02d6fd0b59b356ca504a24982314bb090c383e3cf201c95ef7e2bfcf", size = 111120, upload-time = "2025-03-25T05:01:24.908Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pytorch" +version = "0.1.0" +source = { virtual = "." } +dependencies = [ + { name = "matplotlib" }, + { name = "opencv-python-headless" }, + { name = "pandas" }, + { name = "scikit-image" }, + { name = "scikit-learn" }, + { name = "seaborn" }, + { name = "timm" }, + { name = "torch" }, + { name = "torchcam" }, + { name = "torchinfo" }, + { name = "torchmetrics" }, + { name = "torchvision" }, + { name = "tqdm" }, +] + +[package.metadata] +requires-dist = [ + { name = "matplotlib", specifier = ">=3.10.6" }, + { name = "opencv-python-headless", specifier = ">=4.12.0.88" }, + { name = "pandas", specifier = ">=2.3.2" }, + { name = "scikit-image", specifier = ">=0.25.2" }, + { name = "scikit-learn", specifier = ">=1.7.1" }, + { name = "seaborn", specifier = ">=0.13.2" }, + { name = "timm", specifier = ">=1.0.19" }, + { name = "torch", specifier = ">=2.8.0" }, + { name = "torchcam", specifier = ">=0.3.1" }, + { name = "torchinfo", specifier = ">=1.8.0" }, + { name = "torchmetrics", specifier = ">=1.8.2" }, + { name = "torchvision", specifier = ">=0.23.0" }, + { name = "tqdm", specifier = ">=4.67.1" }, +] + +[[package]] +name = "pytz" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, + { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, + { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, + { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, + { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, + { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, + { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, + { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "safetensors" +version = "0.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ac/cc/738f3011628920e027a11754d9cae9abec1aed00f7ae860abbf843755233/safetensors-0.6.2.tar.gz", hash = "sha256:43ff2aa0e6fa2dc3ea5524ac7ad93a9839256b8703761e76e2d0b2a3fa4f15d9", size = 197968, upload-time = "2025-08-08T13:13:58.654Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/b1/3f5fd73c039fc87dba3ff8b5d528bfc5a32b597fea8e7a6a4800343a17c7/safetensors-0.6.2-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:9c85ede8ec58f120bad982ec47746981e210492a6db876882aa021446af8ffba", size = 454797, upload-time = "2025-08-08T13:13:52.066Z" }, + { url = "https://files.pythonhosted.org/packages/8c/c9/bb114c158540ee17907ec470d01980957fdaf87b4aa07914c24eba87b9c6/safetensors-0.6.2-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d6675cf4b39c98dbd7d940598028f3742e0375a6b4d4277e76beb0c35f4b843b", size = 432206, upload-time = "2025-08-08T13:13:50.931Z" }, + { url = "https://files.pythonhosted.org/packages/d3/8e/f70c34e47df3110e8e0bb268d90db8d4be8958a54ab0336c9be4fe86dac8/safetensors-0.6.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d2d2b3ce1e2509c68932ca03ab8f20570920cd9754b05063d4368ee52833ecd", size = 473261, upload-time = "2025-08-08T13:13:41.259Z" }, + { url = "https://files.pythonhosted.org/packages/2a/f5/be9c6a7c7ef773e1996dc214e73485286df1836dbd063e8085ee1976f9cb/safetensors-0.6.2-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:93de35a18f46b0f5a6a1f9e26d91b442094f2df02e9fd7acf224cfec4238821a", size = 485117, upload-time = "2025-08-08T13:13:43.506Z" }, + { url = "https://files.pythonhosted.org/packages/c9/55/23f2d0a2c96ed8665bf17a30ab4ce5270413f4d74b6d87dd663258b9af31/safetensors-0.6.2-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:89a89b505f335640f9120fac65ddeb83e40f1fd081cb8ed88b505bdccec8d0a1", size = 616154, upload-time = "2025-08-08T13:13:45.096Z" }, + { url = "https://files.pythonhosted.org/packages/98/c6/affb0bd9ce02aa46e7acddbe087912a04d953d7a4d74b708c91b5806ef3f/safetensors-0.6.2-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fc4d0d0b937e04bdf2ae6f70cd3ad51328635fe0e6214aa1fc811f3b576b3bda", size = 520713, upload-time = "2025-08-08T13:13:46.25Z" }, + { url = "https://files.pythonhosted.org/packages/fe/5d/5a514d7b88e310c8b146e2404e0dc161282e78634d9358975fd56dfd14be/safetensors-0.6.2-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8045db2c872db8f4cbe3faa0495932d89c38c899c603f21e9b6486951a5ecb8f", size = 485835, upload-time = "2025-08-08T13:13:49.373Z" }, + { url = "https://files.pythonhosted.org/packages/7a/7b/4fc3b2ba62c352b2071bea9cfbad330fadda70579f617506ae1a2f129cab/safetensors-0.6.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:81e67e8bab9878bb568cffbc5f5e655adb38d2418351dc0859ccac158f753e19", size = 521503, upload-time = "2025-08-08T13:13:47.651Z" }, + { url = "https://files.pythonhosted.org/packages/5a/50/0057e11fe1f3cead9254315a6c106a16dd4b1a19cd247f7cc6414f6b7866/safetensors-0.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:b0e4d029ab0a0e0e4fdf142b194514695b1d7d3735503ba700cf36d0fc7136ce", size = 652256, upload-time = "2025-08-08T13:13:53.167Z" }, + { url = "https://files.pythonhosted.org/packages/e9/29/473f789e4ac242593ac1656fbece6e1ecd860bb289e635e963667807afe3/safetensors-0.6.2-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:fa48268185c52bfe8771e46325a1e21d317207bcabcb72e65c6e28e9ffeb29c7", size = 747281, upload-time = "2025-08-08T13:13:54.656Z" }, + { url = "https://files.pythonhosted.org/packages/68/52/f7324aad7f2df99e05525c84d352dc217e0fa637a4f603e9f2eedfbe2c67/safetensors-0.6.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:d83c20c12c2d2f465997c51b7ecb00e407e5f94d7dec3ea0cc11d86f60d3fde5", size = 692286, upload-time = "2025-08-08T13:13:55.884Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/cad1d9762868c7c5dc70c8620074df28ebb1a8e4c17d4c0cb031889c457e/safetensors-0.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:d944cea65fad0ead848b6ec2c37cc0b197194bec228f8020054742190e9312ac", size = 655957, upload-time = "2025-08-08T13:13:57.029Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/e2158e17bbe57d104f0abbd95dff60dda916cf277c9f9663b4bf9bad8b6e/safetensors-0.6.2-cp38-abi3-win32.whl", hash = "sha256:cab75ca7c064d3911411461151cb69380c9225798a20e712b102edda2542ddb1", size = 308926, upload-time = "2025-08-08T13:14:01.095Z" }, + { url = "https://files.pythonhosted.org/packages/2c/c3/c0be1135726618dc1e28d181b8c442403d8dbb9e273fd791de2d4384bcdd/safetensors-0.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:c7b214870df923cbc1593c3faee16bec59ea462758699bd3fee399d00aac072c", size = 320192, upload-time = "2025-08-08T13:13:59.467Z" }, +] + +[[package]] +name = "scikit-image" +version = "0.25.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "imageio" }, + { name = "lazy-loader" }, + { name = "networkx" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "pillow" }, + { name = "scipy" }, + { name = "tifffile" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/a8/3c0f256012b93dd2cb6fda9245e9f4bff7dc0486880b248005f15ea2255e/scikit_image-0.25.2.tar.gz", hash = "sha256:e5a37e6cd4d0c018a7a55b9d601357e3382826d3888c10d0213fc63bff977dde", size = 22693594, upload-time = "2025-02-18T18:05:24.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c4/97/3051c68b782ee3f1fb7f8f5bb7d535cf8cb92e8aae18fa9c1cdf7e15150d/scikit_image-0.25.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f4bac9196fb80d37567316581c6060763b0f4893d3aca34a9ede3825bc035b17", size = 14003057, upload-time = "2025-02-18T18:04:30.395Z" }, + { url = "https://files.pythonhosted.org/packages/19/23/257fc696c562639826065514d551b7b9b969520bd902c3a8e2fcff5b9e17/scikit_image-0.25.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d989d64ff92e0c6c0f2018c7495a5b20e2451839299a018e0e5108b2680f71e0", size = 13180335, upload-time = "2025-02-18T18:04:33.449Z" }, + { url = "https://files.pythonhosted.org/packages/ef/14/0c4a02cb27ca8b1e836886b9ec7c9149de03053650e9e2ed0625f248dd92/scikit_image-0.25.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2cfc96b27afe9a05bc92f8c6235321d3a66499995675b27415e0d0c76625173", size = 14144783, upload-time = "2025-02-18T18:04:36.594Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9b/9fb556463a34d9842491d72a421942c8baff4281025859c84fcdb5e7e602/scikit_image-0.25.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:24cc986e1f4187a12aa319f777b36008764e856e5013666a4a83f8df083c2641", size = 14785376, upload-time = "2025-02-18T18:04:39.856Z" }, + { url = "https://files.pythonhosted.org/packages/de/ec/b57c500ee85885df5f2188f8bb70398481393a69de44a00d6f1d055f103c/scikit_image-0.25.2-cp311-cp311-win_amd64.whl", hash = "sha256:b4f6b61fc2db6340696afe3db6b26e0356911529f5f6aee8c322aa5157490c9b", size = 12791698, upload-time = "2025-02-18T18:04:42.868Z" }, + { url = "https://files.pythonhosted.org/packages/35/8c/5df82881284459f6eec796a5ac2a0a304bb3384eec2e73f35cfdfcfbf20c/scikit_image-0.25.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8db8dd03663112783221bf01ccfc9512d1cc50ac9b5b0fe8f4023967564719fb", size = 13986000, upload-time = "2025-02-18T18:04:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e6/93bebe1abcdce9513ffec01d8af02528b4c41fb3c1e46336d70b9ed4ef0d/scikit_image-0.25.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:483bd8cc10c3d8a7a37fae36dfa5b21e239bd4ee121d91cad1f81bba10cfb0ed", size = 13235893, upload-time = "2025-02-18T18:04:51.049Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/eda616e33f67129e5979a9eb33c710013caa3aa8a921991e6cc0b22cea33/scikit_image-0.25.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d1e80107bcf2bf1291acfc0bf0425dceb8890abe9f38d8e94e23497cbf7ee0d", size = 14178389, upload-time = "2025-02-18T18:04:54.245Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b5/b75527c0f9532dd8a93e8e7cd8e62e547b9f207d4c11e24f0006e8646b36/scikit_image-0.25.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a17e17eb8562660cc0d31bb55643a4da996a81944b82c54805c91b3fe66f4824", size = 15003435, upload-time = "2025-02-18T18:04:57.586Z" }, + { url = "https://files.pythonhosted.org/packages/34/e3/49beb08ebccda3c21e871b607c1cb2f258c3fa0d2f609fed0a5ba741b92d/scikit_image-0.25.2-cp312-cp312-win_amd64.whl", hash = "sha256:bdd2b8c1de0849964dbc54037f36b4e9420157e67e45a8709a80d727f52c7da2", size = 12899474, upload-time = "2025-02-18T18:05:01.166Z" }, + { url = "https://files.pythonhosted.org/packages/e6/7c/9814dd1c637f7a0e44342985a76f95a55dd04be60154247679fd96c7169f/scikit_image-0.25.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7efa888130f6c548ec0439b1a7ed7295bc10105458a421e9bf739b457730b6da", size = 13921841, upload-time = "2025-02-18T18:05:03.963Z" }, + { url = "https://files.pythonhosted.org/packages/84/06/66a2e7661d6f526740c309e9717d3bd07b473661d5cdddef4dd978edab25/scikit_image-0.25.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:dd8011efe69c3641920614d550f5505f83658fe33581e49bed86feab43a180fc", size = 13196862, upload-time = "2025-02-18T18:05:06.986Z" }, + { url = "https://files.pythonhosted.org/packages/4e/63/3368902ed79305f74c2ca8c297dfeb4307269cbe6402412668e322837143/scikit_image-0.25.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28182a9d3e2ce3c2e251383bdda68f8d88d9fff1a3ebe1eb61206595c9773341", size = 14117785, upload-time = "2025-02-18T18:05:10.69Z" }, + { url = "https://files.pythonhosted.org/packages/cd/9b/c3da56a145f52cd61a68b8465d6a29d9503bc45bc993bb45e84371c97d94/scikit_image-0.25.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8abd3c805ce6944b941cfed0406d88faeb19bab3ed3d4b50187af55cf24d147", size = 14977119, upload-time = "2025-02-18T18:05:13.871Z" }, + { url = "https://files.pythonhosted.org/packages/8a/97/5fcf332e1753831abb99a2525180d3fb0d70918d461ebda9873f66dcc12f/scikit_image-0.25.2-cp313-cp313-win_amd64.whl", hash = "sha256:64785a8acefee460ec49a354706db0b09d1f325674107d7fa3eadb663fb56d6f", size = 12885116, upload-time = "2025-02-18T18:05:17.844Z" }, + { url = "https://files.pythonhosted.org/packages/10/cc/75e9f17e3670b5ed93c32456fda823333c6279b144cd93e2c03aa06aa472/scikit_image-0.25.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:330d061bd107d12f8d68f1d611ae27b3b813b8cdb0300a71d07b1379178dd4cd", size = 13862801, upload-time = "2025-02-18T18:05:20.783Z" }, +] + +[[package]] +name = "scikit-learn" +version = "1.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "numpy" }, + { name = "scipy" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/41/84/5f4af978fff619706b8961accac84780a6d298d82a8873446f72edb4ead0/scikit_learn-1.7.1.tar.gz", hash = "sha256:24b3f1e976a4665aa74ee0fcaac2b8fccc6ae77c8e07ab25da3ba6d3292b9802", size = 7190445, upload-time = "2025-07-18T08:01:54.5Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b4/bd/a23177930abd81b96daffa30ef9c54ddbf544d3226b8788ce4c3ef1067b4/scikit_learn-1.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90c8494ea23e24c0fb371afc474618c1019dc152ce4a10e4607e62196113851b", size = 9334838, upload-time = "2025-07-18T08:01:11.239Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a1/d3a7628630a711e2ac0d1a482910da174b629f44e7dd8cfcd6924a4ef81a/scikit_learn-1.7.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:bb870c0daf3bf3be145ec51df8ac84720d9972170786601039f024bf6d61a518", size = 8651241, upload-time = "2025-07-18T08:01:13.234Z" }, + { url = "https://files.pythonhosted.org/packages/26/92/85ec172418f39474c1cd0221d611345d4f433fc4ee2fc68e01f524ccc4e4/scikit_learn-1.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:40daccd1b5623f39e8943ab39735cadf0bdce80e67cdca2adcb5426e987320a8", size = 9718677, upload-time = "2025-07-18T08:01:15.649Z" }, + { url = "https://files.pythonhosted.org/packages/df/ce/abdb1dcbb1d2b66168ec43b23ee0cee356b4cc4100ddee3943934ebf1480/scikit_learn-1.7.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30d1f413cfc0aa5a99132a554f1d80517563c34a9d3e7c118fde2d273c6fe0f7", size = 9511189, upload-time = "2025-07-18T08:01:18.013Z" }, + { url = "https://files.pythonhosted.org/packages/b2/3b/47b5eaee01ef2b5a80ba3f7f6ecf79587cb458690857d4777bfd77371c6f/scikit_learn-1.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:c711d652829a1805a95d7fe96654604a8f16eab5a9e9ad87b3e60173415cb650", size = 8914794, upload-time = "2025-07-18T08:01:20.357Z" }, + { url = "https://files.pythonhosted.org/packages/cb/16/57f176585b35ed865f51b04117947fe20f130f78940c6477b6d66279c9c2/scikit_learn-1.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3cee419b49b5bbae8796ecd690f97aa412ef1674410c23fc3257c6b8b85b8087", size = 9260431, upload-time = "2025-07-18T08:01:22.77Z" }, + { url = "https://files.pythonhosted.org/packages/67/4e/899317092f5efcab0e9bc929e3391341cec8fb0e816c4789686770024580/scikit_learn-1.7.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:2fd8b8d35817b0d9ebf0b576f7d5ffbbabdb55536b0655a8aaae629d7ffd2e1f", size = 8637191, upload-time = "2025-07-18T08:01:24.731Z" }, + { url = "https://files.pythonhosted.org/packages/f3/1b/998312db6d361ded1dd56b457ada371a8d8d77ca2195a7d18fd8a1736f21/scikit_learn-1.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:588410fa19a96a69763202f1d6b7b91d5d7a5d73be36e189bc6396bfb355bd87", size = 9486346, upload-time = "2025-07-18T08:01:26.713Z" }, + { url = "https://files.pythonhosted.org/packages/ad/09/a2aa0b4e644e5c4ede7006748f24e72863ba2ae71897fecfd832afea01b4/scikit_learn-1.7.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e3142f0abe1ad1d1c31a2ae987621e41f6b578144a911ff4ac94781a583adad7", size = 9290988, upload-time = "2025-07-18T08:01:28.938Z" }, + { url = "https://files.pythonhosted.org/packages/15/fa/c61a787e35f05f17fc10523f567677ec4eeee5f95aa4798dbbbcd9625617/scikit_learn-1.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:3ddd9092c1bd469acab337d87930067c87eac6bd544f8d5027430983f1e1ae88", size = 8735568, upload-time = "2025-07-18T08:01:30.936Z" }, + { url = "https://files.pythonhosted.org/packages/52/f8/e0533303f318a0f37b88300d21f79b6ac067188d4824f1047a37214ab718/scikit_learn-1.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:b7839687fa46d02e01035ad775982f2470be2668e13ddd151f0f55a5bf123bae", size = 9213143, upload-time = "2025-07-18T08:01:32.942Z" }, + { url = "https://files.pythonhosted.org/packages/71/f3/f1df377d1bdfc3e3e2adc9c119c238b182293e6740df4cbeac6de2cc3e23/scikit_learn-1.7.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a10f276639195a96c86aa572ee0698ad64ee939a7b042060b98bd1930c261d10", size = 8591977, upload-time = "2025-07-18T08:01:34.967Z" }, + { url = "https://files.pythonhosted.org/packages/99/72/c86a4cd867816350fe8dee13f30222340b9cd6b96173955819a5561810c5/scikit_learn-1.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:13679981fdaebc10cc4c13c43344416a86fcbc61449cb3e6517e1df9d12c8309", size = 9436142, upload-time = "2025-07-18T08:01:37.397Z" }, + { url = "https://files.pythonhosted.org/packages/e8/66/277967b29bd297538dc7a6ecfb1a7dce751beabd0d7f7a2233be7a4f7832/scikit_learn-1.7.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4f1262883c6a63f067a980a8cdd2d2e7f2513dddcef6a9eaada6416a7a7cbe43", size = 9282996, upload-time = "2025-07-18T08:01:39.721Z" }, + { url = "https://files.pythonhosted.org/packages/e2/47/9291cfa1db1dae9880420d1e07dbc7e8dd4a7cdbc42eaba22512e6bde958/scikit_learn-1.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:ca6d31fb10e04d50bfd2b50d66744729dbb512d4efd0223b864e2fdbfc4cee11", size = 8707418, upload-time = "2025-07-18T08:01:42.124Z" }, + { url = "https://files.pythonhosted.org/packages/61/95/45726819beccdaa34d3362ea9b2ff9f2b5d3b8bf721bd632675870308ceb/scikit_learn-1.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:781674d096303cfe3d351ae6963ff7c958db61cde3421cd490e3a5a58f2a94ae", size = 9561466, upload-time = "2025-07-18T08:01:44.195Z" }, + { url = "https://files.pythonhosted.org/packages/ee/1c/6f4b3344805de783d20a51eb24d4c9ad4b11a7f75c1801e6ec6d777361fd/scikit_learn-1.7.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:10679f7f125fe7ecd5fad37dd1aa2daae7e3ad8df7f3eefa08901b8254b3e12c", size = 9040467, upload-time = "2025-07-18T08:01:46.671Z" }, + { url = "https://files.pythonhosted.org/packages/6f/80/abe18fe471af9f1d181904203d62697998b27d9b62124cd281d740ded2f9/scikit_learn-1.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1f812729e38c8cb37f760dce71a9b83ccfb04f59b3dca7c6079dcdc60544fa9e", size = 9532052, upload-time = "2025-07-18T08:01:48.676Z" }, + { url = "https://files.pythonhosted.org/packages/14/82/b21aa1e0c4cee7e74864d3a5a721ab8fcae5ca55033cb6263dca297ed35b/scikit_learn-1.7.1-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:88e1a20131cf741b84b89567e1717f27a2ced228e0f29103426102bc2e3b8ef7", size = 9361575, upload-time = "2025-07-18T08:01:50.639Z" }, + { url = "https://files.pythonhosted.org/packages/f2/20/f4777fcd5627dc6695fa6b92179d0edb7a3ac1b91bcd9a1c7f64fa7ade23/scikit_learn-1.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b1bd1d919210b6a10b7554b717c9000b5485aa95a1d0f177ae0d7ee8ec750da5", size = 9277310, upload-time = "2025-07-18T08:01:52.547Z" }, +] + +[[package]] +name = "scipy" +version = "1.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/4a/b927028464795439faec8eaf0b03b011005c487bb2d07409f28bf30879c4/scipy-1.16.1.tar.gz", hash = "sha256:44c76f9e8b6e8e488a586190ab38016e4ed2f8a038af7cd3defa903c0a2238b3", size = 30580861, upload-time = "2025-07-27T16:33:30.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/da/91/812adc6f74409b461e3a5fa97f4f74c769016919203138a3bf6fc24ba4c5/scipy-1.16.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:c033fa32bab91dc98ca59d0cf23bb876454e2bb02cbe592d5023138778f70030", size = 36552519, upload-time = "2025-07-27T16:26:29.658Z" }, + { url = "https://files.pythonhosted.org/packages/47/18/8e355edcf3b71418d9e9f9acd2708cc3a6c27e8f98fde0ac34b8a0b45407/scipy-1.16.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:6e5c2f74e5df33479b5cd4e97a9104c511518fbd979aa9b8f6aec18b2e9ecae7", size = 28638010, upload-time = "2025-07-27T16:26:38.196Z" }, + { url = "https://files.pythonhosted.org/packages/d9/eb/e931853058607bdfbc11b86df19ae7a08686121c203483f62f1ecae5989c/scipy-1.16.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:0a55ffe0ba0f59666e90951971a884d1ff6f4ec3275a48f472cfb64175570f77", size = 20909790, upload-time = "2025-07-27T16:26:43.93Z" }, + { url = "https://files.pythonhosted.org/packages/45/0c/be83a271d6e96750cd0be2e000f35ff18880a46f05ce8b5d3465dc0f7a2a/scipy-1.16.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:f8a5d6cd147acecc2603fbd382fed6c46f474cccfcf69ea32582e033fb54dcfe", size = 23513352, upload-time = "2025-07-27T16:26:50.017Z" }, + { url = "https://files.pythonhosted.org/packages/7c/bf/fe6eb47e74f762f933cca962db7f2c7183acfdc4483bd1c3813cfe83e538/scipy-1.16.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cb18899127278058bcc09e7b9966d41a5a43740b5bb8dcba401bd983f82e885b", size = 33534643, upload-time = "2025-07-27T16:26:57.503Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ba/63f402e74875486b87ec6506a4f93f6d8a0d94d10467280f3d9d7837ce3a/scipy-1.16.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adccd93a2fa937a27aae826d33e3bfa5edf9aa672376a4852d23a7cd67a2e5b7", size = 35376776, upload-time = "2025-07-27T16:27:06.639Z" }, + { url = "https://files.pythonhosted.org/packages/c3/b4/04eb9d39ec26a1b939689102da23d505ea16cdae3dbb18ffc53d1f831044/scipy-1.16.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:18aca1646a29ee9a0625a1be5637fa798d4d81fdf426481f06d69af828f16958", size = 35698906, upload-time = "2025-07-27T16:27:14.943Z" }, + { url = "https://files.pythonhosted.org/packages/04/d6/bb5468da53321baeb001f6e4e0d9049eadd175a4a497709939128556e3ec/scipy-1.16.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d85495cef541729a70cdddbbf3e6b903421bc1af3e8e3a9a72a06751f33b7c39", size = 38129275, upload-time = "2025-07-27T16:27:23.873Z" }, + { url = "https://files.pythonhosted.org/packages/c4/94/994369978509f227cba7dfb9e623254d0d5559506fe994aef4bea3ed469c/scipy-1.16.1-cp311-cp311-win_amd64.whl", hash = "sha256:226652fca853008119c03a8ce71ffe1b3f6d2844cc1686e8f9806edafae68596", size = 38644572, upload-time = "2025-07-27T16:27:32.637Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d9/ec4864f5896232133f51382b54a08de91a9d1af7a76dfa372894026dfee2/scipy-1.16.1-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:81b433bbeaf35728dad619afc002db9b189e45eebe2cd676effe1fb93fef2b9c", size = 36575194, upload-time = "2025-07-27T16:27:41.321Z" }, + { url = "https://files.pythonhosted.org/packages/5c/6d/40e81ecfb688e9d25d34a847dca361982a6addf8e31f0957b1a54fbfa994/scipy-1.16.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:886cc81fdb4c6903a3bb0464047c25a6d1016fef77bb97949817d0c0d79f9e04", size = 28594590, upload-time = "2025-07-27T16:27:49.204Z" }, + { url = "https://files.pythonhosted.org/packages/0e/37/9f65178edfcc629377ce9a64fc09baebea18c80a9e57ae09a52edf84880b/scipy-1.16.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:15240c3aac087a522b4eaedb09f0ad061753c5eebf1ea430859e5bf8640d5919", size = 20866458, upload-time = "2025-07-27T16:27:54.98Z" }, + { url = "https://files.pythonhosted.org/packages/2c/7b/749a66766871ea4cb1d1ea10f27004db63023074c22abed51f22f09770e0/scipy-1.16.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:65f81a25805f3659b48126b5053d9e823d3215e4a63730b5e1671852a1705921", size = 23539318, upload-time = "2025-07-27T16:28:01.604Z" }, + { url = "https://files.pythonhosted.org/packages/c4/db/8d4afec60eb833a666434d4541a3151eedbf2494ea6d4d468cbe877f00cd/scipy-1.16.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6c62eea7f607f122069b9bad3f99489ddca1a5173bef8a0c75555d7488b6f725", size = 33292899, upload-time = "2025-07-27T16:28:09.147Z" }, + { url = "https://files.pythonhosted.org/packages/51/1e/79023ca3bbb13a015d7d2757ecca3b81293c663694c35d6541b4dca53e98/scipy-1.16.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f965bbf3235b01c776115ab18f092a95aa74c271a52577bcb0563e85738fd618", size = 35162637, upload-time = "2025-07-27T16:28:17.535Z" }, + { url = "https://files.pythonhosted.org/packages/b6/49/0648665f9c29fdaca4c679182eb972935b3b4f5ace41d323c32352f29816/scipy-1.16.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f006e323874ffd0b0b816d8c6a8e7f9a73d55ab3b8c3f72b752b226d0e3ac83d", size = 35490507, upload-time = "2025-07-27T16:28:25.705Z" }, + { url = "https://files.pythonhosted.org/packages/62/8f/66cbb9d6bbb18d8c658f774904f42a92078707a7c71e5347e8bf2f52bb89/scipy-1.16.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e8fd15fc5085ab4cca74cb91fe0a4263b1f32e4420761ddae531ad60934c2119", size = 37923998, upload-time = "2025-07-27T16:28:34.339Z" }, + { url = "https://files.pythonhosted.org/packages/14/c3/61f273ae550fbf1667675701112e380881905e28448c080b23b5a181df7c/scipy-1.16.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7b8013c6c066609577d910d1a2a077021727af07b6fab0ee22c2f901f22352a", size = 38508060, upload-time = "2025-07-27T16:28:43.242Z" }, + { url = "https://files.pythonhosted.org/packages/93/0b/b5c99382b839854a71ca9482c684e3472badc62620287cbbdab499b75ce6/scipy-1.16.1-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:5451606823a5e73dfa621a89948096c6528e2896e40b39248295d3a0138d594f", size = 36533717, upload-time = "2025-07-27T16:28:51.706Z" }, + { url = "https://files.pythonhosted.org/packages/eb/e5/69ab2771062c91e23e07c12e7d5033a6b9b80b0903ee709c3c36b3eb520c/scipy-1.16.1-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:89728678c5ca5abd610aee148c199ac1afb16e19844401ca97d43dc548a354eb", size = 28570009, upload-time = "2025-07-27T16:28:57.017Z" }, + { url = "https://files.pythonhosted.org/packages/f4/69/bd75dbfdd3cf524f4d753484d723594aed62cfaac510123e91a6686d520b/scipy-1.16.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e756d688cb03fd07de0fffad475649b03cb89bee696c98ce508b17c11a03f95c", size = 20841942, upload-time = "2025-07-27T16:29:01.152Z" }, + { url = "https://files.pythonhosted.org/packages/ea/74/add181c87663f178ba7d6144b370243a87af8476664d5435e57d599e6874/scipy-1.16.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:5aa2687b9935da3ed89c5dbed5234576589dd28d0bf7cd237501ccfbdf1ad608", size = 23498507, upload-time = "2025-07-27T16:29:05.202Z" }, + { url = "https://files.pythonhosted.org/packages/1d/74/ece2e582a0d9550cee33e2e416cc96737dce423a994d12bbe59716f47ff1/scipy-1.16.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0851f6a1e537fe9399f35986897e395a1aa61c574b178c0d456be5b1a0f5ca1f", size = 33286040, upload-time = "2025-07-27T16:29:10.201Z" }, + { url = "https://files.pythonhosted.org/packages/e4/82/08e4076df538fb56caa1d489588d880ec7c52d8273a606bb54d660528f7c/scipy-1.16.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fedc2cbd1baed37474b1924c331b97bdff611d762c196fac1a9b71e67b813b1b", size = 35176096, upload-time = "2025-07-27T16:29:17.091Z" }, + { url = "https://files.pythonhosted.org/packages/fa/79/cd710aab8c921375711a8321c6be696e705a120e3011a643efbbcdeeabcc/scipy-1.16.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2ef500e72f9623a6735769e4b93e9dcb158d40752cdbb077f305487e3e2d1f45", size = 35490328, upload-time = "2025-07-27T16:29:22.928Z" }, + { url = "https://files.pythonhosted.org/packages/71/73/e9cc3d35ee4526d784520d4494a3e1ca969b071fb5ae5910c036a375ceec/scipy-1.16.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:978d8311674b05a8f7ff2ea6c6bce5d8b45a0cb09d4c5793e0318f448613ea65", size = 37939921, upload-time = "2025-07-27T16:29:29.108Z" }, + { url = "https://files.pythonhosted.org/packages/21/12/c0efd2941f01940119b5305c375ae5c0fcb7ec193f806bd8f158b73a1782/scipy-1.16.1-cp313-cp313-win_amd64.whl", hash = "sha256:81929ed0fa7a5713fcdd8b2e6f73697d3b4c4816d090dd34ff937c20fa90e8ab", size = 38479462, upload-time = "2025-07-27T16:30:24.078Z" }, + { url = "https://files.pythonhosted.org/packages/7a/19/c3d08b675260046a991040e1ea5d65f91f40c7df1045fffff412dcfc6765/scipy-1.16.1-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:bcc12db731858abda693cecdb3bdc9e6d4bd200213f49d224fe22df82687bdd6", size = 36938832, upload-time = "2025-07-27T16:29:35.057Z" }, + { url = "https://files.pythonhosted.org/packages/81/f2/ce53db652c033a414a5b34598dba6b95f3d38153a2417c5a3883da429029/scipy-1.16.1-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:744d977daa4becb9fc59135e75c069f8d301a87d64f88f1e602a9ecf51e77b27", size = 29093084, upload-time = "2025-07-27T16:29:40.201Z" }, + { url = "https://files.pythonhosted.org/packages/a9/ae/7a10ff04a7dc15f9057d05b33737ade244e4bd195caa3f7cc04d77b9e214/scipy-1.16.1-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:dc54f76ac18073bcecffb98d93f03ed6b81a92ef91b5d3b135dcc81d55a724c7", size = 21365098, upload-time = "2025-07-27T16:29:44.295Z" }, + { url = "https://files.pythonhosted.org/packages/36/ac/029ff710959932ad3c2a98721b20b405f05f752f07344622fd61a47c5197/scipy-1.16.1-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:367d567ee9fc1e9e2047d31f39d9d6a7a04e0710c86e701e053f237d14a9b4f6", size = 23896858, upload-time = "2025-07-27T16:29:48.784Z" }, + { url = "https://files.pythonhosted.org/packages/71/13/d1ef77b6bd7898720e1f0b6b3743cb945f6c3cafa7718eaac8841035ab60/scipy-1.16.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4cf5785e44e19dcd32a0e4807555e1e9a9b8d475c6afff3d21c3c543a6aa84f4", size = 33438311, upload-time = "2025-07-27T16:29:54.164Z" }, + { url = "https://files.pythonhosted.org/packages/2d/e0/e64a6821ffbb00b4c5b05169f1c1fddb4800e9307efe3db3788995a82a2c/scipy-1.16.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3d0b80fb26d3e13a794c71d4b837e2a589d839fd574a6bbb4ee1288c213ad4a3", size = 35279542, upload-time = "2025-07-27T16:30:00.249Z" }, + { url = "https://files.pythonhosted.org/packages/57/59/0dc3c8b43e118f1e4ee2b798dcc96ac21bb20014e5f1f7a8e85cc0653bdb/scipy-1.16.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8503517c44c18d1030d666cb70aaac1cc8913608816e06742498833b128488b7", size = 35667665, upload-time = "2025-07-27T16:30:05.916Z" }, + { url = "https://files.pythonhosted.org/packages/45/5f/844ee26e34e2f3f9f8febb9343748e72daeaec64fe0c70e9bf1ff84ec955/scipy-1.16.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:30cc4bb81c41831ecfd6dc450baf48ffd80ef5aed0f5cf3ea775740e80f16ecc", size = 38045210, upload-time = "2025-07-27T16:30:11.655Z" }, + { url = "https://files.pythonhosted.org/packages/8d/d7/210f2b45290f444f1de64bc7353aa598ece9f0e90c384b4a156f9b1a5063/scipy-1.16.1-cp313-cp313t-win_amd64.whl", hash = "sha256:c24fa02f7ed23ae514460a22c57eca8f530dbfa50b1cfdbf4f37c05b5309cc39", size = 38593661, upload-time = "2025-07-27T16:30:17.825Z" }, + { url = "https://files.pythonhosted.org/packages/81/ea/84d481a5237ed223bd3d32d6e82d7a6a96e34756492666c260cef16011d1/scipy-1.16.1-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:796a5a9ad36fa3a782375db8f4241ab02a091308eb079746bc0f874c9b998318", size = 36525921, upload-time = "2025-07-27T16:30:30.081Z" }, + { url = "https://files.pythonhosted.org/packages/4e/9f/d9edbdeff9f3a664807ae3aea383e10afaa247e8e6255e6d2aa4515e8863/scipy-1.16.1-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:3ea0733a2ff73fd6fdc5fecca54ee9b459f4d74f00b99aced7d9a3adb43fb1cc", size = 28564152, upload-time = "2025-07-27T16:30:35.336Z" }, + { url = "https://files.pythonhosted.org/packages/3b/95/8125bcb1fe04bc267d103e76516243e8d5e11229e6b306bda1024a5423d1/scipy-1.16.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:85764fb15a2ad994e708258bb4ed8290d1305c62a4e1ef07c414356a24fcfbf8", size = 20836028, upload-time = "2025-07-27T16:30:39.421Z" }, + { url = "https://files.pythonhosted.org/packages/77/9c/bf92e215701fc70bbcd3d14d86337cf56a9b912a804b9c776a269524a9e9/scipy-1.16.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:ca66d980469cb623b1759bdd6e9fd97d4e33a9fad5b33771ced24d0cb24df67e", size = 23489666, upload-time = "2025-07-27T16:30:43.663Z" }, + { url = "https://files.pythonhosted.org/packages/5e/00/5e941d397d9adac41b02839011594620d54d99488d1be5be755c00cde9ee/scipy-1.16.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e7cc1ffcc230f568549fc56670bcf3df1884c30bd652c5da8138199c8c76dae0", size = 33358318, upload-time = "2025-07-27T16:30:48.982Z" }, + { url = "https://files.pythonhosted.org/packages/0e/87/8db3aa10dde6e3e8e7eb0133f24baa011377d543f5b19c71469cf2648026/scipy-1.16.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3ddfb1e8d0b540cb4ee9c53fc3dea3186f97711248fb94b4142a1b27178d8b4b", size = 35185724, upload-time = "2025-07-27T16:30:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/89/b4/6ab9ae443216807622bcff02690262d8184078ea467efee2f8c93288a3b1/scipy-1.16.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4dc0e7be79e95d8ba3435d193e0d8ce372f47f774cffd882f88ea4e1e1ddc731", size = 35554335, upload-time = "2025-07-27T16:30:59.765Z" }, + { url = "https://files.pythonhosted.org/packages/9c/9a/d0e9dc03c5269a1afb60661118296a32ed5d2c24298af61b676c11e05e56/scipy-1.16.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f23634f9e5adb51b2a77766dac217063e764337fbc816aa8ad9aaebcd4397fd3", size = 37960310, upload-time = "2025-07-27T16:31:06.151Z" }, + { url = "https://files.pythonhosted.org/packages/5e/00/c8f3130a50521a7977874817ca89e0599b1b4ee8e938bad8ae798a0e1f0d/scipy-1.16.1-cp314-cp314-win_amd64.whl", hash = "sha256:57d75524cb1c5a374958a2eae3d84e1929bb971204cc9d52213fb8589183fc19", size = 39319239, upload-time = "2025-07-27T16:31:59.942Z" }, + { url = "https://files.pythonhosted.org/packages/f2/f2/1ca3eda54c3a7e4c92f6acef7db7b3a057deb135540d23aa6343ef8ad333/scipy-1.16.1-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:d8da7c3dd67bcd93f15618938f43ed0995982eb38973023d46d4646c4283ad65", size = 36939460, upload-time = "2025-07-27T16:31:11.865Z" }, + { url = "https://files.pythonhosted.org/packages/80/30/98c2840b293a132400c0940bb9e140171dcb8189588619048f42b2ce7b4f/scipy-1.16.1-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:cc1d2f2fd48ba1e0620554fe5bc44d3e8f5d4185c8c109c7fbdf5af2792cfad2", size = 29093322, upload-time = "2025-07-27T16:31:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/c1/e6/1e6e006e850622cf2a039b62d1a6ddc4497d4851e58b68008526f04a9a00/scipy-1.16.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:21a611ced9275cb861bacadbada0b8c0623bc00b05b09eb97f23b370fc2ae56d", size = 21365329, upload-time = "2025-07-27T16:31:21.188Z" }, + { url = "https://files.pythonhosted.org/packages/8e/02/72a5aa5b820589dda9a25e329ca752842bfbbaf635e36bc7065a9b42216e/scipy-1.16.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:8dfbb25dffc4c3dd9371d8ab456ca81beeaf6f9e1c2119f179392f0dc1ab7695", size = 23897544, upload-time = "2025-07-27T16:31:25.408Z" }, + { url = "https://files.pythonhosted.org/packages/2b/dc/7122d806a6f9eb8a33532982234bed91f90272e990f414f2830cfe656e0b/scipy-1.16.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f0ebb7204f063fad87fc0a0e4ff4a2ff40b2a226e4ba1b7e34bf4b79bf97cd86", size = 33442112, upload-time = "2025-07-27T16:31:30.62Z" }, + { url = "https://files.pythonhosted.org/packages/24/39/e383af23564daa1021a5b3afbe0d8d6a68ec639b943661841f44ac92de85/scipy-1.16.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f1b9e5962656f2734c2b285a8745358ecb4e4efbadd00208c80a389227ec61ff", size = 35286594, upload-time = "2025-07-27T16:31:36.112Z" }, + { url = "https://files.pythonhosted.org/packages/95/47/1a0b0aff40c3056d955f38b0df5d178350c3d74734ec54f9c68d23910be5/scipy-1.16.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e1a106f8c023d57a2a903e771228bf5c5b27b5d692088f457acacd3b54511e4", size = 35665080, upload-time = "2025-07-27T16:31:42.025Z" }, + { url = "https://files.pythonhosted.org/packages/64/df/ce88803e9ed6e27fe9b9abefa157cf2c80e4fa527cf17ee14be41f790ad4/scipy-1.16.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:709559a1db68a9abc3b2c8672c4badf1614f3b440b3ab326d86a5c0491eafae3", size = 38050306, upload-time = "2025-07-27T16:31:48.109Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6c/a76329897a7cae4937d403e623aa6aaea616a0bb5b36588f0b9d1c9a3739/scipy-1.16.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c0c804d60492a0aad7f5b2bb1862f4548b990049e27e828391ff2bf6f7199998", size = 39427705, upload-time = "2025-07-27T16:31:53.96Z" }, +] + +[[package]] +name = "seaborn" +version = "0.13.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy" }, + { name = "pandas" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/59/a451d7420a77ab0b98f7affa3a1d78a313d2f7281a57afb1a34bae8ab412/seaborn-0.13.2.tar.gz", hash = "sha256:93e60a40988f4d65e9f4885df477e2fdaff6b73a9ded434c1ab356dd57eefff7", size = 1457696, upload-time = "2024-01-25T13:21:52.551Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, +] + +[[package]] +name = "setuptools" +version = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + +[[package]] +name = "threadpoolctl" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, +] + +[[package]] +name = "tifffile" +version = "2025.9.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3a/a7/b77bd01f97d72bb70194f036e77f45927978f43017254762c784d7e10f49/tifffile-2025.9.9.tar.gz", hash = "sha256:6cf97ef548970eee9940cf8fc4203e57b4462a72e1e5e7a667ecdeb96113bc5f", size = 369652, upload-time = "2025-09-10T00:02:19.534Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/c5/0d57e3547add58285f401afbc421bd3ffeddbbd275a2c0b980b9067fda4a/tifffile-2025.9.9-py3-none-any.whl", hash = "sha256:239247551fa10b5679036ee030cdbeb7762bc1b3f11b1ddaaf50759ef8b4eb26", size = 230668, upload-time = "2025-09-10T00:02:17.839Z" }, +] + +[[package]] +name = "timm" +version = "1.0.19" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, + { name = "pyyaml" }, + { name = "safetensors" }, + { name = "torch" }, + { name = "torchvision" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1c/78/0789838cf20ba1cc09907914a008c1823d087132b48aa1ccde5e7934175a/timm-1.0.19.tar.gz", hash = "sha256:6e71e1f67ac80c229d3a78ca58347090514c508aeba8f2e2eb5289eda86e9f43", size = 2353261, upload-time = "2025-07-24T03:04:05.281Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/74/661c63260cccf19ed5932e8b3f22f95ecd8bb34b9d9e6af9e1e7b961f254/timm-1.0.19-py3-none-any.whl", hash = "sha256:c07b56c32f3d3226c656f75c1b5479c08eb34eefed927c82fd8751a852f47931", size = 2497950, upload-time = "2025-07-24T03:04:03.097Z" }, +] + +[[package]] +name = "torch" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "setuptools", marker = "python_full_version >= '3.12'" }, + { name = "sympy" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/c4/3e7a3887eba14e815e614db70b3b529112d1513d9dae6f4d43e373360b7f/torch-2.8.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:220a06fd7af8b653c35d359dfe1aaf32f65aa85befa342629f716acb134b9710", size = 102073391, upload-time = "2025-08-06T14:53:20.937Z" }, + { url = "https://files.pythonhosted.org/packages/5a/63/4fdc45a0304536e75a5e1b1bbfb1b56dd0e2743c48ee83ca729f7ce44162/torch-2.8.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:c12fa219f51a933d5f80eeb3a7a5d0cbe9168c0a14bbb4055f1979431660879b", size = 888063640, upload-time = "2025-08-06T14:55:05.325Z" }, + { url = "https://files.pythonhosted.org/packages/84/57/2f64161769610cf6b1c5ed782bd8a780e18a3c9d48931319f2887fa9d0b1/torch-2.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:8c7ef765e27551b2fbfc0f41bcf270e1292d9bf79f8e0724848b1682be6e80aa", size = 241366752, upload-time = "2025-08-06T14:53:38.692Z" }, + { url = "https://files.pythonhosted.org/packages/a4/5e/05a5c46085d9b97e928f3f037081d3d2b87fb4b4195030fc099aaec5effc/torch-2.8.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:5ae0524688fb6707c57a530c2325e13bb0090b745ba7b4a2cd6a3ce262572916", size = 73621174, upload-time = "2025-08-06T14:53:25.44Z" }, + { url = "https://files.pythonhosted.org/packages/49/0c/2fd4df0d83a495bb5e54dca4474c4ec5f9c62db185421563deeb5dabf609/torch-2.8.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e2fab4153768d433f8ed9279c8133a114a034a61e77a3a104dcdf54388838705", size = 101906089, upload-time = "2025-08-06T14:53:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/99/a8/6acf48d48838fb8fe480597d98a0668c2beb02ee4755cc136de92a0a956f/torch-2.8.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b2aca0939fb7e4d842561febbd4ffda67a8e958ff725c1c27e244e85e982173c", size = 887913624, upload-time = "2025-08-06T14:56:44.33Z" }, + { url = "https://files.pythonhosted.org/packages/af/8a/5c87f08e3abd825c7dfecef5a0f1d9aa5df5dd0e3fd1fa2f490a8e512402/torch-2.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:2f4ac52f0130275d7517b03a33d2493bab3693c83dcfadf4f81688ea82147d2e", size = 241326087, upload-time = "2025-08-06T14:53:46.503Z" }, + { url = "https://files.pythonhosted.org/packages/be/66/5c9a321b325aaecb92d4d1855421e3a055abd77903b7dab6575ca07796db/torch-2.8.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:619c2869db3ada2c0105487ba21b5008defcc472d23f8b80ed91ac4a380283b0", size = 73630478, upload-time = "2025-08-06T14:53:57.144Z" }, + { url = "https://files.pythonhosted.org/packages/10/4e/469ced5a0603245d6a19a556e9053300033f9c5baccf43a3d25ba73e189e/torch-2.8.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2b2f96814e0345f5a5aed9bf9734efa913678ed19caf6dc2cddb7930672d6128", size = 101936856, upload-time = "2025-08-06T14:54:01.526Z" }, + { url = "https://files.pythonhosted.org/packages/16/82/3948e54c01b2109238357c6f86242e6ecbf0c63a1af46906772902f82057/torch-2.8.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:65616ca8ec6f43245e1f5f296603e33923f4c30f93d65e103d9e50c25b35150b", size = 887922844, upload-time = "2025-08-06T14:55:50.78Z" }, + { url = "https://files.pythonhosted.org/packages/e3/54/941ea0a860f2717d86a811adf0c2cd01b3983bdd460d0803053c4e0b8649/torch-2.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:659df54119ae03e83a800addc125856effda88b016dfc54d9f65215c3975be16", size = 241330968, upload-time = "2025-08-06T14:54:45.293Z" }, + { url = "https://files.pythonhosted.org/packages/de/69/8b7b13bba430f5e21d77708b616f767683629fc4f8037564a177d20f90ed/torch-2.8.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:1a62a1ec4b0498930e2543535cf70b1bef8c777713de7ceb84cd79115f553767", size = 73915128, upload-time = "2025-08-06T14:54:34.769Z" }, + { url = "https://files.pythonhosted.org/packages/15/0e/8a800e093b7f7430dbaefa80075aee9158ec22e4c4fc3c1a66e4fb96cb4f/torch-2.8.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:83c13411a26fac3d101fe8035a6b0476ae606deb8688e904e796a3534c197def", size = 102020139, upload-time = "2025-08-06T14:54:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/4a/15/5e488ca0bc6162c86a33b58642bc577c84ded17c7b72d97e49b5833e2d73/torch-2.8.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:8f0a9d617a66509ded240add3754e462430a6c1fc5589f86c17b433dd808f97a", size = 887990692, upload-time = "2025-08-06T14:56:18.286Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a8/6a04e4b54472fc5dba7ca2341ab219e529f3c07b6941059fbf18dccac31f/torch-2.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:a7242b86f42be98ac674b88a4988643b9bc6145437ec8f048fea23f72feb5eca", size = 241603453, upload-time = "2025-08-06T14:55:22.945Z" }, + { url = "https://files.pythonhosted.org/packages/04/6e/650bb7f28f771af0cb791b02348db8b7f5f64f40f6829ee82aa6ce99aabe/torch-2.8.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:7b677e17f5a3e69fdef7eb3b9da72622f8d322692930297e4ccb52fefc6c8211", size = 73632395, upload-time = "2025-08-06T14:55:28.645Z" }, +] + +[[package]] +name = "torchcam" +version = "0.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "matplotlib" }, + { name = "numpy" }, + { name = "pillow" }, + { name = "torch" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5c/96/c4d2c08eb9d6c6d30cd14561a56e46e24c3a12058b50d7af28dbdbd6a03e/torchcam-0.3.1.tar.gz", hash = "sha256:400d451cbbafe0dbddbf3a22feab9e23d1317e90cf6eae16bca96e0e2ff4f076", size = 25310, upload-time = "2021-10-31T17:55:46.485Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/70/a99d8ea8cf84a2d4805735a9d83cefb93a9d36e145882b04340e40242854/torchcam-0.3.1-py3-none-any.whl", hash = "sha256:50fff3a2996f9cacc76d96faa76de44fda0896f98e2dcef59e94bddbd813059d", size = 23181, upload-time = "2021-10-31T17:55:44.761Z" }, +] + +[[package]] +name = "torchinfo" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/53/d9/2b811d1c0812e9ef23e6cf2dbe022becbe6c5ab065e33fd80ee05c0cd996/torchinfo-1.8.0.tar.gz", hash = "sha256:72e94b0e9a3e64dc583a8e5b7940b8938a1ac0f033f795457f27e6f4e7afa2e9", size = 25880, upload-time = "2023-05-14T19:23:26.377Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/25/973bd6128381951b23cdcd8a9870c6dcfc5606cb864df8eabd82e529f9c1/torchinfo-1.8.0-py3-none-any.whl", hash = "sha256:2e911c2918603f945c26ff21a3a838d12709223dc4ccf243407bce8b6e897b46", size = 23377, upload-time = "2023-05-14T19:23:24.141Z" }, +] + +[[package]] +name = "torchmetrics" +version = "1.8.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "lightning-utilities" }, + { name = "numpy" }, + { name = "packaging" }, + { name = "torch" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/2e/48a887a59ecc4a10ce9e8b35b3e3c5cef29d902c4eac143378526e7485cb/torchmetrics-1.8.2.tar.gz", hash = "sha256:cf64a901036bf107f17a524009eea7781c9c5315d130713aeca5747a686fe7a5", size = 580679, upload-time = "2025-09-03T14:00:54.077Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/21/aa0f434434c48490f91b65962b1ce863fdcce63febc166ca9fe9d706c2b6/torchmetrics-1.8.2-py3-none-any.whl", hash = "sha256:08382fd96b923e39e904c4d570f3d49e2cc71ccabd2a94e0f895d1f0dac86242", size = 983161, upload-time = "2025-09-03T14:00:51.921Z" }, +] + +[[package]] +name = "torchvision" +version = "0.23.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "numpy" }, + { name = "pillow" }, + { name = "torch" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f0/d7/15d3d7bd8d0239211b21673d1bac7bc345a4ad904a8e25bb3fd8a9cf1fbc/torchvision-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:49aa20e21f0c2bd458c71d7b449776cbd5f16693dd5807195a820612b8a229b7", size = 1856884, upload-time = "2025-08-06T14:58:00.237Z" }, + { url = "https://files.pythonhosted.org/packages/dd/14/7b44fe766b7d11e064c539d92a172fa9689a53b69029e24f2f1f51e7dc56/torchvision-0.23.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:01dc33ee24c79148aee7cdbcf34ae8a3c9da1674a591e781577b716d233b1fa6", size = 2395543, upload-time = "2025-08-06T14:58:04.373Z" }, + { url = "https://files.pythonhosted.org/packages/79/9c/fcb09aff941c8147d9e6aa6c8f67412a05622b0c750bcf796be4c85a58d4/torchvision-0.23.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:35c27941831b653f5101edfe62c03d196c13f32139310519e8228f35eae0e96a", size = 8628388, upload-time = "2025-08-06T14:58:07.802Z" }, + { url = "https://files.pythonhosted.org/packages/93/40/3415d890eb357b25a8e0a215d32365a88ecc75a283f75c4e919024b22d97/torchvision-0.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:09bfde260e7963a15b80c9e442faa9f021c7e7f877ac0a36ca6561b367185013", size = 1600741, upload-time = "2025-08-06T14:57:59.158Z" }, + { url = "https://files.pythonhosted.org/packages/df/1d/0ea0b34bde92a86d42620f29baa6dcbb5c2fc85990316df5cb8f7abb8ea2/torchvision-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e0e2c04a91403e8dd3af9756c6a024a1d9c0ed9c0d592a8314ded8f4fe30d440", size = 1856885, upload-time = "2025-08-06T14:58:06.503Z" }, + { url = "https://files.pythonhosted.org/packages/e2/00/2f6454decc0cd67158c7890364e446aad4b91797087a57a78e72e1a8f8bc/torchvision-0.23.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:6dd7c4d329a0e03157803031bc856220c6155ef08c26d4f5bbac938acecf0948", size = 2396614, upload-time = "2025-08-06T14:58:03.116Z" }, + { url = "https://files.pythonhosted.org/packages/e4/b5/3e580dcbc16f39a324f3dd71b90edbf02a42548ad44d2b4893cc92b1194b/torchvision-0.23.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4e7d31c43bc7cbecbb1a5652ac0106b436aa66e26437585fc2c4b2cf04d6014c", size = 8627108, upload-time = "2025-08-06T14:58:12.956Z" }, + { url = "https://files.pythonhosted.org/packages/82/c1/c2fe6d61e110a8d0de2f94276899a2324a8f1e6aee559eb6b4629ab27466/torchvision-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:a2e45272abe7b8bf0d06c405e78521b5757be1bd0ed7e5cd78120f7fdd4cbf35", size = 1600723, upload-time = "2025-08-06T14:57:57.986Z" }, + { url = "https://files.pythonhosted.org/packages/91/37/45a5b9407a7900f71d61b2b2f62db4b7c632debca397f205fdcacb502780/torchvision-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1c37e325e09a184b730c3ef51424f383ec5745378dc0eca244520aca29722600", size = 1856886, upload-time = "2025-08-06T14:58:05.491Z" }, + { url = "https://files.pythonhosted.org/packages/ac/da/a06c60fc84fc849377cf035d3b3e9a1c896d52dbad493b963c0f1cdd74d0/torchvision-0.23.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:2f7fd6c15f3697e80627b77934f77705f3bc0e98278b989b2655de01f6903e1d", size = 2353112, upload-time = "2025-08-06T14:58:26.265Z" }, + { url = "https://files.pythonhosted.org/packages/a0/27/5ce65ba5c9d3b7d2ccdd79892ab86a2f87ac2ca6638f04bb0280321f1a9c/torchvision-0.23.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:a76fafe113b2977be3a21bf78f115438c1f88631d7a87203acb3dd6ae55889e6", size = 8627658, upload-time = "2025-08-06T14:58:15.999Z" }, + { url = "https://files.pythonhosted.org/packages/1f/e4/028a27b60aa578a2fa99d9d7334ff1871bb17008693ea055a2fdee96da0d/torchvision-0.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:07d069cb29691ff566e3b7f11f20d91044f079e1dbdc9d72e0655899a9b06938", size = 1600749, upload-time = "2025-08-06T14:58:10.719Z" }, + { url = "https://files.pythonhosted.org/packages/05/35/72f91ad9ac7c19a849dedf083d347dc1123f0adeb401f53974f84f1d04c8/torchvision-0.23.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:2df618e1143805a7673aaf82cb5720dd9112d4e771983156aaf2ffff692eebf9", size = 2047192, upload-time = "2025-08-06T14:58:11.813Z" }, + { url = "https://files.pythonhosted.org/packages/1d/9d/406cea60a9eb9882145bcd62a184ee61e823e8e1d550cdc3c3ea866a9445/torchvision-0.23.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:2a3299d2b1d5a7aed2d3b6ffb69c672ca8830671967eb1cee1497bacd82fe47b", size = 2359295, upload-time = "2025-08-06T14:58:17.469Z" }, + { url = "https://files.pythonhosted.org/packages/2b/f4/34662f71a70fa1e59de99772142f22257ca750de05ccb400b8d2e3809c1d/torchvision-0.23.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:76bc4c0b63d5114aa81281390f8472a12a6a35ce9906e67ea6044e5af4cab60c", size = 8800474, upload-time = "2025-08-06T14:58:22.53Z" }, + { url = "https://files.pythonhosted.org/packages/6e/f5/b5a2d841a8d228b5dbda6d524704408e19e7ca6b7bb0f24490e081da1fa1/torchvision-0.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:b9e2dabf0da9c8aa9ea241afb63a8f3e98489e706b22ac3f30416a1be377153b", size = 1527667, upload-time = "2025-08-06T14:58:14.446Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[package]] +name = "triton" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "setuptools" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/7d/39/43325b3b651d50187e591eefa22e236b2981afcebaefd4f2fc0ea99df191/triton-3.4.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b70f5e6a41e52e48cfc087436c8a28c17ff98db369447bcaff3b887a3ab4467", size = 155531138, upload-time = "2025-07-30T19:58:29.908Z" }, + { url = "https://files.pythonhosted.org/packages/d0/66/b1eb52839f563623d185f0927eb3530ee4d5ffe9d377cdaf5346b306689e/triton-3.4.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:31c1d84a5c0ec2c0f8e8a072d7fd150cab84a9c239eaddc6706c081bfae4eb04", size = 155560068, upload-time = "2025-07-30T19:58:37.081Z" }, + { url = "https://files.pythonhosted.org/packages/30/7b/0a685684ed5322d2af0bddefed7906674f67974aa88b0fae6e82e3b766f6/triton-3.4.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:00be2964616f4c619193cb0d1b29a99bd4b001d7dc333816073f92cf2a8ccdeb", size = 155569223, upload-time = "2025-07-30T19:58:44.017Z" }, + { url = "https://files.pythonhosted.org/packages/20/63/8cb444ad5cdb25d999b7d647abac25af0ee37d292afc009940c05b82dda0/triton-3.4.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7936b18a3499ed62059414d7df563e6c163c5e16c3773678a3ee3d417865035d", size = 155659780, upload-time = "2025-07-30T19:58:51.171Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, +] + +[[package]] +name = "urllib3" +version = "2.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, +]