메인
투자 노트

이미지와 포인트간의 상관계수 산출

@11/10/2022

초기 속성

구성

이름
내부표정요소
외부표정요소
포인트클라우드
이터레이팅
단일
모든 사진들에 대하여
모든 포인트들에 대하여
source
iop_cam, camera.ssk
eop_txt
pcd_xyz
def find(file, line, index): """ line번째 줄의 index번째 값을 반환 """ return file.split("\n")[line-1].split()[index-1]
Python
복사
eop_txt
iop_cam
camera_ssk
pcd_xyz

내부표정요소

사진을 찍는 카메라의 속성
기호
ff
PxPx
PyPy
spssps
의미
Principal Point x
Principal Point y
단위
mmmm
mmmm
mmmm
mmmm
1.
파일에서 추출
f = find(iop_cam, 3, 2) Px = find(iop_cam, 5, 2) Py = find(iop_cam, 6, 2) sps = find(camera_ssk, 10, 2)
Python
복사
2.
단위 조정 ( 마이크로미터 → 밀리미터 )
sps×0.001sps \times 0.001

외부표정요소

카메라가 찍은 사진들 각각이 가지는 요소
기호
XLX_L
YLY_L
ZLZ_L
Ω\Omega
Φ\Phi
K\Kappa
의미
카메라의 x좌표
카메라의 y좌표
카메라의 z좌표
x축 우회전 각도
y축 우회전 각도
z축 우회전 각도
단위
mm (EPSG:5186)
mm (EPSG:5186)
mm (EPSG:5186)
radian
radian
radian
1.
파일에서 추출
for line in eop_txt.split("\n")[1:]: _, X_L, Y_L, Z_L, Omega, Phi, Kappa = line
Python
복사
2.
단위 조정 ( 도 → 라디안 ) 삼각함수에는 라디안 넣어야 함
Ω×π180\Omega \times \frac{\pi}{180}
Φ×π180\Phi \times \frac{\pi}{180}
K×π180\Kappa \times \frac{\pi}{180}

포인트클라우드

기호
XX
YY
ZZ
의미
포인트의 x좌표
포인트의 y좌표
포인트의 z좌표
단위
mm (EPSG:5186)
mm (EPSG:5186)
mm (EPSG:5186)
1.
파일에서 추출
for line in pcd_xyz.split("\n"): X, Y, Z, _, _, _ = line
Python
복사
2.
단위 조정 없음

연산

3차원 회전변환행렬

m=[cos(Φ)cos(K)sin(Ω)sin(Φ)cos(K)+cos(Ω)sin(K)cos(Ω)sin(Φ)cos(K)+sin(Ω)sin(K)cos(Φ)sin(K)sin(Ω)sin(Φ)sin(K)+cos(Ω)cos(K)cos(Ω)sin(Φ)sin(K)+sin(Ω)cos(K)sin(Φ)sin(Ω)cos(Φ)cos(Ω)cos(Φ)]m = \begin{bmatrix} \cos(\Phi)\cos(\Kappa) & \sin(\Omega)\sin(\Phi)\cos(\Kappa) + \cos(\Omega)\sin(\Kappa) & -\cos(\Omega)\sin(\Phi)\cos(\Kappa) + \sin(\Omega)\sin(\Kappa) \\ -\cos(\Phi)\sin(\Kappa) & -\sin(\Omega)\sin(\Phi)\sin(\Kappa) + \cos(\Omega)\cos(\Kappa) & \cos(\Omega)\sin(\Phi)\sin(\Kappa) + \sin(\Omega)\cos(\Kappa) \\ \sin(\Phi) & -\sin(\Omega)\cos(\Phi) & \cos(\Omega)\cos(\Phi) \\ \end{bmatrix}
기호
mm
의미
단위
행렬

공선조건식

x=fm11(XXL)+m12(YYL)+m13(ZZL)m31(XXL)+m32(YYL)+m33(ZZL)x = -f\frac {m_{11}(X-X_L)+ m_{12}(Y-Y_L)+ m_{13}(Z-Z_L)} {m_{31}(X-X_L)+ m_{32}(Y-Y_L)+ m_{33}(Z-Z_L)}
y=fm21(XXL)+m22(YYL)+m23(ZZL)m31(XXL)+m32(YYL)+m33(ZZL)y = -f\frac {m_{21}(X-X_L)+ m_{22}(Y-Y_L)+ m_{23}(Z-Z_L)} {m_{31}(X-X_L)+ m_{32}(Y-Y_L)+ m_{33}(Z-Z_L)}
기호
xx
yy
의미
투영된 상대적 사진좌표 x
투영 상대적 사진좌표 y
단위
mmmm
mmmm

사진좌표를 픽셀 인덱스로 변환

row=floor((x+Px)sps0.5)row = floor \left( \frac{(x + Px)}{sps} - 0.5 \right)
기호
rowrow
columncolumn
의미
이미지의 픽셀 x 인덱스
이미지의 픽셀 y 인덱스
단위
픽셀
픽셀

포인트와 사진의 일치율을 상관계수로 산출하기

두 점의 거리는 상관계수와 반비례하며 상관계수는 0~1 범위로 나타난다.
1.
포인트와 사진 중점 사이의 거리 구하기
total_row:int # 이미지의 픽셀 너비 total_column:int # 이미지의 픽셀 높이 point_row:int # 포인트의 행 인덱스 point_column:int # 포인트의 열 인덱스 center_row:float = (total_row / 2 - 0.5) center_column:float = (total_row/2 - 0.5) # 포인트가 이미지에서 벗어난 경우는 상관계수가 나와도 해당사항이 없기 때문에 미리 배제해야 한다. assert 0 < point_row <= total_row # 필요조건 1 assert 0 < point_column <= total_column # 필요조건 2 # 포인트와 이미지 중앙 사이의 거리 distance = ( (center_row - point_row) ** 2 + (center_column - point_column) ** 2 ) ** (1/2)
Python
복사
2.
거리를 상관계수로 환산
1distance+1\frac{1}{distance + 1}

결론

이 알고리즘을 사용하면 포인트와 이미지가 다대다 관계로 서로 상관계수를 가지게 할 수 있다. 그러면 하나의 포인트에 대해서 이미지들을 포인트와 일치하는 정도로 정렬할 수 있고, 하나의 이미지에 대해서도 포인트들을 이미지와 일지하는 정도로 정렬할 수 있다.

단일 함수로 구현

import math from math import sin, cos from typing import Tuple def correlation_coefficient( point_x: float, point_y: float, point_z: float, *, focal_length: float, sensor_pixel_size: float, principal_point_x: float, principal_point_y: float, camera_x: float, camera_y: float, camera_z: float, camera_omega: float, camera_phi: float, camera_kappa: float, image_width: int, image_height: int, ) -> Tuple[float]: """ - 포인트와 이미지의 상관계수를 산출해서 반환합니다. - return: float ( 0 ~ 1 ) - 대상 포인트와 이미지(카메라) 데이터를 입력받습니다. - 포인트 정보 - point_x: 포인트 x좌표 (단위: m), - point_y: 포인트 y좌표 (단위: m), - point_z: 포인트 z좌표 (단위: m), - 이미지를 촬영한 카메라 정보 - focal_length: 초점거리, (단위: mm) - sensor_pixel_size: (단위: micrometer) - principal_point_x: 주점의 x좌표 (단위: mm) - principal_point_x: 주점의 y좌표 (단위: mm) - camera_x, camera_y, camera_z: 이미지 촬영 시 카메라의 위치좌표, (단위: m [EPSG:5186]) - camera_omega, camera_phi, camera_kappa: 이미지를 촬영 시 카메라의 각도, (단위: degree) - image_width, image_height: 이미지의 너비, 높이 픽셀 갯수 """ sensor_pixel_size *= 0.001 # micrometer -> mm camera_omega *= math.pi / 180 # degree -> radian camera_phi *= math.pi / 180 # degree -> radian camera_kappa *= math.pi / 180 # degree -> radian # ========== Rotation Matrix ========== m11 = cos(camera_phi) * cos(camera_kappa) m12 = sin(camera_omega) * sin(camera_phi) * cos(camera_kappa) + cos(camera_omega) * sin(camera_kappa) m13 = -cos(camera_omega) * sin(camera_phi) * cos(camera_kappa) + sin(camera_omega) * sin(camera_kappa) m21 = -cos(camera_phi) * sin(camera_kappa) m22 = -sin(camera_omega) * sin(camera_phi) * sin(camera_kappa) + cos(camera_omega) * cos(camera_kappa) m23 = cos(camera_omega) * sin(camera_phi) * sin(camera_kappa) + sin(camera_omega) * cos(camera_kappa) m31 = sin(camera_phi) m32 = -sin(camera_omega) * cos(camera_phi) m33 = cos(camera_omega) * cos(camera_phi) # ======================================== picture_x = ( # 포인트의 투영 사진좌표 x -focal_length * ( m11 * (point_x - camera_x) + m12 * (point_y - camera_y) + m13 * (point_z - camera_z) ) / ( m31 * (point_x - camera_x) + m32 * (point_y - camera_y) + m33 * (point_z - camera_z) ) ) picture_y = ( # 포인트의 투영 사진좌표 y -focal_length * ( m21 * (point_x - camera_x) + m22 * (point_y - camera_y) + m23 * (point_z - camera_z) ) / ( m31 * (point_x - camera_x) + m32 * (point_y - camera_y) + m33 * (point_z - camera_z) ) ) # 사진좌표를 이미지행렬의 픽셀 인덱스로 변환 row_idx = math.floor( ((picture_x + principal_point_x) / sensor_pixel_size) - 0.5 ) column_idx = math.floor( -((picture_y - principal_point_y) / sensor_pixel_size) - 0.5 ) if (not 0 < row_idx <= image_width) or (not 0 < column_idx <= image_height): return 0 # 포인트가 이미지에서 벗어난 경우 상관계수 0 반환 center_row_idx = image_width / 2 - 0.5 center_column_idx = image_height / 2 - 0.5 # 이미지 중심과 포인트 투영점 사이의 거리 distance = math.dist((center_row_idx, center_column_idx), (row_idx, column_idx)) return 1 / (distance + 1) # 거리를 상관계수로 변환
Python
복사