def _convert_2d_to_3d_point_undistort(point_group, camera, fbw, fbh, lcox,
                                      lcoy, camera_fov, frame, pos, depth):
    """
    Convert a 2D point (undistorted) into a 3D point, in world space.

    :param point_group: Camera Point Group for camera.
    :param camera: The camera to use for rolling shutter calculations.
    :param fbw: Camera's film back width value.
    :param fbh: Camera's film back height value.
    :param lcox: Camera lens lens center offset X value.
    :param lcoy: Camera lens lens center offset Y value.
    :param camera_fov: Camera Field of View as list of left, right,
                       bottom and top.
    :param frame: The 2D point's frame number (in internal 3DE frame numbers).
    :param pos: Input 2D data.
    :param depth: The content distance to calculate rolling shutter at.

    :return: Corrected 2D point.
    :rtype: vec2d
    """
    focal = tde4.getCameraFocalLength(camera, frame)
    r3d = vl_sdv.mat3d(tde4.getPGroupRotation3D(point_group, camera, frame))
    p3d = vl_sdv.vec3d(tde4.getPGroupPosition3D(point_group, camera, frame))
    left, right, bottom, top = camera_fov

    p2d = [0, 0]
    p2d[0] = (pos[0] - left) / (right - left)
    p2d[1] = (pos[1] - bottom) / (top - bottom)
    p2d = tde4.removeDistortion2D(camera, frame, p2d)

    p2d_cm = vl_sdv.vec2d((p2d[0] - 0.5) * fbw - lcox,
                          (p2d[1] - 0.5) * fbh - lcoy)
    homogeneous_point = r3d * vl_sdv.vec3d(p2d_cm[0], p2d_cm[1], -focal).unit()
    out_point = homogeneous_point * depth + p3d
    return out_point
def _generate_v2(point_group,
                 camera,
                 points,
                 start_frame=None,
                 undistort=False):
    """
    Generate the UV file format contents, using JSON format.

    :param point_group: The 3DE Point Group containing 'points'
    :type point_group: str

    :param camera: The 3DE Camera containing 2D 'points' data.
    :type camera: str

    :param points: The list of 3DE Points representing 2D data to
                   save.
    :type points: list of str

    :param start_frame: The frame number to be considered at
                       'first frame'. Defaults to 1001 if
                       set to None.
    :type start_frame: None or int

    :param undistort: Should we apply undistortion to the 2D points
                      data? Yes or no.
    :type undistort: bool

    Each point will store:
    - Point name
    - X, Y position (in UV coordinates, per-frame)
    - Point weight (per-frame)
    - Point Set name
    - Point 'Persistent ID'
    """
    assert isinstance(point_group, basestring)
    assert isinstance(camera, basestring)
    assert isinstance(points, (list, tuple))
    assert start_frame is None or isinstance(start_frame, int)
    assert isinstance(undistort, bool)
    if start_frame is None:
        start_frame = 1001
    data = UV_TRACK_HEADER_VERSION_2.copy()
    cam_num_frames = tde4.getCameraNoFrames(camera)

    if len(points) == 0:
        return ''

    frame0 = int(start_frame)
    frame0 -= 1

    data['num_points'] = len(points)
    data['is_undistorted'] = bool(undistort)

    data['points'] = []
    for point in points:
        point_data = {}

        # Query point information
        name = tde4.getPointName(point_group, point)
        uid = None
        if SUPPORT_PERSISTENT_ID is True:
            uid = tde4.getPointPersistentID(point_group, point)
        point_set = tde4.getPointSet(point_group, point)
        point_set_name = None
        if point_set is not None:
            point_set_name = tde4.getSetName(point_group, point_set)
        point_data['name'] = name
        point_data['id'] = uid
        point_data['set_name'] = point_set_name

        # Write per-frame position data
        frame = 1  # 3DE starts at frame '1' regardless of the 'start frame'.
        point_data['per_frame'] = []
        pos_block = tde4.getPointPosition2DBlock(point_group, point, camera, 1,
                                                 cam_num_frames)
        for pos in pos_block:
            if pos[0] == -1.0 or pos[1] == -1.0:
                # No valid data here.
                frame += 1
                continue

            # Does the 2D point go outside the camera FOV? Is that ok?
            valid_2d = tde4.isPointPos2DValid(point_group, point, camera,
                                              frame)
            if valid_2d != 1:
                # No valid data here.
                frame += 1
                continue

            f = frame + frame0
            if undistort is True:
                pos = tde4.removeDistortion2D(camera, frame, pos)
            weight = 1.0
            if SUPPORT_POINT_WEIGHT_BY_FRAME is True:
                weight = tde4.getPointWeightByFrame(point_group, point, camera,
                                                    frame)
            frame_data = {'frame': f, 'pos': pos, 'weight': weight}
            point_data['per_frame'].append(frame_data)
            frame += 1

        data['points'].append(point_data)

    data_str = json.dumps(data)
    return data_str
def _generate_v1(point_group,
                 camera,
                 points,
                 start_frame=None,
                 undistort=False):
    """
    Generate the UV file format contents, using a basic ASCII format.

    :param point_group: The 3DE Point Group containing 'points'
    :type point_group: str

    :param camera: The 3DE Camera containing 2D 'points' data.
    :type camera: str

    :param points: The list of 3DE Points representing 2D data to
                   save.
    :type points: list of str

    :param start_frame: The frame number to be considered at
                       'first frame'. Defaults to 1001 if
                       set to None.
    :type start_frame: None or int

    :param undistort: Should we apply undistortion to the 2D points
                      data? Yes or no.
    :type undistort: bool

    Each point will store:
    - Point name
    - X, Y position (in UV coordinates, per-frame)
    - Point weight (per-frame)
    """
    assert isinstance(point_group, basestring)
    assert isinstance(camera, basestring)
    assert isinstance(points, (list, tuple))
    assert start_frame is None or isinstance(start_frame, int)
    assert isinstance(undistort, bool)
    if start_frame is None:
        start_frame = 1001
    data_str = ''
    cam_num_frames = tde4.getCameraNoFrames(camera)

    if len(points) == 0:
        return data_str

    frame0 = int(start_frame)
    frame0 -= 1

    data_str += '{0:d}\n'.format(len(points))

    for point in points:
        name = tde4.getPointName(point_group, point)
        c2d = tde4.getPointPosition2DBlock(point_group, point, camera, 1,
                                           cam_num_frames)

        # Write per-frame position data
        num_valid_frame = 0
        pos_list = []
        weight_list = []
        frame = 1  # 3DE starts at frame '1' regardless of the 'start-frame'.
        for v in c2d:
            if v[0] == -1.0 or v[1] == -1.0:
                # No valid data here.
                frame += 1
                continue

            # Does the 2D point go outside the camera FOV? Is that ok?
            valid = tde4.isPointPos2DValid(point_group, point, camera, frame)
            if valid == 0:
                # No valid data here.
                frame += 1
                continue
            # Number of points with valid positions
            num_valid_frame += 1

            f = frame + frame0
            if undistort is True:
                v = tde4.removeDistortion2D(camera, frame, v)
            weight = 1.0
            if SUPPORT_POINT_WEIGHT_BY_FRAME is True:
                weight = tde4.getPointWeightByFrame(point_group, point, camera,
                                                    frame)

            pos_list.append((f, v))
            weight_list.append((f, weight))
            frame += 1

        # add data
        data_str += name + '\n'
        data_str += '{0:d}\n'.format(num_valid_frame)
        for pos_data, weight_data in zip(pos_list, weight_list):
            f = pos_data[0]
            v = pos_data[1]
            w = weight_data[1]
            assert f == weight_data[0]
            data_str += '%d %.15f %.15f %.8f\n' % (f, v[0], v[1], w)

    return data_str
Example #4
0
def _generate_v2_v3_and_v4(point_group,
                           camera,
                           points,
                           version=None,
                           **kwargs):
    """
    Generate the UV file format contents, using JSON format.

    Set the individual _generate_v2 or _generate_v3 functions for
    details of what is stored.

    :param point_group: The 3DE Point Group containing 'points'
    :type point_group: str

    :param camera: The 3DE Camera containing 2D 'points' data.
    :type camera: str

    :param points: The list of 3DE Points representing 2D data to
                   save.
    :type points: list of str

    :param version: The version of file to generate,
                    UV_TRACK_FORMAT_VERSION_2 or
                    UV_TRACK_FORMAT_VERSION_3.
    :type version: int

    :param start_frame: Format v2 and v3; The frame number to be
                        considered at 'first frame'.
                        Defaults to 1001 if set to None.
    :type start_frame: None or int

    :param undistort: Format v2; Should we apply undistortion to the 2D
                      points data? Yes or no.
    :type undistort: bool

    :returns: A JSON format string, with the UV Track data in it.
    :rtype: str
    """
    assert isinstance(point_group, basestring)
    assert isinstance(camera, basestring)
    assert isinstance(points, (list, tuple))
    assert isinstance(version, (int, long))
    assert version in [
        UV_TRACK_FORMAT_VERSION_2, UV_TRACK_FORMAT_VERSION_3,
        UV_TRACK_FORMAT_VERSION_4
    ]

    start_frame = kwargs.get('start_frame')
    assert start_frame is None or isinstance(start_frame, int)
    if start_frame is None:
        start_frame = 1001

    undistort = None
    if version == UV_TRACK_FORMAT_VERSION_2:
        undistort = kwargs.get('undistort')
        assert isinstance(undistort, bool)

    data = None
    if version == UV_TRACK_FORMAT_VERSION_2:
        data = UV_TRACK_HEADER_VERSION_2.copy()
    elif version == UV_TRACK_FORMAT_VERSION_3:
        data = UV_TRACK_HEADER_VERSION_3.copy()
    elif version == UV_TRACK_FORMAT_VERSION_4:
        data = UV_TRACK_HEADER_VERSION_4.copy()
    else:
        raise ValueError("Version number is invalid; %r" % version)

    cam_num_frames = tde4.getCameraNoFrames(camera)
    camera_fov = tde4.getCameraFOV(camera)

    if len(points) == 0:
        return ''

    frame0 = int(start_frame)
    frame0 -= 1

    data['num_points'] = len(points)
    data['is_undistorted'] = None
    if version == UV_TRACK_FORMAT_VERSION_2:
        data['is_undistorted'] = bool(undistort)

    data['points'] = []
    for point in points:
        point_data = {}

        # Query point information
        name = tde4.getPointName(point_group, point)
        uid = None
        if SUPPORT_PERSISTENT_ID is True:
            uid = tde4.getPointPersistentID(point_group, point)
        point_set = tde4.getPointSet(point_group, point)
        point_set_name = None
        if point_set is not None:
            point_set_name = tde4.getSetName(point_group, point_set)
        point_data['name'] = name
        point_data['id'] = uid
        point_data['set_name'] = point_set_name
        valid_mode = _get_point_valid_mode(point_group, point)

        # Get the 3D point position
        if version in [UV_TRACK_FORMAT_VERSION_3, UV_TRACK_FORMAT_VERSION_4]:
            point_data['3d'] = _get_3d_data_from_point(point_group, point)

        # Write per-frame position data
        frame = 1  # 3DE starts at frame '1' regardless of the 'start frame'.
        point_data['per_frame'] = []
        pos_block = tde4.getPointPosition2DBlock(point_group, point, camera, 1,
                                                 cam_num_frames)
        for pos in pos_block:
            if pos[0] == -1.0 or pos[1] == -1.0:
                # No valid data here.
                frame += 1
                continue

            # Is the 2D point obscured?
            valid = tde4.isPointPos2DValid(point_group, point, camera, frame)
            if valid == 0:
                # No valid data here.
                frame += 1
                continue

            # Check if we're inside the FOV / Frame or not.
            valid_pos = _is_valid_position(pos, camera_fov, valid_mode)
            if valid_pos is False:
                frame += 1
                continue

            pos_undist = pos
            if undistort is True or undistort is None:
                pos_undist = tde4.removeDistortion2D(camera, frame, pos)
            weight = _get_point_weight(point_group, point, camera, frame)

            f = frame + frame0
            frame_data = {'frame': f, 'pos': pos_undist, 'weight': weight}
            if version in [
                    UV_TRACK_FORMAT_VERSION_3, UV_TRACK_FORMAT_VERSION_4
            ]:
                frame_data['pos_dist'] = pos
            point_data['per_frame'].append(frame_data)
            frame += 1

        data['points'].append(point_data)

    if version == UV_TRACK_FORMAT_VERSION_4:
        lens = tde4.getCameraLens(camera)
        data['camera'] = _generate_camera_data(camera, lens, frame0)

    data_str = json.dumps(data)
    return data_str
Example #5
0
def _generate_v1(point_group, camera, points,
                 start_frame=None,
                 undistort=False,
                 rs_distance=None):
    """
    Generate the UV file format contents, using a basic ASCII format.

    Each point will store:
    - Point name
    - X, Y position (in UV coordinates, per-frame)
    - Point weight (per-frame)

    :param point_group: The 3DE Point Group containing 'points'
    :type point_group: str

    :param camera: The 3DE Camera containing 2D 'points' data.
    :type camera: str

    :param points: The list of 3DE Points representing 2D data to
                   save.
    :type points: list of str

    :param start_frame: The frame number to be considered at
                       'first frame'. Defaults to 1001 if
                       set to None.
    :type start_frame: None or int

    :param undistort: Should we apply undistortion to the 2D points
                      data? Yes or no.
    :type undistort: bool

    :param rs_distance: If not None, correct rolling shutter effects on
        the 2D points at the content distance rs_distance.
    :type rs_distance: None or float

    :returns: A ASCII format string, with the UV Track data in it.
    :rtype: str
    """
    assert isinstance(point_group, TEXT_TYPE)
    assert isinstance(camera, TEXT_TYPE)
    assert isinstance(points, (list, tuple))
    assert start_frame is None or isinstance(start_frame, int)
    assert isinstance(undistort, bool)
    assert rs_distance is None or isinstance(rs_distance, float)
    if start_frame is None:
        start_frame = 1001
    data_str = ''

    cam_num_frames = tde4.getCameraNoFrames(camera)
    camera_fov = tde4.getCameraFOV(camera)

    if len(points) == 0:
        return data_str

    frame0 = int(start_frame)
    frame0 -= 1

    data_str += '{0:d}\n'.format(len(points))

    for point in points:
        name = tde4.getPointName(point_group, point)
        c2d = tde4.getPointPosition2DBlock(
            point_group, point, camera,
            1, cam_num_frames
        )
        valid_mode = _get_point_valid_mode(point_group, point)

        # Write per-frame position data
        num_valid_frame = 0
        pos_list = []
        weight_list = []
        frame = 1  # 3DE starts at frame '1' regardless of the 'start-frame'.
        for v in c2d:
            if v[0] == -1.0 or v[1] == -1.0:
                # No valid data here.
                frame += 1
                continue

            # Does the 2D point go outside the camera FOV? Is that ok?
            valid = tde4.isPointPos2DValid(
                point_group,
                point,
                camera,
                frame
            )
            if valid == 0:
                # No valid data here.
                frame += 1
                continue

            # Check if we're inside the FOV / Frame or not.
            valid_pos = _is_valid_position(v, camera_fov, valid_mode)
            if valid_pos is False:
                frame += 1
                continue

            # Number of points with valid positions
            num_valid_frame += 1

            f = frame + frame0
            if rs_distance is not None:
                v = vl_sdv.vec2d(v[0], v[1])
                v = _remove_rs_from_2d_point(
                    point_group, camera, frame, v, rs_distance)
            if undistort is True:
                v = tde4.removeDistortion2D(camera, frame, v)
            weight = _get_point_weight(point_group, point, camera, frame)

            pos_list.append((f, v))
            weight_list.append((f, weight))
            frame += 1

        # add data
        data_str += name + '\n'
        data_str += '{0:d}\n'.format(num_valid_frame)
        for pos_data, weight_data in zip(pos_list, weight_list):
            f = pos_data[0]
            v = pos_data[1]
            w = weight_data[1]
            assert f == weight_data[0]
            data_str += '%d %.15f %.15f %.8f\n' % (f, v[0], v[1], w)

    return data_str
def getDistortionBoundingBox(camera, lco_x, lco_y):
    # We genererate a number of samples around the image in normalized coordinates.
    # These samples are later unwarped, and the unwarped points
    # will be used to create a bounding box. In general, it is *not* sufficient to
    # undistort only the corners, because distortion might be moustache-shaped.
    # This is our list of samples:
    warped = []
    for i in range(10):
        warped.append([i / 10.0,0.0])
        warped.append([(i + 1) / 10.0,1.0])
        warped.append([0.0,i / 10.0])
        warped.append([1.0,(i + 1) / 10.0])

    # The lens center is by definition the fixed point of the distortion mapping.
    elc = [0.5 + lco_x,0.5 + lco_y]

    # Image size
    w_px = tde4.getCameraImageWidth(camera)
    h_px = tde4.getCameraImageHeight(camera)

    # The bounding boxes for non-symmetrized and symmetrized cased.
    bb_nonsymm = bbdld_bounding_box()
    bb_symm = bbdld_bounding_box()

    # Run through the frames of this camera
    n_frames = tde4.getCameraNoFrames(camera)
    for i_frame in range(n_frames):
        # 3DE4 counts from 1.
        frame = i_frame + 1

        # Now we undistort all edge points for the given
        # camera and frame and extend the bounding boxes.
        for p in warped:
            p_unwarped = tde4.removeDistortion2D(camera,frame,p)
            # Accumulate bounding boxes
            bb_nonsymm.extend(p_unwarped[0],p_unwarped[1])
            bb_symm.extend_symm(p_unwarped[0],p_unwarped[1],elc[0],elc[1])

    # Scale to pixel coordinates and extend to pixel-aligned values
    bb_nonsymm.scale(w_px,h_px)
    bb_nonsymm.extend_to_integer()

    # Image width and height for the non-symmetrized case
    w_nonsymm_px = bb_nonsymm.dx()
    h_nonsymm_px = bb_nonsymm.dy()

    # Lower left corner for the symmetrized case. This tells us
    # how the undistorted image is related to the distorted image.
    x_nonsymm_px = bb_nonsymm.x_min()
    y_nonsymm_px = bb_nonsymm.y_min()

    # Scale to pixel coordinates and extend to pixel-aligned values
    bb_symm.scale(w_px,h_px)
    bb_symm.extend_to_integer()

    # Image width and height for the symmetrized case
    w_symm_px = bb_symm.dx()
    h_symm_px = bb_symm.dy()

    # Lower left corner for the symmetrized case. This tells us
    # how the undistorted image is related to the distorted image.
    x_symm_px = bb_symm.x_min()
    y_symm_px = bb_symm.y_min()

    return x_symm_px,y_symm_px,w_symm_px,h_symm_px