def _get_wire_colors_and_positions(im):
    colors_and_positions = []
    for i in range(len(_BOTTOM_X_BOUNDARIES) - 1):
        wire = get_subset(im, _BOTTOM_X_BOUNDARIES[i:i + 2], _WIRE_Y_BOUNDARIES)
        wire_colors_and_mats = filter(None, (
            _get_wire_color_and_mat_or_none(wire, 354 / 2, (220, 255), (150, 220), WireColor.RED),
            _get_wire_color_and_mat_or_none(wire, 37 / 2, (0, 50), (200, 255), WireColor.WHITE),
            _get_wire_color_and_mat_or_none(wire, 229 / 2, (150, 200), (75, 215), WireColor.BLUE),
        ))
        if not wire_colors_and_mats:
            colors_and_positions.append(None)
            continue

        wire_colors, mats = zip(*wire_colors_and_mats)

        w, h = get_dimens(im)
        left = int((w * _BOTTOM_X_BOUNDARIES[i]) / 100.0)
        top = int((h * _WIRE_Y_BOUNDARIES[0]) / 100.0)

        summed_wires = sum(mats)
        structuring_element1 = cv2.getStructuringElement(cv2.MORPH_RECT, (15, 15))
        summed_wires = cv2.morphologyEx(summed_wires, cv2.MORPH_CLOSE, structuring_element1)

        contour = max(get_contours(summed_wires, close_and_open=False), key=cv2.contourArea)
        center = get_center_for_contour(contour)
        center = apply_offset_to_single_location(center, (left, top))
        # show(summed_wires)
        colors_and_positions.append((wire_colors, center))
    return colors_and_positions
예제 #2
0
def _get_digit_from_image(image):
    contours = get_contours(image, close_and_open=False)
    vertical_centers = []
    horizontal_centers = []
    for contour in contours:
        _, _, contour_w, contour_h = cv2.boundingRect(contour)
        center = get_center_for_contour(contour)
        if contour_w > contour_h:
            horizontal_centers.append(center)
        else:
            vertical_centers.append(center)
            
    w, h = get_dimens(image)
    segments = set()
    for x, y in vertical_centers:
        if x < w/2:
            if y < h/2:
                segments.add(Segments.TOP_LEFT)
            else:
                segments.add(Segments.BOTTOM_LEFT)
        else:
            if y < h/2:
                segments.add(Segments.TOP_RIGHT)
            else:
                segments.add(Segments.BOTTOM_RIGHT)
                
    for x, y in horizontal_centers:
        if y < h/3:
            segments.add(Segments.TOP_CENTER)
        elif h/3 < y < 2*h/3:
            segments.add(Segments.MIDDLE)
        else:
            segments.add(Segments.BOTTOM_CENTER)

    return _SEGMENTS_TO_NUMBER[tuple(sorted(segments, key=lambda seg: seg.value))]
예제 #3
0
def _get_wire_positions(im,
                        wire_color,
                        hue,
                        saturation=(150, 255),
                        value=(100, 255)):
    color = extract_color(im, hue, saturation, value)
    contours = get_contours(color, close_and_open=False)
    return [(get_center_for_contour(c), wire_color) for c in contours]
예제 #4
0
def get_has_parallel_port_for_side(side):
    side_w, side_h = get_dimens(side)
    if side_h > side_w:
        side = cv2.transpose(side)
        side_w, side_h = get_dimens(side)
    color = extract_color(side, 337 / 2, (75, 175), (175, 255))
    contours = sorted(get_contours(color), key=cv2.contourArea)
    if not contours:
        return False
    contour = contours[-1]
    x, y, w, h = cv2.boundingRect(contour)
    width_percent = float(w) / side_w
    height_percent = float(h) / side_h
    return width_percent > _WIDTH_THRESHOLD and height_percent > _HEIGHT_THRESHOLD
예제 #5
0
def get_has_parallel_port_for_side(side):
    side_w, side_h = get_dimens(side)
    if side_h > side_w:
        side = cv2.transpose(side)
        side_w, side_h = get_dimens(side)
    color = extract_color(side, 337 / 2, (75, 175), (175, 255))
    contours = sorted(get_contours(color), key=cv2.contourArea)
    if not contours:
        return False
    contour = contours[-1]
    x, y, w, h = cv2.boundingRect(contour)
    width_percent = float(w) / side_w
    height_percent = float(h) / side_h
    return width_percent > _WIDTH_THRESHOLD and height_percent > _HEIGHT_THRESHOLD
예제 #6
0
def _get_box_for_largest_rect_contour(color):
    # type: (np.array) -> Optional[np.array]
    contours = get_contours(color)
    # print [0.05 * cv2.arcLength(c, True) for c in contours]
    # show(get_drawn_contours(color, contours, True), .25)
    contours = [cv2.approxPolyDP(c, 0.05 * cv2.arcLength(c, True), True) for c in contours]
    height, width = color.shape[:2]
    total_area = height * width
    contours = [c for c in contours if len(c) == 4 and cv2.contourArea(c) / total_area > 0.005]
    if len(contours) == 0:
        return None
    contour = sorted(contours, key=cv2.contourArea)[-1]

    contour = contour_bounding_box_for_contour(contour)
    return contour
예제 #7
0
def _get_largest_contour_area_ratio_for_color(im, color):
    hue_out_of_360 = {
        LitSquare.YELLOW: 60,
        LitSquare.BLUE: 193,
        LitSquare.RED: 19,
        LitSquare.GREEN: 149,
    }[color]

    color_mat = extract_color(im, hue_out_of_360/2, (100, 255), (225, 255))
    contour_areas = [cv2.contourArea(c) for c in get_contours(color_mat)]
    if contour_areas:
        largest_area = sorted(contour_areas)[-1]
    else:
        largest_area = 0

    w, h = get_dimens(im)
    im_area = w * h
    area_ratio = float(largest_area) / im_area
    return area_ratio, color
예제 #8
0
def _get_largest_contour_area_ratio_for_color(im, color):
    hue_out_of_360 = {
        LitSquare.YELLOW: 60,
        LitSquare.BLUE: 193,
        LitSquare.RED: 19,
        LitSquare.GREEN: 149,
    }[color]

    color_mat = extract_color(im, hue_out_of_360 / 2, (100, 255), (225, 255))
    contour_areas = [cv2.contourArea(c) for c in get_contours(color_mat)]
    if contour_areas:
        largest_area = sorted(contour_areas)[-1]
    else:
        largest_area = 0

    w, h = get_dimens(im)
    im_area = w * h
    area_ratio = float(largest_area) / im_area
    return area_ratio, color
예제 #9
0
def get_clock_time_from_full_screenshot(full_screenshot,
                                        current_module_position,
                                        screenshot_helper):
    clock_im = _get_clock_image_from_full_screenshot(full_screenshot,
                                                     current_module_position,
                                                     screenshot_helper)
    assert clock_im is not None, "Unable to find clock"
    clock_bg = extract_color(clock_im, (0, 180), (0, 255), (0, 50))

    contours = [
        c for c in simplify_contours(get_contours(clock_bg), 0.001)
        if len(c) == 4
    ]
    contour = max(contours, key=cv2.contourArea)

    display = four_point_transform(clock_im, contour)

    digits_im = extract_color(display, 0, (250, 255), (250, 255))

    digit_images = [
        get_subset(digits_im,
                   _CLOCK_DIGIT_X_PERCENTS[digit_index:digit_index + 2],
                   (0, 100))
        for digit_index in range(len(_CLOCK_DIGIT_X_PERCENTS) - 1)
    ]
    # Determine if there is a colon or period separator.
    is_colon = get_subset(digit_images[2], (0, 100), (0, 50)).any()
    if is_colon:
        minutes_images = digit_images[:2]
        seconds_images = digit_images[-2:]
    else:
        minutes_images = []
        seconds_images = digit_images[:2]

    minutes_digits = [_get_digit_from_image(im) for im in minutes_images]
    seconds_digits = [_get_digit_from_image(im) for im in seconds_images]

    if not minutes_digits:
        minutes_digits = [0]

    return minutes_digits, seconds_digits
예제 #10
0
def _get_box_for_largest_rect_contour(color):
    # type: (np.array) -> Optional[np.array]
    contours = get_contours(color)
    # print [0.05 * cv2.arcLength(c, True) for c in contours]
    # show(get_drawn_contours(color, contours, True), .25)
    contours = [
        cv2.approxPolyDP(c, 0.05 * cv2.arcLength(c, True), True)
        for c in contours
    ]
    height, width = color.shape[:2]
    total_area = height * width
    contours = [
        c for c in contours
        if len(c) == 4 and cv2.contourArea(c) / total_area > 0.005
    ]
    if len(contours) == 0:
        return None
    contour = sorted(contours, key=cv2.contourArea)[-1]

    contour = contour_bounding_box_for_contour(contour)
    return contour
예제 #11
0
def _get_wire_colors_and_positions(im):
    colors_and_positions = []
    for i in range(len(_BOTTOM_X_BOUNDARIES) - 1):
        wire = get_subset(im, _BOTTOM_X_BOUNDARIES[i:i + 2],
                          _WIRE_Y_BOUNDARIES)
        wire_colors_and_mats = filter(None, (
            _get_wire_color_and_mat_or_none(wire, 354 / 2, (220, 255),
                                            (150, 220), WireColor.RED),
            _get_wire_color_and_mat_or_none(wire, 37 / 2, (0, 50),
                                            (200, 255), WireColor.WHITE),
            _get_wire_color_and_mat_or_none(wire, 229 / 2, (150, 200),
                                            (75, 215), WireColor.BLUE),
        ))
        if not wire_colors_and_mats:
            colors_and_positions.append(None)
            continue

        wire_colors, mats = zip(*wire_colors_and_mats)

        w, h = get_dimens(im)
        left = int((w * _BOTTOM_X_BOUNDARIES[i]) / 100.0)
        top = int((h * _WIRE_Y_BOUNDARIES[0]) / 100.0)

        summed_wires = sum(mats)
        structuring_element1 = cv2.getStructuringElement(
            cv2.MORPH_RECT, (15, 15))
        summed_wires = cv2.morphologyEx(summed_wires, cv2.MORPH_CLOSE,
                                        structuring_element1)

        contour = max(get_contours(summed_wires, close_and_open=False),
                      key=cv2.contourArea)
        center = get_center_for_contour(contour)
        center = apply_offset_to_single_location(center, (left, top))
        # show(summed_wires)
        colors_and_positions.append((wire_colors, center))
    return colors_and_positions
예제 #12
0
def get_clock_time_from_full_screenshot(full_screenshot,
                                        current_module_position,
                                        screenshot_helper):
    clock_im = _get_clock_image_from_full_screenshot(full_screenshot,
                                                     current_module_position,
                                                     screenshot_helper)
    assert clock_im is not None, "Unable to find clock"
    clock_bg = extract_color(clock_im, (0, 180), (0, 255), (0, 50))

    contours = [c for c in simplify_contours(get_contours(clock_bg), 0.001) if len(c) == 4]
    contour = max(contours, key=cv2.contourArea)

    display = four_point_transform(clock_im, contour)

    digits_im = extract_color(display, 0, (250, 255), (250, 255))

    digit_images = [
        get_subset(digits_im, _CLOCK_DIGIT_X_PERCENTS[digit_index:digit_index + 2], (0, 100))
        for digit_index in range(len(_CLOCK_DIGIT_X_PERCENTS) - 1)
    ]
    # Determine if there is a colon or period separator.
    is_colon = get_subset(digit_images[2], (0, 100), (0, 50)).any()
    if is_colon:
        minutes_images = digit_images[:2]
        seconds_images = digit_images[-2:]
    else:
        minutes_images = []
        seconds_images = digit_images[:2]

    minutes_digits = [_get_digit_from_image(im) for im in minutes_images]
    seconds_digits = [_get_digit_from_image(im) for im in seconds_images]

    if not minutes_digits:
        minutes_digits = [0]

    return minutes_digits, seconds_digits
예제 #13
0
def _get_digit_from_image(image):
    contours = get_contours(image, close_and_open=False)
    vertical_centers = []
    horizontal_centers = []
    for contour in contours:
        _, _, contour_w, contour_h = cv2.boundingRect(contour)
        center = get_center_for_contour(contour)
        if contour_w > contour_h:
            horizontal_centers.append(center)
        else:
            vertical_centers.append(center)

    w, h = get_dimens(image)
    segments = set()
    for x, y in vertical_centers:
        if x < w / 2:
            if y < h / 2:
                segments.add(Segments.TOP_LEFT)
            else:
                segments.add(Segments.BOTTOM_LEFT)
        else:
            if y < h / 2:
                segments.add(Segments.TOP_RIGHT)
            else:
                segments.add(Segments.BOTTOM_RIGHT)

    for x, y in horizontal_centers:
        if y < h / 3:
            segments.add(Segments.TOP_CENTER)
        elif h / 3 < y < 2 * h / 3:
            segments.add(Segments.MIDDLE)
        else:
            segments.add(Segments.BOTTOM_CENTER)

    return _SEGMENTS_TO_NUMBER[tuple(
        sorted(segments, key=lambda seg: seg.value))]
예제 #14
0
def _get_indicator_images_and_light_statuses(im):
    red = extract_color(im, 0, (50, 200), (50, 200))
    # show(red)
    w_total, h_total = get_dimens(im)
    w_threshold = int(_INDICATOR_WIDTH_PERCENT_THRESHOLD * w_total)
    h_threshold = int(_INDICATOR_HEIGHT_PERCENT_THRESHOLD * h_total)

    def is_indicator_big_enough(contour):
        _, _, contour_w, contour_h = cv2.boundingRect(contour)
        return contour_w > w_threshold and contour_h > h_threshold

    contours = [
        contour_bounding_box_for_contour(c) for c in get_contours(red)
        if is_indicator_big_enough(c)
    ]
    indicators = [four_point_transform(im, c) for c in contours]
    indicators_and_lights = []
    for indicator in indicators:
        w, h = get_dimens(indicator)
        if w < h:
            # Rotate 90 degrees so it's horizontal
            indicator = rotate_image_clockwise(indicator)
            w, h = get_dimens(indicator)

        # Check if light is on left or right, flip accordingly
        light_width_threshold = w * _LIGHT_WIDTH_THRESHOLD
        light_height_threshold = h * _LIGHT_HEIGHT_THRESHOLD
        light_on = extract_color(indicator, (0, 180), (0, 0), (255, 255))
        light_off = extract_color(indicator, (0, 180), (0, 40), (0, 50))

        # show(light_on)
        # show(light_off)

        def is_light_big_enough(contour):
            _, _, contour_w, contour_h = cv2.boundingRect(contour)
            return contour_w > light_width_threshold and contour_h > light_height_threshold

        light_on_contours = [
            contour_bounding_box_for_contour(c) for c in get_contours(light_on)
            if is_light_big_enough(c)
        ]
        light_off_contours = [
            contour_bounding_box_for_contour(c) for c in get_contours(light_off)
            if is_light_big_enough(c)
        ]
        assert len(light_on_contours) + len(light_off_contours) == 1, \
            "Expected to find exactly one light on the indicator"

        if light_on_contours:
            light_is_on = True
            light_contour = light_on_contours[0]
        else:
            light_is_on = False
            light_contour = light_off_contours[0]

        light_x, _ = get_center_for_contour(light_contour)
        if light_x > (w / 2.0):
            # Light is on the wrong side, need to flip 180
            indicator = rotate_image_180(indicator)

        indicators_and_lights.append((indicator, light_is_on))
    return indicators_and_lights
예제 #15
0
def _get_wire_positions(im, wire_color, hue, saturation=(150, 255), value=(100, 255)):
    color = extract_color(im, hue, saturation, value)
    contours = get_contours(color, close_and_open=False)
    return [(get_center_for_contour(c), wire_color) for c in contours]
예제 #16
0
def _get_indicator_images_and_light_statuses(im):
    red = extract_color(im, 0, (50, 200), (50, 200))
    # show(red)
    w_total, h_total = get_dimens(im)
    w_threshold = int(_INDICATOR_WIDTH_PERCENT_THRESHOLD * w_total)
    h_threshold = int(_INDICATOR_HEIGHT_PERCENT_THRESHOLD * h_total)

    def is_indicator_big_enough(contour):
        _, _, contour_w, contour_h = cv2.boundingRect(contour)
        return contour_w > w_threshold and contour_h > h_threshold

    contours = [
        contour_bounding_box_for_contour(c) for c in get_contours(red)
        if is_indicator_big_enough(c)
    ]
    indicators = [four_point_transform(im, c) for c in contours]
    indicators_and_lights = []
    for indicator in indicators:
        w, h = get_dimens(indicator)
        if w < h:
            # Rotate 90 degrees so it's horizontal
            indicator = rotate_image_clockwise(indicator)
            w, h = get_dimens(indicator)

        # Check if light is on left or right, flip accordingly
        light_width_threshold = w * _LIGHT_WIDTH_THRESHOLD
        light_height_threshold = h * _LIGHT_HEIGHT_THRESHOLD
        light_on = extract_color(indicator, (0, 180), (0, 0), (255, 255))
        light_off = extract_color(indicator, (0, 180), (0, 40), (0, 50))

        # show(light_on)
        # show(light_off)

        def is_light_big_enough(contour):
            _, _, contour_w, contour_h = cv2.boundingRect(contour)
            return contour_w > light_width_threshold and contour_h > light_height_threshold

        light_on_contours = [
            contour_bounding_box_for_contour(c) for c in get_contours(light_on)
            if is_light_big_enough(c)
        ]
        light_off_contours = [
            contour_bounding_box_for_contour(c)
            for c in get_contours(light_off) if is_light_big_enough(c)
        ]
        assert len(light_on_contours) + len(light_off_contours) == 1, \
            "Expected to find exactly one light on the indicator"

        if light_on_contours:
            light_is_on = True
            light_contour = light_on_contours[0]
        else:
            light_is_on = False
            light_contour = light_off_contours[0]

        light_x, _ = get_center_for_contour(light_contour)
        if light_x > (w / 2.0):
            # Light is on the wrong side, need to flip 180
            indicator = rotate_image_180(indicator)

        indicators_and_lights.append((indicator, light_is_on))
    return indicators_and_lights