Halcon은 이미지 처리를 위한 도구로, 그 좌표계의 원점이 왼쪽 상단에 위치한다는 점이 일반적인 수학적 2차원 좌표계와 다릅니다. 일반적인 평면 좌표계는 원점이 왼쪽 하단에 있지만, Halcon에서는 세로 방향이 역방향으로 설정되어 있어, 실제 이미지 내 위치는 위아래가 뒤집힌 형태로 표현됩니다.
다음 예제 코드를 통해 이 차이를 분석해 보겠습니다:
1 gen_image_const (Image, 'byte', 512, 512)
2 dev_set_draw ('margin')
3 * 세 점 생성
4 gen_circle (Circle1, 10, 10, 3)
5 disp_message (3600, '(10, 10)', 'image', 2, 18, 'white', 'false')
6 gen_circle (Circle2, 100, 200, 3)
7 disp_message (3600, '(100, 200)', 'image', 92, 208, 'white', 'false')
8 gen_circle (Circle3, 400, 100, 3)
9 disp_message (3600, '(400, 100)', 'image', 392, 108, 'white', 'false')
10 union2 (Circle1, Circle2, RegionUnion)
11 union2 (RegionUnion, Circle3, RegionUnion)
12 gen_contour_region_xld (RegionUnion, Contours, 'border')
13 write_contour_xld_dxf (Contours, 'C:/Users/happy xia/Desktop/XLD의 반사 변환/threePoint.dxf')
이 코드는 세 개의 원을 생성하고, 이를 합쳐서 하나의 영역으로 만들고, 해당 경계선을 XLD 형식으로 DXF 파일로 내보냅니다. 이후 이 DXF 파일을 텍스트 편집기로 열어 보면, 실제로 저장된 좌표 값들은 화면 상에서의 위치와 다르게 나타납니다.
예를 들어, DXF 파일 내부에 (98.5, 396.5)와 (99.5, 396.5)라는 점이 존재하며, 이들의 중심은 (100, 400)으로 추정됩니다. 그러나 원본 이미지에는 (100, 200)이 아니라 (400, 100)에 점이 찍혀 있습니다. 이는 좌표계의 상하 방향이 반대임을 시사합니다.
결론적으로, Halcon의 좌표계는 일반적인 2차원 좌표계와 상하로 거울 대칭된 구조이며, 이로 인해 XLD 데이터를 DXF로 내보낼 경우, 전체적인 윤곽선이 뒤집혀 나타납니다.
따라서 이 문제를 해결하기 위해 XLD의 상하 반사(반전) 변환이 필요합니다. 아래는 여러 방법으로 이를 수행하는 접근입니다.
방법 1: 영역을 매개로 한 반사 변환
이 방법은 닫힌 XLD에만 적용 가능합니다. 먼저 XLD를 Region으로 변환한 후, mirror_region 연산자를 사용하여 반사하고 다시 XLD로 복원합니다.
1 gen_image_const (Image, 'byte', 7000, 5000)
2 read_contour_xld_dxf (Contours, 'unionContour.dxf', [], [], DxfStatus)
3 * 영역을 통한 반사
4 gen_region_contour_xld (Contours, Region, 'margin')
5 mirror_region (Region, RegionMirror, 'row', 6000)
6 gen_contour_region_xld (RegionMirror, ContoursMirror, 'border')
이 방식은 간단하지만, 닫힌 경로만 처리 가능하고, 일부 세부 정보 손실이 발생할 수 있습니다.
방법 2: 점 단위 반사 후 재구성
각 XLD의 점들을 직접 읽어, 행(세로) 좌표를 기준선에 대해 반사하여 새로운 점 집합을 구성합니다. 이 방법은 모든 종류의 XLD에 적용 가능하지만, 성능을 위해 점들 사이를 간격으로 샘플링하여 처리함으로써 정밀도가 저하될 수 있습니다.
1 gen_image_const (Image, 'byte', 7000, 5000)
2 read_contour_xld_dxf (Contours, 'unionContour.dxf', [], [], DxfStatus)
3 count_obj (Contours, Num)
4 Step := 5
5 axisValue := 6000
6 gen_empty_obj (Contour2)
7 for i := 1 to Num by 1
8 select_obj (Contours, Contour, i)
9 get_contour_xld (Contour, Row, Col)
10 Row1 := []
11 Col1 := []
12 for j := 0 to |Row| - 1 by Step
13 Row1 := [Row1, axisValue - Row[j]]
14 Col1 := [Col1, Col[j]]
15 endfor
16 test_closed_xld (Contour, IsClosed)
17 if (IsClosed = 1)
18 Row1 := [Row1, axisValue - Row[0]]
19 Col1 := [Col1, Col[0]]
20 endif
21 gen_contour_polygon_xld (Contour1, Row1, Col1)
22 smooth_contours_xld (Contour1, SmoothedContours, 3)
23 concat_obj (Contour2, SmoothedContours, Contour2)
24 endfor
이 방법은 유연하지만, 간격 샘플링으로 인해 곡선의 정확도가 감소합니다.
방법 3: 최적의 해법 – 2차원 애핀 변환 (hom_mat2d_reflect)
가장 정교하고 효율적인 방법은 애핀 변환을 이용하는 것입니다. hom_mat2d_reflect는 두 점을 기준으로 객체를 반사하는 변환 행렬을 생성합니다.
1 gen_image_const (Image, 'byte', 7000, 5000)
2 read_contour_xld_dxf (Contours, 'unionContour.dxf', [], [], DxfStatus)
3 hom_mat2d_identity (HomMat2DIdentity)
4 hom_mat2d_reflect (HomMat2DIdentity, 3000, 0, 3000, 100, HomMat2DReflect)
5 affine_trans_contour_xld (Contours, ContoursAffinTrans, HomMat2DReflect)
여기서 hom_mat2d_reflect의 인자는 두 점을 지나는 직선을 기준으로 반사되도록 설정합니다. 예를 들어, (3000, 0)과 (3000, 100)을 연결한 선을 기준으로 상하 반사가 이루어집니다. 이는 정확한 기하학적 반사를 보장하며, 모든 종류의 XLD에 적용 가능하고, 점의 손실 없이 완벽한 결과를 얻을 수 있습니다.
결과적으로, Halcon에서의 좌표계 특성으로 인해 발생하는 상하 뒤집힘 문제는 hom_mat2d_reflect를 활용한 애핀 변환으로 가장 효과적으로 해결할 수 있습니다.