Example #1
0
def reconstruct(settings):
    timer_global = Timer()

    SKIP_UNDISTORT = settings["SKIP_UNDISTORT"]
    SKIP_STEREO = settings["SKIP_STEREO"]
    SKIP_FUSION = settings["SKIP_FUSION"]

    # VALIDATE PATHS
    SCRIPT_DIR = settings["SCRIPT_DIR"].rstrip("/")
    assert os.path.exists(
        SCRIPT_DIR), "ERROR: SCRIPT PATH MISSING AT {}".format(SCRIPT_DIR)

    WORK_DIR = settings["WORK_DIR"].rstrip("/")
    if not os.path.exists(WORK_DIR):
        os.mkdir(WORK_DIR)

    IMAGE_DIR = settings["IMAGE_DIR"]
    IMAGE_DIR = "{}/{}".format(WORK_DIR, IMAGE_DIR)
    if not os.path.exists(IMAGE_DIR):
        os.mkdir(IMAGE_DIR)

    MODEL_DIR = settings["MODEL_DIR"]
    MODEL_DIR = "{}/{}".format(WORK_DIR, MODEL_DIR)
    if not os.path.exists(MODEL_DIR):
        os.mkdir(MODEL_DIR)

    OUTPUT_DIR = settings["OUTPUT_DIR"]
    OUTPUT_DIR = "{}/{}".format(WORK_DIR, OUTPUT_DIR)
    if not os.path.exists(OUTPUT_DIR):
        os.mkdir(OUTPUT_DIR)

    log = LogWriter(WORK_DIR)
    log.heading("DENSE RECONSTRUCTION")

    log.log("Undistorting images...")
    if not SKIP_UNDISTORT:
        timer = Timer()

        raw_input = "{}/shell/dense_undistort.sh {} {} {}".format(
            SCRIPT_DIR, IMAGE_DIR, MODEL_DIR, OUTPUT_DIR)
        args = shlex.split(raw_input)
        p = subprocess.Popen(args)
        p.wait()

        log.log("...complete ({} sec)".format(timer.read()))
    else:
        log.log("Skipped")

    log.log("Stereo reconstruction...")
    if not SKIP_STEREO:
        timer = Timer()

        raw_input = "{}/shell/dense_stereo.sh {}".format(
            SCRIPT_DIR, OUTPUT_DIR)
        args = shlex.split(raw_input)
        p = subprocess.Popen(args)
        p.wait()

        log.log("...complete ({} sec)".format(timer.read()))
    else:
        log.log("Skipped")

    log.log("Dense fusion...")
    if not SKIP_FUSION:
        timer = Timer()

        raw_input = "{}/shell/dense_fusion.sh {}".format(
            SCRIPT_DIR, OUTPUT_DIR)
        args = shlex.split(raw_input)
        p = subprocess.Popen(args)
        p.wait()

        log.log("...complete ({} sec)".format(timer.read()))
    else:
        log.log("Skipped")

    log.log("\n...job finished ({} sec).".format(timer_global.read()))
def reconstruct(settings):
    timer_global = Timer()

    # LOAD SETTINGS
    SKIP_LOAD_IMAGES = settings["SKIP_LOAD_IMAGES"]
    SKIP_FIND_FEATURES = settings["SKIP_FIND_FEATURES"]
    SKIP_FIND_MATCHES = settings["SKIP_FIND_MATCHES"]
    SKIP_RECONSTRUCT = settings["SKIP_RECONSTRUCT"]
    SKIP_MERGE = settings["SKIP_MERGE"]
    SKIP_SPARSE_CONVERT = settings["SKIP_SPARSE_CONVERT"]

    # VALIDATE PATHS
    SCRIPT_DIR = settings["SCRIPT_DIR"].rstrip("/")
    assert os.path.exists(SCRIPT_DIR), "ERROR: SCRIPT PATH MISSING AT {}".format(SCRIPT_DIR)

    WORK_DIR = settings["WORK_DIR"].rstrip("/")
    if not os.path.exists(WORK_DIR):
        os.mkdir(WORK_DIR)

    IMAGE_DIR = "images"
    IMAGE_DIR = "{}/{}".format(WORK_DIR, IMAGE_DIR)
    if not os.path.exists(IMAGE_DIR):
        os.mkdir(IMAGE_DIR)

    FRAME_WIDTH = settings["FRAME_WIDTH"]
    FRAME_HEIGHT = settings["FRAME_HEIGHT"]
    if FRAME_WIDTH < 2 * FRAME_HEIGHT:
        FRAME_WIDTH = 2 * FRAME_HEIGHT
    FRAME_FOV = settings["FRAME_FOV"]
    IMAGE_SCALE = settings["IMAGE_SCALE"]


    # VIDEO TIME SETTINGS
    try:
        TIME_START = int(settings["TIME_START"])
        TIME_END = int(settings["TIME_END"])
    except KeyError:
        TIME_START = 0
        TIME_END = int(math.floor(extractor.getEnd()))
    TIME_INTERVAL = settings["TIME_INTERVAL"]
    NUM_FRAMES = int(math.floor((TIME_END - TIME_START) / float(TIME_INTERVAL)))

    # GET PATHS TO VIDEOS
    # VIDEO_PATHS = [settings["VIDEO_PATH"] + path for path in settings["VIDEO_FILES"]]
    # for video in VIDEO_PATHS:
    #     assert os.path.exists(video), "ERROR: VIDEO MISSING AT {}".format(video)
    # VIDEO_PREFIX = settings["VIDEO_FILES"][0].split('_')[0]
    VIDEO_PATH = settings["VIDEO_PATH"]
    assert os.path.exists(VIDEO_PATH), "ERROR: VIDEO MISSING AT {}".format(VIDEO_PATH)
    VIDEO_PREFIX = VIDEO_PATH.split("/")[-1].split(".")[0]

    FIT_REF = settings["FIT_REF"]
    assert os.path.exists(FIT_REF), "ERROR: FIT REF MISSING AT {}".format(FIT_REF)

    if not SKIP_LOAD_IMAGES or not SKIP_FIND_FEATURES:
        # CREATE FRAME EXTRACTOR OBJECT
        print("\nLOADING VIDEOS... {}".format(VIDEO_PATH))
        extractor = VideoExtractor(
            VIDEO_PATH,
            FIT_REF,
            IMAGE_SCALE,
            frame_width=FRAME_WIDTH,
            frame_height=FRAME_HEIGHT,
            fov=FRAME_FOV
            )

    log = LogWriter(WORK_DIR)
    log.heading("IMAGE LOADING")

    if not SKIP_LOAD_IMAGES:
        timer = Timer()

        log.log("Using video:")
        # for path in VIDEO_PATHS:
        #     log.log(path)
        log.log(VIDEO_PATH.split("\\")[-1])

        # ITERATE THROUGH FRAMES
        frame_data = {}
        subflag = "NESW"

        print("\nEXTRACTING FRAMES:\nSTART: {} sec\nEND: {} sec\nINTERVAL: {} sec\n").format(TIME_START, TIME_END, TIME_INTERVAL)

        img_counter = 0
        for frame in range(NUM_FRAMES):

            frame_ID = "{:05d}".format(frame)

            t = TIME_START + frame*TIME_INTERVAL
            data = extractor.extract(t)
            frames = data[:-1]
            record = data[-1]

            file_names = ["{}_{}_{}.jpg".format(VIDEO_PREFIX, subflag[i], frame_ID) for i in xrange(len(frames))]

            print("GENERATING FRAMES @ {d} sec".format(t))

            frame_data[frame_ID] = record

            file_paths = ["{}/{}".format(IMAGE_DIR, file_name) for file_name in file_names]

            for i,file_path in enumerate(file_paths):
                # print file_path
                cv2.imwrite(file_path, frames[i])
                img_counter += 1

            # if exif_exists:
                # extractor.writeEXIF(file_paths, record)

        # SAVE FRAME DATA
        with open("{}/image_data.json".format(WORK_DIR), mode='w') as f:
            json.dump(frame_data, f, sort_keys=True, indent=4, separators=(',', ': '))

        log.log("Successfully loaded {} images ({} sec)".format(img_counter, timer.read()))
    else:
        log.log("Skipped")


    log.heading("FEATURE EXTRACTION")
    if not SKIP_FIND_FEATURES:
        timer = Timer()

        if os.path.exists("{}/database.db".format(WORK_DIR)):
            os.remove("{}/database.db".format(WORK_DIR))

        # frame_dims = extractor.getDims()
        frame_dims = [FRAME_WIDTH, FRAME_HEIGHT]
        camera_model = settings["CAMERA_MODEL"]
        # camera_intrinsics = [settings["CAMERA_FOCAL_LENGTH"]] + [frame_dims[0]/2, frame_dims[1]/2] + settings["CAMERA_PARAMS"]
        camera_intrinsics = [settings["CAMERA_FOCAL_LENGTH"]] + [frame_dims[0]/2, frame_dims[1]/2]
        if settings["CAMERA_PARAMS"]:
            camera_intrinsics.append(settings["CAMERA_PARAMS"])

        camera_intrinsics_str = ",".join([str(d) for d in camera_intrinsics])

        raw_input = "{}/shell/feature_extract.sh {} {} {}".format(SCRIPT_DIR, WORK_DIR, camera_model, camera_intrinsics_str)
        args = shlex.split(raw_input)
        p = subprocess.Popen(args)
        p.wait()

        log.log("Feature extraction ({} sec)".format(timer.read()))
    else:
        log.log("Skipped")


    log.heading("IMAGE MATCHING")
    if not SKIP_FIND_MATCHES:
        timer = Timer()

        # FEATURE MATCHING
        VOCAB_TREE = "{}/vocab_tree/vocab_tree.bin".format(SCRIPT_DIR)
        raw_input = "{}/shell/match_vocabtree.sh {} {}".format(SCRIPT_DIR, WORK_DIR, VOCAB_TREE)
        args = shlex.split(raw_input)
        p = subprocess.Popen(args)
        p.wait()

        log.log("Image matching finished ({} sec)".format(timer.read()))
    else:
        log.log("Skipped")


    log.heading("MODEL RECONSTRUCTION")
    if not SKIP_RECONSTRUCT:
        timer = Timer()

        if not os.path.exists("{}/sparse".format(WORK_DIR)):
            os.mkdir("{}/sparse".format(WORK_DIR))

        target_num = settings["FRAMES_PER_MODEL"]
        overlap = settings["MODEL_OVERLAP"]
        num_chunks = int(round(float((NUM_FRAMES-overlap))/(target_num-overlap)))
        remainder = NUM_FRAMES - (target_num*num_chunks - overlap*num_chunks + overlap)

        log.log("Number of frames in model: {}".format(NUM_FRAMES))
        log.log("Target model size: {}".format(target_num))
        log.log("Model overlap: {}".format(overlap))
        log.log("Models to generate: {}".format(num_chunks))

        models = range(num_chunks)
        # OVERRIDE TO REGENERATE SPECIFIC MODELS
        # models = [0]

        for i in models:

            start_frame = i * (target_num - overlap)
            end_frame = start_frame + target_num

            if i == num_chunks-1:
                end_frame += remainder

            # MAKE IMAGE FILE
            print("\n\nCONSTRUCTING IMAGE LIST\n\n")
            make_image_list(start_frame, end_frame, WORK_DIR, VIDEO_PREFIX)

            MODEL_DIR = "{}/{}/{}".format(WORK_DIR, "sparse", i)
            if not os.path.exists(MODEL_DIR):
                os.mkdir(MODEL_DIR)

            timer_model = Timer()

            # RECONSTRUCT SPARSE
            raw_input = "{}/shell/sparse_reconstruct.sh {} {}".format(SCRIPT_DIR, WORK_DIR, i, 360, 361)
            args = shlex.split(raw_input)
            print args
            p = subprocess.Popen(args)
            p.wait()

            log.log("Constructed model [{}-{}]({} images) in directory: {} ({} sec)".format(start_frame, end_frame, end_frame-start_frame, MODEL_DIR, timer_model.read()))

        log.log("Reconstruction finished ({} sec)".format(timer.read()))
    else:
        log.log("Skipped")


    log.heading("MODEL MERGING")
    if not SKIP_MERGE:
        timer = Timer()

        # FIND RECONSTRUCTED MODELS
        dirs = os.walk("{}/sparse".format(WORK_DIR))
        model_dirs = next(dirs)[1]
        models = []
        for model_dir in model_dirs:
            # try:
            models.append(int(model_dir))
        models.sort()

        log.log("Found {} models: {}".format(len(models), models))

        if len(models) > 1:

            if not os.path.exists("{}/merged".format(WORK_DIR)):
                os.mkdir("{}/merged".format(WORK_DIR))

            model_1 = "{}/sparse/{}/0".format(WORK_DIR,models.pop(0))

            for i,m in enumerate(models):

                model_2 = "{}/sparse/{}/0".format(WORK_DIR,m)
                merge_dir = "{}/merged/{}".format(WORK_DIR,i)
                if not os.path.exists(merge_dir):
                    os.mkdir(merge_dir)

                # MERGE MODEL
                raw_input = "{}/shell/model_merge.sh {} {} {}".format(SCRIPT_DIR, model_1, model_2, merge_dir)
                args = shlex.split(raw_input)
                print args
                p = subprocess.Popen(args)
                p.wait()

                # BUNDLE ADJUSTMENT
                # raw_input = "{}/shell/bundle_adjuster.sh {}".format(SCRIPT_DIR, merge_dir)
                # args = shlex.split(raw_input)
                # print args
                # p = subprocess.Popen(args)
                # p.wait()

                model_1 = merge_dir

                log.log("Merged models:\n{}\n{}\ninto model:\n{}".format(model_1, model_2, merge_dir))
        else:
            log.log("{} model(s) found, at least 2 needed for merging.".format(len(models)))

        log.log("Merging finished ({} sec)".format(timer.read()))
    else:
        log.log("Skipped")

    log.heading("MODEL CONVERSION TO PLY")
    if not SKIP_SPARSE_CONVERT:
        timer = Timer()

        # FIND MERGED MODELS
        models = []
        merge_dir = "{}/merged/0".format(WORK_DIR)
        if os.path.exists(merge_dir):
            models.append(merge_dir)
        else:
            log.log("No merged model found at\n{}".format(merge_dir))
            dirs = os.walk("{}/sparse".format(WORK_DIR))
            model_dirs = next(dirs)[1]
            models = []
            for model_dir in model_dirs:
                # try:
                models.append(int(model_dir))
            models.sort()
            models = ["{}/sparse/{}/0/".format(WORK_DIR,m) for m in models]

        log.log("Found {} models:{}".format(len(models), '\n'.join(models)))

        convert_dir = "{}/sparse_ply".format(WORK_DIR)
        if not os.path.exists(convert_dir):
            os.mkdir(convert_dir)

        for i,model in enumerate(models):
            # MERGE MODEL
            out_model = "{}/sparse_{}.ply".format(convert_dir,i) \
                if len(models) >1 else \
                "{}/sparse_merged.ply".format(convert_dir)

            raw_input = "{}/shell/model_convert.sh {} {} {}".format(SCRIPT_DIR, model, out_model, "PLY")
            args = shlex.split(raw_input)
            print args
            p = subprocess.Popen(args)
            p.wait()

            log.log("Converted model:\n{}\ninto model:\n{}".format(model, out_model))

        log.log("Conversion finished ({} sec)".format(timer.read()))
    else:
        log.log("Skipped")

    log.log("\n...job finished.")