Spaces:
Runtime error
Runtime error
| # https://planogram-compliance.herokuapp.com/ | |
| # https://dashboard.heroku.com/apps/planogram-compliance/deploy/heroku-git | |
| # https://medium.com/@mohcufe/how-to-deploy-your-trained-pytorch-model-on-heroku-ff4b73085ddd\ | |
| # https://stackoverflow.com/questions/51730880/where-do-i-get-a-cpu-only-version-of-pytorch | |
| # https://blog.jcharistech.com/2020/02/26/how-to-deploy-a-face-detection-streamlit-app-on-heroku/ | |
| # https://towardsdatascience.com/a-quick-tutorial-on-how-to-deploy-your-streamlit-app-to-heroku- | |
| # https://www.analyticsvidhya.com/blog/2021/06/deploy-your-ml-dl-streamlit-application-on-heroku/ | |
| # https://gist.github.com/jeremyjordan/6b506257509e8ba673f145baa568a1ea | |
| import json | |
| # https://www.r-bloggers.com/2020/12/creating-a-streamlit-web-app-building-with-docker-github-actions-and-hosting-on-heroku/ | |
| # https://devcenter.heroku.com/articles/container-registry-and-runtime | |
| # from yolo_inference_util import run_yolo_v5 | |
| import os | |
| from tempfile import NamedTemporaryFile | |
| import cv2 | |
| import numpy as np | |
| import pandas as pd | |
| import streamlit as st | |
| # import matplotlib.pyplot as plt | |
| from app_utils import annotate_planogram_compliance, bucket_sort, do_sorting, xml_to_csv | |
| from inference import run | |
| # from utils.plots import Annotator, colors | |
| # from utils.general import scale_coords | |
| app_formal_name = "Planogram Compliance" | |
| FILE_UPLOAD_DIR = "tmp" | |
| os.makedirs(FILE_UPLOAD_DIR, exist_ok=True) | |
| # Start the app in wide-mode | |
| st.set_page_config( | |
| layout="wide", | |
| page_title=app_formal_name, | |
| ) | |
| # https://github.com/streamlit/streamlit/issues/1361 | |
| uploaded_file = st.file_uploader( | |
| "Choose a planogram image to score", | |
| type=["jpg", "JPEG", "PNG", "JPG", "jpeg"], | |
| ) | |
| uploaded_master_planogram_file = st.file_uploader( | |
| "Upload a master planogram", type=["jpg", "JPEG", "PNG", "JPG", "jpeg"] | |
| ) | |
| annotation_file = st.file_uploader("upload master polanogram", type=["xml"]) | |
| temp_file = NamedTemporaryFile(delete=False) | |
| target_names = [ | |
| "Bottle,100PLUS ACTIVE 1.5L", | |
| "Bottle,100PLUS ACTIVE 500ML", | |
| "Bottle,100PLUS LEMON LIME 1.5L", | |
| "Bottle,100PLUS ORANGE 500ML", | |
| "Bottle,100PLUS ORIGINAL 1.5L", | |
| "Bottle,100PLUS TANGY ORANGE 1.5L", | |
| "Bottle,100PLUS ZERO 1.5L", | |
| "Bottle,100PLUS ZERO 500ML", | |
| "Packet,F:M MAGNOLIA CHOC 1L", | |
| "Bottle,F&N GINGER ADE 1.5L", | |
| "Bottle,F&N GRAPE 1.5L", | |
| "Bottle,F&N ICE CREAM SODA 1.5L", | |
| "Bottle,F&N LYCHEE PEAR 1.5L", | |
| "Bottle,F&N ORANGE 1.5L", | |
| "Bottle,F&N PINEAPPLE PET 1.5L", | |
| "Bottle,F&N SARSI 1.5L", | |
| "Bottle,F&N SS ICE LEM TEA RS 500ML", | |
| "Bottle,F&N SS ICE LEMON TEA RS 1.5L", | |
| "Bottle,F&N SS ICE LEMON TEA 1.5L", | |
| "Bottle,F&N SS ICE LEMON TEA 500ML", | |
| "Bottle,F&N SS ICE PEACH TEA 1.5L", | |
| "Bottle,SS ICE LEMON GT 1.48L", | |
| "Bottle,SS WHITE CHRYS TEA 1.48L", | |
| "Packet,FARMHOUSE FRESH MILK 1L FNDM", | |
| "Packet,FARMHOUSE PLAIN LF 1L", | |
| "Packet,PURA FRESH MILK 1L FS", | |
| "Packet,NUTRISOY REG NO SUGAR ADDED 1L", | |
| "Packet,NUTRISOY PLAIN 475ML", | |
| "Packet,NUTRISOY PLAIN 1L", | |
| "Packet,NUTRISOY OMEGA RD SUGAR 1L", | |
| "Packet,NUTRISOY OMEGA NSA 1L", | |
| "Packet,NUTRISOY ALMOND 1L", | |
| "Packet,MAGNOLIA FRESH MILK 1L FNDM", | |
| "Packet,FM MAG FC PLAIN 200ML", | |
| "Packet,MAG OMEGA PLUS PLAIN 200ML", | |
| "Packet,MAG KURMA MILK 500ML", | |
| "Packet,MAG KURMA MILK 1L", | |
| "Packet,MAG CHOCOLATE FC 500ML", | |
| "Packet,MAG BROWN SUGAR SS MILK 1L", | |
| "Packet,FM MAG LFHC PLN 500ML", | |
| "Packet,FM MAG LFHC OAT 500ML", | |
| "Packet,FM MAG LFHC OAT 1L", | |
| "Packet,FM MAG FC PLAIN 500ML", | |
| "Void,PARTIAL VOID", | |
| "Void,FULL VOID", | |
| "Bottle,F&N SS ICE LEM TEA 500ML", | |
| ] | |
| run_app = st.button("Run the compliance check") | |
| if run_app and uploaded_file is not None: | |
| # Convert the file to an opencv image. | |
| file_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8) | |
| temp_file.write(uploaded_file.getvalue()) | |
| uploaded_img = cv2.imdecode(file_bytes, 1) | |
| cv2.imwrite("tmp/to_score_planogram_tmp.png", uploaded_img) | |
| # if uploaded_master_planogram_file is None: | |
| # master = cv2.imread('./sample_master_planogram.jpeg') | |
| names_dict = {name: id for id, name in enumerate(target_names)} | |
| sorted_xml_df = None | |
| # https://discuss.streamlit.io/t/unable-to-read-files-using-standard-file-uploader/2258/2 | |
| if uploaded_master_planogram_file and annotation_file: | |
| file_bytes = np.asarray( | |
| bytearray(uploaded_master_planogram_file.read()), dtype=np.uint8 | |
| ) | |
| master = cv2.imdecode(file_bytes, 1) | |
| cv2.imwrite("tmp/master_tmp.png", master) | |
| # cv2.imwrite("tmp_uploaded_master_planogram_img.png", master) | |
| # xml = annotation_file.read() | |
| # tmp_xml ="tmp_xml_annotation.xml" | |
| # with open(tmp_xml ,'w',encoding='utf-8') as f: | |
| # xml = f.write(xml) | |
| xml_df = xml_to_csv(annotation_file) | |
| xml_df["cls"] = xml_df["cls"].map(names_dict) | |
| sorted_xml_df = do_sorting(xml_df) | |
| sorted_xml_df.line_number.value_counts() | |
| line_data = sorted_xml_df.line_number.value_counts() | |
| n_rows = int(len(line_data)) | |
| n_cols = int(max(line_data)) | |
| master_table = np.zeros((n_rows, n_cols)) + 101 | |
| master_annotations = [] | |
| for i, row in sorted_xml_df.groupby("line_number"): | |
| # print(f"Adding products in the row {i} to the detected planogram", row.cls.tolist()) | |
| products = row.cls.tolist() | |
| master_table[int(i - 1), 0 : len(products)] = products | |
| annotations = [ | |
| (int(k), int(v)) | |
| for k, v in list( | |
| zip(row.cls.unique(), row.cls.value_counts().tolist()) | |
| ) | |
| ] | |
| master_annotations.append(annotations) | |
| master_table.shape | |
| # print("Annoatated planogram") | |
| # print(np.matrix(master_table)) | |
| elif uploaded_master_planogram_file: | |
| print( | |
| "Finding the amster annotations with the YOLOv5 model predictions" | |
| ) | |
| file_bytes = np.asarray( | |
| bytearray(uploaded_master_planogram_file.read()), dtype=np.uint8 | |
| ) | |
| master = cv2.imdecode(file_bytes, 1) | |
| cv2.imwrite("tmp/master_tmp.png", master) | |
| master_results = run( | |
| weights="base_line_best_model_exp5.pt", | |
| source="tmp/master_tmp.png", | |
| imgsz=[640, 640], | |
| conf_thres=0.6, | |
| iou_thres=0.6, | |
| ) | |
| bb_df = pd.DataFrame( | |
| master_results[0][1].tolist(), | |
| columns=["xmin", "ymin", "xmax", "ymax", "conf", "cls"], | |
| ) | |
| sorted_df = do_sorting(bb_df) | |
| n_rows = int(sorted_df.line_number.max()) | |
| n_cols = int( | |
| sorted_df.groupby("line_number") | |
| .size() | |
| .reset_index(name="counts")["counts"] | |
| .max() | |
| ) | |
| non_null_product = 101 | |
| print("master size", n_rows, n_cols) | |
| master_annotations = [] | |
| master_table = np.zeros((int(n_rows), int(n_cols))) + non_null_product | |
| for i, row in sorted_df.groupby("line_number"): | |
| # print(f"Adding products in the row {i} to the detected planogram", row.cls.tolist()) | |
| products = row.cls.tolist() | |
| col_len = min(len(products), n_cols) | |
| print("col size: ", col_len) | |
| print("row size: ", i - 1) | |
| if n_rows <= (i - 1): | |
| print("more rows than expected in the predictions") | |
| break | |
| master_table[int(i - 1), 0:col_len] = products[:col_len] | |
| annotations = [ | |
| (int(k), int(v)) | |
| for k, v in list( | |
| zip(row.cls.unique(), row.cls.value_counts().tolist()) | |
| ) | |
| ] | |
| master_annotations.append(annotations) | |
| else: | |
| master = cv2.imread("./sample_master_planogram.jpeg") | |
| n_rows = 3 | |
| n_cols = 16 | |
| master_table = np.zeros((n_rows, n_cols)) + 101 | |
| master_annotations = [ | |
| [(32, 12), (8, 4)], | |
| [(36, 1), (41, 6), (50, 4), (51, 3), (52, 2)], | |
| [(23, 5), (24, 6), (54, 5)], | |
| ] | |
| for i, row in enumerate(master_annotations): | |
| idx = 0 | |
| for product, count in row: | |
| master_table[i, idx : idx + count] = product | |
| idx = idx + count | |
| # Now do something with the image! For example, let's display it: | |
| # st.image(opencv_image, channels="BGR") | |
| # uploaded_img = '/content/drive/My Drive/0.CV/0.Planogram_Compliance/planogram_data/images/test/IMG_5718.jpg' | |
| result_list = run( | |
| weights="base_line_best_model_exp5.pt", | |
| source="tmp/to_score_planogram_tmp.png", | |
| imgsz=[640, 640], | |
| conf_thres=0.6, | |
| iou_thres=0.6, | |
| ) | |
| bb_df = pd.DataFrame( | |
| result_list[0][1].tolist(), | |
| columns=["xmin", "ymin", "xmax", "ymax", "conf", "cls"], | |
| ) | |
| sorted_df = do_sorting(bb_df) | |
| non_null_product = 101 | |
| print("master size", n_rows, n_cols) | |
| detected_table = np.zeros((n_rows, n_cols)) + non_null_product | |
| for i, row in sorted_df.groupby("line_number"): | |
| # print(f"Adding products in the row {i} to the detected planogram", row.cls.tolist()) | |
| products = row.cls.tolist() | |
| col_len = min(len(products), n_cols) | |
| print("col size: ", col_len) | |
| print("row size: ", i - 1) | |
| if n_rows <= (i - 1): | |
| print("more rows than expected in the predictions") | |
| break | |
| detected_table[int(i - 1), 0:col_len] = products[:col_len] | |
| # score = (master_table == detected_table).sum() / (master_table != non_null_product).sum() | |
| correct_matches = ( | |
| np.ma.masked_equal(master_table, non_null_product) == detected_table | |
| ).sum() | |
| total_products = (master_table != non_null_product).sum() | |
| score = correct_matches / total_products | |
| # if sorted_xml_df is not None: | |
| # annotate_df = sorted_xml_df[["xmin","ymin", "xmax", "ymax", "line_number","cls"]].astype(int) | |
| # else: | |
| annotate_df = sorted_df[ | |
| ["xmin", "ymin", "xmax", "ymax", "line_number", "cls"] | |
| ].astype(int) | |
| mask = master_table != non_null_product | |
| m_detected_table = np.ma.masked_array(master_table, mask=mask) | |
| m_annotated_table = np.ma.masked_array(detected_table, mask=mask) | |
| # wrong_indexes = np.ravel_multi_index(master_table*mask != detected_table*mask, master_table.shape) | |
| wrong_indexes = np.where(master_table != detected_table) | |
| correct_indexes = np.where(master_table == detected_table) | |
| annotated_planogram = annotate_planogram_compliance( | |
| uploaded_img, annotate_df, correct_indexes, wrong_indexes, target_names | |
| ) | |
| st.title("Target Products") | |
| st.write(json.dumps(target_names)) | |
| st.title("The master planogram annotation") | |
| st.write( | |
| "The annotations are based on the index of products from Target products list " | |
| ) | |
| st.write(json.dumps(master_annotations)) | |
| # https://github.com/streamlit/streamlit/issues/888 | |
| st.image( | |
| [master, annotated_planogram, result_list[0][0]], | |
| width=512, | |
| caption=[ | |
| "Master planogram", | |
| "Planogram Compliance", | |
| "Planogram Predictions", | |
| ], | |
| channels="BGR", | |
| ) | |
| # st.image([master, annotated_planogram], width=512, caption=["Master planogram", "Planogram Compliance"], channels="BGR") | |
| st.title("Planogram Compiance score") | |
| # st.write(f"{correct_matches} / {total_products}") | |
| st.write(score) | |