재구성 품질 보고서
개요
MipMapEngine SDK는 재구성 작업 완료 후 장치 정보, 재구성 효율성, 매개변수 설정 및 결과 품질을 포함하는 상세한 품질 보고서를 생성합니다. 보고서는 JSON 형식으로 report/report.json 파일에 저장되며, 빠른 미리보기를 위한 시각화 썸네일도 함께 제공됩니다.
보고서 구조
1. 장치 정보
재구성에 사용된 하드웨어 구성을 기록합니다:
| 필드 | 타입 | 설명 |
|---|---|---|
cpu_name | string | CPU 이름 |
gpu_name | string | GPU 이름 |
예시:
{
"cpu_name": "Intel(R) Core(TM) i9-10900K CPU @ 3.70GHz",
"gpu_name": "NVIDIA GeForce RTX 3080"
}
2. 재구성 효율성
각 단계의 처리 시간을 기록합니다(분 단위):
| 필드 | 타입 | 설명 |
|---|---|---|
feature_extraction_time | float | 특징 추출 시간 |
feature_match_time | float | 특징 매칭 시간 |
sfm_time | float | 번들 조정 시간 |
at_time | float | 총 AT 시간 |
reconstruction_time | float | 총 재구성 시간(AT 제외) |
예시:
{
"feature_extraction_time": 12.5,
"feature_match_time": 8.3,
"sfm_time": 15.2,
"at_time": 36.0,
"reconstruction_time": 48.6
}
3. 재구성 매개변수
작업 입력 매개변수 및 구성을 기록합니다:
카메라 매개변수
"initial_camera_parameters": [
{
"camera_name": "DJI_FC6310",
"width": 5472,
"height": 3648,
"id": 0,
"parameters": [3850.5, 2736, 1824, -0.02, 0.05, 0.001, -0.001, 0.01]
}
]
매개변수 배열 순서: [f, cx, cy, k1, k2, p1, p2, k3]
f: 초점 거리cx, cy: 주점 좌표k1, k2, k3: 방사 왜곡 계수p1, p2: 접선 왜곡 계수
기타 매개변수
| 필드 | 타입 | 설명 |
|---|---|---|
input_camera_count | int | 입력 카메라 수 |
input_image_count | int | 입력 이미지 수 |
reconstruction_level | int | 재구성 레벨 (1=초고, 2=고, 3=중) |
production_type | string | 제품 유형 |
max_ram | float | 최대 RAM 사용량 (GB) |
좌표계 정보
"production_cs_3d": {
"epsg_code": 4326,
"origin_offset": [0, 0, 0],
"type": 2
}
좌표계 유형:
- 0: LocalENU (로컬 동-북-상)
- 1: Local (로컬 좌표계)
- 2: Geodetic (측지 좌표계)
- 3: Projected (투영 좌표계)
- 4: ECEF (지구 중심-지구 고정)
4. 재구성 결과
AT 후 카메라 매개변수
최적화된 카메라 내부 매개변수를 기록합니다:
"AT_camera_parameters": [
{
"camera_name": "DJI_FC6310",
"width": 5472,
"height": 3648,
"id": 0,
"parameters": [3852.1, 2735.8, 1823.6, -0.019, 0.048, 0.0008, -0.0009, 0.009]
}
]
이미지 위치 차이
각 이미지의 위치 최적화를 기록합니다:
"image_pos_diff": [
{
"id": 0,
"pos_diff": 0.125
},
{
"id": 1,
"pos_diff": 0.087
}
]
품질 메트릭
| 필드 | 타입 | 설명 |
|---|---|---|
removed_image_count | int | AT 후 제거된 이미지 |
residual_rmse | float | 이미지 포인트 잔차 RMSE |
tie_point_count | int | 타이 포인트 수 |
scene_area | float | 장면 면적 (제곱미터) |
scene_gsd | float | 지상 샘플 거리 (미터) |
flight_height | float | 비행 높이 (미터) |
block_count | int | 재구성 블록 수 |
5. 기타 정보
| 필드 | 타입 | 설명 |
|---|---|---|
sdk_version | string | SDK 버전 |
시각화 썸네일
보고서 디렉토리의 thumbnail 폴더에는 다음 시각화 파일이 포함됩니다:
1. 카메라 잔차 플롯
camera_{id}_residual.png - 24비트 컬러 이미지
- 좋은 보정 결과: 잔차가 위치 전반에 걸쳐 비슷한 크기이며 무작위 방향을 보임
- 나쁜 보정 결과: 큰 잔차와 명확한 방향 패턴을 보임
팁
큰 잔차가 반드시 전체적인 정확도가 낮다는 것을 의미하지는 않습니다. 이것은 카메라 내부 정확도만을 반영합니다. 최종 정확도는 체크포인트 좌표 정확도와 모델 품질을 종합적으로 고려해야 합니다.
2. 중첩 지도
overlap_map.png - 8비트 그레이스케일 이미지
- 픽셀 값 범위: 0-255
- 중첩 분포를 표시하기 위해 컬러 맵으로 렌더링 가능
- 비행 경로 설계 및 이미지 커버리지 품질 평가에 사용
3. 측량 영역 썸네일
rgb_thumbnail.jpg - 32비트 컬러 이미지
- 프로젝트의 빠른 미리보기용
- 측량 영역 범위와 재구성 결과를 표시
보고서 해석 예시
전체 보고서 예시
{
"cpu_name": "Intel(R) Core(TM) i9-10900K CPU @ 3.70GHz",
"gpu_name": "NVIDIA GeForce RTX 3080",
"feature_extraction_time": 12.5,
"feature_match_time": 8.3,
"sfm_time": 15.2,
"at_time": 36.0,
"reconstruction_time": 48.6,
"initial_camera_parameters": [{
"camera_name": "DJI_FC6310",
"width": 5472,
"height": 3648,
"id": 0,
"parameters": [3850.5, 2736, 1824, -0.02, 0.05, 0.001, -0.001, 0.01]
}],
"input_camera_count": 1,
"input_image_count": 156,
"reconstruction_level": 2,
"production_type": "all",
"production_cs_3d": {
"epsg_code": 4326,
"origin_offset": [0, 0, 0],
"type": 2
},
"production_cs_2d": {
"epsg_code": 3857,
"origin_offset": [0, 0, 0],
"type": 3
},
"max_ram": 28.5,
"AT_camera_parameters": [{
"camera_name": "DJI_FC6310",
"width": 5472,
"height": 3648,
"id": 0,
"parameters": [3852.1, 2735.8, 1823.6, -0.019, 0.048, 0.0008, -0.0009, 0.009]
}],
"removed_image_count": 2,
"residual_rmse": 0.68,
"tie_point_count": 125840,
"scene_area": 850000.0,
"scene_gsd": 0.025,
"flight_height": 120.5,
"block_count": 1,
"sdk_version": "3.0.1"
}
품질 평가 메트릭
우수한 품질 기준
residual_rmse< 1.0 픽셀removed_image_count/input_image_count< 5%tie_point_count> 10000- 평균 위치 차이 < 0.5 미터
주의가 필요한 상황
residual_rmse> 2.0 픽셀: 가능한 체계적 오류removed_image_count> 10%: 이미지 품질 또는 중첩 문제tie_point_count< 5000: 불충분한 특징점, 정확도에 영향
보고서 분석 도구
Python 분석 예시
import json
import numpy as np
def analyze_quality_report(report_path):
with open(report_path, 'r', encoding='utf-8') as f:
report = json.load(f)
# 효율성 메트릭 계산
total_time = report['at_time'] + report['reconstruction_time']
images_per_minute = report['input_image_count'] / total_time
# 품질 메트릭 계산
removal_rate = report['removed_image_count'] / report['input_image_count']
avg_pos_diff = np.mean([item['pos_diff'] for item in report['image_pos_diff']])
# 분석 보고서 생성
analysis = {
'efficiency': {
'total_time_minutes': total_time,
'images_per_minute': images_per_minute,
'area_per_hour': report['scene_area'] / (total_time / 60)
},
'quality': {
'residual_rmse': report['residual_rmse'],
'removal_rate_percent': removal_rate * 100,
'avg_position_diff_meters': avg_pos_diff,
'tie_points_per_image': report['tie_point_count'] / report['input_image_count']
},
'scale': {
'area_sqm': report['scene_area'],
'gsd_cm': report['scene_gsd'] * 100,
'flight_height_m': report['flight_height']
}
}
return analysis
# 사용 예시
analysis = analyze_quality_report('report/report.json')
print(f"처리 효율성: {analysis['efficiency']['images_per_minute']:.1f} 이미지/분")
print(f"평균 잔차: {analysis['quality']['residual_rmse']:.2f} 픽셀")
print(f"지상 해상도: {analysis['scale']['gsd_cm']:.1f} cm")
품질 보고서 시각화
import matplotlib.pyplot as plt
from PIL import Image
def visualize_quality_report(report_dir):
# 보고서 데이터 읽기
with open(f'{report_dir}/report.json', 'r') as f:
report = json.load(f)
# 차트 생성
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 1. 시간 분포 원형 차트
times = [
report['feature_extraction_time'],
report['feature_match_time'],
report['sfm_time'],
report['reconstruction_time']
]
labels = ['특징 추출', '특징 매칭', '번들 조정', '3D 재구성']
axes[0, 0].pie(times, labels=labels, autopct='%1.1f%%')
axes[0, 0].set_title('처리 시간 분포')
# 2. 위치 차이 히스토그램
pos_diffs = [item['pos_diff'] for item in report['image_pos_diff']]
axes[0, 1].hist(pos_diffs, bins=20, edgecolor='black')
axes[0, 1].set_xlabel('위치 차이 (미터)')
axes[0, 1].set_ylabel('이미지 수')
axes[0, 1].set_title('이미지 위치 최적화 분포')
# 3. 중첩 지도
overlap_img = Image.open(f'{report_dir}/thumbnail/overlap_map.png')
axes[1, 0].imshow(overlap_img, cmap='jet')
axes[1, 0].set_title('이미지 중첩 분포')
axes[1, 0].axis('off')
# 4. 주요 메트릭 텍스트
metrics_text = f"""
입력 이미지: {report['input_image_count']}
제거된 이미지: {report['removed_image_count']}
잔차 RMSE: {report['residual_rmse']:.2f} px
타이 포인트: {report['tie_point_count']:,}
장면 면적: {report['scene_area']/10000:.1f} 헥타르
지상 해상도: {report['scene_gsd']*100:.1f} cm
"""
axes[1, 1].text(0.1, 0.5, metrics_text, fontsize=12,
verticalalignment='center', family='monospace')
axes[1, 1].set_title('주요 품질 메트릭')
axes[1, 1].axis('off')
plt.tight_layout()
plt.savefig('quality_report_summary.png', dpi=150)
plt.show()
자동 품질 검사
품질 임계값 구성
QUALITY_THRESHOLDS = {
'excellent': {
'residual_rmse': 0.5,
'removal_rate': 0.02,
'tie_points_per_image': 1000,
'pos_diff_avg': 0.1
},
'good': {
'residual_rmse': 1.0,
'removal_rate': 0.05,
'tie_points_per_image': 500,
'pos_diff_avg': 0.5
},
'acceptable': {
'residual_rmse': 2.0,
'removal_rate': 0.10,
'tie_points_per_image': 200,
'pos_diff_avg': 1.0
}
}
def assess_quality(report):
"""재구성 품질 수준을 자동으로 평가"""
# 메트릭 계산
removal_rate = report['removed_image_count'] / report['input_image_count']
tie_points_per_image = report['tie_point_count'] / report['input_image_count']
pos_diff_avg = np.mean([item['pos_diff'] for item in report['image_pos_diff']])
# 수준 평가
for level, thresholds in QUALITY_THRESHOLDS.items():
if (report['residual_rmse'] <= thresholds['residual_rmse'] and
removal_rate <= thresholds['removal_rate'] and
tie_points_per_image >= thresholds['tie_points_per_image'] and
pos_diff_avg <= thresholds['pos_diff_avg']):
return level
return 'poor'
보고서 통합 애플리케이션
배치 처리 품질 모니터링
def batch_quality_monitor(project_dirs):
"""배치 프로젝트 품질 모니터링"""
results = []
for project_dir in project_dirs:
report_path = os.path.join(project_dir, 'report/report.json')
if os.path.exists(report_path):
with open(report_path, 'r') as f:
report = json.load(f)
quality_level = assess_quality(report)
results.append({
'project': project_dir,
'images': report['input_image_count'],
'area': report['scene_area'],
'gsd': report['scene_gsd'],
'rmse': report['residual_rmse'],
'quality': quality_level,
'time': report['at_time'] + report['reconstruction_time']
})
# 요약 보고서 생성
df = pd.DataFrame(results)
df.to_csv('batch_quality_report.csv', index=False)
# 통계
print(f"전체 프로젝트: {len(results)}")
print(f"우수: {len(df[df['quality'] == 'excellent'])}")
print(f"양호: {len(df[df['quality'] == 'good'])}")
print(f"허용 가능: {len(df[df['quality'] == 'acceptable'])}")
print(f"불량: {len(df[df['quality'] == 'poor'])}")
return df
모범 사례
- 정기적인 보고서 확인: 각 재구성 후 품질 메트릭 검토
- 기준선 설정: 일반적인 프로젝트의 품질 메트릭을 참조로 기록
- 이상 경고: 비정상적인 메트릭을 감지하는 자동화된 스크립트 설정
- 추세 분석: 시간 경과에 따른 품질 메트릭 추세 추적
- 최적화 제안: 보고서 메트릭에 따라 캡처 및 처리 매개변수 조정
팁: 품질 보고서는 재구성 워크플로우를 평가하고 최적화하는 중요한 도구입니다. 자동화된 워크플로우에 통합하는 것이 좋습니다.