You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
04_IMPLEMENTATION_NOTES §9, 05_USER_GUIDE §4.8, 01_ARCHITECTURE,
README, docs/README, CLAUDE.md §6.
CLAUDE.md 현황표에 **미빌드** 상태를 명시했다. 1차 배치는 PASS 70/FAIL 0 실측이
있지만 2차 배치는 빌드·실행 검증을 하지 않았다(저장소 규칙 §4.2 에 따라 소유자가
직접 빌드한다). 표가 이 차이를 감추면 안 된다.
미결 쟁점 4건(MI-1/EA-2/EC-1/OR-2)과 판정 도형을 잔여 리스크 표에 등록했다.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: README.md
+22-1Lines changed: 22 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -97,6 +97,27 @@ flowchart LR
97
97
|`SelectLargestBlob(const Region&)`|**최대 연결성분(8-연결) 하나만** 남긴 리전을 반환. 동률이면 스캔 순서상 먼저인 것. `FromMask` 는 마스크 전체를 한 리전으로 만들므로(connection 없음), 덩어리가 여럿인 crop 에서 불량 하나만 뽑을 때 쓴다 |
98
98
|`ComputeLargestBlobFeatures(const unsigned char*, w, h, stride, RegionFeatures&)`|**검사기 원샷**: 이진 마스크 한 장 → 최대 blob → 특징값 7종. `FromMask`+`SelectLargestBlob`+`ComputeFeatures` 조합. **이 함수만 `bool` 반환** — 원시 포인터/치수를 직접 받아 입력 오류와 "전경 없음" 을 구분한다 |
99
99
100
+
### 2차 구현 대상 5종 — 2차 모멘트 계열 (2026-07-28)
101
+
102
+
다섯 종이 **2차 중심 모멘트 코어 하나**를 공유하고, 새로 필요한 인프라가 없는 조합으로 골랐습니다.
103
+
정규화 인자가 **없음 / `F²` / `F`** 세 가지라서, 서로가 서로의 대조군이 되도록 한 배치로 묶었습니다.
| 2026-07-21 | `FromMask` 의 `0 < stride < width` 를 빈 리전으로 거부 | 버퍼 밖 읽기를 유발한다. `width` 로 보정해도 읽는 총량이 버퍼를 넘으므로 보정으로는 안전해지지 않는다 |
213
235
| 2026-07-21 | 성분 라벨링을 `core::LabelConnectedRuns` 로 승격(추출) | `SelectLargestBlob` 이 같은 라벨링을 필요로 했다. `TraceOuterContours` 안에 복붙하면 "윤곽 성분" 과 "최대 blob 성분" 이 어긋날 수 있어, **양쪽이 함수 하나만 호출**하게 했다. 기존 윤곽 추적 동작은 불변 |
214
236
| 2026-07-21 | 검사기 원샷 `ComputeLargestBlobFeatures` 추가, 이 함수만 `bool` 반환 | 원시 포인터/치수를 직접 받아 **입력 오류 ≠ 전경 없음** 을 구분해야 한다. 기존 API 는 검증된 `Region` 만 받아 "실패도 0" 으로 충분했다. 기존 시그니처는 전부 불변, **추가**로만 해결 |
237
+
| 2026-07-28 | 2차 배치 결과를 `RegionFeatures` 에 붙이지 않고 **`RegionMoments` 새 구조체**로 분리 | `RegionFeatures` 는 이미 배포된 공개 경계다. 끝에 15개를 붙이면 `sizeof` 가 커져 **옛 헤더로 컴파일된 호출부가 링크는 되면서 스택을 넘겨 쓴다.** 이 라이브러리는 검사기 여러 대에 **소스로** 배포되므로 재컴파일 누락이 실제로 일어난다. 구조체를 나누면 그 사고가 원천적으로 불가능하다 |
238
+
| 2026-07-28 | 대신 `ComputeFeaturesAndMoments` 추가 | 구조체를 나눈 대가(컨텍스트 2회 생성 → 윤곽 추적 2회)를 없앤다. **나눠도 성능 손해가 없게** 만든 뒤에 나눴다 |
239
+
| 2026-07-28 | 미결 쟁점 스위치를 **내부 헤더의 매크로**로 (`src/Core/Moments.h`) | 런타임 `constbool` 분기는 MSVC `/W4` 에서 `C4127`(조건식이 상수)을 낸다. `#if` 는 경고가 없고, 기본 분기가 항상 컴파일된다. 공개 헤더가 아니므로 사용처를 오염시키지 않는다 |
240
+
| 2026-07-28 | `GetMaxContourDistance` 와 최원 윤곽점을 **한 순회**로 통합 | `circularity` 의 `max` 와 `orientation_region` 의 기준점은 같은 점이어야 한다. 순회를 두 벌 두면 언젠가 어긋난다. 값은 불변(초기값만 `0.0`→`-1.0`, 최댓값은 동일) |
§3 은 "곡선 도형의 기댓값을 연속 기하로 잡지 마라" 는 규칙이다. 모멘트에도 그대로 적용했지만,
268
+
**편향의 성질이 다르다는 점은 짚어 둔다.**
269
+
270
+
||`contlength`| 2차 모멘트 |
271
+
|---|---|---|
272
+
| 값의 정체 |**경로 길이** (8-연결 체인) |**픽셀 좌표의 합**|
273
+
| 편향의 원인 | 대각 스텝을 `√2` 로 세는 이산 경로의 성질 | 디지털 도형이 연속 도형과 픽셀 몇 개 다른가 |
274
+
|`R=50` 에서의 크기 |**+5.5%**| 면적 기준 **0.11%** (7845 vs 7853.98) |
275
+
276
+
즉 모멘트의 곡선 오차는 체인 오차보다 **두 자릿수 작다.** 그럼에도 `±2~3%` 를 유지했다.
277
+
이유는 정확도가 아니라 **원칙**이다 — "곡선 도형은 판정에 쓰지 않는다" 를 한 번 예외로 무너뜨리면
278
+
다음 배치에서 반드시 사고가 난다. PASS/FAIL 판정은 전부 **이산 도형**이 담당한다.
279
+
280
+
### 9.2 판별 도형 3종을 추가한 이유
281
+
282
+
**기준 도형 S1~S7 은 전부 대칭 도형이다.** S5 L자조차 반대각선 `c = 99 − r` 에 대해 대칭이다
283
+
(`(r,c) → (99−c, 99−r)` 가 좌팔과 하팔을 맞바꾼다). 그 결과:
284
+
285
+
- 최원 윤곽점이 항상 **동률**이라 `orientation_region` 의 `+π` 분기를 판정할 수 없다
286
+
- 크기가 다른 같은 도형 쌍이 없어 **스케일 불변성**을 판정할 수 없다
287
+
-`Phi = −π/2` 로 떨어지는 도형이 없어 `EA-2` 를 판정할 수 없다
288
+
289
+
그래서 **S1b**(50×50 정사각형) · **S4T**(세로선) · **S8**(비대칭 아령)을 추가했다.
290
+
S8 은 두 정사각형의 **크기를 다르게** 대각 배치해 최원점이 `(0,0)` 하나로 유일해지도록 설계했고,
291
+
좌표를 골라 `Ra = 41`, `Ia = 210125`, `Ib = 14125` 가 **정확한 정수**로 떨어지게 했다.
292
+
293
+
### 9.3 원문의 결함을 해소한 3건 (수식을 그대로 옮기면 안 되는 지점)
294
+
295
+
| # | 원문 | 문제 | 처리 |
296
+
|---|---|---|---|
297
+
| 1 |`Ia = h + sqrt(h² − M20·M02 + M11²)`|`M20 ≈ M02` 에서 큰 두 수의 차 → 자리수 소멸. 대면적에서 `h² ≈ 1e35`. 부동소수 오차로 **음수 → NaN**| 항등 변형 `sqrt(((M20−M02)/2)² + M11²)` 로 구현. **값은 대수적으로 동일**하고 원리적으로 비음이다 |
298
+
| 2 |`elliptic_axis` 의 "normalized and passed to the area" |`F` 인지 `F²` 인지 불명. 옆 오퍼레이터(`_invar`)가 `F²` 라 혼동 위험이 크다 | 연속 원판에서 `Ra = R` 이 성립하는 유일한 값이 `F` — 원문 논리로 확정 (`EA-1`) |
299
+
| 3 |`eccentricity` Assertion `Anisometry >= 1.0` vs Attention "anisometry of 0" | 문서 자기모순 |**Attention(실제 동작 0)을 따른다.** Assertion 쪽을 따르면 1픽셀 스크래치가 "완전한 원" 이 된다 |
300
+
301
+
### 9.4 원시 모멘트를 그대로 모으면 안 된다 (실무 사고 지점)
302
+
303
+
`SUM c²` 를 모아 `mu02 = SUM c² − (SUM c)²/F` 로 빼는 교과서 방식은
304
+
**바타입 급 이미지에서 유효자리가 날아간다.**
305
+
306
+
```
307
+
53580 열 이미지의 작은 blob (폭 10픽셀, 100 px)
308
+
SUM c^2 ~ 100 x 53580^2 ~ 2.9e11
309
+
mu02 ~ 8.3e2
310
+
→ 1e-9 규모의 상대 차이를 double 로 뽑아내야 한다
311
+
```
312
+
313
+
그래서 **무게중심에 가장 가까운 격자점으로 좌표를 먼저 옮긴다.** 남는 소수부는 `|f| <= 0.5` 뿐이다.
314
+
이 시프트가 없으면 검사기 실사용 좌표에서 조용히 값이 흔들린다
315
+
(기준 도형은 좌표가 0~120 이라 **이 문제를 잡아내지 못한다** — 테스트가 통과해도 안심할 수 없는 지점이다).
316
+
317
+
### 9.5 구조 등식으로 잡는 회귀 (T-12)
318
+
319
+
기댓값 표만으로는 "한 오퍼레이터만 고치고 나머지를 안 고친" 회귀를 못 잡는다.
320
+
도형과 무관하게 항상 성립하는 등식 7종을 테스트에 넣었다. 그중 두 개가 결정적이다.
321
+
322
+
```
323
+
I-1 : M**_invar · F^2 == M** §6 ↔ §7 정규화 연쇄
324
+
I-2 : Ra == 2·sqrt(Ia/F) , Rb == 2·sqrt(Ib/F) §6 ↔ §8 정규화 연쇄 (EA-1)
325
+
```
326
+
327
+
**`I-2` 가 가장 중요하다.**`elliptic_axis` 의 정규화를 잘못 넣으면 `Ra` 가 `sqrt(F)` 배 어긋나는데,
328
+
`Phi` 도 `Anisometry` 도 정규화에 둔감해서 못 잡는다. 잡아 주는 것은 정확값 표와 `I-2` 뿐이다.
329
+
330
+
### 9.6 미해결 (HALCON 실측 1회로 전부 해소된다)
331
+
332
+
| ID | 내용 | 잠정 | 판정 도형 | 스위치 |
333
+
|---|---|---|---|---|
334
+
|`MI-1`|`_invar` 의 원점이 무게중심인가 | 무게중심 |**S5**|`GLIM_HALCON_INVAR_ORIGIN_BBOX` (0) |
335
+
|`EA-2`|`Phi = −π/2` 를 `+π/2` 로 접는가 | 접는다 |**S4T**|`GLIM_HALCON_PHI_FOLD_HALF_PI` (1) |
336
+
|`EC-1`|`Rb=0` 의 `StructureFactor` 가 `−1` 인가 `0` 인가 |`−1`|**S4 / S6**|`GLIM_HALCON_STRUCTURE_FACTOR_ZERO_ON_RB0` (0) |
337
+
|`OR-2`|`+π` 후 `[−π, π)` 로 접는가 | 접는다 | (범위 문제) |`GLIM_HALCON_ORIENTATION_WRAP` (1) |
338
+
|`OR-3`| 최원점 동률(대칭 도형) |**판정 불가**| — | 순회 순서 고정 |
339
+
340
+
`EC-1` 의 기본값을 `−1` 로 둔 것은 §2.3 과 같은 판단이다.
341
+
**틀렸을 때 `−1` 은 눈에 띄고 `0` 은 빈 리전 규약에 묻혀 영원히 안 보인다.**
257
342
258
343
확장 시에도 §3 의 규칙(**곡선 도형 기댓값을 연속 기하로 잡지 말 것**)을 반드시 적용한다.
0 commit comments