added export config and user define config support
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.0 MiB |
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"name": "prototype",
|
||||||
|
"version": "1.0",
|
||||||
|
"camera": {
|
||||||
|
"resolution_raw": [1920, 1080],
|
||||||
|
"fps": 60,
|
||||||
|
"units": 15,
|
||||||
|
"units_used": 9,
|
||||||
|
"resolution_stitch": [400, 400],
|
||||||
|
"index": [1,2,3,6,7,8,11,12,13],
|
||||||
|
"pos_default": [[260, 56], [577, 62], [897, 69], [1214, 75], [1530, 81], [256, 391], [570, 397], [889, 403], [1208, 409], [1523, 416], [248, 724], [563, 730], [882, 738], [1201, 743], [1516, 751]]
|
||||||
|
},
|
||||||
|
"stitcher": {
|
||||||
|
"min_area_frac": 0.018,
|
||||||
|
"max_area_frac": 0.035,
|
||||||
|
"max_aspect_ratio": 20
|
||||||
|
},
|
||||||
|
"contact": {
|
||||||
|
"min_contour_area": 3000,
|
||||||
|
"flow_threshold":1,
|
||||||
|
"div_threshold":0.02,
|
||||||
|
"expansion_threshold": 0.01,
|
||||||
|
"downsample_factor": 1,
|
||||||
|
"kernel_size": [5,5],
|
||||||
|
"denoise_sigma": 15
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+2
-2
@@ -7,10 +7,10 @@ import time
|
|||||||
def main():
|
def main():
|
||||||
|
|
||||||
# 方式1: 从视频文件读取
|
# 方式1: 从视频文件读取
|
||||||
# sensor = orisys.Sensor("./s1.mp4", isstitch=True, cuda=True, verbose=True)
|
sensor = orisys.Sensor("./s1.mp4", isstitch=True, cuda=True, verbose=True,config_name="./config/prototype.json")
|
||||||
|
|
||||||
# 方式2: 从摄像头读取(取消注释使用)
|
# 方式2: 从摄像头读取(取消注释使用)
|
||||||
sensor = orisys.Sensor(0, isstitch=True, cuda=False, verbose=True)
|
# sensor = orisys.Sensor(0, isstitch=True, cuda=False, verbose=True,config_name="./config/prototype.json")
|
||||||
|
|
||||||
print("\n按 'q' 退出程序,按 'r' 重置光流追踪器")
|
print("\n按 'q' 退出程序,按 'r' 重置光流追踪器")
|
||||||
|
|
||||||
|
|||||||
@@ -3,30 +3,108 @@ from pathlib import Path
|
|||||||
|
|
||||||
CONFIG_DIR = Path(__file__).parent
|
CONFIG_DIR = Path(__file__).parent
|
||||||
|
|
||||||
def load_config(config_name: str):
|
def load_config(config_name_or_path):
|
||||||
"""
|
"""
|
||||||
Load sensor configuration from JSON file.
|
Load sensor configuration from JSON file.
|
||||||
|
|
||||||
|
Accepts either:
|
||||||
|
1. A file path (absolute or relative) to a JSON config file
|
||||||
|
2. A config name (without .json extension) to load from package configs directory
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
config_name: Name of the config file (without .json extension)
|
config_name_or_path: Either:
|
||||||
|
- A file path string (e.g., "/path/to/config.json" or "./config.json")
|
||||||
|
- A config name string (e.g., "prototype") to load from package configs
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Dictionary containing the configuration
|
Dictionary containing the configuration
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
FileNotFoundError: If the config file doesn't exist
|
FileNotFoundError: If the config file doesn't exist
|
||||||
|
ValueError: If the file path is not a JSON file
|
||||||
"""
|
"""
|
||||||
config_path = CONFIG_DIR / f"{config_name}.json"
|
# Convert to Path object for easier handling
|
||||||
|
config_path = Path(config_name_or_path)
|
||||||
|
|
||||||
if not config_path.exists():
|
# Check if it's an existing file (absolute or relative path)
|
||||||
|
if config_path.exists() and config_path.is_file():
|
||||||
|
# User provided a file path
|
||||||
|
if config_path.suffix.lower() != '.json':
|
||||||
|
raise ValueError(f"Config file must be a JSON file: {config_path}")
|
||||||
|
|
||||||
|
with open(config_path, 'r', encoding='utf-8') as f:
|
||||||
|
return json.load(f)
|
||||||
|
|
||||||
|
# If it's an absolute path but doesn't exist, raise error immediately
|
||||||
|
if config_path.is_absolute():
|
||||||
|
raise FileNotFoundError(f"Config file not found at absolute path: {config_path}")
|
||||||
|
|
||||||
|
# Otherwise, treat it as a config name and look in package directory
|
||||||
|
package_config_path = CONFIG_DIR / f"{config_name_or_path}.json"
|
||||||
|
|
||||||
|
if not package_config_path.exists():
|
||||||
# List available configs for better error message
|
# List available configs for better error message
|
||||||
available = [f.stem for f in CONFIG_DIR.glob("*.json")]
|
available = [f.stem for f in CONFIG_DIR.glob("*.json")]
|
||||||
available_str = ", ".join(available) if available else "none"
|
available_str = ", ".join(available) if available else "none"
|
||||||
raise FileNotFoundError(
|
raise FileNotFoundError(
|
||||||
f"Config file not found: {config_path}\n"
|
f"Config file not found: {config_name_or_path}\n"
|
||||||
f"Available configs: {available_str}"
|
f"Tried as file path: {config_path} (not found)\n"
|
||||||
|
f"Tried as package config: {package_config_path} (not found)\n"
|
||||||
|
f"Available package configs: {available_str}"
|
||||||
)
|
)
|
||||||
|
|
||||||
with open(config_path, 'r') as f:
|
with open(package_config_path, 'r', encoding='utf-8') as f:
|
||||||
return json.load(f)
|
return json.load(f)
|
||||||
|
|
||||||
|
def _format_json_value(value, indent_level=0, indent_str=" "):
|
||||||
|
"""
|
||||||
|
Recursively format JSON value with arrays/lists on single line.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value: The value to format (dict, list, or primitive)
|
||||||
|
indent_level: Current indentation level
|
||||||
|
indent_str: String used for indentation (default: 4 spaces)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Formatted string representation
|
||||||
|
"""
|
||||||
|
if isinstance(value, dict):
|
||||||
|
if not value:
|
||||||
|
return "{}"
|
||||||
|
items = []
|
||||||
|
for k, v in value.items():
|
||||||
|
key_str = json.dumps(k, ensure_ascii=False)
|
||||||
|
value_str = _format_json_value(v, indent_level + 1, indent_str)
|
||||||
|
items.append(f"{indent_str * (indent_level + 1)}{key_str}: {value_str}")
|
||||||
|
return "{\n" + ",\n".join(items) + "\n" + indent_str * indent_level + "}"
|
||||||
|
elif isinstance(value, list):
|
||||||
|
if not value:
|
||||||
|
return "[]"
|
||||||
|
# Format arrays/lists on a single line
|
||||||
|
items = [json.dumps(item, ensure_ascii=False) for item in value]
|
||||||
|
return "[" + ", ".join(items) + "]"
|
||||||
|
else:
|
||||||
|
# Primitive types (string, number, bool, None)
|
||||||
|
return json.dumps(value, ensure_ascii=False)
|
||||||
|
|
||||||
|
def export_config(config, path="./config/exported_config.json"):
|
||||||
|
"""
|
||||||
|
Export configuration to JSON file with readable formatting.
|
||||||
|
Arrays/lists are kept on a single line, while nested objects are indented.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config: Configuration dictionary to export
|
||||||
|
path: Output file path (default: "./config/exported_config.json")
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
The exported config dictionary
|
||||||
|
"""
|
||||||
|
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
with open(path, 'w', encoding='utf-8') as f:
|
||||||
|
formatted = _format_json_value(config)
|
||||||
|
f.write(formatted)
|
||||||
|
f.write('\n') # Add trailing newline
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
@@ -417,9 +417,12 @@ class Sensor:
|
|||||||
# Public API - Configuration & Calibration
|
# Public API - Configuration & Calibration
|
||||||
# =========================================================================
|
# =========================================================================
|
||||||
|
|
||||||
def get_config(self):
|
def export_config(self, path="./config/exported_config.json"):
|
||||||
"""Return current configuration dict."""
|
"""Return current configuration dict."""
|
||||||
return self.config
|
configs.export_config(self.config, path)
|
||||||
|
if self.verbose:
|
||||||
|
print(f"Config exported to {path}")
|
||||||
|
return True
|
||||||
|
|
||||||
def stitch_cal(self):
|
def stitch_cal(self):
|
||||||
"""
|
"""
|
||||||
@@ -462,8 +465,6 @@ class Sensor:
|
|||||||
self.config_stitcher = self.config["stitcher"]
|
self.config_stitcher = self.config["stitcher"]
|
||||||
self.config_contact = self.config["contact"]
|
self.config_contact = self.config["contact"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if self.verbose:
|
if self.verbose:
|
||||||
print(f"Config: {self.config_name}")
|
print(f"Config: {self.config_name}")
|
||||||
print(f" Resolution: {self.config_resolution_raw} → {self.config_resolution_stitch}")
|
print(f" Resolution: {self.config_resolution_raw} → {self.config_resolution_stitch}")
|
||||||
|
|||||||
Reference in New Issue
Block a user