Commit a5c21661 authored by Clément Pinard's avatar Clément Pinard
Browse files

add video frames extractor

parent f7f1428c
import piexif
from fractions import Fraction
def to_deg(value, loc):
"""convert decimal coordinates into degrees, munutes and seconds tuple
Keyword arguments: value is float gps-value, loc is direction list ["S", "N"] or ["W", "E"]
return: tuple like (25, 13, 48.343 ,'N')
"""
if value < 0:
loc_value = loc[0]
elif value > 0:
loc_value = loc[1]
else:
loc_value = ""
abs_value = abs(value)
deg = int(abs_value)
t1 = (abs_value-deg)*60
min = int(t1)
sec = round((t1 - min) * 60, 5)
return [deg, min, sec], loc_value
def to_dec(deg, min, sec, sign):
result = deg[0] / deg[1]
result += min[0] / (60 * min[1])
result += sec[0] / (60 * 60 * sec[1])
return sign * result
def change_to_rational(number):
"""convert a number to rantional
Keyword arguments: number
return: tuple like (1, 2), (numerator, denominator)
"""
f = Fraction(str(number))
return (f.numerator, f.denominator)
def set_gps_location(file_name, lat, lng, altitude):
"""Adds GPS position as EXIF metadata
Keyword arguments:
file_name -- image file
lat -- latitude (as float)
lng -- longitude (as float)
altitude -- altitude (as float)
"""
lat_deg, ref_lat = to_deg(lat, ["S", "N"])
lng_deg, ref_lng = to_deg(lng, ["W", "E"])
exif_lat = list(map(change_to_rational, lat_deg))
exif_lng = list(map(change_to_rational, lng_deg))
ref = 1 if altitude < 0 else 0
gps_ifd = {
piexif.GPSIFD.GPSVersionID: (2, 0, 0, 0),
piexif.GPSIFD.GPSAltitudeRef: ref,
piexif.GPSIFD.GPSAltitude: change_to_rational(abs(altitude)),
piexif.GPSIFD.GPSLatitudeRef: ref_lat,
piexif.GPSIFD.GPSLatitude: exif_lat,
piexif.GPSIFD.GPSLongitudeRef: ref_lng,
piexif.GPSIFD.GPSLongitude: exif_lng,
}
exif_dict = {"GPS": gps_ifd}
exif_bytes = piexif.dump(exif_dict)
piexif.insert(exif_bytes, file_name)
def get_gps_location(file_name):
exif_dict = piexif.load(file_name)
gps = exif_dict['GPS']
if len(gps) == 0:
return
ref_lat = gps[piexif.GPSIFD.GPSLatitudeRef]
ref_lng = gps[piexif.GPSIFD.GPSLongitudeRef]
ref_alt = gps[piexif.GPSIFD.GPSAltitudeRef]
exif_lat = gps[piexif.GPSIFD.GPSLatitude]
exif_lng = gps[piexif.GPSIFD.GPSLongitude]
exif_alt = gps[piexif.GPSIFD.GPSAltitude]
lat = to_dec(*exif_lat, (1 if ref_lat == b'N' else -1))
lng = to_dec(*exif_lng, (1 if ref_lng == b'E' else -1))
alt = exif_alt[0] / exif_alt[1]
if ref_alt == 1:
alt *= -1
return lat, lng, alt
import edit_exif
from subprocess import Popen, PIPE
from path import Path
from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter
import pandas as pd
from tqdm import tqdm
def extract_images(folder_path, file_path, fps):
print("exporting to images with ffmpeg ...")
if fps is not None:
fps_arg = ["-vf", "fps={}".format(fps)]
output = folder_path/"{}_fps{}".format(file_path.namebase, fps)
else:
fps_arg = []
ffmpeg = Popen(["ffmpeg", "-y", "-i", str(file_path), "-qscale:v", "2"] + fps_arg + [str(output/"{}%05d.jpg")],
stdout=PIPE, stderr=PIPE)
ffmpeg.wait()
def extract_metadata(folder_path, file_path, native_wrapper):
name = file_path.namebase
output_file = folder_path/name/"metadata.csv"
print("extracting metadata with vmeta_extract...")
vmeta_extract = Popen([native_wrapper, "vmeta-extract", str(file_path), "--csv", str(output_file)],
stdout=PIPE, stderr=PIPE)
vmeta_extract.wait()
def add_gps_to_exif(folder, fps):
csv_file = folder/"metadata.csv"
metadata = pd.read_csv(csv_file, sep=" ")
metadata = metadata.set_index("time")
metadata.index = pd.to_datetime(metadata.index, unit="us")
if fps is not None:
metadata = metadata.resample("{:.3f}S".format(1/fps)).first()
pictures = sorted(folder.files("*.jpg"))
print("Modifying gps EXIF for colmap...")
for pic_path, row in tqdm(zip(pictures, metadata.iterrows()), total=len(pictures)):
if row[1]["location_valid"] == 1:
edit_exif.set_gps_location(pic_path, row[1]["location_latitude"], row[1]["location_longitude"], row[1]["location_altitude"])
def workflow(folder, video_path, args):
(folder/video_path.namebase).mkdir_p()
print(video_path.namebase)
print(video_path)
extract_images(folder, video_path, args.fps)
extract_metadata(folder, video_path, args.nw)
add_gps_to_exif(folder/video_path.namebase, args.fps)
parser = ArgumentParser(description='image extractor from parrot video',
formatter_class=ArgumentDefaultsHelpFormatter)
parser.add_argument('--root', metavar='DIR', default="~/Images/scan manoir/anafi/video",
help='path to video folder root')
parser.add_argument('--fps', metavar='F', default=None, type=int,
help='fps')
parser.add_argument('--nw', default='',
help="native-wrapper.sh file location")
if __name__ == '__main__':
args = parser.parse_args()
root = Path(args.root)
file_exts = ['.mp4', '.MP4']
if root.isdir():
folders = list(root.walkdirs())
folders.append(root)
for folder in folders:
videos = sum((folder.files('*{}'.format(ext)) for ext in file_exts), [])
if videos:
print("Generating images with gps for videos in {}".format(str(folder)))
for video_path in videos:
workflow(folder, video_path, args)
elif root.isfile() and root.ext in file_exts:
workflow(root.parent, root, args)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment