Exemplo n.º 1
0
def makeOutputFolder(output_folder_base, suffix_counter,
                     overwrite, unique_output_folder):
    if overwrite and unique_output_folder:
        logger.error("specify either --overwrite or --unique_output_folder")
        v2e_quit()
    if suffix_counter > 0:
        output_folder = output_folder_base + '-' + str(suffix_counter)
    else:
        output_folder = output_folder_base
    nonEmptyFolderExists = not overwrite and os.path.exists(output_folder) and os.listdir(output_folder)
    if nonEmptyFolderExists and not overwrite and not unique_output_folder:
        logger.error(
            'non-empty output folder {} already exists \n '
            '- use --overwrite or --unique_output_folder'.format(
                os.path.abspath(output_folder), nonEmptyFolderExists))
        v2e_quit()

    if nonEmptyFolderExists and unique_output_folder:
        return makeOutputFolder(
            output_folder_base, suffix_counter + 1, overwrite, unique_output_folder)
    else:
        logger.info('using output folder {}'.format(output_folder))
        if not os.path.exists(output_folder):
            os.makedirs(output_folder)
        return output_folder
Exemplo n.º 2
0
def main():
    try:
        ga=Gooey(get_args, program_name="v2e", default_size=(575, 600))
        logger.info('Use --ignore-gooey to disable GUI and run with command line arguments')
        ga()
    except:
        logger.warning('Gooey GUI not available, using command line arguments. \n'
                       'You can try to install with "pip install Gooey"')
    args=get_args()
    # args=get_args()
    overwrite: bool = args.overwrite
    output_folder: str = args.output_folder
    unique_output_folder: bool = args.unique_output_folder

    output_folder = makeOutputFolder(output_folder, 0, overwrite, unique_output_folder)

    input_file = args.input
    if not input_file:
        input_file = inputVideoFileDialog()
        if not input_file:
            logger.info('no file selected, quitting')
            v2e_quit()


    output_width: int = args.output_width
    output_height: int = args.output_height
    if (output_width is None) ^ (output_height is None):
        logger.error('set neither or both of output_width and output_height')
        v2e_quit()
    dvs128=args.dvs128
    dvs240=args.dvs240
    dvs346=args.dvs346
    dvs640=args.dvs640
    dvs1024=args.dvs1024

    if dvs128:
        output_width=128
        output_height=128
    elif dvs240:
        output_width=240
        output_height=180
    elif dvs346:
        output_width=346
        output_height=260
    elif dvs640:
        output_width=640
        output_height=480
    elif dvs1024:
        output_width=1024
        output_height=768

    # input file checking
    if not input_file or not Path(input_file).exists():
        logger.error('input file {} does not exist'.format(input_file))
        v2e_quit()

    start_time = args.start_time
    stop_time = args.stop_time

    input_slowmotion_factor:float = args.input_slowmotion_factor
    timestamp_resolution:float = args.timestamp_resolution
    auto_timestamp_resolution:bool=args.auto_timestamp_resolution

    if auto_timestamp_resolution==False and timestamp_resolution is None:
        logger.error('if --auto_timestamp_resolution=False, then --timestamp_resolution must be set to '
                     'some desired DVS event timestamp resolution in seconds, '
                     'e.g. 0.01')
        v2e_quit()

    pos_thres = args.pos_thres
    neg_thres = args.neg_thres
    sigma_thres = args.sigma_thres
    cutoff_hz = args.cutoff_hz
    leak_rate_hz = args.leak_rate_hz
    if leak_rate_hz > 0 and sigma_thres == 0:
        logger.warning(
            'leak_rate_hz>0 but sigma_thres==0, '
            'so all leak events will be synchronous')
    shot_noise_rate_hz = args.shot_noise_rate_hz
    avi_frame_rate = args.avi_frame_rate
    dvs_vid = args.dvs_vid
    dvs_vid_full_scale = args.dvs_vid_full_scale
    dvs_h5 = args.dvs_h5
    # dvs_np = args.dvs_np
    dvs_aedat2 = args.dvs_aedat2
    dvs_text = args.dvs_text
    vid_orig = args.vid_orig
    vid_slomo = args.vid_slomo
    slomo_stats_plot=args.slomo_stats_plot

    preview = not args.no_preview
    rotate180 = args.rotate180
    batch_size = args.batch_size

    exposure_mode, exposure_val, area_dimension = \
        v2e_check_dvs_exposure_args(args)

    infofile = write_args_info(args, output_folder)

    fh = logging.FileHandler(infofile)
    fh.setLevel(logging.INFO)
    formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    fh.setFormatter(formatter)
    logger.addHandler(fh)

    import time
    time_run_started = time.time()

    logger.info("opening video input file " + input_file)

    cap = cv2.VideoCapture(input_file)
    srcFps = cap.get(cv2.CAP_PROP_FPS)
    if srcFps == 0:
        logger.error('source {} fps is 0'.format(input_file))
        v2e_quit()

    # https://stackoverflow.com/questions/25359288/how-to-know-total-number-of-frame-in-a-file-with-cv2-in-python
    srcNumFrames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    if srcNumFrames < 2:
        logger.warning(
            'num frames is less than 2, probably cannot be determined '
            'from cv2.CAP_PROP_FRAME_COUNT')

    srcTotalDuration = (srcNumFrames - 1) / srcFps
    start_frame = int(srcNumFrames * (start_time / srcTotalDuration)) \
        if start_time else 0
    stop_frame = int(srcNumFrames * (stop_time / srcTotalDuration)) \
        if stop_time else srcNumFrames
    srcNumFramesToBeProccessed = stop_frame - start_frame + 1
    srcDurationToBeProcessed = srcNumFramesToBeProccessed / srcFps
    start_time = start_frame / srcFps
    stop_time = stop_frame / srcFps  # todo something replicated here, already have start and stop times

    srcFrameIntervalS = (1. / srcFps) / input_slowmotion_factor

    slomoTimestampResolutionS = None

    slowdown_factor=None
    if not auto_timestamp_resolution:
        slowdown_factor = int(np.ceil(srcFrameIntervalS / timestamp_resolution))
        if slowdown_factor <= 1:
            slowdown_factor = 1
            logger.warning(
                'timestamp resolution={}s is >= source '
                'frame interval={}s, will not upsample'
                    .format(timestamp_resolution, srcFrameIntervalS))

        logger.info(
            'Src video frame rate={:.2f} Hz with slowmotion_factor={:.2f}, \n'
            'timestamp resolution={:.3f} ms, computed slomo upsampling factor={}'
                .format(
                srcFps, input_slowmotion_factor, timestamp_resolution * 1000,
                slowdown_factor))

        slomoTimestampResolutionS = srcFrameIntervalS / slowdown_factor

        if slomoTimestampResolutionS > timestamp_resolution:
            logger.warning(
                'Upsampled src frame intervals of {}s is larger than\n '
                'the desired DVS timestamp resolution of {}s'
                    .format(slomoTimestampResolutionS, timestamp_resolution))

        check_lowpass(cutoff_hz, 1 / slomoTimestampResolutionS, logger)
    else: # auto_timestamp_resolution
        logger.info('--auto_timestamp_resolution=True, \n'
                    'so source video will be automatically upsampled to limit'
                    'maximum interframe motion to 1 pixel')

    # the SloMo model, set no SloMo model if no slowdown
    if auto_timestamp_resolution or slowdown_factor != NO_SLOWDOWN:
        slomo = SuperSloMo(
            model=args.slomo_model, auto_upsample=auto_timestamp_resolution, upsampling_factor=slowdown_factor,
            video_path=output_folder, vid_orig=vid_orig, vid_slomo=vid_slomo,
            preview=preview, batch_size=batch_size)
    else:
        slomo = None

    if exposure_mode == ExposureMode.DURATION:
        dvsFps = 1. / exposure_val

    if not auto_timestamp_resolution:
        logger.info('\n events will have timestamp resolution {}s,'.format(slomoTimestampResolutionS))
        if exposure_mode == ExposureMode.DURATION and dvsFps > (1 / slomoTimestampResolutionS):
            logger.warning(
                'DVS video frame rate={}Hz is larger than '
                'the effective DVS frame rate of {}Hz; '
                'DVS video will have blank frames'.format(
                    dvsFps, (1 / slomoTimestampResolutionS)))

    logger.info(
        'Source video {} has total {} frames with total duration {}s. '
        '\nSource video is {}fps with slowmotion_factor {} '
        '(frame interval {}s),'
        '\nWill convert frames {} to {}\n'
        '(From {}s to {}s, duration {}s)'
            .format(input_file, srcNumFrames, eng(srcTotalDuration),
                    eng(srcFps), eng(input_slowmotion_factor),
                    eng(srcFrameIntervalS),
                    start_frame,stop_frame,
                    start_time,stop_time,(stop_time-start_time)))

    if exposure_mode == ExposureMode.DURATION:
        dvsNumFrames = np.math.floor(
            dvsFps * srcDurationToBeProcessed / input_slowmotion_factor)
        dvsDuration = dvsNumFrames / dvsFps
        dvsPlaybackDuration = dvsNumFrames / avi_frame_rate
        start_time = start_frame / srcFps
        stop_time = stop_frame / srcFps  # todo something replicated here, already have start and stop times

        logger.info('v2e DVS video will have constant-duration frames \n'
                    'at {}fps (accumulation time {}s), '
                    '\nDVS video will have {} frames with duration {}s '
                    'and playback duration {}s\n'
                    .format(eng(dvsFps), eng(1 / dvsFps),
                            dvsNumFrames, eng(dvsDuration),
                            eng(dvsPlaybackDuration)))
    else:
        logger.info('v2e DVS video will have constant-count '
            'frames with {} events), '
                .format(exposure_val))

    emulator = EventEmulator(
        pos_thres=pos_thres, neg_thres=neg_thres,
        sigma_thres=sigma_thres, cutoff_hz=cutoff_hz,
        leak_rate_hz=leak_rate_hz, shot_noise_rate_hz=shot_noise_rate_hz,
        output_folder=output_folder, dvs_h5=dvs_h5, dvs_aedat2=dvs_aedat2,
        dvs_text=dvs_text)

    if args.dvs_params:
        emulator.set_dvs_params(args.dvs_params)

    eventRenderer = EventRenderer(
        output_path=output_folder,
        dvs_vid=dvs_vid, preview=preview, full_scale_count=dvs_vid_full_scale,
        exposure_mode=exposure_mode,
        exposure_value=exposure_val,
        area_dimension=area_dimension)

    # timestamps of DVS start at zero and end with span of video we processed
    srcVideoRealProcessedDuration = (stop_time - start_time) / input_slowmotion_factor
    num_frames = srcNumFramesToBeProccessed
    inputHeight = None
    inputWidth = None
    inputChannels = None
    if start_frame > 0:
        logger.info('skipping to frame {}'.format(start_frame))
        for i in tqdm(range(start_frame), unit='fr', desc='src'):
            ret, _ = cap.read()
            if not ret:
                raise ValueError(
                    'something wrong, got to end of file before '
                    'reaching start_frame')

    logger.info(
        'processing frames {} to {} from video input'.format(
            start_frame, stop_frame))

    with TemporaryDirectory() as source_frames_dir:
        inputWidth = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        inputHeight = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        inputChannels = 3

        if (output_width is None) and (output_height is None):
            output_width = inputWidth
            output_height = inputHeight
            logger.warning(
                'output size ({}x{}) was set automatically to '
                'input video size\n    Are you sure you want this? '
                'It might be slow.\n Consider using\n '
                '    --output_width=346 --output_height=260\n to match Davis346.'
                    .format(output_width, output_height))

        logger.info('Resizing input frames to output size '
                    '(with possible RGG to luma conversion)')
        for inputFrameIndex in tqdm(
                range(srcNumFramesToBeProccessed),
                desc='rgb2luma', unit='fr'):
            # read frame
            ret, inputVideoFrame = cap.read()

            if not ret or inputFrameIndex + start_frame > stop_frame:
                break

            if output_height and output_width and \
                    (inputHeight != output_height or
                     inputWidth != output_width):
                dim = (output_width, output_height)
                (fx, fy) = (float(output_width) / inputWidth,
                            float(output_height) / inputHeight)
                inputVideoFrame = cv2.resize(
                    src=inputVideoFrame, dsize=dim, fx=fx, fy=fy,
                    interpolation=cv2.INTER_AREA)
            if inputChannels == 3:  # color
                if inputFrameIndex == 0:  # print info once
                    logger.info(
                        '\nConverting input frames from RGB color to luma')
                # TODO would break resize if input is gray frames
                # convert RGB frame into luminance.
                inputVideoFrame = cv2.cvtColor(
                    inputVideoFrame, cv2.COLOR_BGR2GRAY)  # much faster

            # save frame into numpy records
            save_path = os.path.join(
                source_frames_dir, str(inputFrameIndex).zfill(8) + ".npy")
            np.save(save_path, inputVideoFrame)
            # print("Writing source frame {}".format(save_path), end="\r")
        cap.release()

        with TemporaryDirectory() as interpFramesFolder:
            interpTimes=None
            # make input to slomo
            if slowdown_factor != NO_SLOWDOWN:
                # interpolated frames are stored to tmpfolder as
                # 1.png, 2.png, etc
                interpTimes,avgUpsamplingFactor=slomo.interpolate(
                    source_frames_dir, interpFramesFolder,
                    (output_width, output_height))
                avgTs = srcFrameIntervalS / avgUpsamplingFactor
                logger.info('SloMo average upsampling factor={:5.2f}; average DVS timestamp resolution={}s'
                            .format(avgUpsamplingFactor, eng(avgTs)))
                # read back to memory
                interpFramesFilenames = all_images(interpFramesFolder)
                # number of frames
                n = len(interpFramesFilenames)
            else:
                logger.info('turning npy frame files to png from {}'
                            .format(source_frames_dir))
                interpFramesFilenames = []
                n=0
                src_files = sorted(
                    glob.glob("{}".format(source_frames_dir) + "/*.npy"))
                for frame_idx, src_file_path in tqdm(
                        enumerate(src_files), desc='npy2png', unit='fr'):
                    src_frame = np.load(src_file_path)
                    tgt_file_path = os.path.join(
                        interpFramesFolder, str(frame_idx) + ".png")
                    interpFramesFilenames.append(tgt_file_path)
                    n+=1
                    cv2.imwrite(tgt_file_path, src_frame)
                interpTimes=np.array(range(n))


            # compute times of output integrated frames
            nFrames=len(interpFramesFilenames)
            # interpTimes is in units of 1 per input frame, normalize it to src video time range
            f=srcVideoRealProcessedDuration/(np.max(interpTimes)-np.min(interpTimes))
            interpTimes = f*interpTimes # compute actual times from video times
            # debug
            if slomo_stats_plot:
                from matplotlib import pyplot as plt  # TODO debug
                dt = np.diff(interpTimes)
                fig=plt.figure()
                ax1=fig.add_subplot(111)
                ax1.set_title('Slo-Mo frame interval stats (close to continue)')
                ax1.plot(interpTimes)
                ax1.plot(interpTimes,'x')
                ax1.set_xlabel('frame')
                ax1.set_ylabel('frame time (s)')
                ax2=ax1.twinx()
                ax2.plot(dt*1e3)
                ax2.set_ylabel('frame interval (ms)')
                logger.info('close plot to continue')
                fig.show()

            events = np.zeros((0, 4), dtype=np.float32)  # array to batch events for rendering to DVS frames
            with tqdm(total=nFrames, desc='dvs', unit='fr') as pbar: # instantiate progress bar
                for i in range(nFrames):
                    fr = read_image(interpFramesFilenames[i])
                    newEvents = emulator.generate_events(fr, interpTimes[i])

                    pbar.update(1)
                    if newEvents is not None and newEvents.shape[0] > 0:
                        events = np.append(events, newEvents, axis=0)
                        events = np.array(events)
                        if i%batch_size==0:
                            eventRenderer.render_events_to_frames(events, height=output_height, width=output_width)
                            events = np.zeros((0, 4), dtype=np.float32)  # clear array
                if len(events)>0: # process leftover
                    eventRenderer.render_events_to_frames(events, height=output_height, width=output_width)

    eventRenderer.cleanup()
    emulator.cleanup()
    if slomo is not None:
        slomo.cleanup()

    if num_frames == 0:
        logger.error('no frames read from file')
        v2e_quit()
    totalTime = (time.time() - time_run_started)
    framePerS = num_frames / totalTime
    sPerFrame = 1 / framePerS
    throughputStr = (str(eng(framePerS)) + 'fr/s') \
        if framePerS > 1 else (str(eng(sPerFrame)) + 's/fr')
    logger.info(
        'done processing {} frames in {}s ({})\n see output folder {}'
            .format(num_frames,
                    eng(totalTime),
                    throughputStr,
                    output_folder))
    logger.info('generated total {} events ({} on, {} off)'
                .format(eng(emulator.num_events_total),
                        eng(emulator.num_events_on),
                        eng(emulator.num_events_off)))
    logger.info(
        'avg event rate {}Hz ({}Hz on, {}Hz off)'
            .format(
            eng(emulator.num_events_total / srcDurationToBeProcessed),
            eng(emulator.num_events_on / srcDurationToBeProcessed),
            eng(emulator.num_events_off / srcDurationToBeProcessed)))
    try:
        desktop.open(os.path.abspath(output_folder))
    except Exception as e:
        logger.warning(
            '{}: could not open {} in desktop'.format(e, output_folder))
Exemplo n.º 3
0
    framePerS = num_frames / totalTime
    sPerFrame = 1 / framePerS
    throughputStr = (str(eng(framePerS)) + 'fr/s') \
        if framePerS > 1 else (str(eng(sPerFrame)) + 's/fr')
    logger.info(
        'done processing {} frames in {}s ({})\n see output folder {}'
            .format(num_frames,
                    eng(totalTime),
                    throughputStr,
                    output_folder))
    logger.info('generated total {} events ({} on, {} off)'
                .format(eng(emulator.num_events_total),
                        eng(emulator.num_events_on),
                        eng(emulator.num_events_off)))
    logger.info(
        'avg event rate {}Hz ({}Hz on, {}Hz off)'
            .format(
            eng(emulator.num_events_total / srcDurationToBeProcessed),
            eng(emulator.num_events_on / srcDurationToBeProcessed),
            eng(emulator.num_events_off / srcDurationToBeProcessed)))
    try:
        desktop.open(os.path.abspath(output_folder))
    except Exception as e:
        logger.warning(
            '{}: could not open {} in desktop'.format(e, output_folder))


if __name__ == "__main__":
    main()
    v2e_quit()