camerakit 1.0.0__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) 2025 Saif Khan
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,104 @@
1
+ Metadata-Version: 2.4
2
+ Name: camerakit
3
+ Version: 1.0.0
4
+ Summary: CLI Tools and Python API for Camera Calibration and Synchronized Capture
5
+ Home-page: https://github.com/saifkhichi96/camerakit
6
+ Author: Saif Khan
7
+ Author-email: saifkhichi96@gmail.com
8
+ License: MIT License
9
+ Project-URL: Bug Tracker, https://github.com/saifkhichi96/camerakit/issues
10
+ Keywords: camera,calibration,synchronized capture
11
+ Platform: any
12
+ Classifier: Programming Language :: Python :: 3
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Information Technology
17
+ Classifier: Intended Audience :: End Users/Desktop
18
+ Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
22
+ Classifier: Topic :: Multimedia :: Video
23
+ Classifier: Topic :: Multimedia :: Graphics
24
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
25
+ Description-Content-Type: text/markdown
26
+ License-File: LICENSE
27
+ Requires-Dist: easydict
28
+ Requires-Dist: matplotlib
29
+ Requires-Dist: mpl_interactions
30
+ Requires-Dist: numpy
31
+ Requires-Dist: opencv-python
32
+ Requires-Dist: toml
33
+ Dynamic: license-file
34
+
35
+ # CameraKit: CLI Tools and Python API for Camera Calibration and Synchronized Capture
36
+
37
+ CameraKit is a Python package that provides command-line tools and an API for camera calibration and synchronized capture. It has the following features:
38
+
39
+ - Camera calibration using checkerboard images or video
40
+ - Synchronized capture from multiple cameras
41
+
42
+ ## Installation
43
+
44
+ You can install CameraKit using pip:
45
+
46
+ ```bash
47
+ pip install camerakit
48
+ ```
49
+
50
+ ## Usage
51
+
52
+ ### Command-Line Interface
53
+
54
+ You can use the command-line interface to perform camera calibration and capture images. Here are some examples:
55
+
56
+ ```bash
57
+ # Calibrate a camera using checkerboard images
58
+ ck-calibrate --images path/to/checkerboard/images --output calibration.toml
59
+ ```
60
+
61
+ ```bash
62
+ # Capture images from multiple cameras
63
+ ck-capture --cameras camera1,camera2 --output path/to/output
64
+ ```
65
+
66
+ ### Python API
67
+ You can also use CameraKit as a Python library. Here is an example of how to use it:
68
+
69
+ ```python
70
+ from camerakit.calibration import calibrate_camera
71
+ calibration_data = calibrate_camera(
72
+ images='path/to/checkerboard/images',
73
+ output='calibration.toml'
74
+ )
75
+ print(calibration_data)
76
+ ```
77
+
78
+ ## Contributing
79
+ Contributions are welcome! If you find a bug or have a feature request, please open an issue on GitHub. You can also submit a pull request with your changes.
80
+
81
+ ## License
82
+ CameraKit is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
83
+
84
+ MIT License
85
+
86
+ Copyright (c) 2025 Saif Khan
87
+
88
+ Permission is hereby granted, free of charge, to any person obtaining a copy
89
+ of this software and associated documentation files (the "Software"), to deal
90
+ in the Software without restriction, including without limitation the rights
91
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
92
+ copies of the Software, and to permit persons to whom the Software is
93
+ furnished to do so, subject to the following conditions:
94
+
95
+ The above copyright notice and this permission notice shall be included in all
96
+ copies or substantial portions of the Software.
97
+
98
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
99
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
100
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
101
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
102
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
103
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
104
+ SOFTWARE.
@@ -0,0 +1,48 @@
1
+ # CameraKit: CLI Tools and Python API for Camera Calibration and Synchronized Capture
2
+
3
+ CameraKit is a Python package that provides command-line tools and an API for camera calibration and synchronized capture. It has the following features:
4
+
5
+ - Camera calibration using checkerboard images or video
6
+ - Synchronized capture from multiple cameras
7
+
8
+ ## Installation
9
+
10
+ You can install CameraKit using pip:
11
+
12
+ ```bash
13
+ pip install camerakit
14
+ ```
15
+
16
+ ## Usage
17
+
18
+ ### Command-Line Interface
19
+
20
+ You can use the command-line interface to perform camera calibration and capture images. Here are some examples:
21
+
22
+ ```bash
23
+ # Calibrate a camera using checkerboard images
24
+ ck-calibrate --images path/to/checkerboard/images --output calibration.toml
25
+ ```
26
+
27
+ ```bash
28
+ # Capture images from multiple cameras
29
+ ck-capture --cameras camera1,camera2 --output path/to/output
30
+ ```
31
+
32
+ ### Python API
33
+ You can also use CameraKit as a Python library. Here is an example of how to use it:
34
+
35
+ ```python
36
+ from camerakit.calibration import calibrate_camera
37
+ calibration_data = calibrate_camera(
38
+ images='path/to/checkerboard/images',
39
+ output='calibration.toml'
40
+ )
41
+ print(calibration_data)
42
+ ```
43
+
44
+ ## Contributing
45
+ Contributions are welcome! If you find a bug or have a feature request, please open an issue on GitHub. You can also submit a pull request with your changes.
46
+
47
+ ## License
48
+ CameraKit is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
@@ -0,0 +1,15 @@
1
+ from .calibration import run_calibration
2
+ from .core import CalibrationData, CalibrationFile, CameraInfo
3
+ from .utils import SynchronizedVideoCapture, find_cameras, get_camera_properties
4
+ from .version import __version__
5
+
6
+
7
+ __all__ = [
8
+ "CalibrationData",
9
+ "CameraInfo",
10
+ "CalibrationFile",
11
+ "SynchronizedVideoCapture",
12
+ "find_cameras",
13
+ "get_camera_properties",
14
+ "run_calibration",
15
+ ]
@@ -0,0 +1,180 @@
1
+ import os
2
+ import time
3
+ from copy import deepcopy
4
+ from datetime import datetime
5
+
6
+ import toml
7
+
8
+ from .utils import calibrate_cams_all, setup_logging
9
+
10
+
11
+ def recursive_update(dict_to_update, dict_with_new_values):
12
+ """
13
+ Update nested dictionaries without overwriting existing keys in any level of nesting
14
+
15
+ Example:
16
+ dict_to_update = {'key': {'key_1': 'val_1', 'key_2': 'val_2'}}
17
+ dict_with_new_values = {'key': {'key_1': 'val_1_new'}}
18
+ returns {'key': {'key_1': 'val_1_new', 'key_2': 'val_2'}}
19
+ while dict_to_update.update(dict_with_new_values) would return {'key': {'key_1': 'val_1_new'}}
20
+ """
21
+
22
+ for key, value in dict_with_new_values.items():
23
+ if (
24
+ key in dict_to_update
25
+ and isinstance(value, dict)
26
+ and isinstance(dict_to_update[key], dict)
27
+ ):
28
+ # Recursively update nested dictionaries
29
+ dict_to_update[key] = recursive_update(dict_to_update[key], value)
30
+ else:
31
+ # Update or add new key-value pairs
32
+ dict_to_update[key] = value
33
+
34
+ return dict_to_update
35
+
36
+
37
+ def determine_level(config_dir):
38
+ """
39
+ Determine the level at which the function is called.
40
+ Level = 1: Trial folder
41
+ Level = 2: Root folder
42
+ """
43
+
44
+ len_paths = [
45
+ len(root.split(os.sep))
46
+ for root, dirs, files in os.walk(config_dir)
47
+ if "Config.toml" in files
48
+ ]
49
+ if len_paths == []:
50
+ raise FileNotFoundError(
51
+ "You need a Config.toml file in each trial or root folder."
52
+ )
53
+ return max(len_paths) - min(len_paths) + 1
54
+
55
+
56
+ def read_config_files(config):
57
+ """
58
+ Read Root and Trial configuration files,
59
+ and output a dictionary with all the parameters.
60
+ """
61
+
62
+ if isinstance(config, dict):
63
+ level = 2 # log_dir = os.getcwd()
64
+ config_dicts = [config]
65
+ if config_dicts[0].get("project").get("project_dir") is None:
66
+ raise ValueError(
67
+ 'Please specify the project directory in config_dict:\n \
68
+ config_dict.get("project").update({"project_dir":"<YOUR_PROJECT_DIRECTORY>"})'
69
+ )
70
+ else:
71
+ # if launched without an argument, config is None, else it is the path to the config directory
72
+ config_dir = ["." if config is None else config][0]
73
+ level = determine_level(config_dir)
74
+
75
+ # Trial level
76
+ if level == 1: # Trial
77
+ try:
78
+ # if batch
79
+ session_config_dict = toml.load(
80
+ os.path.join(config_dir, "..", "Config.toml")
81
+ )
82
+ trial_config_dict = toml.load(os.path.join(config_dir, "Config.toml"))
83
+ session_config_dict = recursive_update(
84
+ session_config_dict, trial_config_dict
85
+ )
86
+ except Exception:
87
+ # if single trial
88
+ session_config_dict = toml.load(os.path.join(config_dir, "Config.toml"))
89
+ session_config_dict.get("project").update({"project_dir": config_dir})
90
+ config_dicts = [session_config_dict]
91
+
92
+ # Root level
93
+ if level == 2:
94
+ session_config_dict = toml.load(os.path.join(config_dir, "Config.toml"))
95
+ config_dicts = []
96
+ # Create config dictionaries for all trials of the participant
97
+ for root, dirs, files in os.walk(config_dir):
98
+ if "Config.toml" in files and root != config_dir:
99
+ trial_config_dict = toml.load(os.path.join(root, files[0]))
100
+ # deep copy, otherwise session_config_dict is modified at each iteration within the config_dicts list
101
+ temp_dict = deepcopy(session_config_dict)
102
+ temp_dict = recursive_update(temp_dict, trial_config_dict)
103
+ temp_dict.get("project").update(
104
+ {"project_dir": os.path.join(config_dir, os.path.relpath(root))}
105
+ )
106
+ if os.path.basename(root) not in temp_dict.get("project").get(
107
+ "exclude_from_batch"
108
+ ):
109
+ config_dicts.append(temp_dict)
110
+
111
+ return level, config_dicts
112
+
113
+
114
+ def run_calibration(config=None):
115
+ """
116
+ Cameras calibration from checkerboards or from qualisys files.
117
+
118
+ config can be a dictionary,
119
+ or a the directory path of a trial, participant, or session,
120
+ or the function can be called without an argument, in which case it the config directory is the current one.
121
+ """
122
+
123
+ level, config_dicts = read_config_files(config)
124
+ config_dict = config_dicts[0]
125
+ try:
126
+ session_dir = os.path.realpath(
127
+ [os.getcwd() if level == 2 else os.path.join(os.getcwd(), "..")][0]
128
+ )
129
+ [
130
+ os.path.join(session_dir, c)
131
+ for c in os.listdir(session_dir)
132
+ if "calib" in c.lower() and not c.lower().endswith(".py")
133
+ ][0]
134
+ except Exception:
135
+ session_dir = os.path.realpath(os.getcwd())
136
+ config_dict.get("project").update({"project_dir": session_dir})
137
+
138
+ # Set up logging
139
+ logger = setup_logging(session_dir)
140
+ currentDateAndTime = datetime.now()
141
+
142
+ # Run calibration
143
+ calib_dir = [
144
+ os.path.join(session_dir, c)
145
+ for c in os.listdir(session_dir)
146
+ if os.path.isdir(os.path.join(session_dir, c)) and "calib" in c.lower()
147
+ ][0]
148
+ logger.info(
149
+ "\n---------------------------------------------------------------------"
150
+ )
151
+ logger.info("Camera calibration")
152
+ logger.info(f"On {currentDateAndTime.strftime('%A %d. %B %Y, %H:%M:%S')}")
153
+ logger.info(f"Calibration directory: {calib_dir}")
154
+ logger.info(
155
+ "---------------------------------------------------------------------\n"
156
+ )
157
+ start = time.time()
158
+
159
+ calibrate_cams_all(config_dict)
160
+
161
+ end = time.time()
162
+ logger.info(f"\nCalibration took {end - start:.2f} s.\n")
163
+
164
+
165
+ def main():
166
+ import argparse
167
+
168
+ parser = argparse.ArgumentParser(description="Camera calibration script")
169
+ parser.add_argument(
170
+ "--config",
171
+ type=str,
172
+ default=None,
173
+ help="Path to the configuration directory or file. If not provided, uses the current directory.",
174
+ )
175
+ args = parser.parse_args()
176
+ run_calibration(args.config)
177
+
178
+
179
+ if __name__ == "__main__":
180
+ main()