Exemple #1
0
def tool(calibration, video, output, start=None, duration=None):
    start = start or 0

    # Load calibration
    log.info('Loading calibration from {0}...'.format(calibration))
    calibration = json.load(open(calibration))
    cam_matrix = np.asarray(calibration['output']['camMatrix'])
    dist_coeffs = np.asarray(calibration['output']['distCoeffs'])
    frame_size = tuple(calibration['output']['frameSize'])

    # Compute optimal new matrix, etc
    new_cam_matrix, valid_roi = cv2.getOptimalNewCameraMatrix(
            cam_matrix, dist_coeffs, frame_size, 1)

    # Calculate undistort maps
    map1, map2 = cv2.initUndistortRectifyMap(
            cam_matrix, dist_coeffs, None, new_cam_matrix, frame_size,
            cv2.CV_16SC2)

    # Load input video
    vc = open_video(video)

    # Prepare output
    vo = open(output, 'wb') if output != '-' else sys.stdout.buffer
    for frame_idx in itertools.count(0):
        flag, frame = vc.read()
        if not flag:
            break

        # Skip frame if we're not processing this one
        if frame_idx < start:
            continue
        if duration is not None and frame_idx >= start + duration:
            break

        log.debug('Processing frame {0}...'.format(frame_idx))

        # Undistort
        output = cv2.remap(frame, map1, map2, cv2.INTER_LINEAR)

        # We need to do color space conversion due to OpenCV's ordering
        vo.write(cv2.cvtColor(output, cv2.COLOR_RGB2BGR).tostring())

    vo.close()

    return 0
Exemple #2
0
def tool(calibration, video, output, start=None, duration=None):
    start = start or 0

    # Load calibration
    log.info('Loading calibration from {0}...'.format(calibration))
    calibration = json.load(open(calibration))
    cam_matrix = np.asarray(calibration['output']['camMatrix'])
    dist_coeffs = np.asarray(calibration['output']['distCoeffs'])
    frame_size = tuple(calibration['output']['frameSize'])

    # Compute optimal new matrix, etc
    new_cam_matrix, valid_roi = cv2.getOptimalNewCameraMatrix(
        cam_matrix, dist_coeffs, frame_size, 1)

    # Calculate undistort maps
    map1, map2 = cv2.initUndistortRectifyMap(cam_matrix, dist_coeffs, None,
                                             new_cam_matrix, frame_size,
                                             cv2.CV_16SC2)

    # Load input video
    vc = open_video(video)

    # Prepare output
    vo = open(output, 'wb') if output != '-' else sys.stdout.buffer
    for frame_idx in itertools.count(0):
        flag, frame = vc.read()
        if not flag:
            break

        # Skip frame if we're not processing this one
        if frame_idx < start:
            continue
        if duration is not None and frame_idx >= start + duration:
            break

        log.debug('Processing frame {0}...'.format(frame_idx))

        # Undistort
        output = cv2.remap(frame, map1, map2, cv2.INTER_LINEAR)

        # We need to do color space conversion due to OpenCV's ordering
        vo.write(cv2.cvtColor(output, cv2.COLOR_RGB2BGR).tostring())

    vo.close()

    return 0
Exemple #3
0
def tool(video, cb_shape, autostop=True, skip=None, output=None, start=None,
        duration=None, threshold=None):
    # Load input video
    vc = open_video(video)

    # Parse chessboard shape
    if len(cb_shape) != 2:
        log.error('Chessboard shape should have 2 components, a width and height.')
        return 1
    log.debug('Using chessboard with shape: {0}x{1}'.format(*cb_shape))

    # Defaults
    skip = skip or 1
    start = start or 0
    log.debug('Processing every {0} frame(s) from {1}'.format(skip, start))

    image_pts = []
    frame_shape = None
    used_frames = []

    # A list of parameters for each board we used
    used_board_params = []
    minmax_parameters = None
    goals = np.asarray((0.7, 0.7, 0.4, 0.5))
    param_labels = ('X', 'Y', 'size', 'skew')

    for frame_idx in itertools.count(0):
        flag, frame = vc.read()
        if not flag:
            break

        # Skip frame if we're not processing this one
        if frame_idx < start or frame_idx % skip != 0:
            continue

        # Stop processing after specified duration
        if duration is not None and frame_idx >= start + duration:
            break

        log.debug('Processing frame {0}'.format(frame_idx))

        # Convert to grayscale
        frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
        if frame_shape is None:
            frame_shape = frame.shape

        # Look for chessboard
        rv, corners = cv2.findChessboardCorners(frame,
                cb_shape, flags=cv2.CALIB_CB_FAST_CHECK)
        if not rv:
            continue

        log.debug('Board found in frame {0}'.format(frame_idx))

        board_params = np.asarray(corner_shape_parameters(corners, frame_shape, cb_shape))
        log.debug('Board has parameters: {0}'.format(board_params))

        log.debug('Automatic selection threshold is {0}'.format(threshold))

        # If we have previous parameters and we auto threshold, see if we go
        # any further
        if len(used_board_params) > 0 and threshold is not None:
            # Compute L1 distance in parameters for each prior board
            min_l1_delta = np.asarray(
                    list(np.sum(np.abs(p - board_params)) for p in used_board_params)
            ).min()

            log.debug('Minimum L1 delta is {0}'.format(min_l1_delta))

            # Is minimum distance not good?
            if min_l1_delta < threshold:
                continue

        # Add this board's parameters to our records
        used_board_params.append(board_params)

        # Update minimum and maximum params
        if minmax_parameters is None:
            minmax_parameters = np.vstack((board_params, board_params))
        else:
            minmax_parameters[0,:] = np.minimum(minmax_parameters[0,:], board_params)
            minmax_parameters[1,:] = np.maximum(minmax_parameters[1,:], board_params)

        # Compute progress towards full coverage
        ranges = minmax_parameters[1,:] - minmax_parameters[0,:]
        ranges[2:] = minmax_parameters[1,2:] # Don't reward small sizes or small skews
        progress = np.clip(ranges / goals, 0, 1)
        progress_str = ' '.join(
                '{1}:{0}%'.format(int(100*x), k) for x, k in zip(progress, param_labels)
        )

        log.info('Using board in frame {0}. Progress: {1}'.format(frame_idx, progress_str))
        log.debug('Parameter ranges: {0}'.format(minmax_parameters.T.tolist()))

        # Refine corners
        cv2.cornerSubPix(frame, corners, (5,5), (-1,-1),
                (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 100, 0.03))

        # Record corners
        image_pts.append(corners)
        used_frames.append(frame_idx)

        # Do we auto-stop?
        if autostop and np.all(progress > 0.99):
            break

    if len(image_pts) == 0:
        log.error('No chessboards found in video')
        return 1

    # Generate chessboard object points
    cb_coords = np.zeros((cb_shape[0] * cb_shape[1], 3), dtype=np.float32)
    cb_coords[:,:2] = np.asarray(list(itertools.product(range(cb_shape[1]), range(cb_shape[0]))))
    cb_pts = [ cb_coords ] * len(image_pts)

    # Calibrate
    log.info('Calibrating with {0} frame(s)...'.format(len(image_pts)))
    cam_matrix = np.eye(3)
    reproj_err, cam_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(
            cb_pts, image_pts, frame_shape[::-1], cam_matrix, None,
            flags=cv2.CALIB_RATIONAL_MODEL,
            criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))

    log.info('Re-projection error is {0} pixels'.format(reproj_err))

    calib_result = {
        'input': {
            'video': video,
            'checkerboard_shape': cb_shape,
            'used_frames': used_frames,
        },
        'output': {
            'frameSize': frame_shape[::-1],
            'reprojError': reproj_err,
            'camMatrix': cam_matrix.tolist(),
            'distCoeffs': dist_coeffs.reshape(-1).tolist(),
        },
    }

    if output is not None:
        log.debug('Writing result to {0}.'.format(output))
    json.dump(calib_result, open(output, 'w') if output is not None else sys.stdout, indent=2)

    return 0