matchypatchy 0.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Conservation Technology Lab
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.4
2
+ Name: matchypatchy
3
+ Version: 0.2.1
4
+ Summary: GUI tool for human validation of AI-powered animal re-identification
5
+ Author-email: Kyra Swanson <tswanson@sdzwa.org>
6
+ Project-URL: Homepage, https://github.com/onservationtechlab/matchypatchy
7
+ Project-URL: Issues, https://github.com/onservationtechlab/matchypatchy/issues
8
+ Requires-Python: >=3.12
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: animl-lite==3.3.2
12
+ Requires-Dist: chromadb>=1.3.4
13
+ Requires-Dist: pyqt6>=6.9.0
14
+ Dynamic: license-file
15
+
16
+ # MatchyPatchy
17
+ <br/>
18
+
19
+ [User Manual](https://conservationtechlab.github.io/matchypatchy/)
20
+
21
+ MatchyPatchy is an open-source GUI tool for human validation of AI-powered animal re-identification.\
22
+ It was developed by the San Diego Zoo Wildlife Alliance Conservation Technology Lab.\
23
+ Author: Kyra Swanson, (c) 2025
24
+ <br/>
25
+
26
+ ---
27
+ ## Installation
28
+
29
+ Matchypatchy is a stand-alone executable built in Python. Download it [here](). \
30
+ [Github Repository](https://github.com/conservationtechlab/matchypatchy)
31
+ <br/>
32
+
33
+ ---
34
+ ## Getting Started
35
+ <br/>
36
+
37
+ ### Download Models
38
+ In order to calculate potential matches, MatchyPatchy requires an animal object detector such as [MegaDetector]()
39
+ and an embedding extractor such as [MiewID](). Both models and more can be obtained from the SDZWA server by selecting
40
+ 'Download Models' and checking the box associated with which models you want to download.
41
+ <br/>
42
+
43
+ ### Select Survey
44
+ In order to add media to the database, you must first specify a Survey using
45
+ the dropdown of available surveys. To add a new survey,
46
+
47
+ 1. Select 'Manage Surveys'
48
+ 2. Select 'New'
49
+ 3. Enter Survey Name
50
+ 4. Enter Survey Region
51
+ 5. (Optional) Enter Survey Start Year
52
+ 6. (Optional) Enter Survey End Year
53
+ 7. Select 'Ok'
54
+ <br/>
55
+
56
+ ### 1. Import Images
57
+ Images can be imported via spreadsheet or by manually selecting a directory of images.
58
+
59
+ **From CSV**
60
+ 1. Select '1. Import from CSV'
61
+ 2. Open .csv file
62
+ 3. Select column headers that correspond to image Filepath, Timestamp, Survey, and Station
63
+ 4. Optionally select column headers that correspond to image Region, Sequence ID, External ID,
64
+ Viewpoint, Species, Individual ID, and Comment
65
+ 5. Select 'Ok'
66
+ <br/>
67
+
68
+ **From Folder**
69
+ 1. Select '1. Import from Folder'
70
+ 2. Open directory containing image files. Can be a whole Survey containg multiple Stations or single Station.
71
+ 3. Select the directory level that corresponds to Station name if available
72
+ 4. Select 'Ok'
73
+ <br/>
74
+
75
+ ### 2. Process Images
76
+ Run images through a sequence of AI models to obtain predicted matches.\
77
+ Note: Models must be accessible in MatchyPatchy's "Models" folder - see Configuration for more.
78
+
79
+ 1. Select '2. Process'
80
+ 2. (Optional) Check Calculate Sequence (improves performance for videos and images captured in quick succession)
81
+ 3. **Select Detector Model** - recommended MegaDetector v5a
82
+ 4. (Optional) Select Species Classifier Model
83
+ 5. **Select Re-Indentification Model** - required to obtain predicted matches, recommended MiewIDv3
84
+ 6. (Optional) Select Viewpoint Model (improves performance by estimating animal viewpoint and limiting search space)
85
+ <br/>
86
+
87
+ ### 3. Validate
88
+ After processing, this pageview allows you to review the imported media for errors, make changes, delete images, etc.
89
+ It can be accessed at any time after image import.
90
+ <br/>
91
+
92
+ Double-clicking on a cell will allow you to edit it.\
93
+ Double-clicking on a single row will pull up a screen to edit multiple fields for an image.\
94
+ Selecting one or more row (either by clicking on the row number or checking the select box) will enable the ability
95
+ to mass edit particular fields, duplicate entries, or delete entries.
96
+ <br/>
97
+
98
+ The **"Show"** Option allows you view the full images or detected ROIS.\
99
+ The **"Save"** Option saves all edits to the database.\
100
+ The **"Undo"** Option undoes the last edit made.
101
+ <br/>
102
+
103
+ **Filters** \
104
+ Images can be filtered by Region, Survey, Station, Species, and Individual.\
105
+ You can also choose to show only "Unidentified" ROIs.\
106
+ You can also display all images marked as "Favorite"
107
+ <br/>
108
+
109
+ ### 4. Match
110
+ After processing, potential matches can be validated at this pageview.
111
+ The left side contains a **Query** image and the right side contains potential **Matches**.
112
+ If "Calculate Sequence" was selected during the processing stage, the entire **Sequence** will be viewable on the Query side.
113
+ The pageview will display the images and associated metadata.
114
+ <br/>
115
+
116
+ _View Options_\
117
+ Adjustments can be made to the **Maximum Number of Matches** shown for each image (within a sequence) and to the maximum distance
118
+ threshold between the two images to qualify as a match. The **Cosine** or **L2** distance of the Match from the Query is displayed above the
119
+ match image. Select which distance metric to use in the dropdown. You must select **"Recalculate Matches"** if changes are made to either option
120
+ in order to display those changes.\
121
+ After matches are validated, you can **"Query by Individual"** to do quality control and ensure all images associated with
122
+ an individual are indeed valid.\
123
+ Images can be **Filtered** by Region, Survey, or Station to narrow the available matches shown.\
124
+ If **"Viewpoint"** was calculated at the processing step, you can filter both the **Query** and the **Match** images by Viewpoint.\
125
+ The **"View Data"** Button at the bottom brings you to the Media Validation pageview.
126
+ <br/>
127
+
128
+ _Image Options_\
129
+ You can adjust the **Brightness, Contrast** and **Sharpness** of each image, as well as **Zoom** using the mouse scroll wheel.\
130
+ The **"Reset"** button returns the image to its original form.\
131
+ The **"Edit Image"** option allows you to make changes to the metadata.\
132
+ The **"Open Image"** option opens the image in your default image viewer.\
133
+ The **"♥"** option marks the image with the "Favorite" tag.
134
+ <br/>
135
+
136
+ To confirm a match between the Query and the Match image, select the **"Match" button** in the middle, or press the 'M' or 'Space Key'.
137
+ Pressing Match again will undo the match, asking you to confirm first.\
138
+ You can navigate between Query Sequences and Matches by using the **"<<"** and **">>"** buttons, or by using the arrow keys.\
139
+ You can also toggle the **Viewpoint** by pressing 'V'.
140
+ <br/>
141
+
142
+ ### 5. Export
143
+ The database can be exported as a .csv file. Simply select '5. Export' and specify the file name and location.
144
+ <br/>
145
+
146
+ ---
147
+ ## Database Management
148
+ <br/>
149
+
150
+ ### Definitions
151
+ * Survey - An ecological study employing camera traps to investigate wildlife of a particular area.
152
+ * Region - A geographical region that may host one or more camera trap surveys.
153
+ * Station - Reference to a physical location containing one or camera traps.
154
+ * Species - The taxonomic and common names refering to a class of animal.
155
+ * Media - Image (and soon video) files obtained from camera traps.
156
+ * ROI - Regions of Interest within media files that contain animals.
157
+ * Individual - A particular, singular example of a given species, can be named/ID'd.
158
+ * Sequence ID - A unique number associated with a set of sequential images or frames in a video.
159
+ * External ID - A unique number used to reference MatchyPatchy output with other datamanagement tools.
160
+ * Viewpoint - The side of the body of the animl facing the camera, eg "Left", "Right", "Top"
161
+ * Comment - Notes or concerns about a particular media file
162
+ * Favorite - A tag marking an image as noteworthy.
163
+ <br/>
164
+
165
+ ### Manage Tables
166
+ **Survey, Station,** and **Species** tables can be managed independently.
167
+ <br/>
168
+
169
+ ### CSV Import
170
+ <br/>
171
+
172
+
173
+ ---
174
+ ## Configuration
175
+ <br/>
176
+
177
+ ### Available Models
178
+ Models currently available and compatible with MatchyPatchy:\
179
+ _Detector Models_:
180
+ - MegaDetector v5a
181
+ - MegaDetector v5b
182
+
183
+ _Re-ID Models_:
184
+ - MiewID v3
185
+ - MiewID v2
186
+
187
+ _Viewpoint Models_:
188
+ - SDZWA Viewpoint
189
+ <br/>
190
+
191
+ ### Link to New Database
192
+ Database files can be shared across multiple users of MatchyPatchy. To link to a new .db file,
193
+ <br/>
194
+
195
+ ### Clear Data
@@ -0,0 +1,180 @@
1
+ # MatchyPatchy
2
+ <br/>
3
+
4
+ [User Manual](https://conservationtechlab.github.io/matchypatchy/)
5
+
6
+ MatchyPatchy is an open-source GUI tool for human validation of AI-powered animal re-identification.\
7
+ It was developed by the San Diego Zoo Wildlife Alliance Conservation Technology Lab.\
8
+ Author: Kyra Swanson, (c) 2025
9
+ <br/>
10
+
11
+ ---
12
+ ## Installation
13
+
14
+ Matchypatchy is a stand-alone executable built in Python. Download it [here](). \
15
+ [Github Repository](https://github.com/conservationtechlab/matchypatchy)
16
+ <br/>
17
+
18
+ ---
19
+ ## Getting Started
20
+ <br/>
21
+
22
+ ### Download Models
23
+ In order to calculate potential matches, MatchyPatchy requires an animal object detector such as [MegaDetector]()
24
+ and an embedding extractor such as [MiewID](). Both models and more can be obtained from the SDZWA server by selecting
25
+ 'Download Models' and checking the box associated with which models you want to download.
26
+ <br/>
27
+
28
+ ### Select Survey
29
+ In order to add media to the database, you must first specify a Survey using
30
+ the dropdown of available surveys. To add a new survey,
31
+
32
+ 1. Select 'Manage Surveys'
33
+ 2. Select 'New'
34
+ 3. Enter Survey Name
35
+ 4. Enter Survey Region
36
+ 5. (Optional) Enter Survey Start Year
37
+ 6. (Optional) Enter Survey End Year
38
+ 7. Select 'Ok'
39
+ <br/>
40
+
41
+ ### 1. Import Images
42
+ Images can be imported via spreadsheet or by manually selecting a directory of images.
43
+
44
+ **From CSV**
45
+ 1. Select '1. Import from CSV'
46
+ 2. Open .csv file
47
+ 3. Select column headers that correspond to image Filepath, Timestamp, Survey, and Station
48
+ 4. Optionally select column headers that correspond to image Region, Sequence ID, External ID,
49
+ Viewpoint, Species, Individual ID, and Comment
50
+ 5. Select 'Ok'
51
+ <br/>
52
+
53
+ **From Folder**
54
+ 1. Select '1. Import from Folder'
55
+ 2. Open directory containing image files. Can be a whole Survey containg multiple Stations or single Station.
56
+ 3. Select the directory level that corresponds to Station name if available
57
+ 4. Select 'Ok'
58
+ <br/>
59
+
60
+ ### 2. Process Images
61
+ Run images through a sequence of AI models to obtain predicted matches.\
62
+ Note: Models must be accessible in MatchyPatchy's "Models" folder - see Configuration for more.
63
+
64
+ 1. Select '2. Process'
65
+ 2. (Optional) Check Calculate Sequence (improves performance for videos and images captured in quick succession)
66
+ 3. **Select Detector Model** - recommended MegaDetector v5a
67
+ 4. (Optional) Select Species Classifier Model
68
+ 5. **Select Re-Indentification Model** - required to obtain predicted matches, recommended MiewIDv3
69
+ 6. (Optional) Select Viewpoint Model (improves performance by estimating animal viewpoint and limiting search space)
70
+ <br/>
71
+
72
+ ### 3. Validate
73
+ After processing, this pageview allows you to review the imported media for errors, make changes, delete images, etc.
74
+ It can be accessed at any time after image import.
75
+ <br/>
76
+
77
+ Double-clicking on a cell will allow you to edit it.\
78
+ Double-clicking on a single row will pull up a screen to edit multiple fields for an image.\
79
+ Selecting one or more row (either by clicking on the row number or checking the select box) will enable the ability
80
+ to mass edit particular fields, duplicate entries, or delete entries.
81
+ <br/>
82
+
83
+ The **"Show"** Option allows you view the full images or detected ROIS.\
84
+ The **"Save"** Option saves all edits to the database.\
85
+ The **"Undo"** Option undoes the last edit made.
86
+ <br/>
87
+
88
+ **Filters** \
89
+ Images can be filtered by Region, Survey, Station, Species, and Individual.\
90
+ You can also choose to show only "Unidentified" ROIs.\
91
+ You can also display all images marked as "Favorite"
92
+ <br/>
93
+
94
+ ### 4. Match
95
+ After processing, potential matches can be validated at this pageview.
96
+ The left side contains a **Query** image and the right side contains potential **Matches**.
97
+ If "Calculate Sequence" was selected during the processing stage, the entire **Sequence** will be viewable on the Query side.
98
+ The pageview will display the images and associated metadata.
99
+ <br/>
100
+
101
+ _View Options_\
102
+ Adjustments can be made to the **Maximum Number of Matches** shown for each image (within a sequence) and to the maximum distance
103
+ threshold between the two images to qualify as a match. The **Cosine** or **L2** distance of the Match from the Query is displayed above the
104
+ match image. Select which distance metric to use in the dropdown. You must select **"Recalculate Matches"** if changes are made to either option
105
+ in order to display those changes.\
106
+ After matches are validated, you can **"Query by Individual"** to do quality control and ensure all images associated with
107
+ an individual are indeed valid.\
108
+ Images can be **Filtered** by Region, Survey, or Station to narrow the available matches shown.\
109
+ If **"Viewpoint"** was calculated at the processing step, you can filter both the **Query** and the **Match** images by Viewpoint.\
110
+ The **"View Data"** Button at the bottom brings you to the Media Validation pageview.
111
+ <br/>
112
+
113
+ _Image Options_\
114
+ You can adjust the **Brightness, Contrast** and **Sharpness** of each image, as well as **Zoom** using the mouse scroll wheel.\
115
+ The **"Reset"** button returns the image to its original form.\
116
+ The **"Edit Image"** option allows you to make changes to the metadata.\
117
+ The **"Open Image"** option opens the image in your default image viewer.\
118
+ The **"♥"** option marks the image with the "Favorite" tag.
119
+ <br/>
120
+
121
+ To confirm a match between the Query and the Match image, select the **"Match" button** in the middle, or press the 'M' or 'Space Key'.
122
+ Pressing Match again will undo the match, asking you to confirm first.\
123
+ You can navigate between Query Sequences and Matches by using the **"<<"** and **">>"** buttons, or by using the arrow keys.\
124
+ You can also toggle the **Viewpoint** by pressing 'V'.
125
+ <br/>
126
+
127
+ ### 5. Export
128
+ The database can be exported as a .csv file. Simply select '5. Export' and specify the file name and location.
129
+ <br/>
130
+
131
+ ---
132
+ ## Database Management
133
+ <br/>
134
+
135
+ ### Definitions
136
+ * Survey - An ecological study employing camera traps to investigate wildlife of a particular area.
137
+ * Region - A geographical region that may host one or more camera trap surveys.
138
+ * Station - Reference to a physical location containing one or camera traps.
139
+ * Species - The taxonomic and common names refering to a class of animal.
140
+ * Media - Image (and soon video) files obtained from camera traps.
141
+ * ROI - Regions of Interest within media files that contain animals.
142
+ * Individual - A particular, singular example of a given species, can be named/ID'd.
143
+ * Sequence ID - A unique number associated with a set of sequential images or frames in a video.
144
+ * External ID - A unique number used to reference MatchyPatchy output with other datamanagement tools.
145
+ * Viewpoint - The side of the body of the animl facing the camera, eg "Left", "Right", "Top"
146
+ * Comment - Notes or concerns about a particular media file
147
+ * Favorite - A tag marking an image as noteworthy.
148
+ <br/>
149
+
150
+ ### Manage Tables
151
+ **Survey, Station,** and **Species** tables can be managed independently.
152
+ <br/>
153
+
154
+ ### CSV Import
155
+ <br/>
156
+
157
+
158
+ ---
159
+ ## Configuration
160
+ <br/>
161
+
162
+ ### Available Models
163
+ Models currently available and compatible with MatchyPatchy:\
164
+ _Detector Models_:
165
+ - MegaDetector v5a
166
+ - MegaDetector v5b
167
+
168
+ _Re-ID Models_:
169
+ - MiewID v3
170
+ - MiewID v2
171
+
172
+ _Viewpoint Models_:
173
+ - SDZWA Viewpoint
174
+ <br/>
175
+
176
+ ### Link to New Database
177
+ Database files can be shared across multiple users of MatchyPatchy. To link to a new .db file,
178
+ <br/>
179
+
180
+ ### Clear Data
@@ -0,0 +1,42 @@
1
+ [project]
2
+ name = "matchypatchy"
3
+ dynamic = ["version"]
4
+ authors = [
5
+ { name="Kyra Swanson", email="tswanson@sdzwa.org" },
6
+ ]
7
+ description = "GUI tool for human validation of AI-powered animal re-identification"
8
+ readme = "README.md"
9
+ requires-python = ">=3.12"
10
+ dependencies = [
11
+ "animl-lite==3.3.2",
12
+ "chromadb>=1.3.4",
13
+ "pyqt6>=6.9.0",
14
+ ]
15
+
16
+ [project.urls]
17
+ Homepage = "https://github.com/onservationtechlab/matchypatchy"
18
+ Issues = "https://github.com/onservationtechlab/matchypatchy/issues"
19
+
20
+ [build-system]
21
+ requires = ["setuptools>=61.0"]
22
+ build-backend = "setuptools.build_meta"
23
+
24
+ [tool.setuptools.dynamic]
25
+ version = {attr = "matchypatchy.__version__"}
26
+
27
+ [tool.setuptools]
28
+ packages = ["matchypatchy"]
29
+ package-dir = {"" = "src"}
30
+
31
+ [tool.setuptools.package-data]
32
+ matchypatchy = ["assets/**/*", "assets/graphics/*"]
33
+
34
+ [tool.pytest.ini_options]
35
+ testpaths = ["tests"]
36
+ addopts = "-v"
37
+
38
+ [tool.pylint.master]
39
+ extension-pkg-whitelist = ["PyQt6"]
40
+
41
+ [tool.pylint.messages_control]
42
+ disable = ["no-name-in-module"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,105 @@
1
+ __version__ = "0.2.1"
2
+
3
+ from matchypatchy import config
4
+ from matchypatchy import database
5
+ from matchypatchy import gui
6
+ from matchypatchy import logging_config
7
+ from matchypatchy import threads
8
+
9
+ from matchypatchy.config import (asset_path, mpConfig, resource_path,)
10
+ from matchypatchy.database import (EditObject, IMAGE_EXT, MatchyPatchyDB,
11
+ THUMBNAIL_NOTFOUND, THUMBNAIL_SIZE,
12
+ TZ_CONVERT_DICT, VIDEO_EXT,
13
+ check_missing_thumbnails, fetch_individual,
14
+ fetch_media, fetch_media_thumbnails,
15
+ fetch_regions, fetch_roi, fetch_roi_media,
16
+ fetch_roi_thumbnails,
17
+ fetch_station_names_from_id, fetch_stations,
18
+ fetch_surveys, get_frame, get_roi_bbox,
19
+ get_sequence, get_sha256,
20
+ individual_roi_dict, location, media,
21
+ media_count, mpdb, save_media_thumbnail,
22
+ save_roi_thumbnail, sequence_roi_dict,
23
+ setup, setup_chromadb, setup_database,
24
+ thumbnails,)
25
+ from matchypatchy.gui import (AlertPopup, ClickableSlider, ComboBoxDelegate,
26
+ ComboBoxSeparator, ConfigPopup, DisplayBase,
27
+ DisplayCompare, DisplayMedia, FilterBar,
28
+ FilterBox, HorizontalSeparator, ImageAdjustBar,
29
+ ImageWidget, ImportCSVPopup, ImportFolderPopup,
30
+ IndividualFillPopup, IndividualPopup,
31
+ MLDownloadPopup, MLOptionsPopup, MainWindow,
32
+ ManualQueryContainer, MediaEditPopup, MediaTable,
33
+ MediaWidget, MetadataPanel, NoHoverDelegate,
34
+ PairXPopup, QC_QueryContainer, QueryContainer,
35
+ READMEPopup, SequenceSelector, SliderWithLabel,
36
+ StandardButton, StationFillPopup, StationPopup,
37
+ SurveyFillPopup, SurveyPopup, TextEditWithSignal,
38
+ ThreePointSlider, UploadManagerPopup,
39
+ VerticalSeparator, VideoPlayerBar, VideoViewer,
40
+ VideoWidget, dialogs, display_base,
41
+ display_compare, display_media, gui_assets,
42
+ main_gui, manual_query, media_table, popup_alert,
43
+ popup_config, popup_import_csv,
44
+ popup_import_folder, popup_individual,
45
+ popup_media_edit, popup_ml, popup_pairx,
46
+ popup_readme, popup_station, popup_survey,
47
+ popup_uploads, qc_query, query, widget_filterbar,
48
+ widget_image_adjustment, widget_media, widgets,)
49
+ from matchypatchy.logging_config import (get_logger, setup_logger,)
50
+ from matchypatchy.threads import (AnimlThread, BasePathUpdateThread,
51
+ BuildManifestThread, CSVImportThread,
52
+ CSVMigrateThread, DownloadMLThread,
53
+ FavoriteMatchObject, FetchTableThread,
54
+ FolderImportThread, MEGADETECTORv1000_SIZE,
55
+ MatchEmbeddingThread, MatchObject,
56
+ ReIDThread, SequenceThread,
57
+ VerifyNewBaseDirsThread, animl_thread,
58
+ delete, get_path, import_thread,
59
+ is_valid_reid_model, load_model,
60
+ match_object, match_thread,
61
+ model_download_thread, reid_thread,
62
+ sequence_thread, table_thread,
63
+ update_model_yml,)
64
+
65
+ __all__ = ['AlertPopup', 'AnimlThread', 'BasePathUpdateThread',
66
+ 'BuildManifestThread', 'CSVImportThread', 'CSVMigrateThread',
67
+ 'ClickableSlider', 'ComboBoxDelegate', 'ComboBoxSeparator',
68
+ 'ConfigPopup', 'DisplayBase', 'DisplayCompare', 'DisplayMedia',
69
+ 'DownloadMLThread', 'EditObject', 'FavoriteMatchObject',
70
+ 'FetchTableThread', 'FilterBar', 'FilterBox', 'FolderImportThread',
71
+ 'HorizontalSeparator', 'IMAGE_EXT', 'ImageAdjustBar', 'ImageWidget',
72
+ 'ImportCSVPopup', 'ImportFolderPopup', 'IndividualFillPopup',
73
+ 'IndividualPopup', 'MEGADETECTORv1000_SIZE', 'MLDownloadPopup',
74
+ 'MLOptionsPopup', 'MainWindow', 'ManualQueryContainer',
75
+ 'MatchEmbeddingThread', 'MatchObject', 'MatchyPatchyDB',
76
+ 'MediaEditPopup', 'MediaTable', 'MediaWidget', 'MetadataPanel',
77
+ 'NoHoverDelegate', 'PairXPopup', 'QC_QueryContainer',
78
+ 'QueryContainer', 'READMEPopup', 'ReIDThread', 'SequenceSelector',
79
+ 'SequenceThread', 'SliderWithLabel', 'StandardButton',
80
+ 'StationFillPopup', 'StationPopup', 'SurveyFillPopup',
81
+ 'SurveyPopup', 'THUMBNAIL_NOTFOUND', 'THUMBNAIL_SIZE',
82
+ 'TZ_CONVERT_DICT', 'TextEditWithSignal', 'ThreePointSlider',
83
+ 'UploadManagerPopup', 'VIDEO_EXT', 'VerifyNewBaseDirsThread',
84
+ 'VerticalSeparator', 'VideoPlayerBar', 'VideoViewer', 'VideoWidget',
85
+ 'animl_thread', 'asset_path', 'check_missing_thumbnails', 'config',
86
+ 'database', 'delete', 'dialogs', 'display_base', 'display_compare',
87
+ 'display_media', 'fetch_individual', 'fetch_media',
88
+ 'fetch_media_thumbnails', 'fetch_regions', 'fetch_roi',
89
+ 'fetch_roi_media', 'fetch_roi_thumbnails',
90
+ 'fetch_station_names_from_id', 'fetch_stations', 'fetch_surveys',
91
+ 'get_frame', 'get_logger', 'get_path', 'get_roi_bbox',
92
+ 'get_sequence', 'get_sha256', 'gui', 'gui_assets', 'import_thread',
93
+ 'individual_roi_dict', 'is_valid_reid_model', 'load_model',
94
+ 'location', 'logging_config', 'main_gui', 'manual_query',
95
+ 'match_object', 'match_thread', 'media', 'media_count',
96
+ 'media_table', 'model_download_thread', 'mpConfig', 'mpdb',
97
+ 'popup_alert', 'popup_config', 'popup_import_csv',
98
+ 'popup_import_folder', 'popup_individual', 'popup_media_edit',
99
+ 'popup_ml', 'popup_pairx', 'popup_readme', 'popup_station',
100
+ 'popup_survey', 'popup_uploads', 'qc_query', 'query', 'reid_thread',
101
+ 'resource_path', 'save_media_thumbnail', 'save_roi_thumbnail',
102
+ 'sequence_roi_dict', 'sequence_thread', 'setup', 'setup_chromadb',
103
+ 'setup_database', 'setup_logger', 'table_thread', 'threads',
104
+ 'thumbnails', 'update_model_yml', 'widget_filterbar',
105
+ 'widget_image_adjustment', 'widget_media', 'widgets']
@@ -0,0 +1,78 @@
1
+ '''
2
+ Main entry point for MatchyPatchy application
3
+ '''
4
+
5
+ import os
6
+ import sys
7
+ import time
8
+ from pathlib import Path
9
+ from PyQt6.QtWidgets import QApplication
10
+
11
+ from matchypatchy.logging_config import setup_logger, get_logger
12
+ from matchypatchy.gui import MainWindow
13
+
14
+
15
+ def setup_cuda_path():
16
+ """Dynamically find and add NVIDIA CUDA/cuDNN libraries to PATH"""
17
+ try:
18
+ # Try to find nvidia packages in site-packages
19
+ import site
20
+ site_packages = site.getsitepackages()
21
+
22
+ if isinstance(site_packages, str):
23
+ site_packages = [site_packages]
24
+
25
+ for site_dir in site_packages:
26
+ nvidia_lib_path = Path(site_dir) / "nvidia"
27
+
28
+ if nvidia_lib_path.exists():
29
+ dll_folders = [
30
+ nvidia_lib_path / "cuda_runtime" / "bin",
31
+ nvidia_lib_path / "cuda_nvrtc" / "bin",
32
+ nvidia_lib_path / "cublas" / "bin",
33
+ nvidia_lib_path / "cudnn" / "bin",
34
+ ]
35
+
36
+ for folder in dll_folders:
37
+ if folder.exists():
38
+ os.environ['PATH'] = str(folder) + os.pathsep + os.environ['PATH']
39
+
40
+ return True
41
+ except Exception as e:
42
+ print(f"Warning: Could not setup CUDA path: {e}")
43
+
44
+ return False
45
+
46
+
47
+ if __name__ == "__main__":
48
+ start_time = time.time()
49
+
50
+ # Setup application-wide logging
51
+ root_logger = setup_logger()
52
+ logger = get_logger(__name__)
53
+ logger.info("=" * 70)
54
+ logger.info("MatchyPatchy starting up...")
55
+
56
+ exit_code = 1 # Default to error; overwritten on successful run
57
+
58
+ try:
59
+ setup_cuda_path()
60
+ app = QApplication(sys.argv)
61
+ window = MainWindow(logger)
62
+ logger.info("Main window initialized")
63
+ window.show()
64
+
65
+ startup_time = time.time() - start_time
66
+ logger.info(f"Startup took {startup_time:.2f} seconds")
67
+ logger.info("-" * 70)
68
+
69
+ exit_code = app.exec()
70
+
71
+ except Exception as e:
72
+ logger.error(f"Fatal error during startup: {e}", exc_info=True)
73
+ exit_code = 1
74
+
75
+ finally:
76
+ logger.info("MatchyPatchy shutting down")
77
+ logger.info("=" * 70)
78
+ sys.exit(exit_code)
@@ -0,0 +1,25 @@
1
+ MODELS:
2
+ "MegaDetector":
3
+ - ["md_v1000.0.0-sorrel.onnx"]
4
+ - ["https://sandiegozoo.box.com/shared/static/7z9xagk8zweu6op3dgdk386jf9ayl2gt.onnx"]
5
+ "miewid_v3":
6
+ - ["miewid_v3.onnx", "miewid_v3.onnx.data"]
7
+ - ["https://sandiegozoo.box.com/shared/static/ppm0odjgscvpj9lf5ax86p3fqu5vraxw.onnx",
8
+ "https://sandiegozoo.box.com/shared/static/xi1dijx35ta2tqtu2sa28bd09ve9li6f.data"]
9
+ "Jaguar Viewpoint":
10
+ - ["sdzwa_jaguar_viewpoint.onnx", "sdzwa_jaguar_viewpoint.onnx.data"]
11
+ - ["https://sandiegozoo.box.com/shared/static/nkuku5aeicg9hugo0hogdjxg667xodlb.onnx",
12
+ "https://sandiegozoo.box.com/shared/static/3563emet6b6tubtgtqce8144dlq3z8y5.data"]
13
+
14
+
15
+ DETECTOR_MODELS:
16
+ - "MegaDetector"
17
+
18
+ REID_MODELS: ["miewid_v3"]
19
+ VIEWPOINT_MODELS: ["Jaguar Viewpoint"]
20
+
21
+ VIEWPOINTS:
22
+ 'Any': "Any"
23
+ 'None': "None"
24
+ '0': "Right"
25
+ '1': "Left"
@@ -0,0 +1,106 @@
1
+ TABLE: metadata
2
+ CREATE TABLE metadata (
3
+ id INTEGER PRIMARY KEY,
4
+ mp_version TEXT NOT NULL,
5
+ key TEXT UNIQUE NOT NULL )
6
+ INDEX: sqlite_autoindex_metadata_1
7
+ None
8
+ TABLE: region
9
+ CREATE TABLE region (
10
+ id INTEGER PRIMARY KEY,
11
+ name TEXT UNIQUE NOT NULL,
12
+ timezone TEXT)
13
+ INDEX: sqlite_autoindex_region_1
14
+ None
15
+ TABLE: survey
16
+ CREATE TABLE survey (
17
+ id INTEGER PRIMARY KEY,
18
+ name TEXT UNIQUE NOT NULL,
19
+ region_id INTEGER,
20
+ year_start INTEGER,
21
+ year_end INTEGER,
22
+ FOREIGN KEY (region_id) REFERENCES region (id) ON DELETE SET NULL)
23
+ INDEX: sqlite_autoindex_survey_1
24
+ None
25
+ TABLE: station
26
+ CREATE TABLE station (
27
+ id INTEGER PRIMARY KEY,
28
+ name TEXT NOT NULL,
29
+ lat REAL,
30
+ long REAL,
31
+ survey_id INTEGER NOT NULL,
32
+ FOREIGN KEY (survey_id) REFERENCES survey (id) ON DELETE CASCADE)
33
+ TABLE: camera
34
+ CREATE TABLE camera (
35
+ id INTEGER PRIMARY KEY,
36
+ name TEXT NOT NULL,
37
+ station_id INTEGER NOT NULL,
38
+ FOREIGN KEY (station_id) REFERENCES station (id) ON DELETE CASCADE)
39
+ TABLE: uploads
40
+ CREATE TABLE uploads (
41
+ id INTEGER PRIMARY KEY,
42
+ base_dir TEXT UNIQUE NOT NULL,
43
+ created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
44
+ INDEX: sqlite_autoindex_uploads_1
45
+ None
46
+ TABLE: media
47
+ CREATE TABLE media (
48
+ id INTEGER PRIMARY KEY,
49
+ base_dir_id INTEGER NOT NULL,
50
+ relative_path TEXT UNIQUE NOT NULL,
51
+ sha256 TEXT UNIQUE NOT NULL,
52
+ ext TEXT NOT NULL,
53
+ timestamp TEXT NOT NULL,
54
+ station_id INTEGER NOT NULL,
55
+ camera_id INTEGER,
56
+ sequence_id INTEGER,
57
+ external_id INTEGER,
58
+ comment TEXT,
59
+ FOREIGN KEY (base_dir_id) REFERENCES uploads (id) ON DELETE CASCADE,
60
+ FOREIGN KEY (station_id) REFERENCES station (id) ON DELETE CASCADE,
61
+ FOREIGN KEY (camera_id) REFERENCES camera (id) ON DELETE SET NULL,
62
+ FOREIGN KEY (sequence_id) REFERENCES sequence (id) ON DELETE SET NULL)
63
+ INDEX: sqlite_autoindex_media_1
64
+ None
65
+ INDEX: sqlite_autoindex_media_2
66
+ None
67
+ TABLE: roi
68
+ CREATE TABLE roi (
69
+ id INTEGER PRIMARY KEY,
70
+ media_id INTEGER NOT NULL,
71
+ frame INTEGER NOT NULL,
72
+ bbox_x REAL NOT NULL,
73
+ bbox_y REAL NOT NULL,
74
+ bbox_w REAL NOT NULL,
75
+ bbox_h REAL NOT NULL,
76
+ viewpoint INTEGER,
77
+ reviewed INTEGER NOT NULL,
78
+ favorite INTEGER NOT NULL,
79
+ individual_id INTEGER,
80
+ emb INTEGER,
81
+ FOREIGN KEY(media_id) REFERENCES media (id) ON DELETE CASCADE,
82
+ FOREIGN KEY(individual_id) REFERENCES individual (id) ON DELETE SET NULL)
83
+ TABLE: individual
84
+ CREATE TABLE individual (
85
+ id INTEGER PRIMARY KEY,
86
+ name TEXT NOT NULL,
87
+ sex TEXT,
88
+ age TEXT)
89
+ TABLE: sequence
90
+ CREATE TABLE sequence (id INTEGER PRIMARY KEY)
91
+ TABLE: media_thumbnails
92
+ CREATE TABLE media_thumbnails (
93
+ id INTEGER PRIMARY KEY,
94
+ fid INTEGER UNIQUE NOT NULL,
95
+ filepath TEXT NOT NULL,
96
+ FOREIGN KEY(fid) REFERENCES media (id) ON DELETE CASCADE)
97
+ INDEX: sqlite_autoindex_media_thumbnails_1
98
+ None
99
+ TABLE: roi_thumbnails
100
+ CREATE TABLE roi_thumbnails (
101
+ id INTEGER PRIMARY KEY,
102
+ fid INTEGER UNIQUE NOT NULL,
103
+ filepath TEXT NOT NULL,
104
+ FOREIGN KEY(fid) REFERENCES roi (id) ON DELETE CASCADE)
105
+ INDEX: sqlite_autoindex_roi_thumbnails_1
106
+ None
@@ -0,0 +1,188 @@
1
+ """
2
+ Functions for Handling Config Yaml
3
+
4
+ """
5
+ import os
6
+ import sys
7
+ from pathlib import Path
8
+ import yaml
9
+ import animl
10
+
11
+
12
+ class mpConfig():
13
+ def __init__(self, home_dir):
14
+ """Initiate configuration file with default values if not present"""
15
+
16
+ home_dir = Path(home_dir)
17
+
18
+ # initiate defualts
19
+ self.HOME_DIR = home_dir
20
+ self.CONFIG_PATH = home_dir / '.config.yml'
21
+ self.DB_DIR = home_dir / 'Database'
22
+ self.ML_DIR = home_dir / 'Models'
23
+ self.THUMBNAIL_DIR = home_dir / 'Thumbnails'
24
+ self.FRAME_DIR = home_dir / 'Frames'
25
+ self.BATCH_SIZE = 1
26
+ self.N_FRAMES = 3
27
+ self.SMART_FRAMES = True
28
+ self.VIDEO_FPS = 1
29
+ self.REID_KEY = None
30
+ self.VIEWPOINT_KEY = None
31
+ self.DETECTOR_KEY = None
32
+ self.KNN = 100
33
+ self.SEQUENCE_DURATION = 60
34
+ self.SEQUENCE_N = 3
35
+ # Check if CUDA is available and set DEVICE accordingly
36
+ providers = animl.get_onnx_device(quiet=True)
37
+ if "CUDAExecutionProvider" in providers:
38
+ self.DEVICE = "CUDAExecutionProvider"
39
+ else:
40
+ self.DEVICE = "CPUExecutionProvider"
41
+
42
+ # load configuration if it exists
43
+ if home_dir.exists():
44
+ self.load()
45
+ # create a new project folder and save
46
+ else:
47
+ home_dir.mkdir(parents=True, exist_ok=True)
48
+ # create necessary project folders
49
+ self.create_folders()
50
+ # save to yaml
51
+ self.save()
52
+
53
+ def load(self):
54
+ """Load configuration from the YAML file if it exists."""
55
+ if self.CONFIG_PATH.exists():
56
+ with open(self.CONFIG_PATH, 'r') as cfg_file:
57
+ cfg = yaml.safe_load(cfg_file)
58
+ self.DB_DIR = Path(cfg.get('DB_DIR', self.HOME_DIR / 'Database'))
59
+ self.ML_DIR = Path(cfg.get('ML_DIR', self.HOME_DIR / 'Models'))
60
+ self.THUMBNAIL_DIR = Path(cfg.get('THUMBNAIL_DIR', self.HOME_DIR / 'Thumbnails'))
61
+ self.FRAME_DIR = Path(cfg.get('FRAME_DIR', self.HOME_DIR / 'Frames'))
62
+ self.BATCH_SIZE = cfg.get('BATCH_SIZE', 1)
63
+ self.VIDEO_FPS = cfg.get('VIDEO_FPS', 1)
64
+ self.N_FRAMES = cfg.get('N_FRAMES', 3)
65
+ self.SMART_FRAMES = cfg.get('SMART_FRAMES', True)
66
+
67
+ self.REID_KEY = cfg.get('REID_KEY', None)
68
+ self.VIEWPOINT_KEY = cfg.get('VIEWPOINT_KEY', None)
69
+ self.DETECTOR_KEY = cfg.get('DETECTOR_KEY', None)
70
+ self.KNN = cfg.get('KNN', 100)
71
+ self.SEQUENCE_DURATION = cfg.get('SEQUENCE_DURATION', 60)
72
+ self.SEQUENCE_N = cfg.get('SEQUENCE_N', 3)
73
+ self.DEVICE = cfg.get('DEVICE', "CPUExecutionProvider")
74
+
75
+ # config file not found, save the current defaults
76
+ else:
77
+ print(f"Configuration file not found at {self.CONFIG_PATH}. Saving default configuration.")
78
+ self.HOME_DIR.mkdir(parents=True, exist_ok=True)
79
+ self.set_default()
80
+ self.save()
81
+
82
+ # make sure all necessary directories exist
83
+ self.create_folders()
84
+
85
+
86
+ def save(self):
87
+ """Save the current configuration to the YAML file."""
88
+ output_cfg = {
89
+ 'HOME_DIR': str(self.HOME_DIR),
90
+ 'DB_DIR': str(self.DB_DIR),
91
+ 'ML_DIR': str(self.ML_DIR),
92
+ 'THUMBNAIL_DIR': str(self.THUMBNAIL_DIR),
93
+ 'BATCH_SIZE': self.BATCH_SIZE,
94
+ 'VIDEO_FPS': self.VIDEO_FPS,
95
+ 'N_FRAMES': self.N_FRAMES,
96
+ 'SMART_FRAMES': self.SMART_FRAMES,
97
+ 'REID_KEY': self.REID_KEY,
98
+ 'VIEWPOINT_KEY': self.VIEWPOINT_KEY,
99
+ 'DETECTOR_KEY': self.DETECTOR_KEY,
100
+ 'KNN': self.KNN,
101
+ 'SEQUENCE_DURATION': self.SEQUENCE_DURATION,
102
+ 'SEQUENCE_N': self.SEQUENCE_N,
103
+ 'DEVICE': self.DEVICE,
104
+ }
105
+ with open(self.CONFIG_PATH, 'w') as cfg_file:
106
+ yaml.dump(output_cfg, cfg_file)
107
+
108
+ def set_default(self):
109
+ """Reset the configuration to default values."""
110
+ self.DB_DIR = self.HOME_DIR / 'Database'
111
+ self.ML_DIR = self.HOME_DIR / 'Models'
112
+ self.THUMBNAIL_DIR = self.HOME_DIR / 'Thumbnails'
113
+ self.FRAME_DIR = self.HOME_DIR / 'Frames'
114
+ self.BATCH_SIZE = 1
115
+ self.VIDEO_FPS = 1
116
+ self.N_FRAMES = 3
117
+ self.SMART_FRAMES = True
118
+ self.REID_KEY = None
119
+ self.VIEWPOINT_KEY = None
120
+ self.DETECTOR_KEY = None
121
+ self.KNN = 100
122
+ self.SEQUENCE_DURATION = 60
123
+ self.SEQUENCE_N = 3
124
+ if "CUDAExecutionProvider" in animl.get_onnx_device(quiet=True):
125
+ self.DEVICE = "CUDAExecutionProvider"
126
+ else:
127
+ self.DEVICE = "CPUExecutionProvider"
128
+
129
+ def create_folders(self):
130
+ """Create necessary project folders if they do not exist."""
131
+ self.DB_DIR.mkdir(parents=True, exist_ok=True)
132
+ self.ML_DIR.mkdir(parents=True, exist_ok=True)
133
+ self.THUMBNAIL_DIR.mkdir(parents=True, exist_ok=True)
134
+ self.FRAME_DIR.mkdir(parents=True, exist_ok=True)
135
+
136
+ def update(self, key_dict):
137
+ """Update the configuration with new key-value pairs."""
138
+ for key, value in key_dict.items():
139
+ setattr(self, key, value)
140
+
141
+ # rewrite config
142
+ self.save()
143
+
144
+ def update_home_dir(self, home_dir):
145
+ """Update the home directory and related paths."""
146
+ self.HOME_DIR = Path(home_dir)
147
+ self.DB_DIR = self.HOME_DIR / 'Database'
148
+ self.ML_DIR = self.HOME_DIR / 'Models'
149
+ self.THUMBNAIL_DIR = self.HOME_DIR / 'Thumbnails'
150
+ self.FRAME_DIR = self.HOME_DIR / 'Frames'
151
+ self.save()
152
+
153
+
154
+ # ==============================================================================
155
+ def resource_path(relative_path):
156
+ # TODO: test with installer
157
+ """ Get path to resource whether running in dev or installed bundle """
158
+ if getattr(sys, 'frozen', False):
159
+ return os.path.join(sys._MEIPASS, relative_path)
160
+
161
+ if "__file__" in globals() or "__file__" in locals():
162
+ current_location = Path(__file__).resolve()
163
+ if 'site-packages' in current_location.parts:
164
+ matchypatchy_dir = current_location.parents[0] # Go up 1 level
165
+ else:
166
+ matchypatchy_dir = current_location.parents[2] # Go up 2 levels
167
+ # Assumes this function is in src/matchypatchy/
168
+ return matchypatchy_dir / relative_path
169
+
170
+ return os.path.abspath(relative_path)
171
+
172
+
173
+ def asset_path(relative_path):
174
+ """ Get path to resource whether running in dev or installed bundle """
175
+ if getattr(sys, 'frozen', False):
176
+ return os.path.join(sys._MEIPASS, relative_path)
177
+
178
+ if "__file__" in globals() or "__file__" in locals():
179
+ current_location = Path(__file__).resolve()
180
+
181
+ if 'site-packages' in current_location.parts:
182
+ matchypatchy_dir = current_location.parents[0] # tbd
183
+ else:
184
+ matchypatchy_dir =current_location.parents[0]
185
+
186
+ return matchypatchy_dir / 'assets' / relative_path
187
+
188
+ return os.path.abspath(relative_path)
@@ -0,0 +1,54 @@
1
+ import logging
2
+ import logging.handlers
3
+ from pathlib import Path
4
+
5
+
6
+ def setup_logger(log_file="matchypatchy.log", log_level=logging.INFO):
7
+ """
8
+ Setup application-wide logger that all modules can use.
9
+ Returns the root logger configured with file and console handlers.
10
+ """
11
+
12
+ # Get root logger
13
+ root_logger = logging.getLogger()
14
+ root_logger.setLevel(log_level)
15
+
16
+ # Remove any existing handlers to avoid duplicates
17
+ for handler in root_logger.handlers[:]:
18
+ root_logger.removeHandler(handler)
19
+
20
+ # Create formatters
21
+ file_formatter = logging.Formatter(
22
+ '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
23
+ datefmt='%Y-%m-%d %H:%M:%S'
24
+ )
25
+ console_formatter = logging.Formatter(
26
+ '%(levelname)s - %(name)s - %(message)s'
27
+ )
28
+
29
+ # File handler (rotating to avoid huge log files)
30
+ log_path = Path(log_file)
31
+ file_handler = logging.handlers.RotatingFileHandler(
32
+ log_path,
33
+ maxBytes=10*1024*1024, # 10MB
34
+ backupCount=5 # Keep 5 backup files
35
+ )
36
+ file_handler.setLevel(log_level)
37
+ file_handler.setFormatter(file_formatter)
38
+ root_logger.addHandler(file_handler)
39
+
40
+ # Console handler (optional - for development)
41
+ console_handler = logging.StreamHandler()
42
+ console_handler.setLevel(logging.WARNING) # Only warnings and errors to console
43
+ console_handler.setFormatter(console_formatter)
44
+ root_logger.addHandler(console_handler)
45
+
46
+ return root_logger
47
+
48
+
49
+ def get_logger(name):
50
+ """
51
+ Get a logger for a specific module.
52
+ Use this in all your modules: logger = get_logger(__name__)
53
+ """
54
+ return logging.getLogger(name)
@@ -0,0 +1,195 @@
1
+ Metadata-Version: 2.4
2
+ Name: matchypatchy
3
+ Version: 0.2.1
4
+ Summary: GUI tool for human validation of AI-powered animal re-identification
5
+ Author-email: Kyra Swanson <tswanson@sdzwa.org>
6
+ Project-URL: Homepage, https://github.com/onservationtechlab/matchypatchy
7
+ Project-URL: Issues, https://github.com/onservationtechlab/matchypatchy/issues
8
+ Requires-Python: >=3.12
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Requires-Dist: animl-lite==3.3.2
12
+ Requires-Dist: chromadb>=1.3.4
13
+ Requires-Dist: pyqt6>=6.9.0
14
+ Dynamic: license-file
15
+
16
+ # MatchyPatchy
17
+ <br/>
18
+
19
+ [User Manual](https://conservationtechlab.github.io/matchypatchy/)
20
+
21
+ MatchyPatchy is an open-source GUI tool for human validation of AI-powered animal re-identification.\
22
+ It was developed by the San Diego Zoo Wildlife Alliance Conservation Technology Lab.\
23
+ Author: Kyra Swanson, (c) 2025
24
+ <br/>
25
+
26
+ ---
27
+ ## Installation
28
+
29
+ Matchypatchy is a stand-alone executable built in Python. Download it [here](). \
30
+ [Github Repository](https://github.com/conservationtechlab/matchypatchy)
31
+ <br/>
32
+
33
+ ---
34
+ ## Getting Started
35
+ <br/>
36
+
37
+ ### Download Models
38
+ In order to calculate potential matches, MatchyPatchy requires an animal object detector such as [MegaDetector]()
39
+ and an embedding extractor such as [MiewID](). Both models and more can be obtained from the SDZWA server by selecting
40
+ 'Download Models' and checking the box associated with which models you want to download.
41
+ <br/>
42
+
43
+ ### Select Survey
44
+ In order to add media to the database, you must first specify a Survey using
45
+ the dropdown of available surveys. To add a new survey,
46
+
47
+ 1. Select 'Manage Surveys'
48
+ 2. Select 'New'
49
+ 3. Enter Survey Name
50
+ 4. Enter Survey Region
51
+ 5. (Optional) Enter Survey Start Year
52
+ 6. (Optional) Enter Survey End Year
53
+ 7. Select 'Ok'
54
+ <br/>
55
+
56
+ ### 1. Import Images
57
+ Images can be imported via spreadsheet or by manually selecting a directory of images.
58
+
59
+ **From CSV**
60
+ 1. Select '1. Import from CSV'
61
+ 2. Open .csv file
62
+ 3. Select column headers that correspond to image Filepath, Timestamp, Survey, and Station
63
+ 4. Optionally select column headers that correspond to image Region, Sequence ID, External ID,
64
+ Viewpoint, Species, Individual ID, and Comment
65
+ 5. Select 'Ok'
66
+ <br/>
67
+
68
+ **From Folder**
69
+ 1. Select '1. Import from Folder'
70
+ 2. Open directory containing image files. Can be a whole Survey containg multiple Stations or single Station.
71
+ 3. Select the directory level that corresponds to Station name if available
72
+ 4. Select 'Ok'
73
+ <br/>
74
+
75
+ ### 2. Process Images
76
+ Run images through a sequence of AI models to obtain predicted matches.\
77
+ Note: Models must be accessible in MatchyPatchy's "Models" folder - see Configuration for more.
78
+
79
+ 1. Select '2. Process'
80
+ 2. (Optional) Check Calculate Sequence (improves performance for videos and images captured in quick succession)
81
+ 3. **Select Detector Model** - recommended MegaDetector v5a
82
+ 4. (Optional) Select Species Classifier Model
83
+ 5. **Select Re-Indentification Model** - required to obtain predicted matches, recommended MiewIDv3
84
+ 6. (Optional) Select Viewpoint Model (improves performance by estimating animal viewpoint and limiting search space)
85
+ <br/>
86
+
87
+ ### 3. Validate
88
+ After processing, this pageview allows you to review the imported media for errors, make changes, delete images, etc.
89
+ It can be accessed at any time after image import.
90
+ <br/>
91
+
92
+ Double-clicking on a cell will allow you to edit it.\
93
+ Double-clicking on a single row will pull up a screen to edit multiple fields for an image.\
94
+ Selecting one or more row (either by clicking on the row number or checking the select box) will enable the ability
95
+ to mass edit particular fields, duplicate entries, or delete entries.
96
+ <br/>
97
+
98
+ The **"Show"** Option allows you view the full images or detected ROIS.\
99
+ The **"Save"** Option saves all edits to the database.\
100
+ The **"Undo"** Option undoes the last edit made.
101
+ <br/>
102
+
103
+ **Filters** \
104
+ Images can be filtered by Region, Survey, Station, Species, and Individual.\
105
+ You can also choose to show only "Unidentified" ROIs.\
106
+ You can also display all images marked as "Favorite"
107
+ <br/>
108
+
109
+ ### 4. Match
110
+ After processing, potential matches can be validated at this pageview.
111
+ The left side contains a **Query** image and the right side contains potential **Matches**.
112
+ If "Calculate Sequence" was selected during the processing stage, the entire **Sequence** will be viewable on the Query side.
113
+ The pageview will display the images and associated metadata.
114
+ <br/>
115
+
116
+ _View Options_\
117
+ Adjustments can be made to the **Maximum Number of Matches** shown for each image (within a sequence) and to the maximum distance
118
+ threshold between the two images to qualify as a match. The **Cosine** or **L2** distance of the Match from the Query is displayed above the
119
+ match image. Select which distance metric to use in the dropdown. You must select **"Recalculate Matches"** if changes are made to either option
120
+ in order to display those changes.\
121
+ After matches are validated, you can **"Query by Individual"** to do quality control and ensure all images associated with
122
+ an individual are indeed valid.\
123
+ Images can be **Filtered** by Region, Survey, or Station to narrow the available matches shown.\
124
+ If **"Viewpoint"** was calculated at the processing step, you can filter both the **Query** and the **Match** images by Viewpoint.\
125
+ The **"View Data"** Button at the bottom brings you to the Media Validation pageview.
126
+ <br/>
127
+
128
+ _Image Options_\
129
+ You can adjust the **Brightness, Contrast** and **Sharpness** of each image, as well as **Zoom** using the mouse scroll wheel.\
130
+ The **"Reset"** button returns the image to its original form.\
131
+ The **"Edit Image"** option allows you to make changes to the metadata.\
132
+ The **"Open Image"** option opens the image in your default image viewer.\
133
+ The **"♥"** option marks the image with the "Favorite" tag.
134
+ <br/>
135
+
136
+ To confirm a match between the Query and the Match image, select the **"Match" button** in the middle, or press the 'M' or 'Space Key'.
137
+ Pressing Match again will undo the match, asking you to confirm first.\
138
+ You can navigate between Query Sequences and Matches by using the **"<<"** and **">>"** buttons, or by using the arrow keys.\
139
+ You can also toggle the **Viewpoint** by pressing 'V'.
140
+ <br/>
141
+
142
+ ### 5. Export
143
+ The database can be exported as a .csv file. Simply select '5. Export' and specify the file name and location.
144
+ <br/>
145
+
146
+ ---
147
+ ## Database Management
148
+ <br/>
149
+
150
+ ### Definitions
151
+ * Survey - An ecological study employing camera traps to investigate wildlife of a particular area.
152
+ * Region - A geographical region that may host one or more camera trap surveys.
153
+ * Station - Reference to a physical location containing one or camera traps.
154
+ * Species - The taxonomic and common names refering to a class of animal.
155
+ * Media - Image (and soon video) files obtained from camera traps.
156
+ * ROI - Regions of Interest within media files that contain animals.
157
+ * Individual - A particular, singular example of a given species, can be named/ID'd.
158
+ * Sequence ID - A unique number associated with a set of sequential images or frames in a video.
159
+ * External ID - A unique number used to reference MatchyPatchy output with other datamanagement tools.
160
+ * Viewpoint - The side of the body of the animl facing the camera, eg "Left", "Right", "Top"
161
+ * Comment - Notes or concerns about a particular media file
162
+ * Favorite - A tag marking an image as noteworthy.
163
+ <br/>
164
+
165
+ ### Manage Tables
166
+ **Survey, Station,** and **Species** tables can be managed independently.
167
+ <br/>
168
+
169
+ ### CSV Import
170
+ <br/>
171
+
172
+
173
+ ---
174
+ ## Configuration
175
+ <br/>
176
+
177
+ ### Available Models
178
+ Models currently available and compatible with MatchyPatchy:\
179
+ _Detector Models_:
180
+ - MegaDetector v5a
181
+ - MegaDetector v5b
182
+
183
+ _Re-ID Models_:
184
+ - MiewID v3
185
+ - MiewID v2
186
+
187
+ _Viewpoint Models_:
188
+ - SDZWA Viewpoint
189
+ <br/>
190
+
191
+ ### Link to New Database
192
+ Database files can be shared across multiple users of MatchyPatchy. To link to a new .db file,
193
+ <br/>
194
+
195
+ ### Clear Data
@@ -0,0 +1,19 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/matchypatchy/__init__.py
5
+ src/matchypatchy/__main__.py
6
+ src/matchypatchy/config.py
7
+ src/matchypatchy/logging_config.py
8
+ src/matchypatchy.egg-info/PKG-INFO
9
+ src/matchypatchy.egg-info/SOURCES.txt
10
+ src/matchypatchy.egg-info/dependency_links.txt
11
+ src/matchypatchy.egg-info/requires.txt
12
+ src/matchypatchy.egg-info/top_level.txt
13
+ src/matchypatchy/assets/models.yml
14
+ src/matchypatchy/assets/schema.txt
15
+ src/matchypatchy/assets/graphics/desktop_icon.ico
16
+ src/matchypatchy/assets/graphics/desktop_icon.png
17
+ src/matchypatchy/assets/graphics/fluent_pencil_icon.png
18
+ src/matchypatchy/assets/graphics/logo.png
19
+ src/matchypatchy/assets/graphics/thumbnail_notfound.png
@@ -0,0 +1,3 @@
1
+ animl-lite==3.3.2
2
+ chromadb>=1.3.4
3
+ pyqt6>=6.9.0
@@ -0,0 +1 @@
1
+ matchypatchy