Skip to content

Repository files navigation

Halcon-Library

HALCON 13 · Regions ▸ Features 자체 구현 엔진

MVTec HALCON 의 리전 특징값 오퍼레이터를, SDK 없이 C++ 로 재현합니다.

C++PlatformDependenciesHeaderOperatorsTestsPending


이게 뭔가

검사 프로그램이 불량 Blob 의 형상 특징값(면적·원형도·볼록도·장단축·방향 등)을 HALCON 런타임 라이선스 없이 HALCON 과 같은 수치로 얻게 해주는 C++ 라이브러리입니다.

배포 형태static lib (GlimHalcon.lib) 또는 DLL (GlimHalcon.dll + import lib)
공개 면적헤더 1개include/GlimHalcon.h
의존성없음. 표준 라이브러리만 씁니다. OpenCV·Halcon 을 링크하지 않습니다
표준 / 문자셋C++14 / 멀티바이트(_MBCS). 유니코드 매크로를 켜지 않습니다
스레드오퍼레이터는 무상태 순수 함수. Region 을 스레드마다 따로 만들면 락 없이 병렬 호출 가능

성공 기준은 하나뿐입니다 — HALCON 실측값과 일치하는가. 구현 개수는 성과가 아닙니다. 값이 틀린 40종보다 값이 맞는 5종이 낫습니다.


1. 검사기 프로젝트에 붙이기

1-1. static lib 로 링크 (권장)

DLL 보다 이쪽을 권장합니다. CRT 버전·/MT·/MD 불일치 문제가 원천적으로 없고, 배포 시 DLL 을 따라다니게 할 필요가 없습니다.

① 빌드해서 산출물 얻기

cmake -S . -B build -G "Visual Studio 18 2026" -A x64
cmake --build build --config Release
build\Release\GlimHalcon.lib ← 이 파일
include\GlimHalcon.h ← 이 헤더

② Visual Studio 프로젝트 속성 (검사기 프로젝트에서, 구성·플랫폼 모두 동일하게)

속성 페이지항목
C/C++ ▸ 일반추가 포함 디렉터리C:\glim\pgm\Halcon-Library\include
링커 ▸ 일반추가 라이브러리 디렉터리...\build\Release
링커 ▸ 입력추가 종속성GlimHalcon.lib

③ 반드시 맞춰야 하는 것 — 안 맞으면 링크가 깨집니다

항목설명
플랫폼검사기가 x86 이면 라이브러리도 x86 (-A Win32). 섞이면 LNK1112
런타임 라이브러리C/C++ ▸ 코드 생성 ▸ 런타임 라이브러리가 양쪽 동일해야 합니다 (/MD/MD, /MT/MT). 다르면 LNK2038
플랫폼 도구 집합되도록 같은 툴셋(v140 / v143 …)으로. 다르면 표준 라이브러리 심볼이 어긋날 수 있습니다
문자셋라이브러리는 _MBCS 로 빌드됩니다. 공개 헤더에 문자열 타입이 없어 실제 영향은 없지만, 맞춰 두는 편이 안전합니다

LNK2019: ComputeCentralMoments2nd 외부 기호를 확인할 수 없습니다 가 뜨면 라이브러리 쪽에 src/Core/Moments.cpp 가 빠진 것입니다. CMake 로 재생성하면 해결됩니다.

1-2. DLL 로 링크

cmake -S . -B build -G "Visual Studio 18 2026" -A x64 -DGLIM_HALCON_BUILD_SHARED=ON
cmake --build build --config Release
build\Release\GlimHalcon.dll ← 실행 파일 옆에 복사
build\Release\GlimHalcon.lib ← import lib. 링커 ▸ 입력에 추가

사용처에서는 아무것도 정의하지 않습니다. 헤더가 알아서 dllimport 로 동작합니다.

DLL 을 쓸 때 지켜야 할 것 공개 헤더에 std:: 타입이 하나도 없고, Region 의 생성·복사·소멸이 전부 DLL 안에서 일어나도록 설계했습니다. 그래서 CRT 가 달라도 힙이 섞이지 않습니다. 대신 헤더에 인라인 함수를 추가하지 마세요. 사용처에서 인라인으로 할당·해제가 일어나는 순간 이 보장이 깨집니다.


2. 호출하기

2-1. 가장 흔한 경우 — 이진 마스크 crop 한 장

검사기가 이진화한 128×128 crop 을 던지면, 그 안의 최대 blob 하나를 골라 특징값 7개를 돌려줍니다.

#include"GlimHalcon.h"usingnamespaceglim::halcon;
RegionFeatures f;
if (ComputeLargestBlobFeatures(pMask, 128, 128, 128, f))
{
// f.area 면적 (픽셀 개수)// f.row, f.column 무게중심 (HALCON 관례 = y, x)// f.contLength 윤곽 길이 (구멍 제외)// f.circularity 원형도 0~1// f.compactness 조밀도 >= 1// f.convexity 볼록도 <= 1if (f.convexity < 0.85)
nDefectType = DEFECT_TEAR; // 볼록도가 낮으면 찢김
}
else
{
// 입력이 잘못됐거나(널 포인터 / w,h <= 0 / 0 < stride < width)// 전경이 하나도 없다. 이때 f 는 전 필드 0 이다.
}

stride 규약

동작
0 이하width 로 간주
>= width그대로 사용 (행 패딩이 있는 버퍼)
0 < stride < width빈 리전 반환. 성립할 수 없는 값이라 읽지 않습니다

2-2. 마스크에서 Region 을 만들어 개별 오퍼레이터 호출

기존 HALCON 스크립트를 1:1 로 옮길 때 씁니다. 함수 이름이 HALCON 원명과 대응됩니다.

Region region = Region::FromMask(pMask, width, height, stride);
long area; double row, column;
AreaCenter(region, area, row, column); // HALCON: area_centerdouble ra, rb, phi;
EllipticAxis(region, ra, rb, phi); // HALCON: elliptic_axisdouble aniso, bulk, sf;
Eccentricity(region, aniso, bulk, sf); // HALCON: eccentricity

Region 은 값 타입입니다. 복사는 O(1)(내부 데이터 공유), 소멸은 자동입니다. delete 하지 마세요.

2-3. 값이 2개 이상 필요하면 배치 API 를 쓰세요

개별로 호출하면 같은 중간산물을 매번 다시 계산합니다. 1차 5종을 따로 부르면 윤곽 추적만 4번 돕니다. 배치 API 는 리전당 1회입니다.

RegionFeatures f;
RegionMoments m;
ComputeFeaturesAndMoments(region, f, m); // 값은 개별 호출과 완전히 동일

3. 검사 결과를 CSV 로 쓰기

실제 목적지가 CSV 라면 이 형태가 됩니다. 멀티바이트 MFC 기준입니다.

#include"GlimHalcon.h"usingnamespaceglim::halcon;// 헤더는 파일을 새로 만들 때 한 번만staticvoidWriteCsvHeader(FILE* fp)
{
fprintf(fp,
"Frame,Lane,BlobNo,""Area,Row,Column,ContLength,Circularity,Compactness,Convexity,""M11,M20,M02,Ia,Ib,Ra,Rb,Phi,Anisometry,Bulkiness,StructureFactor,Orientation\n");
}
// blob 한 개를 한 줄로staticvoidWriteCsvRow(FILE* fp, int frame, int lane, int blobNo,
const RegionFeatures& f, const RegionMoments& m)
{
// %.9g : 유효자리를 보존하면서 지수표기 남발을 막는다.// %f 로 쓰면 M20 같은 큰 값에서 자리수가 잘리고, 엑셀에서 되돌릴 수 없다.fprintf(fp,
"%d,%d,%d,""%ld,%.9g,%.9g,%.9g,%.9g,%.9g,%.9g,""%.9g,%.9g,%.9g,%.9g,%.9g,%.9g,%.9g,%.9g,%.9g,%.9g,%.9g,%.9g\n",
frame, lane, blobNo,
f.area, f.row, f.column, f.contLength, f.circularity, f.compactness, f.convexity,
m.m11, m.m20, m.m02, m.ia, m.ib,
m.ra, m.rb, m.phi, m.anisometry, m.bulkiness, m.structureFactor, m.orientation);
}
// 검사 루프voidCInspector::SaveBlobFeatures(int frame, int lane,
constunsignedchar* pMask, int w, int h, int stride)
{
Region region = Region::FromMask(pMask, w, h, stride);
Region blob = SelectLargestBlob(region); // 최대 blob 하나만
RegionFeatures f;
RegionMoments m;
ComputeFeaturesAndMoments(blob, f, m);
FILE* fp = fopen(m_strCsvPath, "at"); // 멀티바이트 경로if (fp == NULL)
return;
if (_filelength(_fileno(fp)) == 0)
WriteCsvHeader(fp);
WriteCsvRow(fp, frame, lane, 0, f, m);
fclose(fp);
}

CSV 로 쓸 때 실수하기 쉬운 것 3가지

%f 로 쓰지 마세요M20 은 큰 면적에서 1e17 규모까지 갑니다. %f 는 자리수를 잘라버려 되돌릴 수 없습니다. %.9g 또는 %.17g 를 쓰세요
프레임당 열지 마세요매 프레임 fopen/fclose 는 실시간 경로에서 비쌉니다. 핸들을 유지하거나 메모리에 모아 배치로 flush 하세요
Anisometry = 0 을 필터로 지우지 마세요아래 §5 를 보세요. 가장 길쭉한 불량이 0 을 냅니다

4. 구현된 오퍼레이터 — 14 / 40

4-1. 원문 그룹 G1~G5 — 40종을 어떻게 나눴는가

HALCON 13 Operator Reference 의 Regions ▸ Features 40종을 원문 아카이브 5개 그룹으로 나눠 수집했습니다. 이 분류는 편의상 붙인 것이 아니라, 원문에서 공통 사항·수식 규약을 공유하는 단위입니다(예: G4 는 7종 전부가 같은 정규화 비교표를 씁니다).

그룹분류원문종수구현진행
G1기본 / 크기G1_basic_size.md86██████░░ 75%
G2형상 계수G2_shape_factors.md86██████░░ 75%
G3외접 / 내접 / 런렝스G3_geometry_runlength.md70░░░░░░░ 0%
G4모멘트G4_moments.md72██░░░░░ 29%
G5선택 / 관계G5_select_relation.md100░░░░░░░░░░ 0%
합계2,094줄401435%

구현 순서는 그룹 순서가 아닙니다. 그룹은 원문의 묶음이고, 구현은 그것을 가로질러 "값을 해석적으로 검증할 수 있는 5종 조합" 단위(배치)로 진행합니다. 그래서 1차 배치는 G1 2종 + G2 3종이었고, 3차 배치는 G1 4종이었습니다.

그룹별 40종 전체 목록 펼치기

G1 — 기본 / 크기 (6 / 8)

오퍼레이터상태비고
area_center1차 배치
area_holes3차 배치 / 배경 4-연결 (미결 HC-1·HC-3)
contlength1차 배치 / 구멍 제외
diameter_region3차 배치 / hull + 회전 캘리퍼스 (판정불가 DR-2)
connect_and_holes3차 배치 / 전경 8 ↔ 배경 4
euler_number3차 배치 / NumConnected − NumHoles 코어 공유
get_region_thickness단일 리전만, 첫 성분만
region_features63 feature 파사드

G2 — 형상 계수 (6 / 8)

오퍼레이터상태비고
circularity1차 배치 / min 클리핑
compactness1차 배치 / max 클리핑 (방향 반대)
convexity1차 배치 / F_o / F_c
eccentricity2차 배치 / Rb=0 방어 (미결 EC-1)
elliptic_axis2차 배치 / Phi 부호 함정 (미결 EA-2)
orientation_region2차 배치 / 미결 OR-2
rectangularity닫힌 수식 없음 — 최난도
roundness4출력

G3 — 외접 / 내접 / 런렝스 (0 / 7)

오퍼레이터상태비고
inner_circle
inner_rectangle1"largest" 기준 원문 미명시
smallest_circleradius +0.5 보정
smallest_rectangle1
smallest_rectangle2Length = 반변 (OpenCV 대비 2배)
runlength_distributionindex 0 은 항상 0
runlength_featuresLFactor 정의 모호

G4 — 모멘트 (2 / 7)

오퍼레이터상태비고
moments_region_2nd2차 배치 / 정규화 없음 (5출력)
moments_region_2nd_invar2차 배치 / 정규화 (미결 MI-1)
moments_region_2nd_rel_invarPHI1, PHI2 — 다음 배치 후보
moments_region_3rd부호 규약이 여기서부터 값을 바꾼다
moments_region_3rd_invarmu_00^3 정규화
moments_region_centralI1~I4
moments_region_central_invarPSI1~PSI4, 아핀 불변

G5 — 선택 / 관계 (0 / 10)

오퍼레이터상태비고
select_shape63 feature 이름 체계의 근간
select_shape_protoOperation 파라미터 없음
select_shape_std
select_region_spatial
select_region_point
spatial_relation
hamming_distanceSimilarity 수식 미확보
hamming_distance_norm출력명은 Distance
find_neighborsMaxDistance 범위 1~255
get_region_index

정의·검증·구현 3단 상태는 docs/00_OVERVIEW.md §7 이 원본입니다.

4-2. 배치별 구현 현황

1차 배치 · 기본 형상 ✅ 실측 통과 (PASS 70 / FAIL 0)

오퍼레이터C++ 함수출력
area_centerAreaCenter면적 · 무게중심
contlengthContLength윤곽 길이 (구멍 제외)
circularityCircularitymin(1, F/(max²π))
compactnessCompactnessmax(1, L²/(4Fπ))
convexityConvexityF_o / F_c

2차 배치 · 2차 모멘트 계열 🟡 빌드 검증 대기

오퍼레이터C++ 함수출력정규화
moments_region_2ndMomentsRegion2ndM11 M20 M02 Ia Ib없음 (순수 합)
moments_region_2nd_invarMomentsRegion2ndInvarM11 M20 M02
elliptic_axisEllipticAxisRa Rb Phi내부 F
eccentricityEccentricityAnisometry Bulkiness StructureFactor
orientation_regionOrientationRegionPhi (-π ≤ φ < π)

3차 배치 · 구멍 검출 계열 🟡 빌드 검증 대기

오퍼레이터C++ 함수출력연결성
area_holesAreaHolesArea (구멍 픽셀 총합)배경 4-연결
connect_and_holesConnectAndHolesNumConnected NumHoles전경 8 ↔ 배경 4
euler_numberEulerNumberEulerNumber (음수 가능)위와 같은 코어
diameter_regionDiameterRegionRow1 Column1 Row2 Column2 Diameter— (hull)

전경과 배경의 연결성은 서로 반대여야 합니다. 둘 다 8-연결로 잡으면 대각으로만 닫힌 고리에서 "구멍 안이 바깥과 통하는" 위상적 모순이 생겨, 세 값이 동시에 틀립니다. 원문에 명시가 없어 미결(HC-1)로 등록하고 내부 스위치로 뒤집을 수 있게 뒀습니다.

HALCON 원명 대응이 없는 추가 API 7개

함수용도
ComputeFeatures(region, RegionFeatures&)1차 5종의 값 7개를 한 번에
ComputeMoments(region, RegionMoments&)2차 5종의 값 15개를 한 번에
ComputeTopology(region, RegionTopology&)3차 4종의 값 9개를 한 번에
ComputeFeaturesAndMoments(region, f, m)7값 + 15값. 윤곽 추적 1회 · hull 1회 · 모멘트 1회
ComputeFeaturesMomentsAndTopology(region, f, m, t)위에 9값까지. 컨텍스트 하나로 전부
SelectLargestBlob(region)최대 연결성분(8-연결) 하나만 남긴 리전. 동률이면 스캔 순서상 먼저인 것
ComputeLargestBlobFeatures(data, w, h, stride, f)검사기 원샷. 이 함수만 bool 반환

ComputeLargestBlobFeaturesbool 인가 다른 함수는 이미 검증을 통과한 Region 을 받으므로 "실패" 가 사실상 빈 리전뿐입니다. 그러나 이 함수는 원시 포인터와 치수를 직접 받아 입력 자체가 틀릴 수 있고, 그것은 "전경이 없는 정상 리전(면적 0)" 과 의미가 다릅니다. 검사기가 둘을 구분하지 못하면 조용히 틀린 판정을 내립니다.

전체 40종 현황은 docs/00_OVERVIEW.md 에 있습니다.


5. 값 규약 — 모르면 오판합니다

빈 리전 / 실패는 전부 0

HALCON 규약을 그대로 따릅니다. 예외를 공개 API 밖으로 던지지 않습니다.

Anisometry 는 1픽셀 두께 리전에서 0 입니다

픽셀을 면적 1의 사각형이 아니라 무한소 점으로 보기 때문에 Rb = 0 이 되고, Anisometry = Ra/Rb 가 정의될 수 없어 0 이 됩니다. HALCON 실제 동작을 재현한 것입니다.

if (m.anisometry > 5.0) nType = SCRATCH; // ✗ 가장 길쭉한 1px 스크래치를 놓칩니다
if (m.rb == 0.0 || m.anisometry > 5.0) nType = SCRATCH; //

같은 이유로 StructureFactor 는 이때 -1.0 입니다. 자세한 내용은 docs/05_USER_GUIDE.md §4.8.

RegionFeatures · RegionMoments · RegionTopology 는 POD 이고, 레이아웃이 곧 ABI 입니다

필드를 추가하면 sizeof 가 바뀌어, 옛 헤더로 컴파일된 호출부가 링크는 되면서 스택을 넘겨 씁니다.

  • 필드는 끝에만 추가합니다 (중간 삽입·순서 변경·타입 변경 금지)
  • 필드를 추가한 버전으로 올릴 때는 라이브러리와 검사기를 함께 재컴파일합니다

6. 내부가 어떻게 돌아가는가

┌──────────────────────────────────────────────────────────┐
│ Facade namespace glim::halcon │ ← 사용처가 보는 전부
│ AreaCenter() EllipticAxis() … │ HALCON 이름 그대로
├──────────────────────────────────────────────────────────┤
│ Feature FeatureContext 중간산물 캐시(지연계산) │ ← 성능의 핵심
├──────────────────────────────────────────────────────────┤
│ Core Region (런렝스, 불변) │
│ Contour · ConvexHull · Moments · Holes │
└──────────────────────────────────────────────────────────┘
전 계층 표준 라이브러리만 사용 — 외부 의존성 없음
요소어떻게 구현했나
Region픽셀 배열이 아니라 런렝스(row, colBegin, colEnd) 목록입니다. 정렬·중복·인접을 정규화해 보관하므로, 면적과 모멘트를 O(면적)이 아니라 O(런 수) 로 계산합니다. PIMPL + 내부 공유라 복사가 O(1) 입니다
윤곽 추적8-연결 런 라벨링(union-find) 후 Moore 경계 추적. 픽셀 소속 판정을 dense 라벨 이미지가 아니라 런 이진탐색으로 하기 때문에 메모리가 O(런 수) 입니다(풀프레임에서 1.3GB 짜리 라벨 이미지가 사라집니다)
ContLength체인 스텝을 직교 1 · 대각 √2 로 누적합니다. 구멍 윤곽은 제외합니다(원문 명시)
ConvexHullmonotone chain 으로 껍질을 구한 뒤 스캔라인 래스터화해 픽셀을 셉니다. 폴리곤 면적을 쓰면 정사각형에서 convexity = 1.0203 이 나와 HALCON 자신의 Assertion(≤1)을 위반합니다
2차 모멘트런당 상수시간(등차수열 합 + Faulhaber 제곱합). 무게중심에 가장 가까운 격자점으로 좌표를 먼저 옮기고 소수부만 보정합니다 — 원시 모멘트를 그대로 빼면 큰 이미지에서 자리수가 통째로 날아갑니다
Ia / Ib공분산 고유값을 원문 형태가 아니라 항등 변형((M20−M02)/2)² + M11² 으로 계산합니다. 원문 형태는 큰 두 수의 차라 대면적에서 유효자리가 전멸하고, 부동소수 오차로 음수가 되어 sqrt 가 NaN 을 냅니다. 값은 대수적으로 같습니다
구멍 검출배경도 런렝스로 표현하고 "바깥" 가상 노드 하나로 union-find 합니다. 배경 런 수는 전경 런 수의 2배 이하라 메모리가 O(런 수)이고, 바운딩박스 크기와 무관합니다. area_holes·connect_and_holes·euler_number 가 이 결과 하나를 나눠 쓰므로 Euler = NC − NH 가 구조적으로 깨질 수 없습니다
diameter_region최대 거리 쌍은 반드시 hull 정점 쌍이므로 hull 위에서 회전 캘리퍼스로 찾습니다. 비교는 제곱거리 정수로 하고 sqrt 는 마지막 한 번뿐입니다 — 부동소수로 비교하면 동률 판정이 흔들려 결과가 결정론적이지 않게 됩니다
FeatureContext윤곽·hull·모멘트·최원점·구멍을 리전당 1회만 계산하고 캐시합니다. 배치 API 가 빠른 이유가 이것입니다
OpenCV 미사용편의상 뺀 게 아니라 값이 달라서 뺐습니다. cv::arcLength 는 근사 폴리곤, cv::contourArea 는 폴리곤 면적, cv::minAreaRect 는 HALCON 대비 2배(반변 규약)입니다

설계 제약과 근거는 docs/01_ARCHITECTURE.md, 구현 세부는 docs/04_IMPLEMENTATION_NOTES.md.


7. 빌드

cmake -S . -B build -G "Visual Studio 18 2026" -A x64
cmake --build build --config Release
cd build && ctest -C Release --output-on-failure
옵션기본설명
-A x64 / -A Win32검사기 플랫폼에 맞춥니다
-DGLIM_HALCON_BUILD_SHARED=ONOFFDLL 로 빌드 (기본은 static lib)
-DGLIM_HALCON_BUILD_EXAMPLES=OFFON예제 실행파일 제외

생성기는 설치된 Visual Studio 에 맞춰 바꿉니다 (Visual Studio 17 2022 등). 실행 가능한 예제 5개가 examples/ 에 있습니다.


8. 문서

📚 문서 허브 — docs/README.md 가 진입점입니다.

읽는 순서 · 카탈로그 · 오퍼레이터별 정의/검증/원문 역인덱스가 그곳에 있습니다.

문서내용
docs/05_USER_GUIDE.md사용처(검사기) 관점의 API 매뉴얼
CLAUDE.md개발 참여 전 필수. AI 에이전트 / 신규 참여자 지침
docs/00_OVERVIEW.md범위 · 원칙 · 함정 14건 · 40종 현황표
docs/01_ARCHITECTURE.md설계 제약과 적용 패턴
docs/02_DEFINITIONS.md특징값 정의서 — 구현의 유일한 근거
docs/03_VERIFICATION.md기준 도형 · 기댓값 손계산 · 검증 스크립트
docs/04_IMPLEMENTATION_NOTES.md구현 노트 · 실측 결과
docs/reference/halcon13/HALCON 13 원문 아카이브
CONTRIBUTING.md빌드·테스트·기여 절차

HALCON 은 MVTec Software GmbH 의 상표입니다. 이 프로젝트는 MVTec 과 무관하며,
공개된 오퍼레이터 명세를 근거로 한 독립 구현입니다. HALCON 코드를 포함하지 않습니다.

About

HALCON 13 Regions/Features 오퍼레이터 40종을 SDK 없이 C++ 로 재현하는 라이브러리. 정확도 우선 — 정의→검증→구현.

Topics

Resources

Contributing

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages