-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path01_split_tiffs.py
More file actions
174 lines (140 loc) · 6.47 KB
/
Copy path01_split_tiffs.py
File metadata and controls
174 lines (140 loc) · 6.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
"""Splits a multipage TIFF file of a FLIR IR camera into individual frames.
The output directory contain the following directories:
- `preview`: 8-bit grayscale preview frames (JPG) of the IR video
- `radiometric`: 16-bit grayscale radiometric frames (TIFF) of the IR video
"""
import glob
import os
import csv
import json
from math import floor
import cv2
import numpy as np
from tqdm import tqdm
import tifffile
import simplekml
def to_decimal_degrees(degrees_n, degrees_d, minutes_n, minutes_d,
seconds_n, seconds_d):
"""Converts degrees, minutes and seconds into decimal degrees."""
degrees = degrees_n / degrees_d
minutes = minutes_n / minutes_d
seconds = seconds_n / seconds_d
deg_loc = degrees + (minutes/60) + (seconds/3600)
return deg_loc
def exif_gps_to_degrees(gps_info):
"""Transforms EXIF GPS info into degrees north and east.
Positive values correspond to north and east whereas negative
values correspond to south and west.
"""
latitude_deg = to_decimal_degrees(*gps_info['GPSLatitude'])
longitude_deg = to_decimal_degrees(*gps_info['GPSLongitude'])
if gps_info['GPSLatitudeRef'] == "S":
latitude_deg *= -1.0
if gps_info['GPSLongitudeRef'] == "W":
longitude_deg *= -1.0
return latitude_deg, longitude_deg
def create_preview(image_radiometric):
temp_range = image_radiometric.max() - image_radiometric.min()
image_preview = (image_radiometric - image_radiometric.min()) / temp_range
image_preview = (255*image_preview).astype(np.uint8)
return image_preview
def get_num_rgb_frames(rgb_files):
"""Return the number of frames in the provided videos.
Args:
rgb_files (`list` of `str`): List of video files names.
Returns:
Number of video frames (`int`).
"""
n_rgb = 0
for rgb_file in rgb_files:
cap = cap = cv2.VideoCapture(rgb_file)
n_rgb += cap.get(cv2.CAP_PROP_FRAME_COUNT)
return int(n_rgb)
def get_num_ir_frames(tiff_files):
"""Return the number of frames in the provided videos (TIFF stacks)."""
n_ir = 0
for tiff_file in tiff_files:
with tifffile.TiffFile(tiff_file) as tif:
for page in tif.pages:
n_ir += 1
return int(n_ir)
def get_ir_frame_number(rgb_idx, n_ir, n_rgb):
"""Returns index of IR frame corresponding to the RGB frame idx."""
ir_idx = floor(n_ir*float(rgb_idx)/n_rgb)
return ir_idx
def run(input, output_dir, input_rgb=None, extract_gps=True, sync_rgb=True):
for dirname in ["radiometric", "preview", "gps"]:
os.makedirs(os.path.join(output_dir, dirname), exist_ok=True)
tiff_files = sorted(glob.glob(input))
n_ir = get_num_ir_frames(tiff_files)
print("Found {} TIFF videos with {} frames for splitting".format(
len(tiff_files), n_ir))
if sync_rgb and (input_rgb is not None):
os.makedirs(os.path.join(output_dir, "rgb"), exist_ok=True)
rgb_files = sorted(glob.glob(input_rgb))
n_rgb = get_num_rgb_frames(rgb_files)
assert get_ir_frame_number(n_rgb, n_ir, n_rgb) == n_ir
print("Found {} RGB videos with {} frames for splitting".format(
len(rgb_files), n_rgb))
frame_idx = 0
gps_positions = []
for i, tiff_file in enumerate(tiff_files):
print("Splitting TIFF file {} of {}".format(i+1, len(tiff_files)))
with tifffile.TiffFile(tiff_file) as tif:
for page in tqdm(tif.pages, total=len(tif.pages)):
image_radiometric = page.asarray().astype(np.uint16) # BUG: for Optris camera conversion to int is detrimental to accuracy as raw values in TIFF are float
image_preview = create_preview(image_radiometric)
radiometric_file = os.path.join(
output_dir, "radiometric", "frame_{:06d}.tiff".format(
frame_idx))
preview_file = os.path.join(
output_dir, "preview", "frame_{:06d}.jpg".format(
frame_idx))
cv2.imwrite(radiometric_file, image_radiometric)
cv2.imwrite(preview_file, image_preview)
# extract GPS position
if extract_gps:
try:
gps_info = page.tags["GPSTag"].value
except KeyError:
continue
deg_lat, deg_long = exif_gps_to_degrees(gps_info)
gps_positions.append((deg_long, deg_lat))
frame_idx += 1
# synchronize RGB videos
if sync_rgb and (input_rgb is not None):
rgb_frame_idx = 0
last_frame_idx = None
for rgb_file in rgb_files:
cap = cv2.VideoCapture(rgb_file)
for _ in range(int(cap.get(cv2.CAP_PROP_FRAME_COUNT))):
res, frame = cap.read()
if res:
frame_idx = get_ir_frame_number(rgb_frame_idx, n_ir, n_rgb)
if last_frame_idx is None or frame_idx != last_frame_idx:
out_path = os.path.join(output_dir,
"rgb", "frame_{:06d}.jpg".format(frame_idx))
cv2.imwrite(
out_path, frame, [cv2.IMWRITE_JPEG_QUALITY, 100])
last_frame_idx = frame_idx
rgb_frame_idx += 1
# store extracted GPS positions to disk
if extract_gps and len(gps_positions) > 0:
# save GPS trajectory to CSV
with open(os.path.join(
output_dir, "gps", "gps.csv"), "w", newline="") as csvfile:
writer = csv.writer(csvfile, delimiter=",")
for row in gps_positions:
writer.writerow(row)
# save GPS trajectory to JSON
json.dump(gps_positions, open(os.path.join(
output_dir, "gps", "gps.json"), "w"))
# save GPS trajectory to KML file
kml_file = simplekml.Kml()
kml_file.newlinestring(name="trajectory", coords=gps_positions)
kml_file.save(os.path.join(output_dir, "gps", "gps.kml"))
if __name__ == "__main__":
input_ir = "/storage/data/raw/20210510_Schmalenbach/02_north/aIR/*.TIFF"
input_rgb = "/storage/data/raw/20210510_Schmalenbach/02_north/VIS/*.mov"
output_dir = "/storage/data/splitted/20210510_Schmalenbach/02_north"
run(input_ir, output_dir, input_rgb, extract_gps=True, sync_rgb=True)