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

bug fixes

parent 4f2fb6b9
......@@ -41,3 +41,79 @@ To be extended but roughly, here are the key steps of the dataset creation :
6. For each video : register all the video frames in the reconstructed model
- It is not recommended to do it with all the videos at the same time, or the last bundle_adjustement will be very slow.
- See [here]() for more details on frames registration
## Detailed method with the "Manoir" example
### Scene presentation
### Data acquisition
### Set-by-step commands
1. Extract frames from the videos. For the moment, extract only frames that will help the general reconstruction.
2. Put images in the following tree strcture:
```
├── images
│   ├── anafi
│   │   ├── raw
│   │   ├── rectilinear
│   │   └── video
│   │   ├── 4K30
│   │   └── 720p120
│   └── apn
└── images_mask
```
3. Generate masks in the folder `images_mask`
`python generate_sky_map.py --root images`
5. First COLMAP step : feature extraction
```
colmap feature_extractor --database scan.db --image
```
6. Second COLMAP step : matching. For less than 1000 images, you can use exhaustive matching (this will take around 2hours). If there is too much images, you can use either spatial matching or vocab tree matching
```
colmap exhaustive_matcher --database scan.db
```
or
```
colmap spatial_matcher --database scan.db
```
or
```
colmap vocab_tree_matcher --database scan.db
```
7. Third COLMAP step : mapping.
```
mkdir -p output/sparse
colmap mapper --Mapper.multiple_models 0 --database_path scan.db --output_path output/sparse/ --image_path images
```
This will create a model file in the folder `output/sparse` (or `output/sparse/0`), in the form of 3 files
```
└── sparse
└── 0
├── cameras.bin
├── images.bin
├── points3D.bin
└── project.ini
```
8. Third COLMAP step : [georeferencing](https://colmap.github.io/faq.html#geo-registration)
* Create an `images.txt` with the image name and their XYZ position, relative to the centered Lidar Point using the file `cloud_centroid.txt`created at step 4
```
python align_frames_with_lidar.py --root images --centroid_path cloud_centroid.txt --output images.txt
```
This will create a file with image paths and corresponding XYZ coordinates at each line.
* ```
mkdir -p output/georeferenced
colmap model_aligner --input_path output/sparse --output_sparse output/georeferenced --ref_images_path images.txt
......@@ -11,7 +11,7 @@ parser = ArgumentParser(description='extract XYZ data from exif and substract cl
parser.add_argument('--root', metavar='DIR',
help='path to video folder root')
parser.add_argument('--centroid_path')
parser.add_argument('--centroid_path', default=None)
parser.add_argument('--system', default='epsg:2154')
parser.add_argument('--output', metavar='PATH', default='images.txt')
......@@ -19,7 +19,6 @@ parser.add_argument('--output', metavar='PATH', default='images.txt')
def main():
args = parser.parse_args()
root = Path(args.root)
images = sorted(root.files('*.jpg'))
if args.centroid_path is not None:
centroid = np.loadtxt(args.centroid_path)
else:
......@@ -27,14 +26,21 @@ def main():
proj = Proj(args.system)
result = []
for img in tqdm(images):
folders = [root] + list(root.walkdirs())
file_exts = ['jpg', 'JPG']
for folder in tqdm(folders):
current_folder = root.relpathto(folder)
images = sum((folder.files('*{}'.format(ext)) for ext in file_exts), [])
for img in images:
loc = get_gps_location(img)
if loc is None:
continue
lat, lon, alt = loc
x, y = proj(lon, lat)
pos = np.array([x, y, alt]) - centroid
result.append('{} {} {} {}\n'.format(img.basename(), *pos))
result.append('{} {} {} {}\n'.format(current_folder/img.basename(), *pos))
with open(args.output, 'w') as f:
f.writelines(result)
......
......@@ -11,18 +11,16 @@ 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")],
ffmpeg = Popen(["ffmpeg", "-y", "-i", str(file_path), "-qscale:v", "2"] + fps_arg + [str(folder_path/"%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"
output_file = folder_path/"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)
......@@ -43,31 +41,42 @@ def add_gps_to_exif(folder, fps):
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"])
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()
def workflow(output_folder, video_path, args):
output_folder /= video_path.namebase
if args.fps is not None:
output_folder += "_{}fps".format(args.fps)
output_folder.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)
extract_images(output_folder, video_path, args.fps)
extract_metadata(output_folder, video_path, args.nw)
add_gps_to_exif(output_folder, 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')
help='path to video folder root', type=Path)
parser.add_argument('--fps', metavar='F', default=None, type=int,
help='fps')
parser.add_argument('--output_folder', metavar='PATH', default=None, type=Path)
parser.add_argument('--nw', default='',
help="native-wrapper.sh file location")
if __name__ == '__main__':
args = parser.parse_args()
root = Path(args.root)
root = args.root
if args.output_folder is None:
output_folder = root
else:
output_folder = args.output_folder
file_exts = ['.mp4', '.MP4']
if root.isdir():
folders = list(root.walkdirs())
......@@ -77,6 +86,6 @@ if __name__ == '__main__':
if videos:
print("Generating images with gps for videos in {}".format(str(folder)))
for video_path in videos:
workflow(folder, video_path, args)
workflow(output_folder/(folder.relpath(root)), video_path, args)
elif root.isfile() and root.ext in file_exts:
workflow(root.parent, root, args)
workflow(root.parent, output_folder, args)
......@@ -9,8 +9,8 @@ parser = ArgumentParser(description='Convert las cloud to ply along with centroi
parser.add_argument('las',
help='path to video folder root')
parser.add_argument('--output_ply', metavar='PATH')
parser.add_argument('--output_txt', metavar='PATH')
parser.add_argument('--output_ply', metavar='PATH', default=None)
parser.add_argument('--output_txt', metavar='PATH', default=None)
def main():
......
......@@ -7,3 +7,5 @@ piexif
pandas
imageio
pyntcloud
ezdxf
meshio
\ No newline at end of file
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