<jupyter_start><jupyter_text>Animalwatch validator<jupyter_code>import glob
import os.path as op

import numpy as np
from io import open
from ruamel.yaml import YAML
yaml = YAML(typ="unsafe")
true_annotations_path = "E:\\data\\lynx_lynx\\zdo\\anotace"
annotations_path = "E:\\data\\lynx_lynx\\zdo\\anotace_test"

def evaluate_dir(true_annotations_path, annotations_path):
    """
    :param true_annotations_path: path to directory with subdirectories with annotations
    :param annotations_path: path to students annotations with no subdirs
    """
    
    true_annotation_files = glob.glob(op.join(true_annotations_path, "**", "*.y*ml"))
    score = []
    score_failed = []
    nok = 0
    nerr = 0
    print("Score - video file")
    print("-------")
    for true_annotation_fn in true_annotation_files:
        annotation_fn, video_fn = find_annotation(annotations_path, true_annotation_fn)
        if annotation_fn is None:
            print("0.0 - " + str(video_fn) + " - Annotation not found")
#             print("annotations_path: ", annotations_path)
#             print("true_annotation_fn: ", true_annotation_fn)
            score_failed.append(0.0)
        else:
            sc = compare_yaml_objs(
                get_yaml_obj(annotation_fn),
                get_yaml_obj(true_annotation_fn)
            )
            score.append(sc)
            print(str(sc) + " - " + str(video_fn))
        
    print("=======")
    score_ok = np.average(score)
    print("Score without failed (" + str(len(score)) +"/" + str(len(score) + len(score_failed)) + "): " + str(score_ok))
    score.extend(score_failed)
    score = np.average(score)
    print("Score: " + str(score))
    return score
    


def get_iou(bb1, bb2):
    """
    Calculate the Intersection over Union (IoU) of two bounding boxes.
    
    by <NAME>

    Parameters
    ----------
    bb1 : dict
        Keys: {'x1', 'x2', 'y1', 'y2'}
        The (x1, y1) position is at the top left corner,
        the (x2, y2) position is at the bottom right corner
    bb2 : dict
        Keys: {'x1', 'x2', 'y1', 'y2'}
        The (x, y) position is at the top left corner,
        the (x2, y2) position is at the bottom right corner

    Returns
    -------
    float
        in [0, 1]
    """
    assert bb1['x1'] < bb1['x2']
    assert bb1['y1'] < bb1['y2']
    assert bb2['x1'] < bb2['x2']
    assert bb2['y1'] < bb2['y2']

    # determine the coordinates of the intersection rectangle
    x_left = max(bb1['x1'], bb2['x1'])
    y_top = max(bb1['y1'], bb2['y1'])
    x_right = min(bb1['x2'], bb2['x2'])
    y_bottom = min(bb1['y2'], bb2['y2'])

    if x_right < x_left or y_bottom < y_top:
        return 0.0

    # The intersection of two axis-aligned bounding boxes is always an
    # axis-aligned bounding box
    intersection_area = (x_right - x_left) * (y_bottom - y_top)

    # compute the area of both AABBs
    bb1_area = (bb1['x2'] - bb1['x1']) * (bb1['y2'] - bb1['y1'])
    bb2_area = (bb2['x2'] - bb2['x1']) * (bb2['y2'] - bb2['y1'])

    # compute the intersection over union by taking the intersection
    # area and dividing it by the sum of prediction + ground-truth
    # areas - the interesection area
    iou = intersection_area / float(bb1_area + bb2_area - intersection_area)
    assert iou >= 0.0
    assert iou <= 1.0
    return iou

def get_iou_safe(bb1, bb2):
    if len(bb1) == 0 and len(bb2) == 0:
        score = 1.0
    else:
        try:
            score = get_iou(bb1, bb2)
        except Exception as e:
            score = 0.0
    
    
    return score

def find_annotation(annotations_path, true_annotation_file):
    annotation_files = glob.glob(op.join(annotations_path, "*.y*ml"))
    true_video_fn = get_video_file_name(true_annotation_file)
    found_annotation_fn = []
    for filename in annotation_files:
        video_fn = get_video_file_name(filename)
        found_annotation_fn.append(video_fn)
#         print("video_fn: ", video_fn)
        if video_fn.upper() == true_video_fn.upper():
            return filename, video_fn
            
    
    print("true_video_fn: ", true_video_fn)
    print("found_annotation_fn", found_annotation_fn)
#     print("annotation_files: ", annotation_files)
    return None, true_video_fn


def compare_bboxes(bboxes1, bboxes2):
    scores = []
    lbb1 = len(bboxes1)
    lbb2 = len(bboxes2)
    
    if lbb1 == 0 and lbb2 == 0:
            return 1.0
    elif lbb1 == 0:
            return 0.0
    elif lbb2 == 0:
            return 0.0

    for bbox1 in bboxes1:
        scores_for_one = []
        for bbox2 in bboxes2:
            scores_for_one.append(get_iou_safe(bbox1, bbox2))
#             print(bbox1, bbox2)
        
        scores.append(np.max(scores_for_one))
#     print("compare_bboxes ", len(bboxes1), len(bboxes2), scores)
    return np.average(scores)

def compare_bboxes_symmetric(bboxes1, bboxes2):
    return np.average([
        compare_bboxes(bboxes1, bboxes2),
        compare_bboxes(bboxes2, bboxes1),
    ])
        
def compare_frames(true_yaml_obj, yaml_obj, frame_number):
    bb1 = get_bboxes_from_frame(true_yaml_obj, frame_number)
    bb2 = get_bboxes_from_frame(yaml_obj, frame_number)
    return compare_bboxes_symmetric(bb1, bb2)
    
def get_frame_number(yaml_obj):
    return np.max(list(yaml_obj["frames"]))


def compare_yaml_objs(true_yaml_obj, yaml_obj):
    frame_number = int(np.max([get_frame_number(yaml_obj), get_frame_number(true_yaml_obj)]))
    scores = []
    for i in range(0, frame_number):
        scores.append(compare_frames(true_yaml_obj, yaml_obj, frame_number=i))
    
#     print(scores)
    return np.average(scores)
                       
def get_yaml_obj(yaml_fn):
    with open(yaml_fn, encoding="utf-8") as f:
        obj = yaml.load(f)
    return obj

def get_video_file_name(yaml_fn):
    obj = get_yaml_obj(yaml_fn)
    _, video_fn = op.split(obj["path"])
    return video_fn
    
def get_bboxes_from_frame(yaml_obj, frame_number):
#     print(frame_number)
    if frame_number in yaml_obj["frames"]:
        bboxes = yaml_obj["frames"][frame_number]
    else:
        bboxes = [
#                 {
#                 "x1": 0,
#                 "x2": 0,
#                 "y1": 0,
#                 "y2": 0,
#             }
        ]
#         print("zero")
    return bboxes

# def compare_bboxes(bboxes1, bboxes2):
#     scores = []
#     lbb1 = len(bboxes1)
#     lbb2 = len(bboxes2)
    
#     if lbb1 == 0 and lbb2 == 0:
#             return 1.0
#     elif lbb1 == 0:
#             return 0.0
#     elif lbb2 == 0:
#             return 0.0

#     for bbox1 in bboxes1:
#         scores_for_one = []
#         for bbox2 in bboxes2:
#             scores_for_one.append(get_iou_safe(bbox1, bbox2))
# #             print(bbox1, bbox2)
        
#         scores.append(np.max(scores_for_one))
# #     print("compare_bboxes ", len(bboxes1), len(bboxes2), scores)
#     return np.average(scores)

# def compare_bboxes_symmetric(bboxes1, bboxes2):
#     return np.average([
#         compare_bboxes(bboxes1, bboxes2),
#         compare_bboxes(bboxes2, bboxes1),
#     ])
        
# def compare_frames(true_yaml_obj, yaml_obj, frame_number):
#     bb1 = get_bboxes_from_frame(true_yaml_obj, frame_number)
#     bb2 = get_bboxes_from_frame(yaml_obj, frame_number)
#     return compare_bboxes_symmetric(bb1, bb2)
    
# def get_frame_number(yaml_obj):
#     return np.max(list(yaml_obj["frames"]))


# def compare_yaml_objs(true_yaml_obj, yaml_obj):
#     frame_number = int(np.max([get_frame_number(yaml_obj), get_frame_number(true_yaml_obj)]))
#     scores = []
#     for i in range(0, frame_number):
#         scores.append(compare_frames(true_yaml_obj, yaml_obj, frame_number=i))
    
# #     print(scores)
#     return np.average(scores)
                       
# def get_yaml_obj(yaml_fn):
#     with open(yaml_fn, encoding="utf-8") as f:
#         obj = yaml.load(f)
#     return obj

# def get_video_file_name(yaml_fn):
#     obj = get_yaml_obj(yaml_fn)
#     video_fn = obj["path"]
#     return video_fn
    
# def get_bboxes_from_frame(yaml_obj, frame_number):
# #     print(frame_number)
#     if frame_number in yaml_obj["frames"]:
#         bboxes = yaml_obj["frames"][frame_number]
#     else:
#         bboxes = [
# #                 {
# #                 "x1": 0,
# #                 "x2": 0,
# #                 "y1": 0,
# #                 "y2": 0,
# #             }
#         ]
# #         print("zero")
#     return bboxes<jupyter_output><empty_output><jupyter_text>Example<jupyter_code>evaluate_dir(true_annotations_path, annotations_path)<jupyter_output>Score - video file
-------
0.0 - IMAG0017.AVI - Annotation not found
annotations_path:  E:\data\lynx_lynx\zdo\anotace_test
true_annotation_fn:  E:\data\lynx_lynx\zdo\anotace\01\IMAG0017.yaml
0.0 - IMAG0021.AVI - Annotation not found
annotations_path:  E:\data\lynx_lynx\zdo\anotace_test
true_annotation_fn:  E:\data\lynx_lynx\zdo\anotace\01\IMAG0021.yaml
0.0 - IMAG0023.AVI - Annotation not found
annotations_path:  E:\data\lynx_lynx\zdo\anotace_test
true_annotation_fn:  E:\data\lynx_lynx\zdo\anotace\01\IMAG0023.yaml
0.0 - IMAG0056.AVI - Annotation not found
annotations_path:  E:\data\lynx_lynx\zdo\anotace_test
true_annotation_fn:  E:\data\lynx_lynx\zdo\anotace\01\IMAG0056.yaml
0.48312611012433393 - IMAG0035.AVI
1.0 - IMAG0039.AVI
0.0 - IMAG0041.AVI - Annotation not found
annotations_path:  E:\data\lynx_lynx\zdo\anotace_test
true_annotation_fn:  E:\data\lynx_lynx\zdo\anotace\03\IMAG0041.yml
0.0 - v__00019.avi - Annotation not found
annotations_path:  E:\data\lynx_lynx\zdo\anotace_test
true[...]<jupyter_text>Debug tests<jupyter_code># filename = "anotace.yaml"

# yaml = YAML(typ="unsafe")
# with open(filename, encoding="utf-8") as f:
#     obj = yaml.load(f)
files = glob.glob(op.join(annotations_path, "*.y*ml"))
files[0]
yaml_fn = files[1]

video_fn = get_video_file_name(yaml_fn)
# print(video_fn, yaml_fn)
true_yaml_obj = get_yaml_obj(yaml_fn)

bb1 = true_yaml_obj["frames"][1][0]
bb2 = true_yaml_obj["frames"][5][0]

get_iou(bb1, bb2)
            
        
    
compare_bboxes(get_bboxes_from_frame(true_yaml_obj, 5), get_bboxes_from_frame(true_yaml_obj, 1))
assert(compare_bboxes(
    [{'x1': 341, 'x2': 459, 'y1': 417, 'y2': 491}, {'x1': 541, 'x2': 559, 'y1': 517, 'y2': 591}], 
    [{'x1': 341, 'x2': 459, 'y1': 417, 'y2': 491}, {'x1': 541, 'x2': 559, 'y1': 517, 'y2': 591}]) == 1.0)
compare_bboxes_symmetric(
    [{'x1': 341, 'x2': 459, 'y1': 417, 'y2': 491}, {'x1': 541, 'x2': 559, 'y1': 517, 'y2': 591}],
    [{'x1': 341, 'x2': 459, 'y1': 417, 'y2': 491}], 
)
assert(
    compare_bboxes_symmetric(
        [{'x1': 341, 'x2': 459, 'y1': 417, 'y2': 491}, {'x1': 541, 'x2': 559, 'y1': 517, 'y2': 591}],
        [{'x1': 0, 'x2': 1, 'y1': 0, 'y2': 0}], 
    ) == 0.0
)
# true_yaml_obj
assert(
    compare_frames(true_yaml_obj, true_yaml_obj, frame_number=5) == 1
)
assert(
    compare_yaml_objs(get_yaml_obj(files[0]), get_yaml_obj(files[0])) == 1
)
assert('E:\\data\\lynx_lynx\\zdo\\anotace_test\\IMAG0021.yaml' in files)
fn1, fn2 = find_annotation(true_annotations_path, files[1])
assert(fn1 is None)
# "asd" == "asd"
# files<jupyter_output><empty_output><jupyter_text>Debug 4 files found<jupyter_code>find_annotation(
    r"C:\Users\miros\projects\zdo_lynx_lynx\ZDO_SP_Sosnova_Cincera\Anotace",
    r"E:\data\lynx_lynx\zdo\anotace\01\IMAG0017.yaml"
)
# "sdfa".upper()
import os.path as op
_, uu = op.split("uur/safs/asdfsda.avi")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.1398065022226096, 'fraction_numerical': 0.041837357273598885, 'mean_word_length': 2.90006798096533, 'pattern_counts': {'":': 8, '<': 24, '<?xml version=': 0, '>': 18, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '7885', 'license': 'MIT', 'n_tokens_mistral': 4654, 'n_tokens_neox': 4294, 'n_words': 826, 'path': 'devel/validator.ipynb', 'repo_name': 'mjirik/animalwatch', 'size': '11479'}