diff --git a/.gitignore b/.gitignore index 0429931..66c9887 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ log/ __pycache__/ *.pyc .vscode/ +.obsidian/ diff --git a/doc/2026-08-15_test1_notes.md b/doc/2026-08-15_test1_notes.md new file mode 100644 index 0000000..4998677 --- /dev/null +++ b/doc/2026-08-15_test1_notes.md @@ -0,0 +1,101 @@ +# 2026-08-15 1차 현장 테스트 — 노출/게인/조리개 재조정 + +> `camera_exposure_design_notes.md`(설계노트), `question_1.md`/`answer_1.md`(하드웨어 실측 확인) 후속. 1차 테스트 결과를 반영해 조리개 결정 절차 방향을 바꾼다. + +--- + +## 1. 테스트 조건 및 관찰 + +| 항목 | 값 | +|---|---| +| 조리개 | f/5.6 | +| 노출 | Auto Exposure | +| 게인 | Auto Gain | +| 도구 | MVS 소프트웨어 | + +**관찰:** 중간 밝기의 실내에서 카메라 이미지가 조금 밝은 경향. 자동 노출 알고리즘(전체 프레임 평균 밝기 기준 `AutoTargetBrightness`, `camera_exposure_design_notes.md` 4.1절)이 원인으로 추정됨. + +**결정:** +1. 고정 노출값 + 고정 게인값을 먼저 정하고, 그 상태에서 적절한 조리개 값을 찾는 절차로 전환한다. +2. **지하주차장 등 매우 어두운 곳의 스캔은 포기**하고, 밝은 야외(직사광)를 확실히 커버하는 쪽을 우선한다. 이에 따라 조리개를 f/5.6보다 더 조이는 방향을 검토 중. + +--- + +## 2. 조이기 전에 먼저 확인할 것 — 노출 하한 쪽 여유가 훨씬 크다 + +"밝은 야외를 커버하려면 더 조여야 한다"는 방향 자체는 맞지만, 계산해보면 **조리개보다 노출 하한 쪽에 훨씬 큰 미사용 여유가 남아 있다.** + +``` +f/5.6 → f/8 (한 단 더 조임): + Δstop = 2·log2(8/5.6) = 1.03 stop 확보 + 대신 Airy disk 7.5µm(2.17px) → 10.7µm(3.1px)로 회절 블러 악화 (2절 참조) + +현재 exposure_auto_min = 100 µs +카메라 실제 하한(MV-CS016-10UC 데이터시트, Standard exposure mode) = 15 µs: + Δstop = log2(100/15) = 2.74 stop 확보, 해상력 손실 없음 +``` + +노출 하한을 100 µs에서 15 µs 근방으로 낮추는 것만으로 f/8로 조이는 것보다 **더 큰 stop을 해상력 손실 없이** 얻는다. **조리개를 더 조이는 건 이 여유를 다 쓰고도 모자랄 때 쓰는 마지막 카드로 남겨둔다.** 다음 테스트 전에 `exposure_auto_min`이 실제로 몇으로 설정되어 있는지부터 확인. + +--- + +## 3. 고정 t / gain 값을 정하는 방법 — "밝기 맞추기"가 아니라 독립된 물리 제약으로 + +지금 겪은 문제(AE가 조금 밝게 나옴)의 근본 원인은 `AutoTargetBrightness`가 높게 잡혀 있거나 전체 평균 측광이 밝은 벽/조명에 끌려가는 것이다. 이 문제를 "고정 노출/게인 값을 스캔해서 밝기가 맞는 값 찾기"로 풀면, 그 값은 **그 장면 하나에만 맞는 우연의 값**이 된다. 조명이 다른 장면으로 가면 다시 틀어진다. + +올바른 순서는 **t와 gain을 서로 다른 물리적 제약으로 각각 독립적으로 결정**하고, **밝기 맞추기는 오로지 조리개의 몫**으로 넘기는 것 (설계노트 3절). + +### 3.1 t (노출시간) — 블러 예산으로 결정 + +``` +t_blur_max = 블러목표[px] / (f_px · ω) +f_px ≈ 1159 (VM0420MP5 4mm ÷ 3.45µm, 실측 캘리브레이션 fx≈1200과 일치 — 설계노트 3.1절) +``` + +IMU 로그에서 회전 각속도 95퍼센타일을 뽑아 대입한다. 아직 실측 전이면 기존 참고값(ω=1.5 rad/s·블러 1px → 0.58 ms, ω=1.0 rad/s·블러 1.5px → 1.29 ms) 중 하나로 t≈0.8~1 ms를 잠정 상한으로 잡고 시작, 실측 IMU 데이터가 나오면 재계산한다. **이 값은 밝기가 아니라 블러로 정해지므로 장면이 바뀌어도 바뀌면 안 된다.** + +### 3.2 gain — 노이즈/특징점 품질 스윕으로 결정 + +같은 장면을 gain 0 / 6 / 12 / 16.9 dB(이 카메라 실측 상한)로 바꿔가며 촬영 → ORB/FAST 특징점 개수와 매칭 인라이어 비율이 급격히 꺾이는 지점 직전을 `g_work`로 잡는다. + +**단, 어두운 곳을 포기하기로 했으니 이번엔 낮은 쪽을 선택한다.** 원래 설계노트의 g_work≈12dB 권장은 지하주차장까지 커버하려고 게인을 최대한 끌어쓰려던 전제였다. 그 전제를 버렸으니, 밝은/중간 밝기 장면에서 노이즈를 최소화하는 **낮은 gain(0~6 dB)** 이 지금 목표에 더 맞는다. + +--- + +## 4. 조리개 결정 절차 — "밝은 쪽" 기준으로 전환 (설계노트 3.4절을 주 절차로 승격) + +원래 설계노트는 "가장 어두운 곳" 기준으로 조리개를 여는 절차였는데, 어두운 곳을 포기했으니 순서를 뒤집는다. + +1. MVS에서 수동 모드: `ExposureTime = t_blur_max`(3.1절), `Gain = g_work`(3.2절, 낮게)로 고정 +2. **가장 밝을 것으로 예상되는 실외(직사광)**로 이동 +3. MVS 히스토그램/통계 도구로 ROI(하늘 제외) 확인: **98퍼센타일이 포화 근처(8-bit 기준 DN 245 이상)에 안 걸리는지** 체크 +4. 걸리면 → 먼저 **2절의 노출 하한(15 µs 근방)이 실제로 적용되어 있는지부터 확인**. 그래도 부족하면 그때 조리개를 한 단 조이고 3번부터 반복 +5. 이 조리개가 정해지면, 처음 테스트한 "중간 밝기 실내" 장면으로 돌아가 같은 t/gain에서 median DN이 너무 어둡지 않은지 확인 (설계노트 3.3절 DN 100~120 목표) + +4번에서 조리개를 계속 조여야 하는 상황이 반복되면, 그건 원래 문제(f/8~f/11의 회절 손실, 설계노트 2절)로 되돌아가는 신호다. 2.4절의 ORB 특징점-vs-조리개 스윕으로 실제 손실을 확인하며 진행할 것. + +--- + +## 5. 배포 시엔 완전 고정보다 "좁게 bound된 Auto"를 권장 + +t/gain을 계산·스윕으로 정하는 것은 맞지만, 실제 촬영에서 정말 하나의 상수로 완전 고정하면 밝은 쪽 여유(15µs까지 내려가는 6~7 stop)를 못 쓴다. 대신: + +- `exposure_auto: true` 유지, `exposure_auto_min ≈ 15~30 µs`, `exposure_auto_max = t_blur_max`(3.1절 값)로 **범위를 좁게 bound** +- `gain`은 낮은 값으로 고정하거나 아주 좁은 범위(예: 0~6 dB)로 bound +- `exposure_auto_target_brightness`를 지금보다 낮춰서 "조금 밝은 경향" 자체도 같이 완화 + +이렇게 하면 밝은 야외에서는 노출이 자동으로 15 µs 근방까지 짧아져 포화를 피하고, 블러 상한은 여전히 지켜지며, 조리개는 f/5.6에서 더 조이지 않아도 될 가능성이 높다. + +덤으로, 노출시간 변동폭을 이렇게 좁게 묶으면 설계노트 5.4절이 지적한 "카메라 3대가 서로 다른 노출시간 → 유효시각 어긋남" 문제도 자연히 줄어든다. + +--- + +## 요약 + +| 질문 | 결론 | +|---|---| +| AE가 실내에서 밝게 나오는 이유 | `AutoTargetBrightness` + 전체평균 측광 (설계노트 4.1절과 동일 원인) | +| 밝은 야외 커버하려고 지금 조여야 하는가 | 조이기 전에 `exposure_auto_min`(현재 100µs)부터 15µs 근방으로 낮출 것 — 조리개 1단(1.03 stop, 해상력 손실 있음)보다 노출 하한(2.74 stop, 손실 없음)이 더 큰 여유 | +| 고정 t/gain을 어떻게 정하는가 | t는 블러 예산(3.1절)으로, gain은 특징점 품질 스윕(3.2절)으로 — 밝기로 맞추지 않음. 어두운 곳 포기했으니 gain은 낮게(0~6dB) | +| 조리개는 어떻게 정하는가 | 4절 — 이제는 "가장 밝은 곳에서 포화 안 되는지"가 1순위 기준, "가장 어두운 곳"은 검증만 | +| 실제 배포 설정 | 완전 고정보다 좁게 bound된 Auto Exposure/Gain 권장 (5절) | diff --git a/src/hik_camera_ros2_driver/config/camera_params_cam1.yaml b/src/hik_camera_ros2_driver/config/camera_params_cam1.yaml index a718f2a..727df07 100644 --- a/src/hik_camera_ros2_driver/config/camera_params_cam1.yaml +++ b/src/hik_camera_ros2_driver/config/camera_params_cam1.yaml @@ -1,8 +1,8 @@ /hik_camera_cam1: ros__parameters: camera_info_url: "package://hik_camera_ros2_driver/config/camera_info_cam1.yaml" - pixel_format: "BayerRG8" # Recommended Option: "RGB8Packed", "BayerRG8" - adc_bit_depth: "Bits_8" # If using "BayerRG8", must be set as "Bits_8"; otherwise, it can be "Bits_8" or "Bits_12" + pixel_format: "BayerRG8" # Recommended Option: "RGB8Packed", "BayerRG8" + adc_bit_depth: "Bits_8" # If using "BayerRG8", must be set as "Bits_8"; otherwise, it can be "Bits_8" or "Bits_12" use_sensor_data_qos: false camera_name: "cam1" # frame_id: "optical_frame" # If not set, it will be set as _optical_frame @@ -37,19 +37,30 @@ dev_clock_recalib_interval_sec: 2.0 # 프리런 모드(trigger_enable: false)일 때만 적용 - acquisition_frame_rate: 10.0 # Unit: Hz + acquisition_frame_rate: 10.0 # Unit: Hz - exposure_auto: true - exposure_auto_target_brightness: 110 - exposure_auto_min: 100.0 + # 자동 노출인 경우 + exposure_auto: false + exposure_auto_target_brightness: 100 + exposure_auto_min: 50.0 exposure_auto_max: 5000.0 - exposure_time: 5000 # Unit: us - gain: 12.0 # Range: 0.0 ~ 16.9, Unit: dB + + # 수동 노출인 경우 + exposure_time: 50 # Unit: us + gain: 0.0 # Range: 0.0 ~ 16.9, Unit: dB # 화이트밸런스 — cam1/cam2 겹치는 영역 색감을 맞추기 위해 두 카메라에 동일한 # 수동 R/G/B 비율을 고정한다 (2026-07-15, 두 카메라 Continuous AWB 수렴값의 평균). # cam1 실측: R=1414 G=1024 B=2060 / cam2 실측: R=1408 G=1024 B=2184 → 평균 적용 + # 2대의 카메라가 아닌 3대의 카메라에 대한 화이트 벨런스 로직으로 개선이 필요함 + # 조리개, 초점링 조절을 위해 화이트 벨런스를 오프함 + # 오프시 1024라는 수치로 조절하면 됨 + balance_white_auto: false - balance_ratio_red: 1411 + balance_ratio_red: 1024 balance_ratio_green: 1024 - balance_ratio_blue: 2122 + balance_ratio_blue: 1024 + + # balance_ratio_red: 1411 + # balance_ratio_green: 1024 + # balance_ratio_blue: 2122 diff --git a/src/hik_camera_ros2_driver/config/camera_params_cam2.yaml b/src/hik_camera_ros2_driver/config/camera_params_cam2.yaml index d6a5545..6dd2f60 100644 --- a/src/hik_camera_ros2_driver/config/camera_params_cam2.yaml +++ b/src/hik_camera_ros2_driver/config/camera_params_cam2.yaml @@ -1,8 +1,8 @@ /hik_camera_cam2: ros__parameters: camera_info_url: "package://hik_camera_ros2_driver/config/camera_info_cam2.yaml" - pixel_format: "BayerRG8" # Recommended Option: "RGB8Packed", "BayerRG8" - adc_bit_depth: "Bits_8" # If using "BayerRG8", must be set as "Bits_8"; otherwise, it can be "Bits_8" or "Bits_12" + pixel_format: "BayerRG8" # Recommended Option: "RGB8Packed", "BayerRG8" + adc_bit_depth: "Bits_8" # If using "BayerRG8", must be set as "Bits_8"; otherwise, it can be "Bits_8" or "Bits_12" use_sensor_data_qos: false camera_name: "cam2" # frame_id: "optical_frame" # If not set, it will be set as _optical_frame @@ -37,19 +37,30 @@ dev_clock_recalib_interval_sec: 2.0 # 프리런 모드(trigger_enable: false)일 때만 적용 - acquisition_frame_rate: 10.0 # Unit: Hz + acquisition_frame_rate: 10.0 # Unit: Hz - exposure_auto: true - exposure_auto_target_brightness: 128 - exposure_auto_min: 100.0 + # 자동 노출인 경우 + exposure_auto: false + exposure_auto_target_brightness: 100 + exposure_auto_min: 50.0 exposure_auto_max: 5000.0 - exposure_time: 5000 # Unit: us - gain: 15.0 # Range: 0.0 ~ 16.9, Unit: dB + + # 수동 노출인 경우 + exposure_time: 50 # Unit: us + gain: 0.0 # Range: 0.0 ~ 16.9, Unit: dB # 화이트밸런스 — cam1/cam2 겹치는 영역 색감을 맞추기 위해 두 카메라에 동일한 # 수동 R/G/B 비율을 고정한다 (2026-07-15, 두 카메라 Continuous AWB 수렴값의 평균). # cam1 실측: R=1414 G=1024 B=2060 / cam2 실측: R=1408 G=1024 B=2184 → 평균 적용 + # 2대의 카메라가 아닌 3대의 카메라에 대한 화이트 벨런스 로직으로 개선이 필요함 + # 조리개, 초점링 조절을 위해 화이트 벨런스를 오프함 + # 오프시 1024라는 수치로 조절하면 됨 + balance_white_auto: false - balance_ratio_red: 1411 + balance_ratio_red: 1024 balance_ratio_green: 1024 - balance_ratio_blue: 2122 + balance_ratio_blue: 1024 + + # balance_ratio_red: 1411 + # balance_ratio_green: 1024 + # balance_ratio_blue: 2122 diff --git a/src/hik_camera_ros2_driver/config/camera_params_cam3.yaml b/src/hik_camera_ros2_driver/config/camera_params_cam3.yaml index 26b99a8..4d7aa66 100644 --- a/src/hik_camera_ros2_driver/config/camera_params_cam3.yaml +++ b/src/hik_camera_ros2_driver/config/camera_params_cam3.yaml @@ -1,8 +1,8 @@ /hik_camera_cam3: ros__parameters: camera_info_url: "package://hik_camera_ros2_driver/config/camera_info_cam3.yaml" - pixel_format: "BayerRG8" # Recommended Option: "RGB8Packed", "BayerRG8" - adc_bit_depth: "Bits_8" # If using "BayerRG8", must be set as "Bits_8"; otherwise, it can be "Bits_8" or "Bits_12" + pixel_format: "BayerRG8" # Recommended Option: "RGB8Packed", "BayerRG8" + adc_bit_depth: "Bits_8" # If using "BayerRG8", must be set as "Bits_8"; otherwise, it can be "Bits_8" or "Bits_12" use_sensor_data_qos: false camera_name: "cam3" # frame_id: "optical_frame" # If not set, it will be set as _optical_frame @@ -37,16 +37,30 @@ dev_clock_recalib_interval_sec: 2.0 # 프리런 모드(trigger_enable: false)일 때만 적용 - acquisition_frame_rate: 10.0 # Unit: Hz + acquisition_frame_rate: 10.0 # Unit: Hz - # cam1/cam2와 동일하게 맞춤 (밝기 차이 최소화) - exposure_auto: true - exposure_auto_target_brightness: 145 - exposure_auto_min: 100.0 - exposure_auto_max: 8000.0 - exposure_time: 5000 # Unit: us - gain: 12.0 # Range: 0.0 ~ 16.9, Unit: dB + # 자동 노출인 경우 + exposure_auto: false + exposure_auto_target_brightness: 100 + exposure_auto_min: 50.0 + exposure_auto_max: 5000.0 - balance_ratio_red: 1411 + # 수동 노출인 경우 + exposure_time: 50 # Unit: us + gain: 0.0 # Range: 0.0 ~ 16.9, Unit: dB + + # 화이트밸런스 — cam1/cam2 겹치는 영역 색감을 맞추기 위해 두 카메라에 동일한 + # 수동 R/G/B 비율을 고정한다 (2026-07-15, 두 카메라 Continuous AWB 수렴값의 평균). + # cam1 실측: R=1414 G=1024 B=2060 / cam2 실측: R=1408 G=1024 B=2184 → 평균 적용 + # 2대의 카메라가 아닌 3대의 카메라에 대한 화이트 벨런스 로직으로 개선이 필요함 + # 조리개, 초점링 조절을 위해 화이트 벨런스를 오프함 + # 오프시 1024라는 수치로 조절하면 됨 + + balance_white_auto: false + balance_ratio_red: 1024 balance_ratio_green: 1024 - balance_ratio_blue: 2122 + balance_ratio_blue: 1024 + + # balance_ratio_red: 1411 + # balance_ratio_green: 1024 + # balance_ratio_blue: 2122