Beispiel #1
0
def test_clamp():
    assert utils.clamp(1, 50, 100) == 50
    assert utils.clamp(1, 1, 100) == 1
    assert utils.clamp(1, 100, 100) == 100
    assert utils.clamp(1, -2, 100) == 1
    assert utils.clamp(0, 1, 0) == 0
    assert utils.clamp(1, 99, 100) == 99
    assert utils.clamp(1, 110, 100) == 100
Beispiel #2
0
def _match_template(image: Image.Image, template: Image.Image,
                    tolerance: float) -> Iterator[Region]:
    """Use opencv's matchTemplate() to slide the `template` over
    `image` to calculate correlation coefficients, and then
    filter with a tolerance to find all relevant global maximums.
    """
    template_width, template_height = template.size

    if image.mode == "RGBA":
        image = image.convert("RGB")
    if template.mode == "RGBA":
        template = template.convert("RGB")

    image = numpy.array(image)
    template = numpy.array(template)

    image = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
    template = cv2.cvtColor(template, cv2.COLOR_RGB2BGR)

    # Template matching result is a single channel array of shape:
    # Width:  Image width  - template width  + 1
    # Height: Image height - template height + 1
    coefficients = cv2.matchTemplate(image, template, cv2.TM_CCOEFF_NORMED)
    coeff_height, coeff_width = coefficients.shape

    while True:
        # The point (match_x, match_y) is the top-left of the best match
        _, match_coeff, _, (match_x, match_y) = cv2.minMaxLoc(coefficients)
        if match_coeff < tolerance:
            break

        # Zero out values for a template-sized region around the best match
        # to prevent duplicate matches for the same element.
        left = clamp(0, match_x - template_width // 2, coeff_width)
        top = clamp(0, match_y - template_height // 2, coeff_height)
        right = clamp(0, match_x + template_width // 2, coeff_width)
        bottom = clamp(0, match_y + template_height // 2, coeff_height)

        coefficients[top:bottom, left:right] = 0

        yield Region.from_size(match_x, match_y, template_width,
                               template_height)
Beispiel #3
0
def _to_tolerance(confidence):
    """Convert confidence value to tolerance.

    Confidence is a logarithmic scale from 1 to 100,
    tolerance is a linear scale from 0.01 to 1.00.
    """
    value = float(confidence)
    value = clamp(1, value, 100)
    value = log2lin(1, value, 100)
    value = value / 100.0
    return value
Beispiel #4
0
def find(image: Union[Image.Image, Path],
         text: str,
         confidence: float = DEFAULT_CONFIDENCE):
    """Scan image for text and return a list of regions
    that contain it (or something close to it).

    :param image: Path to image or Image object
    :param text: Text to find in image
    :param confidence: Minimum confidence for text similaritys
    """
    image = to_image(image)
    confidence = clamp(1, float(confidence), 100)

    text = str(text).strip()
    if not text:
        raise ValueError("Empty search string")

    try:
        data = pytesseract.image_to_data(image,
                                         output_type=pytesseract.Output.DICT)
    except TesseractNotFoundError as err:
        raise EnvironmentError(INSTALL_PROMPT) from err

    lines = defaultdict(list)
    for word in _iter_rows(data):
        if word["level"] != 5:
            continue

        if not word["text"].strip():
            continue

        key = "{:d}-{:d}-{:d}".format(word["block_num"], word["par_num"],
                                      word["line_num"])
        region = Region.from_size(word["left"], word["top"], word["width"],
                                  word["height"])

        # NOTE: Currently ignoring confidence in tesseract results
        lines[key].append({"text": word["text"], "region": region})
        assert len(lines[key]) == word["word_num"]

    matches = _match_lines(lines.values(), text, confidence)
    return matches
Beispiel #5
0
def find(
    image: Union[Image.Image, Path],
    text: str,
    confidence: float = DEFAULT_CONFIDENCE,
    region: Optional[Region] = None,
):
    """Scan image for text and return a list of regions
    that contain it (or something close to it).

    :param image: Path to image or Image object
    :param text: Text to find in image
    :param confidence: Minimum confidence for text similaritys
    """
    image = to_image(image)
    confidence = clamp(1, float(confidence), 100)

    text = str(text).strip()
    if not text:
        raise ValueError("Empty search string")

    if region is not None:
        region = geometry.to_region(region)
        image = image.crop(region.as_tuple())

    try:
        data = pytesseract.image_to_data(image, output_type=pytesseract.Output.DICT)
    except TesseractNotFoundError as err:
        raise EnvironmentError(INSTALL_PROMPT) from err

    lines = _dict_lines(data)
    matches = _match_lines(lines, text, confidence)

    if region is not None:
        for match in matches:
            match["region"] = match["region"].move(region.left, region.top)

    return matches