Загрузка данных


import json
import csv
from pathlib import Path

from reader import MeterReader


ROOT = Path(__file__).resolve().parent.parent

PHOTO_DIR = Path(
    r"G:\Robotization\Recognizer\KiloWatcher\9_Грибанова"
)

JSON_FILE = Path(
    r"G:\Robotization\Recognizer\аннотации\9_Грибанова.json"
)

reader = MeterReader(
    ROOT / "data" / "best.pt"
)


def levenshtein(a, b):

    if a == b:
        return 0

    m = len(a)
    n = len(b)

    dp = [[0] * (n + 1) for _ in range(m + 1)]

    for i in range(m + 1):
        dp[i][0] = i

    for j in range(n + 1):
        dp[0][j] = j

    for i in range(1, m + 1):

        for j in range(1, n + 1):

            cost = 0 if a[i - 1] == b[j - 1] else 1

            dp[i][j] = min(
                dp[i - 1][j] + 1,
                dp[i][j - 1] + 1,
                dp[i - 1][j - 1] + cost
            )

    return dp[m][n]


with open(
    JSON_FILE,
    "r",
    encoding="utf-8"
) as f:

    data = json.load(f)

metadata = data["_via_img_metadata"]

total = 0
exact_match = 0

empty_ocr = 0

wrong_1 = 0
wrong_2 = 0
wrong_3_plus = 0

char_total = 0
char_correct = 0

lev_sum = 0

errors = []

print(
    f"Найдено записей: {len(metadata)}"
)

for item in metadata.values():

    filename = item.get(
        "filename",
        ""
    )

    regions = item.get(
        "regions"
    ) or []

    true_value = None

    for region in regions:

        if not isinstance(
            region,
            dict
        ):
            continue

        attrs = region.get(
            "region_attributes",
            {}
        )

        name = (
            attrs.get(
                "name",
                ""
            )
            .strip()
            .lower()
        )

        if name == "indications":

            true_value = (
                attrs.get(
                    "values",
                    ""
                )
                .strip()
            )

            break

    if not true_value:
        continue

    photo_path = PHOTO_DIR / filename

    if not photo_path.exists():

        errors.append(
            [
                filename,
                true_value,
                "FILE_NOT_FOUND"
            ]
        )

        continue

    total += 1

    print(
        f"[{total}/{len(metadata)}] {filename}"
    )

    try:

        pred = reader.read(
            str(photo_path)
        )

    except Exception as ex:

        print(
            f"Ошибка OCR: {filename}"
        )

        print(ex)

        pred = ""

    pred = str(pred).strip()

    if pred == "":
        empty_ocr += 1

    if pred == true_value:

        exact_match += 1

    else:

        dist = levenshtein(
            true_value,
            pred
        )

        if dist == 1:
            wrong_1 += 1

        elif dist == 2:
            wrong_2 += 1

        else:
            wrong_3_plus += 1

        errors.append(
            [
                filename,
                true_value,
                pred
            ]
        )

    max_len = max(
        len(true_value),
        len(pred)
    )

    char_total += max_len

    for i in range(
        min(
            len(true_value),
            len(pred)
        )
    ):

        if true_value[i] == pred[i]:
            char_correct += 1

    lev_sum += levenshtein(
        true_value,
        pred
    )

accuracy = (
    exact_match / total * 100
) if total else 0

char_accuracy = (
    char_correct / char_total * 100
) if char_total else 0

avg_lev = (
    lev_sum / total
) if total else 0

print()
print("=" * 60)
print("OCR EVALUATION")
print("=" * 60)

print(
    f"Всего изображений: {total}"
)

print(
    f"Точные совпадения: {exact_match}"
)

print(
    f"Accuracy: {accuracy:.2f}%"
)

print()

print(
    f"Ошибок: {total - exact_match}"
)

print(
    f"Ошибка в 1 символ: {wrong_1}"
)

print(
    f"Ошибка в 2 символа: {wrong_2}"
)

print(
    f"Ошибка в 3+ символов: {wrong_3_plus}"
)

print(
    f"Пустой OCR: {empty_ocr}"
)

print()

print(
    f"Character Accuracy: {char_accuracy:.2f}%"
)

print(
    f"Средняя Levenshtein Distance: {avg_lev:.3f}"
)

csv_file = ROOT / "ocr_errors.csv"

with open(
    csv_file,
    "w",
    newline="",
    encoding="utf-8-sig"
) as f:

    writer = csv.writer(f)

    writer.writerow(
        [
            "filename",
            "true",
            "predicted"
        ]
    )

    writer.writerows(
        errors
    )

print()
print(
    f"Ошибок сохранено: {len(errors)}"
)

print(
    f"CSV: {csv_file}"
)