def nose_state()

in source/backend/chalicelib/nose.py [0:0]


def nose_state(params, frame, context):
    init_context(context, frame)

    image_width = params['imageWidth']
    image_height = params['imageHeight']

    # Validating if face is inside area (with tolerance)
    area_width_tolerance = params['areaWidth'] * _AREA_BOX_TOLERANCE
    area_height_tolerance = params['areaHeight'] * _AREA_BOX_TOLERANCE
    area_box = (params['areaLeft'] - area_width_tolerance,
                params['areaTop'] - area_height_tolerance,
                params['areaWidth'] + 2 * area_width_tolerance,
                params['areaHeight'] + 2 * area_height_tolerance)
    rek_metadata = frame['rekMetadata'][0]
    rek_face_box = [
        image_width * rek_metadata['BoundingBox']['Left'],
        image_height * rek_metadata['BoundingBox']['Top'],
        image_width * rek_metadata['BoundingBox']['Width'],
        image_height * rek_metadata['BoundingBox']['Height']
    ]
    inside_area_box = _is_inside_area_box(area_box, rek_face_box)
    _log.debug('inside_area_box: %s', inside_area_box)
    if not inside_area_box:
        return CHALLENGE_FAIL

    # Validating nose position (with tolerance)
    nose_width_tolerance = params['noseWidth'] * _NOSE_BOX_TOLERANCE
    nose_height_tolerance = params['noseHeight'] * _NOSE_BOX_TOLERANCE
    nose_box = (params['noseLeft'] - nose_width_tolerance,
                params['noseTop'] - nose_height_tolerance,
                params['noseWidth'] + 2 * nose_width_tolerance,
                params['noseHeight'] + 2 * nose_height_tolerance)
    rek_landmarks = rek_metadata['Landmarks']
    inside_nose_box = False
    for landmark in rek_landmarks:
        if landmark['Type'] == 'nose':
            nose_left = image_width * landmark['X']
            nose_top = image_height * landmark['Y']
            context['nose_trajectory'].append((landmark['X'], landmark['Y']))
            inside_nose_box = (nose_box[0] <= nose_left <= nose_box[0] + nose_box[2] and
                               nose_box[1] <= nose_top <= nose_box[1] + nose_box[3])
    _log.debug('inside_nose_box: %s', inside_nose_box)
    if not inside_nose_box:
        return STATE_CONTINUE

    # Validating continuous and linear nose trajectory
    nose_trajectory_x = [nose[0] for nose in context['nose_trajectory']]
    nose_trajectory_y = [nose[1] for nose in context['nose_trajectory']]
    # noinspection PyTupleAssignmentBalance
    _, residuals, _, _, _ = np.polyfit(nose_trajectory_x, nose_trajectory_y, 2, full=True)
    trajectory_error = math.sqrt(residuals / len(context['nose_trajectory']))
    if trajectory_error > _TRAJECTORY_ERROR_THRESHOLD:
        _log.info('invalid_trajectory')
        return CHALLENGE_FAIL

    # Plotting landmarks from the first frame in a histogram
    original_landmarks_x = [image_width * landmark['X'] for landmark in context['original_landmarks']]
    original_landmarks_y = [image_height * landmark['Y'] for landmark in context['original_landmarks']]
    original_histogram, _, _ = np.histogram2d(original_landmarks_x,
                                              original_landmarks_y,
                                              bins=_HISTOGRAM_BINS)
    original_histogram = np.reshape(original_histogram, _HISTOGRAM_BINS ** 2) / len(
        original_landmarks_x)
    # Plotting landmarks from the last frame in a histogram
    current_landmarks_x = [image_width * landmark['X'] for landmark in rek_landmarks]
    current_landmarks_y = [image_height * landmark['Y'] for landmark in rek_landmarks]
    current_histogram, _, _ = np.histogram2d(current_landmarks_x,
                                             current_landmarks_y,
                                             bins=_HISTOGRAM_BINS)
    current_histogram = np.reshape(current_histogram, _HISTOGRAM_BINS ** 2) / len(current_landmarks_x)
    # Calculating the Euclidean distance between histograms
    dist = np.linalg.norm(original_histogram - current_histogram)
    # Estimating left and right rotation
    yaw = rek_metadata['Pose']['Yaw']
    rotated_right = yaw > _ROTATION_THRESHOLD
    rotated_left = yaw < - _ROTATION_THRESHOLD
    rotated_face = rotated_left or rotated_right
    # Validating distance according to rotation
    challenge_in_the_right = params['noseLeft'] + _NOSE_BOX_SIZE / 2 > image_width / 2
    if (rotated_right and challenge_in_the_right) or (rotated_left and not challenge_in_the_right):
        min_dist = _MIN_DIST * _MIN_DIST_FACTOR_ROTATED
    elif not rotated_face:
        min_dist = _MIN_DIST * _MIN_DIST_FACTOR_NOT_ROTATED
    else:
        _log.info('invalid_rotation')
        return CHALLENGE_FAIL
    if dist > min_dist:
        _log.info('valid_distance')
        return CHALLENGE_SUCCESS
    _log.info('invalid_distance')
    return CHALLENGE_FAIL