ajustes no bayer padrao e extract bayer channels

This commit is contained in:
Diego Freitas 2026-05-12 10:23:09 -03:00
parent 4a04ab6b18
commit d886e282f8
11 changed files with 310 additions and 37 deletions

View File

@ -144,7 +144,7 @@ def main():
parser.add_argument("--height", type=int, default=RAW_SIZE[1], help="Altura óptica da câmera.") parser.add_argument("--height", type=int, default=RAW_SIZE[1], help="Altura óptica da câmera.")
parser.add_argument("--interval", type=float, default=1.0, help="Intervalo em segundos para auto-save quando ligado.") parser.add_argument("--interval", type=float, default=1.0, help="Intervalo em segundos para auto-save quando ligado.")
parser.add_argument("--preview_upscale", type=int, default=2, help="Fator de upscale visual do preview.") parser.add_argument("--preview_upscale", type=int, default=2, help="Fator de upscale visual do preview.")
parser.add_argument("--bayer", default="RGGB", choices=["GBRG", "GRBG", "RGGB", "BGGR"], help="Padrão Bayer das câmeras.") parser.add_argument("--bayer", default="BGGR", choices=["GBRG", "GRBG", "RGGB", "BGGR"], help="Padrão Bayer das câmeras.")
parser.add_argument("--output_dtype", default="float32", choices=["uint8", "uint16", "float32"], help="Dtype do payload processado no Pi.") parser.add_argument("--output_dtype", default="float32", choices=["uint8", "uint16", "float32"], help="Dtype do payload processado no Pi.")
parser.add_argument("--frame_type", default="RAW_BRUTO", choices=["RAW_BRUTO", "RGB", "MULTISPEC"], help="Tipo de payload pedido ao Pi.") parser.add_argument("--frame_type", default="RAW_BRUTO", choices=["RAW_BRUTO", "RGB", "MULTISPEC"], help="Tipo de payload pedido ao Pi.")
parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"], help="Modo de captura desejado no módulo.") parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"], help="Modo de captura desejado no módulo.")

View File

@ -14,7 +14,7 @@ class OakFcc3Client:
self, self,
width=640, width=640,
height=400, height=400,
bayer="RGGB", bayer="BGGR",
fps=30, fps=30,
frame_type="RAW_BRUTO", frame_type="RAW_BRUTO",
output_dtype="uint8", output_dtype="uint8",

View File

@ -33,8 +33,8 @@ class OakFcc3Manager:
self.roles = roles or { self.roles = roles or {
"CAM_A": "rgb", "CAM_A": "rgb",
"CAM_B": "nir", "CAM_B": "re",
"CAM_C": "re", "CAM_C": "nir",
} }
self.sync_mode = sync_mode self.sync_mode = sync_mode

View File

@ -7,10 +7,13 @@ from typing import Optional
class RawProcessorCore: class RawProcessorCore:
def __init__(self, sensor_width: int, sensor_height: int, bayer_pattern: str = "GBRG", calibration_json_path=None): def __init__(self, sensor_width: int, sensor_height: int, bayer_pattern: str = "BGGR", calibration_json_path=None):
self.sensor_width = sensor_width self.sensor_width = sensor_width
self.sensor_height = sensor_height self.sensor_height = sensor_height
self.bayer_pattern = bayer_pattern.upper() self.bayer_pattern = bayer_pattern.upper()
self.rgb_processing_config = {
"mode": "linear_demosaic", # "linear_demosaic" ou "bayer_planes"
}
self.fusion_config = { self.fusion_config = {
"alignment_mode": "manual_affine", "alignment_mode": "manual_affine",
@ -174,39 +177,42 @@ class RawProcessorCore:
return raw16 return raw16
def extract_bayer_channels(self, raw16: np.ndarray) -> dict: def extract_bayer_channels(self, raw16: np.ndarray) -> dict:
p = self.bayer_pattern p = self.bayer_pattern.upper()
if p == "GBRG": if p == "RGGB":
g1 = raw16[0::2, 0::2] r = raw16[0::2, 0::2]
b = raw16[0::2, 1::2]
r = raw16[1::2, 0::2]
g2 = raw16[1::2, 1::2]
elif p == "GRBG":
g1 = raw16[0::2, 0::2]
r = raw16[0::2, 1::2]
b = raw16[1::2, 0::2]
g2 = raw16[1::2, 1::2]
elif p == "RGGB":
b = raw16[0::2, 0::2]
g1 = raw16[0::2, 1::2] g1 = raw16[0::2, 1::2]
g2 = raw16[1::2, 0::2] g2 = raw16[1::2, 0::2]
r = raw16[1::2, 1::2] b = raw16[1::2, 1::2]
elif p == "BGGR": elif p == "BGGR":
b = raw16[0::2, 0::2] b = raw16[0::2, 0::2]
g1 = raw16[0::2, 1::2] g1 = raw16[0::2, 1::2]
g2 = raw16[1::2, 0::2] g2 = raw16[1::2, 0::2]
r = raw16[1::2, 1::2] r = raw16[1::2, 1::2]
elif p == "GRBG":
g1 = raw16[0::2, 0::2]
r = raw16[0::2, 1::2]
b = raw16[1::2, 0::2]
g2 = raw16[1::2, 1::2]
elif p == "GBRG":
g1 = raw16[0::2, 0::2]
b = raw16[0::2, 1::2]
r = raw16[1::2, 0::2]
g2 = raw16[1::2, 1::2]
else: else:
raise ValueError(f"Padrão Bayer não suportado: {p}") raise ValueError(f"Padrão Bayer não suportado: {p}")
return {"R": r, "G1": g1, "G2": g2, "B": b} return {"R": r, "G1": g1, "G2": g2, "B": b}
def build_training_rgb( def bayer_planes_to_rgb_linear(
self, self,
raw16: np.ndarray, raw16: np.ndarray,
output_dtype: str = "float32",
bit_depth: int = 10, bit_depth: int = 10,
) -> np.ndarray: ) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
ch = self.extract_bayer_channels(raw16) ch = self.extract_bayer_channels(raw16)
max_val = float((1 << bit_depth) - 1) max_val = float((1 << bit_depth) - 1)
@ -215,12 +221,75 @@ class RawProcessorCore:
g = ((ch["G1"].astype(np.float32) + ch["G2"].astype(np.float32)) * 0.5) / max_val g = ((ch["G1"].astype(np.float32) + ch["G2"].astype(np.float32)) * 0.5) / max_val
b = ch["B"].astype(np.float32) / max_val b = ch["B"].astype(np.float32) / max_val
return (
np.clip(r, 0.0, 1.0),
np.clip(g, 0.0, 1.0),
np.clip(b, 0.0, 1.0),
)
def demosaic_raw16_to_rgb_linear(
self,
raw16: np.ndarray,
bit_depth: int = 10,
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
code_map = {
"RGGB": cv2.COLOR_BayerRG2BGR_EA,
"BGGR": cv2.COLOR_BayerBG2BGR_EA,
"GRBG": cv2.COLOR_BayerGR2BGR_EA,
"GBRG": cv2.COLOR_BayerGB2BGR_EA,
}
p = self.bayer_pattern.upper()
if p not in code_map:
raise ValueError(f"Padrão Bayer não suportado para demosaic: {p}")
raw16 = np.asarray(raw16)
if raw16.dtype != np.uint16:
raw16 = raw16.astype(np.uint16)
out = cv2.cvtColor(raw16, code_map[p])
max_val = float((1 << bit_depth) - 1)
out = np.clip(out.astype(np.float32) / max_val, 0.0, 1.0)
r = out[:, :, 0]
g = out[:, :, 1]
b = out[:, :, 2]
return r, g, b
def build_training_rgb(
self,
raw16: np.ndarray,
output_dtype: str = "float32",
bit_depth: int = 10,
) -> np.ndarray:
rgb_mode = str(
(getattr(self, "rgb_processing_config", {}) or {}).get("mode", "linear_demosaic")
).lower()
if rgb_mode in ("linear_demosaic", "demosaic", "full_res"):
r, g, b = self.demosaic_raw16_to_rgb_linear(
raw16,
bit_depth=bit_depth,
)
elif rgb_mode in ("bayer_planes", "bayer", "half_res"):
r, g, b = self.bayer_planes_to_rgb_linear(
raw16,
bit_depth=bit_depth,
)
else:
raise ValueError(f"rgb_processing.mode inválido: {rgb_mode}")
rgb_cal = getattr(self, "rgb_calibration", {}) or {} rgb_cal = getattr(self, "rgb_calibration", {}) or {}
if rgb_cal.get("enabled", False): if rgb_cal.get("enabled", False):
gains = rgb_cal.get("gains", {}) or {} gains = rgb_cal.get("gains", {}) or {}
r *= float(gains.get("R", 1.0)) r = r * float(gains.get("R", 1.0))
g *= float(gains.get("G", 1.0)) g = g * float(gains.get("G", 1.0))
b *= float(gains.get("B", 1.0)) b = b * float(gains.get("B", 1.0))
chw = np.stack([r, g, b], axis=0).astype(np.float32) chw = np.stack([r, g, b], axis=0).astype(np.float32)
chw = np.clip(chw, 0.0, 1.0) chw = np.clip(chw, 0.0, 1.0)
@ -767,6 +836,47 @@ class RawProcessorCore:
h, w = out.shape[1], out.shape[2] h, w = out.shape[1], out.shape[2]
result["tensor_stats_before"] = self._tensor_channel_stats(out, channel_names) result["tensor_stats_before"] = self._tensor_channel_stats(out, channel_names)
# Guarda anti-roxo para normalização por patches.
# Usa uma máscara comum RGB calculada antes de qualquer escala.
patch_sat_guard_enabled = bool(cfg.get("rgb_saturation_guard_enabled", True))
patch_sat_guard_mode = str(cfg.get("rgb_saturation_guard_mode", "fade_strength")).lower()
patch_sat_soft_start = float(cfg.get("rgb_saturation_soft_start", 0.88))
patch_sat_hard = float(cfg.get("rgb_saturation_hard", 0.97))
patch_sat_threshold = float(cfg.get("rgb_saturation_threshold", 0.97))
rgb_original = out[:3].copy() if out.shape[0] >= 3 else None
rgb_sat_mask = None
rgb_strength_mask = None
if patch_sat_guard_enabled and rgb_original is not None:
rgb_max = np.max(rgb_original, axis=0)
rgb_sat_mask = rgb_max >= patch_sat_threshold
denom = max(patch_sat_hard - patch_sat_soft_start, 1e-6)
t = (rgb_max - patch_sat_soft_start) / denom
t = np.clip(t, 0.0, 1.0)
# 1.0 = aplica normalização normal
# 0.0 = preserva original
rgb_strength_mask = 1.0 - t
result["rgb_saturation_guard"] = {
"enabled": True,
"mode": patch_sat_guard_mode,
"soft_start": patch_sat_soft_start,
"hard": patch_sat_hard,
"threshold": patch_sat_threshold,
"sat_pct": float(np.mean(rgb_sat_mask) * 100.0),
"mean_strength": float(np.mean(rgb_strength_mask)),
}
else:
result["rgb_saturation_guard"] = {
"enabled": False
}
# Para o tensor final fusionado, a geometria de referência é o espaço do RGB. # Para o tensor final fusionado, a geometria de referência é o espaço do RGB.
# Como RE/NIR são alinhados por homografia para casar no RGB, as ROIs usadas # Como RE/NIR são alinhados por homografia para casar no RGB, as ROIs usadas
# na normalização final devem ser as ROIs da role rgb, com suporte a múltiplas # na normalização final devem ser as ROIs da role rgb, com suporte a múltiplas
@ -876,6 +986,26 @@ class RawProcessorCore:
output_after_clip_stats = self._array01_stats(out_ch) output_after_clip_stats = self._array01_stats(out_ch)
out[ci] = out_ch out[ci] = out_ch
# Anti-roxo: não deixa patch_normalization recolorir pixels RGB saturados.
if (
patch_sat_guard_enabled
and ci < 3
and rgb_original is not None
and rgb_strength_mask is not None
):
original_ch = rgb_original[ci]
if patch_sat_guard_mode == "skip":
if rgb_sat_mask is not None:
out_ch = np.where(rgb_sat_mask, original_ch, out_ch)
elif patch_sat_guard_mode == "fade_strength":
# Mistura entre canal original e canal normalizado.
# Em região normal: strength=1 -> usa out_ch.
# Em saturação: strength=0 -> preserva original.
s = rgb_strength_mask.astype(np.float32)
out_ch = original_ch * (1.0 - s) + out_ch * s
result["scales"][ch_name] = { result["scales"][ch_name] = {
"scale": scale, "scale": scale,
"scale_raw_gray": scale_raw, "scale_raw_gray": scale_raw,
@ -1478,6 +1608,12 @@ class RawProcessorCore:
with open(path, "r", encoding="utf-8") as f: with open(path, "r", encoding="utf-8") as f:
data = json.load(f) data = json.load(f)
self.bayer_pattern = data.get("bayer_pattern", self.bayer_pattern)
rgb_proc = data.get("rgb_processing")
if isinstance(rgb_proc, dict):
self.rgb_processing_config = self._merge_config(self.rgb_processing_config, rgb_proc)
fusion = data.get("fusion_config") fusion = data.get("fusion_config")
if isinstance(fusion, dict): if isinstance(fusion, dict):
self.fusion_config = self._merge_config(self.fusion_config, fusion) self.fusion_config = self._merge_config(self.fusion_config, fusion)
@ -1693,6 +1829,11 @@ class RawProcessorCore:
clip_output = bool(cfg.get("clip_output", True)) clip_output = bool(cfg.get("clip_output", True))
corrected = {} corrected = {}
# Guarda anti-roxo / anti-artefato em saturação
sat_guard_enabled = bool(cfg.get("saturation_guard_enabled", True))
sat_mode = str(cfg.get("saturation_guard_mode", "fade_strength")).lower()
sat_threshold = float(cfg.get("saturation_guard_threshold", 0.97))
for cam_id, item in decoded.items(): for cam_id, item in decoded.items():
role = str(item.get("role") or item.get("meta", {}).get("role") or "").lower() role = str(item.get("role") or item.get("meta", {}).get("role") or "").lower()
img = item.get("image") img = item.get("image")
@ -1711,11 +1852,20 @@ class RawProcessorCore:
out = img.astype(np.float32).copy() out = img.astype(np.float32).copy()
# Máscara comum RGB:
# se qualquer canal estiver perto de saturar, tratamos os 3 canais juntos.
# Isso evita R/G/B receberem correções diferentes e criarem magenta/roxo.
saturation_mask = None
if sat_guard_enabled:
rgb_max = np.max(out[:, :, :3], axis=2)
saturation_mask = rgb_max >= sat_threshold
for idx, ch in enumerate(("R", "G", "B")): for idx, ch in enumerate(("R", "G", "B")):
out[:, :, idx] = self._apply_flat_gain_single_channel( out[:, :, idx] = self._apply_flat_gain_single_channel(
out[:, :, idx], out[:, :, idx],
ch, ch,
clip_output=clip_output, clip_output=clip_output,
saturation_mask=saturation_mask,
) )
new_item["image"] = out new_item["image"] = out
@ -1723,10 +1873,18 @@ class RawProcessorCore:
elif role in ("re", "nir"): elif role in ("re", "nir"):
ch = "RE" if role == "re" else "NIR" ch = "RE" if role == "re" else "NIR"
# Para RE/NIR a guarda pode ser por canal mesmo.
# Não existe cor roxa aqui, mas ainda evita mexer em pixels clipados.
saturation_mask = None
img_f = img.astype(np.float32)
if sat_guard_enabled:
saturation_mask = img_f >= sat_threshold
new_item["image"] = self._apply_flat_gain_single_channel( new_item["image"] = self._apply_flat_gain_single_channel(
img.astype(np.float32), img_f,
ch, ch,
clip_output=clip_output, clip_output=clip_output,
saturation_mask=saturation_mask,
) )
else: else:
@ -1735,6 +1893,12 @@ class RawProcessorCore:
new_meta["flatfield_applied"] = True new_meta["flatfield_applied"] = True
new_meta["flatfield_map_type"] = cfg.get("map_type", "gain") new_meta["flatfield_map_type"] = cfg.get("map_type", "gain")
new_meta["flatfield_saturation_guard"] = {
"enabled": sat_guard_enabled,
"mode": sat_mode,
"threshold": sat_threshold,
}
new_item["meta"] = new_meta new_item["meta"] = new_meta
corrected[cam_id] = new_item corrected[cam_id] = new_item
@ -1768,7 +1932,7 @@ class RawProcessorCore:
out = np.maximum(base - dark, 0.0) out = np.maximum(base - dark, 0.0)
return out.astype(np.float32, copy=False) return out.astype(np.float32, copy=False)
def _apply_flat_gain_single_channel( def _apply_flat_gain_single_channel_bkp(
self, self,
img: np.ndarray, img: np.ndarray,
channel_name: str, channel_name: str,
@ -1801,6 +1965,115 @@ class RawProcessorCore:
return out.astype(np.float32, copy=False) return out.astype(np.float32, copy=False)
def _apply_flat_gain_single_channel(
self,
img: np.ndarray,
channel_name: str,
clip_output: bool = True,
saturation_mask: np.ndarray | None = None,
) -> np.ndarray:
ch = str(channel_name).upper()
entry = self.flatfield_maps.get(ch)
if not entry:
return img.astype(np.float32, copy=False)
gain = entry.get("gain")
if gain is None:
return img.astype(np.float32, copy=False)
cfg = self.flatfield_config or {}
base = img.astype(np.float32)
gain = gain.astype(np.float32)
if gain.shape[:2] != base.shape[:2]:
gain = cv2.resize(
gain,
(base.shape[1], base.shape[0]),
interpolation=cv2.INTER_LINEAR,
)
# Suavização extra em runtime.
# Útil para corrigir apenas o borrão grande, não microtextura/ruído.
runtime_smooth_ksize = int(cfg.get("runtime_smooth_ksize", 0) or 0)
if runtime_smooth_ksize >= 3:
if runtime_smooth_ksize % 2 == 0:
runtime_smooth_ksize += 1
gain = cv2.GaussianBlur(
gain,
(runtime_smooth_ksize, runtime_smooth_ksize),
0,
)
# Intensidade global e por canal:
# strength=0.0 -> não aplica flatfield
# strength=1.0 -> aplica mapa integral
strength = float(cfg.get("strength", 1.0))
strength_by_channel = cfg.get("strength_by_channel", {}) or {}
if ch in strength_by_channel:
try:
strength = float(strength_by_channel[ch])
except Exception:
pass
gain_min_runtime = float(cfg.get("gain_min_runtime", 0.0))
gain_max_runtime = float(cfg.get("gain_max_runtime", 999.0))
# Guarda de saturação.
sat_guard_enabled = bool(cfg.get("saturation_guard_enabled", True))
sat_mode = str(cfg.get("saturation_guard_mode", "fade_strength")).lower()
sat_soft_start = float(cfg.get("saturation_guard_soft_start", 0.90))
sat_hard = float(cfg.get("saturation_guard_hard", 0.98))
# Se não veio uma máscara RGB comum, usa máscara do próprio canal.
if saturation_mask is None and sat_guard_enabled:
sat_threshold = float(cfg.get("saturation_guard_threshold", 0.97))
saturation_mask = base >= sat_threshold
# ============================================================
# Calcula ganho efetivo
# ============================================================
if sat_guard_enabled and sat_mode == "fade_strength":
# Reduz gradualmente a força do flatfield conforme aproxima saturação.
# A força cai de 1.0 para 0.0 entre soft_start e hard.
denom = max(sat_hard - sat_soft_start, 1e-6)
t = (base - sat_soft_start) / denom
t = np.clip(t, 0.0, 1.0)
# strength_mask:
# 1.0 longe da saturação
# 0.0 perto/acima de sat_hard
strength_mask = 1.0 - t
# Se uma máscara comum RGB foi passada, zera força nesses pixels.
# Isso mantém a neutralidade entre R/G/B em pixels suspeitos.
if saturation_mask is not None:
strength_mask = np.where(saturation_mask, 0.0, strength_mask)
gain_eff = 1.0 + (strength * strength_mask) * (gain - 1.0)
else:
# Modo normal com força fixa.
gain_eff = 1.0 + strength * (gain - 1.0)
gain_eff = np.clip(gain_eff, gain_min_runtime, gain_max_runtime)
out = base * gain_eff
# Modo skip: onde saturou, não aplica flatfield.
# O pixel continua queimado, mas não vira magenta/roxo artificial.
if sat_guard_enabled and sat_mode == "skip" and saturation_mask is not None:
out = np.where(saturation_mask, base, out)
if clip_output:
out = np.clip(out, 0.0, 1.0)
return out.astype(np.float32, copy=False)
def normalize_decoded_by_capture_controls(self, decoded: dict, meta: dict | None = None) -> dict: def normalize_decoded_by_capture_controls(self, decoded: dict, meta: dict | None = None) -> dict:
cfg = self.radiometric_normalization_config or {} cfg = self.radiometric_normalization_config or {}

View File

@ -48,7 +48,7 @@ class RawProcessorPreview:
"GRBG": cv2.COLOR_BayerGR2BGR, "GRBG": cv2.COLOR_BayerGR2BGR,
"RGGB": cv2.COLOR_BayerRG2BGR, "RGGB": cv2.COLOR_BayerRG2BGR,
"BGGR": cv2.COLOR_BayerBG2BGR, "BGGR": cv2.COLOR_BayerBG2BGR,
} }
if self.bayer_pattern not in mapping: if self.bayer_pattern not in mapping:
raise ValueError(f"Padrão Bayer não suportado: {self.bayer_pattern}") raise ValueError(f"Padrão Bayer não suportado: {self.bayer_pattern}")

View File

@ -234,7 +234,7 @@ def build_multispec_from_raw_native_multi(group: dict, meta: dict):
sensor_width = int(meta.get("sensor_width", 1280)) sensor_width = int(meta.get("sensor_width", 1280))
sensor_height = int(meta.get("sensor_height", 800)) sensor_height = int(meta.get("sensor_height", 800))
bayer = meta.get("bayer_pattern", "RGGB") bayer = meta.get("bayer_pattern", "BGGR")
# Tenta usar o mesmo module_params que foi usado na captura. # Tenta usar o mesmo module_params que foi usado na captura.
calib_path = meta.get("camera_params_json") or "calibration/module_params.json" calib_path = meta.get("camera_params_json") or "calibration/module_params.json"
@ -316,7 +316,7 @@ def build_visual_from_saved_payload(payload_path: Path, meta: dict, cam_id: str
role = cam_meta.get("role", cam_id) role = cam_meta.get("role", cam_id)
interface = cam_meta.get("interface", "") interface = cam_meta.get("interface", "")
bit_depth = int(cam_meta.get("bit_depth", 10)) bit_depth = int(cam_meta.get("bit_depth", 10))
bayer = cam_meta.get("bayer_pattern", meta.get("bayer_pattern", "GBRG")) bayer = cam_meta.get("bayer_pattern", meta.get("bayer_pattern", "BGGR"))
# USB RGB nativo # USB RGB nativo
if interface.upper() == "USB" or (arr.ndim == 3 and arr.shape[2] == 3 and arr.dtype == np.uint8): if interface.upper() == "USB" or (arr.ndim == 3 and arr.shape[2] == 3 and arr.dtype == np.uint8):
@ -411,7 +411,7 @@ def build_visual_from_saved_payload(payload_path: Path, meta: dict, cam_id: str
stream_meta = meta.get("stream_meta", {}) stream_meta = meta.get("stream_meta", {})
source_camera = stream_meta.get("source_camera", {}) or {} source_camera = stream_meta.get("source_camera", {}) or {}
bayer = source_camera.get("bayer_pattern", meta.get("bayer_pattern", "GBRG")) bayer = source_camera.get("bayer_pattern", meta.get("bayer_pattern", "BGGR"))
bit_depth = int(source_camera.get("bit_depth", 10)) bit_depth = int(source_camera.get("bit_depth", 10))
sensor_height = int(meta.get("sensor_height")) sensor_height = int(meta.get("sensor_height"))
@ -442,7 +442,7 @@ def build_visual_from_saved_payload(payload_path: Path, meta: dict, cam_id: str
stream_meta = meta.get("stream_meta", {}) or {} stream_meta = meta.get("stream_meta", {}) or {}
source_camera = stream_meta.get("source_camera", {}) or {} source_camera = stream_meta.get("source_camera", {}) or {}
bayer = source_camera.get("bayer_pattern", meta.get("bayer_pattern", "GBRG")) bayer = source_camera.get("bayer_pattern", meta.get("bayer_pattern", "BGGR"))
bit_depth = int(source_camera.get("bit_depth", 10)) bit_depth = int(source_camera.get("bit_depth", 10))
sensor_height = int(meta.get("sensor_height")) sensor_height = int(meta.get("sensor_height"))

View File

@ -664,7 +664,7 @@ def main():
parser.add_argument("--fps", type=int, default=20) parser.add_argument("--fps", type=int, default=20)
parser.add_argument("--width", type=int, default=1280) parser.add_argument("--width", type=int, default=1280)
parser.add_argument("--height", type=int, default=800) parser.add_argument("--height", type=int, default=800)
parser.add_argument("--bayer", default="RGGB", choices=["GBRG", "GRBG", "RGGB", "BGGR"]) parser.add_argument("--bayer", default="BGGR", choices=["GBRG", "GRBG", "RGGB", "BGGR"])
parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"]) parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"])
parser.add_argument("--raw_policy", default="require_triple", choices=["allow_single", "require_triple"]) parser.add_argument("--raw_policy", default="require_triple", choices=["allow_single", "require_triple"])
parser.add_argument("--module_calibration_json", default="calibration/module_params.json") parser.add_argument("--module_calibration_json", default="calibration/module_params.json")

View File

@ -1110,7 +1110,7 @@ def main():
parser.add_argument("--fps", type=int, default=20) parser.add_argument("--fps", type=int, default=20)
parser.add_argument("--width", type=int, default=1280) parser.add_argument("--width", type=int, default=1280)
parser.add_argument("--height", type=int, default=800) parser.add_argument("--height", type=int, default=800)
parser.add_argument("--bayer", default="RGGB", choices=["GBRG", "GRBG", "RGGB", "BGGR"]) parser.add_argument("--bayer", default="BGGR", choices=["GBRG", "GRBG", "RGGB", "BGGR"])
parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"]) parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"])
parser.add_argument("--raw_policy", default="require_triple", choices=["allow_single", "require_triple"]) parser.add_argument("--raw_policy", default="require_triple", choices=["allow_single", "require_triple"])
parser.add_argument("--module_calibration_json", default="calibration/module_params.json") parser.add_argument("--module_calibration_json", default="calibration/module_params.json")

View File

@ -505,7 +505,7 @@ def main():
parser.add_argument("--fps", type=int, default=20) parser.add_argument("--fps", type=int, default=20)
parser.add_argument("--width", type=int, default=1280) parser.add_argument("--width", type=int, default=1280)
parser.add_argument("--height", type=int, default=800) parser.add_argument("--height", type=int, default=800)
parser.add_argument("--bayer", default="RGGB", choices=["GBRG", "GRBG", "RGGB", "BGGR"]) parser.add_argument("--bayer", default="BGGR", choices=["GBRG", "GRBG", "RGGB", "BGGR"])
parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"]) parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"])
parser.add_argument("--raw_policy", default="allow_single", choices=["allow_single", "require_triple"]) parser.add_argument("--raw_policy", default="allow_single", choices=["allow_single", "require_triple"])
parser.add_argument("--preview_scale", type=float, default=1.0) parser.add_argument("--preview_scale", type=float, default=1.0)

View File

@ -233,7 +233,7 @@ def main():
parser.add_argument("--fps", type=int, default=20) parser.add_argument("--fps", type=int, default=20)
parser.add_argument("--width", type=int, default=1280) parser.add_argument("--width", type=int, default=1280)
parser.add_argument("--height", type=int, default=800) parser.add_argument("--height", type=int, default=800)
parser.add_argument("--bayer", default="RGGB", choices=["GBRG", "GRBG", "RGGB", "BGGR"]) parser.add_argument("--bayer", default="BGGR", choices=["GBRG", "GRBG", "RGGB", "BGGR"])
parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"]) parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"])
parser.add_argument("--raw_policy", default="allow_single", choices=["allow_single", "require_triple"]) parser.add_argument("--raw_policy", default="allow_single", choices=["allow_single", "require_triple"])
parser.add_argument("--baseline_mm", type=float, default=75.0) parser.add_argument("--baseline_mm", type=float, default=75.0)

View File

@ -873,7 +873,7 @@ def main():
parser.add_argument("--fps", type=int, default=20) parser.add_argument("--fps", type=int, default=20)
parser.add_argument("--width", type=int, default=1280) parser.add_argument("--width", type=int, default=1280)
parser.add_argument("--height", type=int, default=800) parser.add_argument("--height", type=int, default=800)
parser.add_argument("--bayer", default="RGGB", choices=["GBRG", "GRBG", "RGGB", "BGGR"]) parser.add_argument("--bayer", default="BGGR", choices=["GBRG", "GRBG", "RGGB", "BGGR"])
parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"]) parser.add_argument("--capture_mode", default="AUTO", choices=["AUTO", "SINGLE", "DOUBLE", "TRIPLE"])
parser.add_argument("--raw_policy", default="allow_single", choices=["allow_single", "require_triple"]) parser.add_argument("--raw_policy", default="allow_single", choices=["allow_single", "require_triple"])
parser.add_argument("--preview_scale", type=float, default=1.0) parser.add_argument("--preview_scale", type=float, default=1.0)