@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
내부표정요소
사진을 찍는 카메라의 속성
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.
단위 조정 ( 마이크로미터 → 밀리미터 )
외부표정요소
카메라가 찍은 사진들 각각이 가지는 요소
기호 | ||||||
의미 | 카메라의 x좌표 | 카메라의 y좌표 | 카메라의 z좌표 | x축 우회전 각도 | y축 우회전 각도 | z축 우회전 각도 |
단위 | (EPSG:5186) | (EPSG:5186) | (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.
단위 조정 ( 도 → 라디안 ) 삼각함수에는 라디안 넣어야 함
포인트클라우드
기호 | |||
의미 | 포인트의 x좌표 | 포인트의 y좌표 | 포인트의 z좌표 |
단위 | (EPSG:5186) | (EPSG:5186) | (EPSG:5186) |
1.
파일에서 추출
for line in pcd_xyz.split("\n"):
X, Y, Z, _, _, _ = line
Python
복사
2.
단위 조정 없음
연산
3차원 회전변환행렬
공선조건식
기호 | ||
의미 | 투영된 상대적 사진좌표 x | 투영 상대적 사진좌표 y |
단위 |
사진좌표를 픽셀 인덱스로 변환
기호 | ||
의미 | 이미지의 픽셀 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.
거리를 상관계수로 환산
결론
이 알고리즘을 사용하면 포인트와 이미지가 다대다 관계로 서로 상관계수를 가지게 할 수 있다.
그러면 하나의 포인트에 대해서 이미지들을 포인트와 일치하는 정도로 정렬할 수 있고, 하나의 이미지에 대해서도 포인트들을 이미지와 일지하는 정도로 정렬할 수 있다.
단일 함수로 구현
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
복사