|
""" |
|
TOC: |
|
0) IMPORTS |
|
1) METADATA |
|
2) UPLOAD |
|
3) ANNOTATIONS |
|
-1) MAIN |
|
""" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import os |
|
from io import BytesIO |
|
import argparse |
|
|
|
|
|
import gradio as gr |
|
|
|
|
|
from tkinter import Tk, filedialog |
|
from pathlib import Path |
|
from PIL import Image, ExifTags |
|
from PIL.ExifTags import TAGS |
|
|
|
|
|
import numpy as np |
|
import pandas as pd |
|
|
|
|
|
import csv |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def decode_utf16_little_endian(binary_data): |
|
try: |
|
|
|
|
|
|
|
decoded_text = binary_data.decode("utf-16-le").rstrip("\x00") |
|
except Exception as e: |
|
decoded_text = "Encoded" |
|
return decoded_text |
|
|
|
|
|
''' |
|
def get_exif(list_file_paths): |
|
metadata_all_file = {} |
|
df = pd.DataFrame() |
|
for file_path in list_file_paths: |
|
metadata = {} |
|
metadata["name"] = file_path.split("/")[-1] |
|
print(file_path) |
|
try: |
|
image = Image.open(file_path) |
|
exifdata = image._getexif() |
|
if exifdata is not None: |
|
print(len(exifdata.items())) |
|
for tagid, value in exifdata.items(): |
|
# print(tagid, value) |
|
# print(f"Value:{value}") |
|
tagname = str(TAGS.get(tagid, tagid)) |
|
# value = exifdata.get(tagid) |
|
# Handle binary data |
|
if isinstance(value, bytes): |
|
# print(f"Value bytes {value}") |
|
# print(f"Value bytes {type(value)}") |
|
# print(f"Value str {decode_utf16_little_endian(value)}") |
|
value = decode_utf16_little_endian(value) |
|
print(tagname) |
|
print(type(tagname)) |
|
print(value) |
|
if type(tagname) is not str: |
|
print(">>>>>>>>>>>> here " + type(tagname)) |
|
try: |
|
metadata[str(tagname)] = value |
|
except: |
|
try: |
|
metadata[repr(tagname)] = value |
|
except: |
|
pass |
|
else: |
|
metadata[tagname] = value |
|
""" |
|
for key in metadata.keys(): |
|
if type(key) is not str: |
|
try: |
|
metadata[str(key)] = metadata[key] |
|
except: |
|
try: |
|
metadata[repr(key)] = metadata[key] |
|
except: |
|
pass |
|
del metadata[key] |
|
""" |
|
# print(f"\t{metadata}") |
|
print(metadata) |
|
print(pd.DataFrame([metadata])) |
|
df = pd.concat([df, pd.DataFrame([metadata])], ignore_index=True) |
|
# new_row = {"name": file_path, **metadata} |
|
# df = pd.concat([df, pd.DataFrame([new_row])], ignore_index=True) |
|
# metadata_all_file[file_path] = metadata |
|
else: |
|
return "No EXIF metadata found." |
|
except Exception as e: |
|
return f"Error : {e}" |
|
print(pd.concat([df, pd.DataFrame([metadata])], ignore_index=True)) |
|
print(f"FINAL DF \n \n \n {df}") |
|
return df |
|
''' |
|
import pandas as pd |
|
from PIL import Image |
|
from PIL.ExifTags import TAGS |
|
|
|
|
|
def decode_utf16_little_endian(value): |
|
try: |
|
return value.decode("utf-16le").strip() |
|
except: |
|
return value |
|
|
|
|
|
def extract_particular_value_from_exif_file(metadata, tagname, value): |
|
pass |
|
|
|
|
|
def get_exif(list_file_paths): |
|
df = pd.DataFrame() |
|
|
|
for file_path in list_file_paths: |
|
metadata = {"name": file_path.split("/")[-1]} |
|
print(file_path) |
|
|
|
try: |
|
image = Image.open(file_path) |
|
exifdata = image._getexif() |
|
|
|
if exifdata is not None: |
|
for tagid, value in exifdata.items(): |
|
tagname = TAGS.get(tagid, str(tagid)) |
|
print(type(tagname)) |
|
if isinstance(value, bytes): |
|
value = decode_utf16_little_endian(value) |
|
if isinstance(value, dict): |
|
|
|
|
|
|
|
|
|
value = str(value) |
|
print(value) |
|
print(type(value)) |
|
metadata[tagname] = value |
|
print(metadata) |
|
if all(isinstance(k, str) for k in metadata.keys()): |
|
df = pd.concat([df, pd.DataFrame([metadata])], ignore_index=True) |
|
else: |
|
print("Skipping metadata with non-string keys.") |
|
else: |
|
print(f"No EXIF metadata found for {file_path}") |
|
|
|
except Exception as e: |
|
print(f"Error processing {file_path}: {e}") |
|
|
|
print(f"FINAL DF:\n{df}") |
|
return df |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_file_names(files_): |
|
""" |
|
Get a list of the name of files splitted to get only the proper name |
|
Input: Uploaded files |
|
Output: ['name of file 1', 'name of file 2']""" |
|
return [file.name for file in files_] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_annotation(files_): |
|
""" |
|
Get the label and accuracy from pretrained (or futur custom model) |
|
Input: Uploaded files |
|
Output: Df that contains: file_name | label | accuracy |
|
""" |
|
|
|
df_exif = get_exif(get_file_names(files_)) |
|
return df_exif |
|
|
|
|
|
def update_dataframe(df): |
|
return df |
|
|
|
|
|
def df_to_csv(df_, encodings=None): |
|
""" |
|
Get the df and convert it as an gradio file output ready for download |
|
Input: DF created |
|
Output: gr.File() |
|
""" |
|
if encodings is None: |
|
encodings = ["utf-8", "utf-8-sig", "latin1", "iso-8859-1", "cp1252"] |
|
|
|
for encoding in encodings: |
|
try: |
|
df_.to_csv("output.csv", encoding=encoding, index=False) |
|
|
|
return gr.File(value="output.csv", visible=True) |
|
except Exception as e: |
|
print(f"Failed with encoding {encoding}: {e}") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_files(files_): |
|
""" |
|
Main function |
|
- Get uploaded files |
|
- Get annotations # TODO |
|
- Get the corresponding df |
|
- Get the csv output |
|
""" |
|
df = get_annotation(files_) |
|
return df |
|
|
|
|
|
with gr.Blocks() as interface: |
|
gr.Markdown("# Wildlife.ai Annotation tools") |
|
|
|
with gr.Row(): |
|
upload_btn = gr.UploadButton( |
|
"Upload raw data", |
|
file_types=["image", "video"], |
|
file_count="multiple", |
|
) |
|
update_btn = gr.Button("Modify raw data") |
|
download_raw_btn = gr.Button("Generate raw data as csv") |
|
download_modified_btn = gr.Button("Generate new data as a csv") |
|
|
|
gr.Markdown("## Results") |
|
df = gr.DataFrame(interactive=False) |
|
download_raw_btn.click( |
|
fn=df_to_csv, |
|
inputs=[df], |
|
outputs=gr.File(visible=False), |
|
) |
|
gr.Markdown("## Modified results") |
|
df_modified = gr.DataFrame(interactive=True) |
|
download_modified_btn.click( |
|
fn=df_to_csv, |
|
inputs=[df_modified], |
|
outputs=gr.File(visible=False), |
|
show_progress=False, |
|
) |
|
|
|
|
|
upload_btn.upload(fn=process_files, inputs=upload_btn, outputs=df) |
|
update_btn.click(fn=update_dataframe, inputs=df, outputs=df_modified) |
|
|
|
|
|
if __name__ == "__main__": |
|
interface.launch(debug=True) |
|
|