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.
- matchypatchy-0.2.1/LICENSE +21 -0
- matchypatchy-0.2.1/PKG-INFO +195 -0
- matchypatchy-0.2.1/README.md +180 -0
- matchypatchy-0.2.1/pyproject.toml +42 -0
- matchypatchy-0.2.1/setup.cfg +4 -0
- matchypatchy-0.2.1/src/matchypatchy/__init__.py +105 -0
- matchypatchy-0.2.1/src/matchypatchy/__main__.py +78 -0
- matchypatchy-0.2.1/src/matchypatchy/assets/graphics/desktop_icon.ico +0 -0
- matchypatchy-0.2.1/src/matchypatchy/assets/graphics/desktop_icon.png +0 -0
- matchypatchy-0.2.1/src/matchypatchy/assets/graphics/fluent_pencil_icon.png +0 -0
- matchypatchy-0.2.1/src/matchypatchy/assets/graphics/logo.png +0 -0
- matchypatchy-0.2.1/src/matchypatchy/assets/graphics/thumbnail_notfound.png +0 -0
- matchypatchy-0.2.1/src/matchypatchy/assets/models.yml +25 -0
- matchypatchy-0.2.1/src/matchypatchy/assets/schema.txt +106 -0
- matchypatchy-0.2.1/src/matchypatchy/config.py +188 -0
- matchypatchy-0.2.1/src/matchypatchy/logging_config.py +54 -0
- matchypatchy-0.2.1/src/matchypatchy.egg-info/PKG-INFO +195 -0
- matchypatchy-0.2.1/src/matchypatchy.egg-info/SOURCES.txt +19 -0
- matchypatchy-0.2.1/src/matchypatchy.egg-info/dependency_links.txt +1 -0
- matchypatchy-0.2.1/src/matchypatchy.egg-info/requires.txt +3 -0
- matchypatchy-0.2.1/src/matchypatchy.egg-info/top_level.txt +1 -0
|
@@ -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,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)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
matchypatchy
|