diff --git a/.gitattributes b/.gitattributes
index a6344aac8c09253b3b630fb776ae94478aa0275b..b9e8893120f3fe820cec27746238ed95a58459f4 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.zst filter=lfs diff=lfs merge=lfs -text
*tfevents* filter=lfs diff=lfs merge=lfs -text
+*.mp4 filter=lfs diff=lfs merge=lfs -text
+*.pdf filter=lfs diff=lfs merge=lfs -text
+*.ipynb filter=lfs diff=lfs merge=lfs -text
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..eaec302aedde3e6da4db86aedf3a646710d8b1e3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,54 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+bin/
+build/
+develop-eggs/
+dist/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+
+# Mr Developer
+.mr.developer.cfg
+.project
+.pydevproject
+
+# Rope
+.ropeproject
+
+# Django stuff:
+*.log
+*.pot
+
+# Sphinx documentation
+docs/_build/
+Share
+
+# mac
+.DS_Store
diff --git a/Backend/BrandRecognition/Dynamic/Brand_Count_Vid.py b/Backend/BrandRecognition/Dynamic/Brand_Count_Vid.py
new file mode 100644
index 0000000000000000000000000000000000000000..1390e2d0fd7f99512f1ad00511ba4070d323bb29
--- /dev/null
+++ b/Backend/BrandRecognition/Dynamic/Brand_Count_Vid.py
@@ -0,0 +1,135 @@
+import cv2
+import numpy as np
+from collections import deque, defaultdict
+from ultralytics import YOLO
+
+
+
+def iou(box1, box2):
+ x1 = max(box1[0], box2[0])
+ y1 = max(box1[1], box2[1])
+ x2 = min(box1[2], box2[2])
+ y2 = min(box1[3], box2[3])
+
+ intersection = max(0, x2 - x1) * max(0, y2 - y1)
+ area1 = (box1[2] - box1[0]) * (box1[3] - box1[1])
+ area2 = (box2[2] - box2[0]) * (box2[3] - box2[1])
+
+ iou = intersection / float(area1 + area2 - intersection)
+ return iou
+
+def smooth_box(box_history):
+ if not box_history:
+ return None
+ return np.mean(box_history, axis=0)
+
+def process_video(input_path, output_path):
+ model = YOLO('kitkat_s.pt')
+ cap = cv2.VideoCapture(input_path)
+
+ width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
+ height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
+ fps = int(cap.get(cv2.CAP_PROP_FPS))
+
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
+ out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))
+
+ detected_items = {}
+ frame_count = 0
+
+ detections_history = defaultdict(lambda: defaultdict(int))
+
+ while cap.isOpened():
+ ret, frame = cap.read()
+ if not ret:
+ break
+
+ frame_count += 1
+
+ if frame_count % 5 == 0:
+ results = model(frame)
+
+ current_frame_detections = []
+
+ for r in results:
+ boxes = r.boxes
+ for box in boxes:
+ x1, y1, x2, y2 = box.xyxy[0].tolist()
+ conf = box.conf.item()
+ cls = int(box.cls.item())
+ brand = model.names[cls]
+
+ current_frame_detections.append((brand, [x1, y1, x2, y2], conf))
+
+ for brand, box, conf in current_frame_detections:
+ matched = False
+ for item_id, item_info in detected_items.items():
+ if iou(box, item_info['smoothed_box']) > 0.5:
+ item_info['frames_detected'] += 1
+ item_info['total_conf'] += conf
+ item_info['box_history'].append(box)
+ if len(item_info['box_history']) > 10:
+ item_info['box_history'].popleft()
+ item_info['smoothed_box'] = smooth_box(item_info['box_history'])
+ item_info['last_seen'] = frame_count
+ matched = True
+ break
+
+ if not matched:
+ item_id = len(detected_items)
+ detected_items[item_id] = {
+ 'brand': brand,
+ 'box_history': deque([box], maxlen=10),
+ 'smoothed_box': box,
+ 'frames_detected': 1,
+ 'total_conf': conf,
+ 'last_seen': frame_count
+ }
+
+ detections_history[brand][frame_count] += 1
+
+
+ for item_id, item_info in list(detected_items.items()):
+ if frame_count - item_info['last_seen'] > fps * 2: # 2 seconds
+ del detected_items[item_id]
+ continue
+
+ if item_info['smoothed_box'] is not None:
+ alpha = 0.3
+ current_box = item_info['smoothed_box']
+ target_box = item_info['box_history'][-1] if item_info['box_history'] else current_box
+ interpolated_box = [
+ current_box[i] * (1 - alpha) + target_box[i] * alpha
+ for i in range(4)
+ ]
+ item_info['smoothed_box'] = interpolated_box
+
+ x1, y1, x2, y2 = map(int, interpolated_box)
+ cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
+ cv2.putText(frame, f"{item_info['brand']}",
+ (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
+
+ out.write(frame)
+
+ cap.release()
+ out.release()
+
+ total_frames = frame_count
+ confirmed_items = {}
+ for brand, frame_counts in detections_history.items():
+ detection_frames = len(frame_counts)
+ if detection_frames > total_frames * 0.1:
+ avg_count = sum(frame_counts.values()) / detection_frames
+ confirmed_items[brand] = round(avg_count)
+
+ return confirmed_items
+
+def annotate_video(input_video):
+ output_path = 'annotated_output.mp4'
+ confirmed_items = process_video(input_video, output_path)
+
+ item_list = [(brand, quantity) for brand, quantity in confirmed_items.items()]
+
+ status_message = "Video processed successfully!"
+
+ return output_path, item_list, status_message
\ No newline at end of file
diff --git a/Backend/BrandRecognition/Static/Brand_Count_Img.py b/Backend/BrandRecognition/Static/Brand_Count_Img.py
new file mode 100644
index 0000000000000000000000000000000000000000..1df0525e67b1e899af94561a660a9b1eaf434a17
--- /dev/null
+++ b/Backend/BrandRecognition/Static/Brand_Count_Img.py
@@ -0,0 +1,132 @@
+import cv2
+import numpy as np
+from ultralytics import YOLO
+from Database.mongodb import DatabaseManager
+
+def preprocess_image(image, input_size=(640, 640), augment=False):
+ """
+ Advanced image preprocessing for multi-brand object detection.
+
+ Args:
+ image (numpy.ndarray): Input image in BGR format.
+ input_size (tuple): Target image dimensions (width, height).
+ augment (bool): Apply data augmentation for training.
+
+ Returns:
+ numpy.ndarray: Preprocessed image in RGB format.
+ """
+
+ # Convert image to RGB
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
+
+ # Resize and enhance
+ resized_image = cv2.resize(image_rgb, input_size, interpolation=cv2.INTER_NEAREST)
+ enhanced_image = cv2.convertScaleAbs(resized_image, alpha=1.65, beta=1.75)
+
+ return enhanced_image
+
+def detect_grocery_items(image, model_path=None, threshold=0.5):
+
+ """
+ Detect grocery items in an image.
+
+ Args:
+ image (numpy.ndarray): Input image in BGR format.
+ model_path (str, optional): Path to YOLO model weights.
+ threshold (float, optional): Confidence threshold for detection.
+
+ Returns:
+ tuple: Annotated image, summary table, and status message
+ """
+
+ db_manager = DatabaseManager()
+
+ # Validate image input
+ if image is None or image.size == 0:
+ return None, [], "Invalid image input"
+
+ # Use default model path if not provided
+ if model_path is None:
+ model_path = 'Weights/kitkat_s.pt'
+
+ # Load YOLO model
+ try:
+ model = YOLO(model_path)
+ except Exception as e:
+ return None, [], f"Model loading error: {str(e)}"
+
+ # Preprocess image
+ processed_image = preprocess_image(image)
+
+ # Detect objects
+ try:
+ results = model(processed_image)
+
+ # If no results, return early
+ if len(results[0].boxes) == 0:
+ return processed_image, [], "No items detected"
+
+ # Annotate image
+ annotated_image = results[0].plot()
+
+ # Process detection results
+ class_ids = results[0].boxes.cls.cpu().numpy()
+ confidences = results[0].boxes.conf.cpu().numpy()
+
+ # Aggregate results
+ class_counts = {}
+ class_confidences = {}
+
+ # Iterate over detected objects
+ for i, class_id in enumerate(class_ids):
+
+ # Get class name and confidence
+ confidence = confidences[i]
+
+ # Filter by confidence threshold
+ if confidence >= threshold:
+
+ # Get class name
+ class_name = model.names[int(class_id)]
+ class_counts[class_name] = class_counts.get(class_name, 0) + 1
+
+ # Store confidence values
+ if class_name not in class_confidences:
+ class_confidences[class_name] = []
+
+ # Add confidence value
+ class_confidences[class_name].append(confidence)
+
+ # Create summary table
+ summary_table = [
+ [class_name, count, f"{np.mean(class_confidences[class_name]):.2f}"]
+ for class_name, count in class_counts.items()
+ ]
+
+ # Add brand records to the database
+ for brand, count in class_counts.items():
+ db_manager.add_brand_record(brand, count)
+
+ # Convert back to RGB for display
+ annotated_image_rgb = annotated_image[:, :, ::-1]
+
+ return annotated_image_rgb, summary_table, "Objects Recognised Successfully 🥳"
+
+ except Exception as e:
+ return None, [], f"Detection error: {str(e)}"
+
+
+# Optional: Batch processing function
+def batch_detect_grocery_items(images, model_path=None, threshold=0.4):
+ """
+ Detect grocery items in multiple images.
+
+ Args:
+ images (list): List of input images in BGR format.
+ model_path (str, optional): Path to YOLO model weights.
+ threshold (float, optional): Confidence threshold for detection.
+
+ Returns:
+ list: List of detection results for each image
+ """
+ return [detect_grocery_items(img, model_path, threshold) for img in images]
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Fresh_1.png b/Backend/Fruit_Freshness/Apples/Photos/Fresh_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..193916cd91556a5562bdf9913b9ca5a5de79e83f
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Fresh_1.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Fresh_2.png b/Backend/Fruit_Freshness/Apples/Photos/Fresh_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..98ced8d972b4f3a4106f151c2bdc4734e96626d2
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Fresh_2.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Fresh_3.png b/Backend/Fruit_Freshness/Apples/Photos/Fresh_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..ccbc38433ae69896e1aa795b2e56d0b9a7657018
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Fresh_3.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Fresh_4.png b/Backend/Fruit_Freshness/Apples/Photos/Fresh_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..f2fcb1467c5d7a6b9b9e0ea385c2225c8dce9aee
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Fresh_4.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Fresh_5.png b/Backend/Fruit_Freshness/Apples/Photos/Fresh_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..747583a96394428ade2105bbe9c623d1f3b9403c
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Fresh_5.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Rotten_1.png b/Backend/Fruit_Freshness/Apples/Photos/Rotten_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd179fff58ef1ae7222862756b6a7a0e66b8956f
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Rotten_1.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Rotten_2.png b/Backend/Fruit_Freshness/Apples/Photos/Rotten_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a779971c9cbcc14e84e70ca0e1306607bd05a2c
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Rotten_2.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Rotten_3.png b/Backend/Fruit_Freshness/Apples/Photos/Rotten_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..9fd08da64beeba23067a22f2642ae2d3aeac1edf
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Rotten_3.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Photos/Rotten_4.png b/Backend/Fruit_Freshness/Apples/Photos/Rotten_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d22b9ba50c68a454d87204ade73daa849ee8b2f
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Photos/Rotten_4.png differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8.zip b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8.zip
new file mode 100644
index 0000000000000000000000000000000000000000..16f58591b955761305f4644a11d9e564ae29db90
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8.zip
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5ad993b6a4cda53115519046abf74f9b61cca502ce32a795f97c00e00afaaa50
+size 984758
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/README.dataset.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/README.dataset.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d004fa3d6c2f1143e0402c8a8188d635e157b644
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/README.dataset.txt
@@ -0,0 +1,6 @@
+# Rotten Apple Labeller > Rotten Apples
+https://universe.roboflow.com/shyam-krishna/rotten-apple-labeller
+
+Provided by a Roboflow user
+License: CC BY 4.0
+
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/README.roboflow.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/README.roboflow.txt
new file mode 100644
index 0000000000000000000000000000000000000000..422b7199a4da8a8aa2f7b1f33991a1652cf72ce8
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/README.roboflow.txt
@@ -0,0 +1,32 @@
+
+Rotten Apple Labeller - v1 Rotten Apples
+==============================
+
+This dataset was exported via roboflow.com on March 15, 2023 at 6:50 AM GMT
+
+Roboflow is an end-to-end computer vision platform that helps you
+* collaborate with your team on computer vision projects
+* collect & organize images
+* understand and search unstructured image data
+* annotate, and create datasets
+* export, train, and deploy computer vision models
+* use active learning to improve your dataset over time
+
+For state of the art Computer Vision training notebooks you can use with this dataset,
+visit https://github.com/roboflow/notebooks
+
+To find over 100k other datasets and pre-trained models, visit https://universe.roboflow.com
+
+The dataset includes 62 images.
+Rotten-Apples are annotated in YOLOv8 format.
+
+The following pre-processing was applied to each image:
+* Auto-orientation of pixel data (with EXIF-orientation stripping)
+* Resize to 416x416 (Stretch)
+
+The following augmentation was applied to create 3 versions of each source image:
+* 50% probability of horizontal flip
+* 50% probability of vertical flip
+* Equal probability of one of the following 90-degree rotations: none, clockwise, counter-clockwise, upside-down
+
+
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/data.yaml b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/data.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..532511c65ae9d48d2ded8b1a06af7cbd4b679b8d
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/data.yaml
@@ -0,0 +1,13 @@
+train: ../train/images
+val: ../valid/images
+test: ../test/images
+
+nc: 1
+names: ['Rotten Apple']
+
+roboflow:
+ workspace: shyam-krishna
+ project: rotten-apple-labeller
+ version: 1
+ license: CC BY 4.0
+ url: https://universe.roboflow.com/shyam-krishna/rotten-apple-labeller/dataset/1
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-2-54-49-PM_png.rf.2557a1048acae352cd5420528e467e18.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-2-54-49-PM_png.rf.2557a1048acae352cd5420528e467e18.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8f8b9a52ae461b3890a3ed418045b30de7afd62e
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-2-54-49-PM_png.rf.2557a1048acae352cd5420528e467e18.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-2-57-13-PM_png.rf.e9da17a0710d447581911d0a686a64bb.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-2-57-13-PM_png.rf.e9da17a0710d447581911d0a686a64bb.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e5861a959aa0b24fcf72ee9d893408bb20f50884
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-2-57-13-PM_png.rf.e9da17a0710d447581911d0a686a64bb.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-3-02-24-PM_png.rf.fce9e910b977026e4356db03caaf7835.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-3-02-24-PM_png.rf.fce9e910b977026e4356db03caaf7835.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..5bd58031a56adc0d4b0b492126720fd2cc0cc205
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-3-02-24-PM_png.rf.fce9e910b977026e4356db03caaf7835.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-3-02-51-PM_png.rf.193331860c01427edcafb663e15d5f8c.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-3-02-51-PM_png.rf.193331860c01427edcafb663e15d5f8c.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2c709f71f4e811a83eb29a7a0a2e3c99d472cd54
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/images/Screen-Shot-2018-06-07-at-3-02-51-PM_png.rf.193331860c01427edcafb663e15d5f8c.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-2-54-49-PM_png.rf.2557a1048acae352cd5420528e467e18.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-2-54-49-PM_png.rf.2557a1048acae352cd5420528e467e18.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8e5880eaa45dc2d4cd901a0cdb9f9e6d936957f0
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-2-54-49-PM_png.rf.2557a1048acae352cd5420528e467e18.txt
@@ -0,0 +1 @@
+0 0.4795673076923077 0.5108173076923077 0.7235576923076923 0.7836538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-2-57-13-PM_png.rf.e9da17a0710d447581911d0a686a64bb.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-2-57-13-PM_png.rf.e9da17a0710d447581911d0a686a64bb.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ea7aae8040f533a33f3477db035a52902888f6c6
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-2-57-13-PM_png.rf.e9da17a0710d447581911d0a686a64bb.txt
@@ -0,0 +1 @@
+0 0.5853365384615384 0.5180288461538461 0.7175480769230769 0.7043269230769231
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-3-02-24-PM_png.rf.fce9e910b977026e4356db03caaf7835.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-3-02-24-PM_png.rf.fce9e910b977026e4356db03caaf7835.txt
new file mode 100644
index 0000000000000000000000000000000000000000..45f8992d1c092e774d405f9663a75d94c0cde38f
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-3-02-24-PM_png.rf.fce9e910b977026e4356db03caaf7835.txt
@@ -0,0 +1 @@
+0 0.49759615384615385 0.4723557692307692 0.8028846153846154 0.8509615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-3-02-51-PM_png.rf.193331860c01427edcafb663e15d5f8c.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-3-02-51-PM_png.rf.193331860c01427edcafb663e15d5f8c.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3246ed8a838ef3b1ac5a7819c8acbb268e456b11
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/test/labels/Screen-Shot-2018-06-07-at-3-02-51-PM_png.rf.193331860c01427edcafb663e15d5f8c.txt
@@ -0,0 +1 @@
+0 0.49038461538461536 0.4963942307692308 0.7223557692307693 0.7415865384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.17a1184c9996ed00a4e7f232de6060ea.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.17a1184c9996ed00a4e7f232de6060ea.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ded789504c442e190a5b7475df4d4b056a3cc6bf
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.17a1184c9996ed00a4e7f232de6060ea.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.82f8c8cd7117007c6c219b76568b83a4.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.82f8c8cd7117007c6c219b76568b83a4.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..30389df020e86eba4e24d1d22a1d146a5174516a
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.82f8c8cd7117007c6c219b76568b83a4.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.e324b699b3d1948c6212a7ec533fe981.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.e324b699b3d1948c6212a7ec533fe981.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..2ab34852b582014c919e1dfec0dbdc927ddcace9
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.e324b699b3d1948c6212a7ec533fe981.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.163b037e01da46c3ec715755c291aa95.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.163b037e01da46c3ec715755c291aa95.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..057418799b2f9056a75b7c4075932e4863401d51
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.163b037e01da46c3ec715755c291aa95.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.89f62e24f24e80e8031ce669fb74718e.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.89f62e24f24e80e8031ce669fb74718e.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..cfb08ac5f7001e573ad88133ef6a90a690bf7321
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.89f62e24f24e80e8031ce669fb74718e.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.bb9cacf69bb23894866f1982caea0ccf.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.bb9cacf69bb23894866f1982caea0ccf.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3c92e398baad605d7063d3d2d5b030b25f25fc89
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.bb9cacf69bb23894866f1982caea0ccf.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.5ed4084cc0d8b7812c8cc819480ba10f.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.5ed4084cc0d8b7812c8cc819480ba10f.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..aec2056f751989f9f4dadff946600d7bbc91b52a
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.5ed4084cc0d8b7812c8cc819480ba10f.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.ac4d108659b63c81acf73865dc81ee9c.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.ac4d108659b63c81acf73865dc81ee9c.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..cd0565b59630ff3408dfb2ad1238a60d30884404
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.ac4d108659b63c81acf73865dc81ee9c.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.0bab53e4576f3dcdc3eecbad1f2e2a25.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.0bab53e4576f3dcdc3eecbad1f2e2a25.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f7e77e89d71be4c1fc92288505ebdd9a34a06a99
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.0bab53e4576f3dcdc3eecbad1f2e2a25.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.10803b835c52cbd24433f1a0515668e4.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.10803b835c52cbd24433f1a0515668e4.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c184a3044a30f17c39948fc063b910274cb6bffb
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.10803b835c52cbd24433f1a0515668e4.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.bd3f4db76c39859bc11bcf30418b654e.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.bd3f4db76c39859bc11bcf30418b654e.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4c4d185466361a02b46e90298d891f641e51d827
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.bd3f4db76c39859bc11bcf30418b654e.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.40e834e8eb8867403264b94970229392.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.40e834e8eb8867403264b94970229392.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..ceea3adbfc5953801a3c714a897d3b4fc7c3cf76
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.40e834e8eb8867403264b94970229392.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.449428299a5d3574754e53017cb74a08.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.449428299a5d3574754e53017cb74a08.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a166e609774b7dc55fe2c0d9dba0a9379633f390
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.449428299a5d3574754e53017cb74a08.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.dcf06ba791b8c9e2ed6a5deaecff39b9.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.dcf06ba791b8c9e2ed6a5deaecff39b9.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..6b31126c09d1847b13c617ffbd969f6672ab5050
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.dcf06ba791b8c9e2ed6a5deaecff39b9.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.227c73b163d364d8da4dc460d373e21a.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.227c73b163d364d8da4dc460d373e21a.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..734aed88ddb40e2e870caca92ba3756b1ece8de6
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.227c73b163d364d8da4dc460d373e21a.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.83e9e5ac4fcaee7b11b3a535c0c1d2ef.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.83e9e5ac4fcaee7b11b3a535c0c1d2ef.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4b7bfd8bba633d165c9bb516e1b533e3de74cbba
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.83e9e5ac4fcaee7b11b3a535c0c1d2ef.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.970a7fa1fa583318b57baa9255ef021d.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.970a7fa1fa583318b57baa9255ef021d.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..57ccedeb69e230a19574b787d3f603d7538eb0c3
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.970a7fa1fa583318b57baa9255ef021d.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.51d0712871be1b778ac39dbe8d10392b.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.51d0712871be1b778ac39dbe8d10392b.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..a3e7292ce9439905a96cf0294b967fba3a71d408
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.51d0712871be1b778ac39dbe8d10392b.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.ddd660cf6503243277404540b277a30f.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.ddd660cf6503243277404540b277a30f.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..368db78eca34d1fed9f6f2c4ae2fe661e71488a5
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.ddd660cf6503243277404540b277a30f.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.f891d92a399c50347fff17b9721486e1.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.f891d92a399c50347fff17b9721486e1.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..76eabfcdd2053d1f55ee87a4a50d09626d3c5d9e
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.f891d92a399c50347fff17b9721486e1.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.5ae2dbffe4997cd0502a4604f79b5a4a.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.5ae2dbffe4997cd0502a4604f79b5a4a.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..b9e069bef83ae225941b3173064d029b18102455
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.5ae2dbffe4997cd0502a4604f79b5a4a.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.8cf78686362e2f91096c65afa93974cf.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.8cf78686362e2f91096c65afa93974cf.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..035012cda785e32e93beaae304d61ddb452aee52
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.8cf78686362e2f91096c65afa93974cf.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.dbb43335e14c7a61d9719fc63e744a46.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.dbb43335e14c7a61d9719fc63e744a46.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3b1ccde3f8ac72efa8ebb679668a0806f9ebf8e5
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.dbb43335e14c7a61d9719fc63e744a46.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.7f27375200a5f1f25f11cfc2dadaa1cc.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.7f27375200a5f1f25f11cfc2dadaa1cc.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..47bd2d8c8711f9eea164193f88ea0fa685e671ca
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.7f27375200a5f1f25f11cfc2dadaa1cc.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.a4416d86ea25aad74339a40630da321e.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.a4416d86ea25aad74339a40630da321e.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9b8cba00255350823d154bb16eb827d63d579838
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.a4416d86ea25aad74339a40630da321e.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.ee4f683c43a86075893bd1a38a4ee82e.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.ee4f683c43a86075893bd1a38a4ee82e.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1548f1355afcded3e7a7b592954c78fe326b7c5e
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.ee4f683c43a86075893bd1a38a4ee82e.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.5a1e0269ef4ab171fffbdb6f85c091d6.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.5a1e0269ef4ab171fffbdb6f85c091d6.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..bf39b50a0a782d17f6e1003dc2defeda36380907
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.5a1e0269ef4ab171fffbdb6f85c091d6.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.856a01e58177add7b60c377d71715dea.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.856a01e58177add7b60c377d71715dea.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..95d62d412be46f101f338503527f6f2260d3576c
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.856a01e58177add7b60c377d71715dea.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.9c32fca973f4486a6a128b912090c415.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.9c32fca973f4486a6a128b912090c415.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c95bacf48672c58c30f8224739adba1aac529067
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.9c32fca973f4486a6a128b912090c415.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.5304966e11ca83a1d1c1f3dd835709fe.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.5304966e11ca83a1d1c1f3dd835709fe.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..129c55f86257d6932c97b2500f5e8a2fce36f9aa
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.5304966e11ca83a1d1c1f3dd835709fe.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.da45775370d67e67b9f23f5d18eb30d9.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.da45775370d67e67b9f23f5d18eb30d9.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..516f6bb926638417717f0aeb2514b5e1cad40d3d
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.da45775370d67e67b9f23f5d18eb30d9.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.ed7f8a7c657232656d7579bf23b17f76.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.ed7f8a7c657232656d7579bf23b17f76.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..e9ea627e325eadabc2b07226c21d5709be712fd7
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.ed7f8a7c657232656d7579bf23b17f76.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.2440f7bd0b126225c68b9ee141215faf.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.2440f7bd0b126225c68b9ee141215faf.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..c478c1ed78c0edb71dc4297428e09b3857a9d53b
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.2440f7bd0b126225c68b9ee141215faf.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.bc3ab24c3622f024dc5c7e126ea8f582.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.bc3ab24c3622f024dc5c7e126ea8f582.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..844a37fca5848ef6667845662e8d35dfd0c48253
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.bc3ab24c3622f024dc5c7e126ea8f582.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.faaded75fbe8d465fb16ccd3115f5ed4.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.faaded75fbe8d465fb16ccd3115f5ed4.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4d9966e3a7d77d909de9d41785197f92ec648c5c
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.faaded75fbe8d465fb16ccd3115f5ed4.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.11d342fc6aa70928f9432bafd7769553.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.11d342fc6aa70928f9432bafd7769553.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..43f18945f20c4230c42f101f87839bb8f9d1e654
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.11d342fc6aa70928f9432bafd7769553.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.453049958d98a93802727642dc9a6cf9.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.453049958d98a93802727642dc9a6cf9.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..1413ecf99a215cde6d05f944e6480e91e582824e
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.453049958d98a93802727642dc9a6cf9.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.ba72972514ea5be3d6d146e0871d81dc.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.ba72972514ea5be3d6d146e0871d81dc.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..971ecfc82753c22b119f0b9b484e8892ece811d3
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.ba72972514ea5be3d6d146e0871d81dc.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-33-PM_png.rf.78d5ab252bf99ac64f7987a7f1dfd4a6.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-33-PM_png.rf.78d5ab252bf99ac64f7987a7f1dfd4a6.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..7b4c4e5adee321b1b23bb186974e040791e3b8cb
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-33-PM_png.rf.78d5ab252bf99ac64f7987a7f1dfd4a6.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.290ef6fc3ca73d93ddc2ba2ecb00e611.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.290ef6fc3ca73d93ddc2ba2ecb00e611.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..4f088e3813b175937008662221db932294337b18
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.290ef6fc3ca73d93ddc2ba2ecb00e611.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ccf881e5d3a765d463a57465bc5bbde2.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ccf881e5d3a765d463a57465bc5bbde2.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..8fe82b84ae1534f3202d02ee25ebdf62cf2037d1
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ccf881e5d3a765d463a57465bc5bbde2.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ec94dfbaa5708eeb0185fc325b999b9c.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ec94dfbaa5708eeb0185fc325b999b9c.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..3180b18426a3c0c670edb5fc61683b2ad417949a
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ec94dfbaa5708eeb0185fc325b999b9c.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.095db36d944f2b2c293c5bccc0e7fd4d.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.095db36d944f2b2c293c5bccc0e7fd4d.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..96c7f1f982a1442a9ccf56d947fdb1f91e1c84e2
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.095db36d944f2b2c293c5bccc0e7fd4d.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.0f5f321b3a7b6f0c40f913e421f0adb0.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.0f5f321b3a7b6f0c40f913e421f0adb0.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..56f16e7ac69c25a7a491025e1e16313eec12696c
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.0f5f321b3a7b6f0c40f913e421f0adb0.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.274dffe00b4690ce3724bf038918f304.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.274dffe00b4690ce3724bf038918f304.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..bb0d084cfb62d32ff21d12fbe28a3e1f53c51bd9
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.274dffe00b4690ce3724bf038918f304.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.42a0359b7b0fbc5f093fb73024fbe40c.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.42a0359b7b0fbc5f093fb73024fbe40c.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9bd4c590d138d65227ada2da2ce2717464f19973
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.42a0359b7b0fbc5f093fb73024fbe40c.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.af1b331cf0209c46f300dde9988edf17.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.af1b331cf0209c46f300dde9988edf17.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..23969d40b9d7b13e03d1007e795ed7d4472414ff
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.af1b331cf0209c46f300dde9988edf17.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.fa0b0d250e2f3b04bed7141927e27b4a.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.fa0b0d250e2f3b04bed7141927e27b4a.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f744408c31fa12f3bbc083b42f39d7daeeb76236
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.fa0b0d250e2f3b04bed7141927e27b4a.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.12e1b5b2f4c245de56993db7f6288fa4.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.12e1b5b2f4c245de56993db7f6288fa4.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..9cd955cf5fcb61eca8a0a4e14b6a7020c4b8321e
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.12e1b5b2f4c245de56993db7f6288fa4.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.67937efbd8246216d9fac52503bc39d3.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.67937efbd8246216d9fac52503bc39d3.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f2b0f216d959b11b6d68ecffa7e135549cde8254
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.67937efbd8246216d9fac52503bc39d3.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.749b317509283779beb2d5085eef8633.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.749b317509283779beb2d5085eef8633.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..149d9bb9ad02d3a5364fea7de75938375279afc3
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.749b317509283779beb2d5085eef8633.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.deabd394932e8757803d1f57ac2d78e6.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.deabd394932e8757803d1f57ac2d78e6.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..6e4445f5d87a2596382186e2994a23e2b55a7ed7
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.deabd394932e8757803d1f57ac2d78e6.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.f6db48668ca0ecd5b5593a71ca18ace7.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.f6db48668ca0ecd5b5593a71ca18ace7.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..45a72efaf9ce069708f49c9ed46e7ce97c41cc45
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/images/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.f6db48668ca0ecd5b5593a71ca18ace7.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.17a1184c9996ed00a4e7f232de6060ea.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.17a1184c9996ed00a4e7f232de6060ea.txt
new file mode 100644
index 0000000000000000000000000000000000000000..04e16f9898be98dc4a485d5d92e5c2c88450a643
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.17a1184c9996ed00a4e7f232de6060ea.txt
@@ -0,0 +1 @@
+0 0.5420673076923077 0.4639423076923077 0.8317307692307693 0.8461538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.82f8c8cd7117007c6c219b76568b83a4.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.82f8c8cd7117007c6c219b76568b83a4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..04e16f9898be98dc4a485d5d92e5c2c88450a643
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.82f8c8cd7117007c6c219b76568b83a4.txt
@@ -0,0 +1 @@
+0 0.5420673076923077 0.4639423076923077 0.8317307692307693 0.8461538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.e324b699b3d1948c6212a7ec533fe981.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.e324b699b3d1948c6212a7ec533fe981.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7e549609d1028667ccd925598e57cc61d90f7089
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-20-PM_png.rf.e324b699b3d1948c6212a7ec533fe981.txt
@@ -0,0 +1 @@
+0 0.5420673076923077 0.5360576923076923 0.8317307692307693 0.8461538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.163b037e01da46c3ec715755c291aa95.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.163b037e01da46c3ec715755c291aa95.txt
new file mode 100644
index 0000000000000000000000000000000000000000..15ba9679ba1a0e8922d3e9c8c9591910d06b1776
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.163b037e01da46c3ec715755c291aa95.txt
@@ -0,0 +1 @@
+0 0.5276442307692307 0.4891826923076923 0.9086538461538461 0.7692307692307693
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.89f62e24f24e80e8031ce669fb74718e.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.89f62e24f24e80e8031ce669fb74718e.txt
new file mode 100644
index 0000000000000000000000000000000000000000..941f8c7e6220b6ddb71d2d416e0d92b7c9c1cf92
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.89f62e24f24e80e8031ce669fb74718e.txt
@@ -0,0 +1 @@
+0 0.4723557692307692 0.5108173076923077 0.9086538461538461 0.7692307692307693
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.bb9cacf69bb23894866f1982caea0ccf.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.bb9cacf69bb23894866f1982caea0ccf.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2c5886842d051e60fe3872b35ce69e35db270fab
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-53-33-PM_png.rf.bb9cacf69bb23894866f1982caea0ccf.txt
@@ -0,0 +1 @@
+0 0.4891826923076923 0.4723557692307692 0.7692307692307693 0.9086538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.5ed4084cc0d8b7812c8cc819480ba10f.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.5ed4084cc0d8b7812c8cc819480ba10f.txt
new file mode 100644
index 0000000000000000000000000000000000000000..60317a85314f28e7f8643120a633c5e47d05e727
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.5ed4084cc0d8b7812c8cc819480ba10f.txt
@@ -0,0 +1 @@
+0 0.5576923076923077 0.5432692307692307 0.78125 0.7211538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.ac4d108659b63c81acf73865dc81ee9c.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.ac4d108659b63c81acf73865dc81ee9c.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b8b508650680200b3f5a79d182edea0c479358e1
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-08-PM_png.rf.ac4d108659b63c81acf73865dc81ee9c.txt
@@ -0,0 +1 @@
+0 0.5432692307692307 0.4423076923076923 0.7211538461538461 0.78125
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.0bab53e4576f3dcdc3eecbad1f2e2a25.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.0bab53e4576f3dcdc3eecbad1f2e2a25.txt
new file mode 100644
index 0000000000000000000000000000000000000000..990c45bc6b2cf8dec3434f8a323f261c4b2c8957
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.0bab53e4576f3dcdc3eecbad1f2e2a25.txt
@@ -0,0 +1 @@
+0 0.39903846153846156 0.5384615384615384 0.6418269230769231 0.7740384615384616
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.10803b835c52cbd24433f1a0515668e4.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.10803b835c52cbd24433f1a0515668e4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..09cf87959e87e428db9363897a698d64e26628a6
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.10803b835c52cbd24433f1a0515668e4.txt
@@ -0,0 +1 @@
+0 0.6009615384615384 0.5384615384615384 0.6418269230769231 0.7740384615384616
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.bd3f4db76c39859bc11bcf30418b654e.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.bd3f4db76c39859bc11bcf30418b654e.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c6e7af2fb065a9847f7554f9fcbad032c4184851
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-54-58-PM_png.rf.bd3f4db76c39859bc11bcf30418b654e.txt
@@ -0,0 +1 @@
+0 0.39903846153846156 0.46153846153846156 0.6418269230769231 0.7740384615384616
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.40e834e8eb8867403264b94970229392.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.40e834e8eb8867403264b94970229392.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a7b819100e49690308a70b2d1ca70cda24eab32b
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.40e834e8eb8867403264b94970229392.txt
@@ -0,0 +1 @@
+0 0.5024038461538461 0.5012019230769231 0.8533653846153846 0.8509615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.449428299a5d3574754e53017cb74a08.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.449428299a5d3574754e53017cb74a08.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e7dec3ea633f8674b658da3d012f34f4750c2152
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.449428299a5d3574754e53017cb74a08.txt
@@ -0,0 +1 @@
+0 0.5012019230769231 0.5024038461538461 0.8509615384615384 0.8533653846153846
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.dcf06ba791b8c9e2ed6a5deaecff39b9.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.dcf06ba791b8c9e2ed6a5deaecff39b9.txt
new file mode 100644
index 0000000000000000000000000000000000000000..a7b819100e49690308a70b2d1ca70cda24eab32b
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-55-27-PM_png.rf.dcf06ba791b8c9e2ed6a5deaecff39b9.txt
@@ -0,0 +1 @@
+0 0.5024038461538461 0.5012019230769231 0.8533653846153846 0.8509615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.227c73b163d364d8da4dc460d373e21a.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.227c73b163d364d8da4dc460d373e21a.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e8963e84970e50123ffd159bd0571b475c9ba67d
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.227c73b163d364d8da4dc460d373e21a.txt
@@ -0,0 +1 @@
+0 0.4891826923076923 0.45552884615384615 0.6394230769230769 0.7259615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.83e9e5ac4fcaee7b11b3a535c0c1d2ef.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.83e9e5ac4fcaee7b11b3a535c0c1d2ef.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e8963e84970e50123ffd159bd0571b475c9ba67d
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.83e9e5ac4fcaee7b11b3a535c0c1d2ef.txt
@@ -0,0 +1 @@
+0 0.4891826923076923 0.45552884615384615 0.6394230769230769 0.7259615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.970a7fa1fa583318b57baa9255ef021d.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.970a7fa1fa583318b57baa9255ef021d.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ac927ba5709f277d00a58455312f14aa8cc2e45c
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-56-57-PM_png.rf.970a7fa1fa583318b57baa9255ef021d.txt
@@ -0,0 +1 @@
+0 0.45552884615384615 0.4891826923076923 0.7259615384615384 0.6394230769230769
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.51d0712871be1b778ac39dbe8d10392b.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.51d0712871be1b778ac39dbe8d10392b.txt
new file mode 100644
index 0000000000000000000000000000000000000000..96d77e75df2967dc5ca2dff96613b2cf88bd04b2
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.51d0712871be1b778ac39dbe8d10392b.txt
@@ -0,0 +1 @@
+0 0.5300480769230769 0.5144230769230769 0.6899038461538461 0.6706730769230769
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.ddd660cf6503243277404540b277a30f.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.ddd660cf6503243277404540b277a30f.txt
new file mode 100644
index 0000000000000000000000000000000000000000..db7749ac6310dd16d6d6b30f30e4d72475b07b84
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.ddd660cf6503243277404540b277a30f.txt
@@ -0,0 +1 @@
+0 0.4699519230769231 0.5144230769230769 0.6899038461538461 0.6706730769230769
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.f891d92a399c50347fff17b9721486e1.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.f891d92a399c50347fff17b9721486e1.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c1bdd5de029e1fc1161bf0f417ae8aeda09bf044
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-05-PM_png.rf.f891d92a399c50347fff17b9721486e1.txt
@@ -0,0 +1 @@
+0 0.5144230769230769 0.4699519230769231 0.6706730769230769 0.6899038461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.5ae2dbffe4997cd0502a4604f79b5a4a.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.5ae2dbffe4997cd0502a4604f79b5a4a.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4b964056086271dac357ced4e58855b14ef51c02
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.5ae2dbffe4997cd0502a4604f79b5a4a.txt
@@ -0,0 +1 @@
+0 0.49158653846153844 0.5336538461538461 0.9086538461538461 0.8076923076923077
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.8cf78686362e2f91096c65afa93974cf.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.8cf78686362e2f91096c65afa93974cf.txt
new file mode 100644
index 0000000000000000000000000000000000000000..7df6aaea8c97fb7f68ba0af83c181b937de0a7ac
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.8cf78686362e2f91096c65afa93974cf.txt
@@ -0,0 +1 @@
+0 0.5336538461538461 0.5084134615384616 0.8076923076923077 0.9086538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.dbb43335e14c7a61d9719fc63e744a46.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.dbb43335e14c7a61d9719fc63e744a46.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6ceb39549a8ef360f76d2227496de59c841b1eb0
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-26-PM_png.rf.dbb43335e14c7a61d9719fc63e744a46.txt
@@ -0,0 +1 @@
+0 0.49158653846153844 0.46634615384615385 0.9086538461538461 0.8076923076923077
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.7f27375200a5f1f25f11cfc2dadaa1cc.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.7f27375200a5f1f25f11cfc2dadaa1cc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..9f9e7520d63c8444c1cd9fcaf021248672b68d30
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.7f27375200a5f1f25f11cfc2dadaa1cc.txt
@@ -0,0 +1 @@
+0 0.48677884615384615 0.4831730769230769 0.7836538461538461 0.7860576923076923
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.a4416d86ea25aad74339a40630da321e.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.a4416d86ea25aad74339a40630da321e.txt
new file mode 100644
index 0000000000000000000000000000000000000000..19c51316e2fa5344ed071e5ed6c451587d2c2c34
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.a4416d86ea25aad74339a40630da321e.txt
@@ -0,0 +1 @@
+0 0.4831730769230769 0.5132211538461539 0.7860576923076923 0.7836538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.ee4f683c43a86075893bd1a38a4ee82e.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.ee4f683c43a86075893bd1a38a4ee82e.txt
new file mode 100644
index 0000000000000000000000000000000000000000..51e304cd247a9e23c82dc405780c1821234c3ca5
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-42-PM_png.rf.ee4f683c43a86075893bd1a38a4ee82e.txt
@@ -0,0 +1 @@
+0 0.5132211538461539 0.4831730769230769 0.7836538461538461 0.7860576923076923
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.5a1e0269ef4ab171fffbdb6f85c091d6.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.5a1e0269ef4ab171fffbdb6f85c091d6.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5c2003717f586169d356d22b25ef623a2c0cc0ec
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.5a1e0269ef4ab171fffbdb6f85c091d6.txt
@@ -0,0 +1 @@
+0 0.44471153846153844 0.43028846153846156 0.6706730769230769 0.5985576923076923
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.856a01e58177add7b60c377d71715dea.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.856a01e58177add7b60c377d71715dea.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1c83f3e7810dc2fa519ed5885a01e5c1ee2b646a
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.856a01e58177add7b60c377d71715dea.txt
@@ -0,0 +1 @@
+0 0.43028846153846156 0.5552884615384616 0.5985576923076923 0.6706730769230769
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.9c32fca973f4486a6a128b912090c415.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.9c32fca973f4486a6a128b912090c415.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fc9e85fc334032ba6df1e64b6fd56fcfce6abad2
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-57-49-PM_png.rf.9c32fca973f4486a6a128b912090c415.txt
@@ -0,0 +1 @@
+0 0.43028846153846156 0.44471153846153844 0.5985576923076923 0.6706730769230769
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.5304966e11ca83a1d1c1f3dd835709fe.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.5304966e11ca83a1d1c1f3dd835709fe.txt
new file mode 100644
index 0000000000000000000000000000000000000000..32ef3cfd9d8ec820d0f81c4dc507485dc4a43158
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.5304966e11ca83a1d1c1f3dd835709fe.txt
@@ -0,0 +1 @@
+0 0.4879807692307692 0.4795673076923077 0.8245192307692307 0.8028846153846154
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.da45775370d67e67b9f23f5d18eb30d9.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.da45775370d67e67b9f23f5d18eb30d9.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d2d424c496ffa227b1b389276ae56fc260c4ef8d
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.da45775370d67e67b9f23f5d18eb30d9.txt
@@ -0,0 +1 @@
+0 0.5204326923076923 0.4879807692307692 0.8028846153846154 0.8245192307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.ed7f8a7c657232656d7579bf23b17f76.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.ed7f8a7c657232656d7579bf23b17f76.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ee5b3868107d8222b178e1a01c7da87a8c7b67bf
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-38-PM_png.rf.ed7f8a7c657232656d7579bf23b17f76.txt
@@ -0,0 +1 @@
+0 0.5204326923076923 0.5120192307692307 0.8028846153846154 0.8245192307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.2440f7bd0b126225c68b9ee141215faf.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.2440f7bd0b126225c68b9ee141215faf.txt
new file mode 100644
index 0000000000000000000000000000000000000000..96925f9efbfb1557685073e4b5ed15d0321a898a
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.2440f7bd0b126225c68b9ee141215faf.txt
@@ -0,0 +1 @@
+0 0.47115384615384615 0.5024038461538461 0.8701923076923077 0.9134615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.bc3ab24c3622f024dc5c7e126ea8f582.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.bc3ab24c3622f024dc5c7e126ea8f582.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6847a2db45fc82ea995da67d61dd8fc316009635
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.bc3ab24c3622f024dc5c7e126ea8f582.txt
@@ -0,0 +1 @@
+0 0.47115384615384615 0.49759615384615385 0.8701923076923077 0.9134615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.faaded75fbe8d465fb16ccd3115f5ed4.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.faaded75fbe8d465fb16ccd3115f5ed4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..08e29d9d5d04a59b1046930e9c518589fc64a41f
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-2-59-52-PM_png.rf.faaded75fbe8d465fb16ccd3115f5ed4.txt
@@ -0,0 +1 @@
+0 0.49759615384615385 0.5288461538461539 0.9134615384615384 0.8701923076923077
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.11d342fc6aa70928f9432bafd7769553.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.11d342fc6aa70928f9432bafd7769553.txt
new file mode 100644
index 0000000000000000000000000000000000000000..32f93d46d47da617133278b641c3f44b7c7b2a89
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.11d342fc6aa70928f9432bafd7769553.txt
@@ -0,0 +1 @@
+0 0.4639423076923077 0.5216346153846154 0.875 0.7884615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.453049958d98a93802727642dc9a6cf9.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.453049958d98a93802727642dc9a6cf9.txt
new file mode 100644
index 0000000000000000000000000000000000000000..71d0584cb806158f78316640f28a5fa388afa8c8
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.453049958d98a93802727642dc9a6cf9.txt
@@ -0,0 +1 @@
+0 0.5216346153846154 0.5360576923076923 0.7884615384615384 0.875
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.ba72972514ea5be3d6d146e0871d81dc.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.ba72972514ea5be3d6d146e0871d81dc.txt
new file mode 100644
index 0000000000000000000000000000000000000000..64d54f85b2dee57413a553ac54ba393e38b77213
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-00-PM_png.rf.ba72972514ea5be3d6d146e0871d81dc.txt
@@ -0,0 +1 @@
+0 0.5360576923076923 0.47836538461538464 0.875 0.7884615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-33-PM_png.rf.78d5ab252bf99ac64f7987a7f1dfd4a6.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-33-PM_png.rf.78d5ab252bf99ac64f7987a7f1dfd4a6.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b652d4ac8647ce0f06078b2eb7fe58c6e9295df4
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-33-PM_png.rf.78d5ab252bf99ac64f7987a7f1dfd4a6.txt
@@ -0,0 +1 @@
+0 0.5240384615384616 0.5180288461538461 0.8870192307692307 0.7764423076923077
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.290ef6fc3ca73d93ddc2ba2ecb00e611.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.290ef6fc3ca73d93ddc2ba2ecb00e611.txt
new file mode 100644
index 0000000000000000000000000000000000000000..48b4d27ec40ca100087e67bf8030dd97d51db5c9
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.290ef6fc3ca73d93ddc2ba2ecb00e611.txt
@@ -0,0 +1 @@
+0 0.47836538461538464 0.4987980769230769 0.8557692307692307 0.7932692307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ccf881e5d3a765d463a57465bc5bbde2.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ccf881e5d3a765d463a57465bc5bbde2.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f4689a8fc7059803b055cec0cec74119cb9dd5b0
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ccf881e5d3a765d463a57465bc5bbde2.txt
@@ -0,0 +1 @@
+0 0.5012019230769231 0.47836538461538464 0.7932692307692307 0.8557692307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ec94dfbaa5708eeb0185fc325b999b9c.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ec94dfbaa5708eeb0185fc325b999b9c.txt
new file mode 100644
index 0000000000000000000000000000000000000000..322be8c8671ebef247dc0c11904c85014456e2d2
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-40-PM_png.rf.ec94dfbaa5708eeb0185fc325b999b9c.txt
@@ -0,0 +1 @@
+0 0.5216346153846154 0.4987980769230769 0.8557692307692307 0.7932692307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.095db36d944f2b2c293c5bccc0e7fd4d.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.095db36d944f2b2c293c5bccc0e7fd4d.txt
new file mode 100644
index 0000000000000000000000000000000000000000..da3478d75fa63b47d2390fc0c80fbc5bbd1cd6f7
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.095db36d944f2b2c293c5bccc0e7fd4d.txt
@@ -0,0 +1 @@
+0 0.47475961538461536 0.5300480769230769 0.8125 0.8173076923076923
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.0f5f321b3a7b6f0c40f913e421f0adb0.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.0f5f321b3a7b6f0c40f913e421f0adb0.txt
new file mode 100644
index 0000000000000000000000000000000000000000..ff3b9c59d26ce261230d7a14e2d67f33d8cee113
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.0f5f321b3a7b6f0c40f913e421f0adb0.txt
@@ -0,0 +1 @@
+0 0.5300480769230769 0.5252403846153846 0.8173076923076923 0.8125
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.274dffe00b4690ce3724bf038918f304.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.274dffe00b4690ce3724bf038918f304.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c75b0e9e671788900875b9e124f7f14b51f1c4a3
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-00-46-PM_png.rf.274dffe00b4690ce3724bf038918f304.txt
@@ -0,0 +1 @@
+0 0.4699519230769231 0.5252403846153846 0.8173076923076923 0.8125
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.42a0359b7b0fbc5f093fb73024fbe40c.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.42a0359b7b0fbc5f093fb73024fbe40c.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5703b8d220d1812adf800bd4069f8c35d2b2e9f9
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.42a0359b7b0fbc5f093fb73024fbe40c.txt
@@ -0,0 +1 @@
+0 0.5096153846153846 0.5180288461538461 0.875 0.8245192307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.af1b331cf0209c46f300dde9988edf17.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.af1b331cf0209c46f300dde9988edf17.txt
new file mode 100644
index 0000000000000000000000000000000000000000..5703b8d220d1812adf800bd4069f8c35d2b2e9f9
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.af1b331cf0209c46f300dde9988edf17.txt
@@ -0,0 +1 @@
+0 0.5096153846153846 0.5180288461538461 0.875 0.8245192307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.fa0b0d250e2f3b04bed7141927e27b4a.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.fa0b0d250e2f3b04bed7141927e27b4a.txt
new file mode 100644
index 0000000000000000000000000000000000000000..1b408b34cc04587c274ecb1bc84541e99d1e3495
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-01-54-PM_png.rf.fa0b0d250e2f3b04bed7141927e27b4a.txt
@@ -0,0 +1 @@
+0 0.5096153846153846 0.48197115384615385 0.875 0.8245192307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.12e1b5b2f4c245de56993db7f6288fa4.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.12e1b5b2f4c245de56993db7f6288fa4.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2b37ad27db4d07bae7f514dd9be4a4296bb3705f
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.12e1b5b2f4c245de56993db7f6288fa4.txt
@@ -0,0 +1 @@
+0 0.4951923076923077 0.5108173076923077 0.9134615384615384 0.8173076923076923
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.67937efbd8246216d9fac52503bc39d3.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.67937efbd8246216d9fac52503bc39d3.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e5151b3b1a83b0a390b43f3ec7fcf7f6cc383e9d
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-02-09-PM_png.rf.67937efbd8246216d9fac52503bc39d3.txt
@@ -0,0 +1 @@
+0 0.5048076923076923 0.5108173076923077 0.9134615384615384 0.8173076923076923
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.749b317509283779beb2d5085eef8633.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.749b317509283779beb2d5085eef8633.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c2c7130ea00d963ccf068eace3ba55e87f4103e6
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.749b317509283779beb2d5085eef8633.txt
@@ -0,0 +1 @@
+0 0.49278846153846156 0.48677884615384615 0.7884615384615384 0.7836538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.deabd394932e8757803d1f57ac2d78e6.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.deabd394932e8757803d1f57ac2d78e6.txt
new file mode 100644
index 0000000000000000000000000000000000000000..cb612b3a9e79793f108204da4f576a08af56fa7b
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.deabd394932e8757803d1f57ac2d78e6.txt
@@ -0,0 +1 @@
+0 0.48677884615384615 0.49278846153846156 0.7836538461538461 0.7884615384615384
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.f6db48668ca0ecd5b5593a71ca18ace7.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.f6db48668ca0ecd5b5593a71ca18ace7.txt
new file mode 100644
index 0000000000000000000000000000000000000000..19c01e6a87d4ca0c69123ec1caa02b41e4ab9183
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/train/labels/Screen-Shot-2018-06-07-at-3-03-12-PM_png.rf.f6db48668ca0ecd5b5593a71ca18ace7.txt
@@ -0,0 +1 @@
+0 0.5072115384615384 0.48677884615384615 0.7884615384615384 0.7836538461538461
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-2-55-52-PM_png.rf.9f10c3aa9db7f57919672e9705dc7249.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-2-55-52-PM_png.rf.9f10c3aa9db7f57919672e9705dc7249.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..7cf46f0fd715af01e668521c0ed0668608e5eb71
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-2-55-52-PM_png.rf.9f10c3aa9db7f57919672e9705dc7249.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-2-57-17-PM_png.rf.22c8b64bad0f7560685e089b9643c6b7.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-2-57-17-PM_png.rf.22c8b64bad0f7560685e089b9643c6b7.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..f862c6f956b4425ce7485c7d7cf5b8bba6f59572
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-2-57-17-PM_png.rf.22c8b64bad0f7560685e089b9643c6b7.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-00-17-PM_png.rf.fc8acb3e0f5f9129bcb748fd87e3f8bf.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-00-17-PM_png.rf.fc8acb3e0f5f9129bcb748fd87e3f8bf.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..aff0a4493f8da893e2366926ebeb99eed0f9040b
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-00-17-PM_png.rf.fc8acb3e0f5f9129bcb748fd87e3f8bf.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-02-02-PM_png.rf.297d61f6484098859a807863d1e9b5ab.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-02-02-PM_png.rf.297d61f6484098859a807863d1e9b5ab.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..38059734f2a34911c7ae8f44cdc174664a7111fb
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-02-02-PM_png.rf.297d61f6484098859a807863d1e9b5ab.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-02-18-PM_png.rf.05359c37ec6ed9974dc4fd39cf9e909e.jpg b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-02-18-PM_png.rf.05359c37ec6ed9974dc4fd39cf9e909e.jpg
new file mode 100644
index 0000000000000000000000000000000000000000..44c2a1b04de761c5d609041be26e647463b373ee
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/images/Screen-Shot-2018-06-07-at-3-02-18-PM_png.rf.05359c37ec6ed9974dc4fd39cf9e909e.jpg differ
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-2-55-52-PM_png.rf.9f10c3aa9db7f57919672e9705dc7249.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-2-55-52-PM_png.rf.9f10c3aa9db7f57919672e9705dc7249.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b5cabaf6505bda03af7998ab573e73edd9c845bd
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-2-55-52-PM_png.rf.9f10c3aa9db7f57919672e9705dc7249.txt
@@ -0,0 +1 @@
+0 0.5372596153846154 0.4723557692307692 0.7367788461538461 0.8701923076923077
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-2-57-17-PM_png.rf.22c8b64bad0f7560685e089b9643c6b7.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-2-57-17-PM_png.rf.22c8b64bad0f7560685e089b9643c6b7.txt
new file mode 100644
index 0000000000000000000000000000000000000000..2ad4103b57dd5e9dd22faefb6c82350bfdf00ecc
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-2-57-17-PM_png.rf.22c8b64bad0f7560685e089b9643c6b7.txt
@@ -0,0 +1 @@
+0 0.45913461538461536 0.49038461538461536 0.7331730769230769 0.8653846153846154
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-00-17-PM_png.rf.fc8acb3e0f5f9129bcb748fd87e3f8bf.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-00-17-PM_png.rf.fc8acb3e0f5f9129bcb748fd87e3f8bf.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c963d1fdcd680c5d8510501cabd75f072fbb7829
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-00-17-PM_png.rf.fc8acb3e0f5f9129bcb748fd87e3f8bf.txt
@@ -0,0 +1 @@
+0 0.4831730769230769 0.5036057692307693 0.8293269230769231 0.8377403846153846
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-02-02-PM_png.rf.297d61f6484098859a807863d1e9b5ab.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-02-02-PM_png.rf.297d61f6484098859a807863d1e9b5ab.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8e36a5748cabfc8739d88e73f8e1b89fe79832aa
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-02-02-PM_png.rf.297d61f6484098859a807863d1e9b5ab.txt
@@ -0,0 +1 @@
+0 0.5072115384615384 0.5036057692307693 0.84375 0.8557692307692307
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-02-18-PM_png.rf.05359c37ec6ed9974dc4fd39cf9e909e.txt b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-02-18-PM_png.rf.05359c37ec6ed9974dc4fd39cf9e909e.txt
new file mode 100644
index 0000000000000000000000000000000000000000..0c0462e634f0d44694a40177e51f6640e545c8e1
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/Rotten Apple Labeller.v1-rotten-apples.yolov8/valid/labels/Screen-Shot-2018-06-07-at-3-02-18-PM_png.rf.05359c37ec6ed9974dc4fd39cf9e909e.txt
@@ -0,0 +1 @@
+0 0.515625 0.5060096153846154 0.8064903846153846 0.859375
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/hue.py b/Backend/Fruit_Freshness/Apples/hue.py
new file mode 100644
index 0000000000000000000000000000000000000000..1e75bd243f36f0a80e6f605f6c1dee8695dae4f1
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/hue.py
@@ -0,0 +1,64 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Dec 10 12:38:54 2024
+
+@author: jishu
+"""
+import cv2
+import numpy as np
+import matplotlib.pyplot as plt
+
+def find_orange_yellow_frequency(image):
+
+ if image is None:
+ print("Error: Image not found!")
+ return None
+
+ # Step 2: Convert the image to HSV color space
+ hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
+
+ # Step 3: Extract the Hue channel
+ hue_channel = hsv_image[:, :, 0]
+
+ # Step 4: Calculate the histogram for the Hue channel
+ hist = cv2.calcHist([hue_channel], [0], None, [180], [0, 180])
+
+ # Step 5: Calculate the frequency for orange and yellow hues, excluding red
+ orange_range = range(10, 30) # Hue values for orange
+ yellow_range = range(30, 60) # Hue values for yellow
+
+ # Sum the frequencies for the orange range
+ orange_frequency = sum(hist[hue] for hue in orange_range)
+ yellow_frequency = sum(hist[hue] for hue in yellow_range)
+
+ # Combine frequencies for orange and yellow
+ total_orange_yellow_frequency = orange_frequency + yellow_frequency
+
+ # Normalize the histogram for percentage calculation
+ total_pixels = hue_channel.size
+ orange_percentage = (orange_frequency / total_pixels) * 100
+ yellow_percentage = (yellow_frequency / total_pixels) * 100
+ combined_percentage = (total_orange_yellow_frequency / total_pixels) * 100
+
+ return (orange_percentage, yellow_percentage)
+
+ # print(f"Orange Percentage: {orange_percentage[0]:.2f}%")
+ # print(f"Yellow Percentage: {yellow_percentage[0]:.2f}%")
+ # print(f"Combined Percentage of Orange and Yellow: {combined_percentage[0]:.2f}%")
+
+ # Step 6: Visualize the histogram using matplotlib
+ # plt.figure(figsize=(10, 5))
+ # plt.title("Hue Histogram (Ignoring Red)")
+ # plt.xlabel("Hue Value")
+ # plt.ylabel("Frequency")
+ # plt.plot(hist, color='orange', label='Hue Histogram')
+ # plt.axvspan(10, 30, color='orange', alpha=0.3, label='Orange Range')
+ # plt.axvspan(30, 60, color='yellow', alpha=0.3, label='Yellow Range')
+ # plt.legend()
+ # plt.show()
+
+ # # Step 7: Display the image using OpenCV
+ # cv2.imshow("Original Image", image)
+ # cv2.waitKey(0)
+ # cv2.destroyAllWindows()
+
diff --git a/Backend/Fruit_Freshness/Apples/mask.py b/Backend/Fruit_Freshness/Apples/mask.py
new file mode 100644
index 0000000000000000000000000000000000000000..5b2c2b0a50713e9d87d259a031db403df3798cfe
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/mask.py
@@ -0,0 +1,30 @@
+import cv2
+import numpy as np
+
+def detect_low_pixel_values(image, mask, threshold=50):
+ # Step 1: Apply the mask to the original image (this keeps the fruit area, sets background to black)
+ masked_image = cv2.bitwise_and(image, image, mask=mask)
+
+ # Step 2: Convert the image to grayscale for easier pixel value comparison
+ gray_masked_image = cv2.cvtColor(masked_image, cv2.COLOR_BGR2GRAY)
+
+ # Step 3: Detect low pixel values below the threshold
+ low_pixel_mask = gray_masked_image < threshold # Pixels below threshold will be True
+ high_pixel_mask = gray_masked_image > threshold
+
+ # Step 4: Convert the result back to an image for visualization
+ low_pixel_image = np.zeros_like(image) # Create an empty image to highlight low pixel values
+ low_pixel_image[low_pixel_mask] = [255, 255, 255] # Set low-value pixels to red (for visualization)
+
+
+ dark_pixel_count = np.count_nonzero(low_pixel_mask)/10000 # Number of dark pixels (low pixel values)
+ # print(f"Number of dark pixels: {dark_pixel_count}")
+ high_pixel_count = np.count_nonzero(high_pixel_mask)/1000
+ # print(f"Number of high pixels: {high_pixel_count}")
+ # Step 5: Display the results
+ # cv2.imshow("Original Image with Low Pixel Values", low_pixel_image) # Show the highlighted low pixel values
+ # cv2.imshow("Masked Image", masked_image) # Show the masked image
+ # cv2.waitKey(0) # Wait for a key press to close the images
+ # cv2.destroyAllWindows() # Close all OpenCV windows
+
+ return high_pixel_count # Return the mask of low pixel values
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/run.py b/Backend/Fruit_Freshness/Apples/run.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc64c8470c8849111fe89460906edc6d355210fa
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/run.py
@@ -0,0 +1,120 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Dec 10 17:15:04 2024
+
+@author: jishu
+"""
+
+from Backend.Fruit_Freshness.Apples import shape as sp
+from Backend.Fruit_Freshness.Apples import mask as mk
+from Backend.Fruit_Freshness.Apples import hue as hu
+from Database.mongodb import DatabaseManager
+
+import cv2
+import numpy as np
+
+
+def run(image, stale_flag=False, fresh_flag=False, score=10):
+
+ # Case 1: Fresh Apple
+ case_1 = """
+ Fresh Apple
+ Shelf-Life: 5-7 days (at room temperature)
+ Characteristics: Firm texture, bright and vibrant color, no visible bruises or spots, a sweet and crisp taste.
+ Eatable or not: Definitely eatable.
+ """
+
+ # Case 2: Moderately Stale Apple
+ case_2 = """
+ Moderately Stale Apple
+ Shelf-Life: 8-14 days (room temperature) or 4 weeks (refrigerated)
+ Characteristics : Slightly softer texture, slight discoloration or dull appearance, taste may be slightly sour but still acceptable.
+ Eatable or not: Eatable but should be consumed soon.
+ """
+
+ # Case 3: Rotten Apple
+ case_3 = """
+ Rotten Apple
+ Shelf-Life: Exceeds 14 days (room temperature) or 4 weeks (refrigerated)
+ Characteristics: Mushy texture, dark or blackened spots, foul smell, and signs of mold or fermentation.
+ Eatable or not: Not eatable.
+ """
+
+ # Case 4: Rotten Apple
+ case_4 = """
+ Rotten Apple
+ Shelf-Life: Exceeds 14 days (room temperature) or 4 weeks (refrigerated)
+ Characteristics: Mushy texture even though no blackened spots or fermentation, foul smell.
+ Eatable or not: Not eatable.
+ """
+ # First Check for Colour COncentration
+ orange_percentage, yellow_percentage = hu.find_orange_yellow_frequency(image)
+
+ if not fresh_flag:
+ if yellow_percentage > 50:
+ score = 10
+ fresh_flag = True
+
+
+ if not fresh_flag:
+ if orange_percentage > 10:
+ score = 5
+
+ # Then Check if there are wrinkles on the fruit
+ block_size = (30, 30) # Size of each block
+ densities = sp.calculate_edge_density(image, block_size)
+
+ if not fresh_flag:
+ if densities > 1.2:
+ score = score - 2
+
+ # Assume you already have a mask for the fruit (from previous steps)
+ hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
+ lower_bound = np.array([0, 100, 100]) # Example: Orange-ish fruit
+ upper_bound = np.array([10, 150, 255])
+ binary_mask = cv2.inRange(hsv_image, lower_bound, upper_bound)
+
+ kernel = np.ones((5, 5), np.uint8)
+ refined_mask = cv2.morphologyEx(binary_mask, cv2.MORPH_CLOSE, kernel)
+ refined_mask = cv2.morphologyEx(refined_mask, cv2.MORPH_OPEN, kernel)
+
+ # Detect low pixel values in the fruit area using the mask
+ high_pixel_count = mk.detect_low_pixel_values(image, refined_mask)
+
+ if not fresh_flag:
+ if high_pixel_count > 8:
+ stale_flag = True
+
+
+ if stale_flag:
+ score = 0
+
+ answer = ""
+ db_manager = DatabaseManager()
+
+ if score <=3 and score >= 0:
+ if stale_flag:
+ answer = case_3
+ db_manager.add_freshness_record("Apple", "Exceeds 14 days (room temperature) or 4 weeks (refrigerated)", "Mushy texture, dark or blackened spots, foul smell, and signs of mold or fermentation.", "Not eatable.")
+ else:
+ answer = case_4
+ db_manager.add_freshness_record("Apple", "Exceeds 14 days (room temperature) or 4 weeks (refrigerated)", "Mushy texture even though no blackened spots or fermentation, foul smell.", "Not eatable.")
+
+ elif score >= 4 and score <= 7:
+ answer = case_2
+ db_manager.add_freshness_record("Apple", "8-14 days (room temperature) or 4 weeks (refrigerated)", "Slightly softer texture, slight discoloration or dull appearance, taste may be slightly sour but still acceptable.", "Eatable but should be consumed soon.")
+
+ else:
+ answer = case_1
+ db_manager.add_freshness_record("Apple", "5-7 days (at room temperature)", "Firm texture, bright and vibrant color, no visible bruises or spots, a sweet and crisp taste.", "Definitely eatable.")
+
+ return answer
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Apples/shape.py b/Backend/Fruit_Freshness/Apples/shape.py
new file mode 100644
index 0000000000000000000000000000000000000000..3b4f013893b397d14c61954782149dda51cfb9a8
--- /dev/null
+++ b/Backend/Fruit_Freshness/Apples/shape.py
@@ -0,0 +1,66 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Dec 10 09:15:10 2024
+
+This code calculates the edge density of an image in blocks. It uses Canny edge detection to identify edges and calculates
+the percentage of edge pixels in each block. The results can be used to analyze features such as wrinkles on fruit surfaces.
+
+@author: jishu
+"""
+
+import cv2
+import numpy as np
+
+def calculate_edge_density(image, block_size=(50, 50)):
+ """
+ Calculates edge density in blocks for a given image.
+
+ Parameters:
+ image_path (str): Path to the input image.
+ block_size (tuple): Dimensions of the blocks (height, width).
+
+ Returns:
+ list: Edge densities for each block (in percentage).
+ """
+
+ if image is None:
+ print("Error: Image not found!")
+ return None
+
+ # Step 2: Resize the image for consistent processing
+ resized_image = cv2.resize(image, (512, 512))
+
+ # Step 3: Apply Gaussian Blur to reduce noise
+ blurred = cv2.GaussianBlur(resized_image, (5, 5), 0)
+
+ # Step 4: Perform Canny edge detection
+ edges = cv2.Canny(blurred, threshold1=50, threshold2=100)
+
+ # Step 5: Display the edge-detected image using OpenCV
+ # cv2.imshow("Edge Detection", edges)
+ # cv2.waitKey(0)
+ # cv2.destroyAllWindows()
+
+ # Step 6: Calculate edge density for each block
+ densities = []
+ height, width = edges.shape
+ block_height, block_width = block_size
+
+ # Loop through the image in blocks
+ for y in range(0, height, block_height):
+ for x in range(0, width, block_width):
+ # Define the block region
+ block = edges[y:y+block_height, x:x+block_width]
+
+ # Handle the case where the block goes out of image bounds
+ block = block[:block_height, :block_width]
+
+ # Calculate edge density
+ edge_pixels = np.sum(block == 255) # White pixels in the Canny output
+ total_pixels = block.size
+ density = (edge_pixels / total_pixels) * 100 # Convert to percentage
+ densities.append(density)
+
+ return np.mean(np.array(densities))
+
+
diff --git a/Backend/Fruit_Freshness/Apples/sharp_regions.png b/Backend/Fruit_Freshness/Apples/sharp_regions.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab9652bda19d987675b943691f23d75735721a19
Binary files /dev/null and b/Backend/Fruit_Freshness/Apples/sharp_regions.png differ
diff --git a/Backend/Fruit_Freshness/Banana/Pictures/1.png b/Backend/Fruit_Freshness/Banana/Pictures/1.png
new file mode 100644
index 0000000000000000000000000000000000000000..39fc564041134507e8282e1cdaa53a5a015f2909
Binary files /dev/null and b/Backend/Fruit_Freshness/Banana/Pictures/1.png differ
diff --git a/Backend/Fruit_Freshness/Banana/Pictures/2.png b/Backend/Fruit_Freshness/Banana/Pictures/2.png
new file mode 100644
index 0000000000000000000000000000000000000000..87e019be012795e111a127fd56dadefceb9e712b
Binary files /dev/null and b/Backend/Fruit_Freshness/Banana/Pictures/2.png differ
diff --git a/Backend/Fruit_Freshness/Banana/Pictures/4.png b/Backend/Fruit_Freshness/Banana/Pictures/4.png
new file mode 100644
index 0000000000000000000000000000000000000000..46f1942cb125df5de5d1b576d1583fa3826320e8
Binary files /dev/null and b/Backend/Fruit_Freshness/Banana/Pictures/4.png differ
diff --git a/Backend/Fruit_Freshness/Banana/Pictures/5.png b/Backend/Fruit_Freshness/Banana/Pictures/5.png
new file mode 100644
index 0000000000000000000000000000000000000000..9fd5a54d25b6480b82db7d426f3f929253b0bd2f
Binary files /dev/null and b/Backend/Fruit_Freshness/Banana/Pictures/5.png differ
diff --git a/Backend/Fruit_Freshness/Banana/Pictures/6.png b/Backend/Fruit_Freshness/Banana/Pictures/6.png
new file mode 100644
index 0000000000000000000000000000000000000000..e1a12ac2e9c31150ed841bc62e3bf3b3ab0fa7c8
Binary files /dev/null and b/Backend/Fruit_Freshness/Banana/Pictures/6.png differ
diff --git a/Backend/Fruit_Freshness/Banana/Pictures/7.png b/Backend/Fruit_Freshness/Banana/Pictures/7.png
new file mode 100644
index 0000000000000000000000000000000000000000..0303d8cb90d00541d6f2a8f6a78d145104bead5b
Binary files /dev/null and b/Backend/Fruit_Freshness/Banana/Pictures/7.png differ
diff --git a/Backend/Fruit_Freshness/Banana/Pictures/8.png b/Backend/Fruit_Freshness/Banana/Pictures/8.png
new file mode 100644
index 0000000000000000000000000000000000000000..989df489f30b940620f2eceec6c978030ffae149
Binary files /dev/null and b/Backend/Fruit_Freshness/Banana/Pictures/8.png differ
diff --git a/Backend/Fruit_Freshness/Banana/Pictures/Image_3.png b/Backend/Fruit_Freshness/Banana/Pictures/Image_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..926242dc01f277b4d1087338a6c5cdb2c540f38d
Binary files /dev/null and b/Backend/Fruit_Freshness/Banana/Pictures/Image_3.png differ
diff --git a/Backend/Fruit_Freshness/Banana/hue.py b/Backend/Fruit_Freshness/Banana/hue.py
new file mode 100644
index 0000000000000000000000000000000000000000..07b1d8e02995974a73d85d13a062b0e1edd9cd27
--- /dev/null
+++ b/Backend/Fruit_Freshness/Banana/hue.py
@@ -0,0 +1,40 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Dec 10 19:30:18 2024
+
+@author: jishu
+"""
+
+import cv2
+import numpy as np
+from Backend.Fruit_Freshness.Banana import hue as hu
+from Backend.Fruit_Freshness.Banana import mask as mp
+
+def detect_low_pixel_values(image, mask, threshold=50):
+ # Step 1: Apply the mask to the original image (this keeps the fruit area, sets background to black)
+ masked_image = cv2.bitwise_and(image, image, mask=mask)
+
+ # Step 2: Convert the image to grayscale for easier pixel value comparison
+ gray_masked_image = cv2.cvtColor(masked_image, cv2.COLOR_BGR2GRAY)
+
+ # Step 3: Detect low pixel values below the threshold
+ low_pixel_mask = gray_masked_image < threshold # Pixels below threshold will be True
+ high_pixel_mask = gray_masked_image > threshold
+
+ # Step 4: Convert the result back to an image for visualization
+ low_pixel_image = np.zeros_like(image) # Create an empty image to highlight low pixel values
+ low_pixel_image[low_pixel_mask] = [255, 255, 255] # Set low-value pixels to red (for visualization)
+
+
+ dark_pixel_count = np.count_nonzero(low_pixel_mask)/10000 # Number of dark pixels (low pixel values)
+ # print(f"Number of dark pixels: {dark_pixel_count}")
+ high_pixel_count = np.count_nonzero(high_pixel_mask)/1000
+ # print(f"Number of high pixels: {high_pixel_count}")
+ # Step 5: Display the results
+ # cv2.imshow("Original Image with Low Pixel Values", low_pixel_image) # Show the highlighted low pixel values
+ # cv2.imshow("Masked Image", masked_image) # Show the masked image
+ # cv2.waitKey(0) # Wait for a key press to close the images
+ # cv2.destroyAllWindows() # Close all OpenCV windows
+
+ return high_pixel_count # Return the mask of low pixel values
+
diff --git a/Backend/Fruit_Freshness/Banana/mask.py b/Backend/Fruit_Freshness/Banana/mask.py
new file mode 100644
index 0000000000000000000000000000000000000000..9febc04d1a1d083f48636d76706e6bc24909f801
--- /dev/null
+++ b/Backend/Fruit_Freshness/Banana/mask.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Dec 10 19:06:01 2024
+
+@author: jishu
+"""
+
+import cv2
+import numpy as np
+
+# Function to remove background using GrabCut
+def remove_background_grabcut(image):
+
+ if image is None:
+ print("Error: Image not found!")
+ return None, None
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
+
+ # Define a mask initialized to zero
+ mask = np.zeros(image.shape[:2], np.uint8)
+
+ # Define the background and foreground models (required by GrabCut)
+ bgdModel = np.zeros((1, 65), np.float64)
+ fgdModel = np.zeros((1, 65), np.float64)
+
+ # Define a rectangle around the object (this is an approximation)
+ height, width = image.shape[:2]
+ rect = (10, 10, width - 30, height - 30) # Adjust the rectangle if necessary
+
+ # Apply GrabCut algorithm
+ cv2.grabCut(image, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
+
+ # Modify the mask to separate foreground from background
+ mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
+
+ # Refine the mask to remove noise (shadows, small regions, etc.)
+ kernel = np.ones((5, 5), np.uint8)
+ refined_mask = cv2.morphologyEx(mask2, cv2.MORPH_CLOSE, kernel)
+ refined_mask = cv2.morphologyEx(refined_mask, cv2.MORPH_OPEN, kernel)
+
+ # Apply the refined mask to the image
+ foreground = image * refined_mask[:, :, np.newaxis]
+
+ # Replace the background with white
+ background = np.full_like(image, 255) # Create a white background
+ result = np.where(refined_mask[:, :, np.newaxis] == 1, foreground, background)
+
+ return image, result
+
diff --git a/Backend/Fruit_Freshness/Banana/run.py b/Backend/Fruit_Freshness/Banana/run.py
new file mode 100644
index 0000000000000000000000000000000000000000..666c3c892277b2e4f2b9e3b37a4a5b865d5e5a84
--- /dev/null
+++ b/Backend/Fruit_Freshness/Banana/run.py
@@ -0,0 +1,92 @@
+# -*- coding: utf-8 -*-
+"""
+Created on Tue Dec 10 20:23:56 2024
+
+@author: jishu
+"""
+import cv2
+import numpy as np
+from Backend.Fruit_Freshness.Banana import mask as mp
+from Backend.Fruit_Freshness.Banana import hue as hu
+
+def run(image, score):
+
+ # Case 1: Fresh Banana
+ case_1 = """
+ Fresh Banana
+ Shelf-Life: 2-7 days (at room temperature)
+ Characteristics: Firm texture, bright yellow color with a few small spots, sweet aroma, and no bruises or browning.
+ Eatable or not: Definitely eatable.
+ """
+
+ # Case 2: Moderately Stale Banana
+ case_2 = """
+ Moderately Stale Banana
+ Shelf-Life: 7-10 days (room temperature)
+ Characteristics: Softer texture, increased browning or spotting on the peel, slightly mushy inside, and a more pronounced sweet flavor.
+ Eatable or not: Eatable but may not be as enjoyable; best used in smoothies or baking.
+ """
+
+ # Case 3: Rotten Banana
+ case_3 = """
+ Rotten Banana
+ Shelf-Life: Exceeds 10 days (room temperature)
+ Characteristics: Very soft or mushy texture, dark brown or blackened peel, very strong, fermented smell, and signs of decay.
+ Eatable or not: Not eatable.
+ """
+
+
+ original, image = mp.remove_background_grabcut(image)
+
+ # Assume you already have a mask for the fruit (from previous steps)
+ hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
+ lower_bound_1 = np.array([0, 0, 30]) # Example: Orange-ish fruit
+ upper_bound_1 = np.array([180, 255, 100])
+ binary_mask_1 = cv2.inRange(hsv_image, lower_bound_1, upper_bound_1)
+
+ # Apply morphological operations to refine the mask
+ kernel = np.ones((5, 5), np.uint8)
+ refined_mask_1 = cv2.morphologyEx(binary_mask_1, cv2.MORPH_CLOSE, kernel)
+ refined_mask_1 = cv2.morphologyEx(refined_mask_1, cv2.MORPH_OPEN, kernel)
+
+ # Detect low pixel values in the fruit area using the mask
+ low_pixel_mask_1 = hu.detect_low_pixel_values(image, refined_mask_1)
+ # print("Dark Pixels:", low_pixel_mask_1)
+
+ hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
+ lower_bound_2 = np.array([10, 50, 100]) # Example: Orange-ish fruit
+ upper_bound_2 = np.array([20, 200, 255])
+ binary_mask_2 = cv2.inRange(hsv_image, lower_bound_2, upper_bound_2)
+
+ # Apply morphological operations to refine the mask
+ kernel = np.ones((5, 5), np.uint8)
+ refined_mask_2 = cv2.morphologyEx(binary_mask_2, cv2.MORPH_CLOSE, kernel)
+ refined_mask_2 = cv2.morphologyEx(refined_mask_2, cv2.MORPH_OPEN, kernel)
+
+ # Detect low pixel values in the fruit area using the mask
+ low_pixel_mask_2 = hu.detect_low_pixel_values(image, refined_mask_2)
+ # print("Brown Pixels:", low_pixel_mask_2)
+
+
+ if low_pixel_mask_1 > 13:
+ score = 0
+
+ elif low_pixel_mask_2 > 20:
+ score = 5
+ else:
+ score = 10
+
+
+ answer = ""
+ if score <=3 and score >= 0:
+ answer = case_3
+
+ elif score >= 4 and score <= 7:
+ answer = case_2
+ else:
+ answer = case_1
+
+ return answer
+
+
+
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Freshness_main.py b/Backend/Fruit_Freshness/Freshness_main.py
new file mode 100644
index 0000000000000000000000000000000000000000..8afd16ee18fd05005899a75249ca12800111163e
--- /dev/null
+++ b/Backend/Fruit_Freshness/Freshness_main.py
@@ -0,0 +1,56 @@
+import gradio as gr
+import cv2
+import numpy as np
+from ultralytics import YOLO
+import Backend.Fruit_Freshness.Banana.run as brn
+import Backend.Fruit_Freshness.Apples.run as arn
+
+
+# Define the freshness function
+def freshness(img):
+ # Convert Gradio image (PIL.Image) to OpenCV format
+ img = np.array(img)
+ img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
+
+ # Load the model
+ model = YOLO("Weights/freshness.pt", verbose=False)
+
+ # Run inference
+ results = model(img)
+
+ # Class names mapping
+ class_names = {
+ 0: 'fresh apple', 1: 'fresh banana', 2: 'fresh bell pepper', 3: 'fresh carrot', 4: 'fresh cucumber',
+ 5: 'fresh mango', 6: 'fresh orange', 7: 'fresh potato', 8: 'fresh strawberry', 9: 'fresh tomato',
+ 10: 'rotten apple', 11: 'rotten banana', 12: 'rotten bell pepper', 13: 'rotten carrot', 14: 'rotten cucumber',
+ 15: 'rotten mango', 16: 'rotten orange', 17: 'rotten potato', 18: 'rotten strawberry', 19: 'rotten tomato'
+ }
+
+ output_text = ""
+
+ for i in range(len(results)):
+ # Get detected class and bounding box
+ detected_class = int(results[i].boxes.cls[0])
+ class_name = class_names[detected_class]
+ coordinates = results[i].boxes.xyxy
+
+ # Process each bounding box
+ for j, box in enumerate(coordinates):
+ x1, y1, x2, y2 = map(int, box[:4])
+ crop_img = img[y1:y2, x1:x2]
+
+ if detected_class in {1, 11}: # Banana classes
+ score = 0
+ result = brn.run(crop_img, score)
+ output_text += f"Detected: {class_name}, Banana Freshness: {result}\n"
+
+ elif detected_class in {0, 10}: # Apple classes
+ score = 10
+ fresh_flag = False
+ stale_flag = False
+ result = arn.run(crop_img, stale_flag, fresh_flag, score)
+ output_text += f"Detected: {class_name}, Apple Freshness: {result}\n"
+
+ return output_text
+
+
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/.gitignore b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..84384219f8b521e7dcc12b5df4018b8ef31b6739
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/.gitignore
@@ -0,0 +1,132 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+pip-wheel-metadata/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+.python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# Idea files
+.idea/*
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/LICENSE b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/LICENSE
new file mode 100644
index 0000000000000000000000000000000000000000..04febed0cdbba969ab20c89ccca492234e721c20
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2022 Riccardo Spolaor
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/README.md b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..78056417f70662a61b21e40b44a07144f1d810e7
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/README.md
@@ -0,0 +1,213 @@
+# :apple: 🥝 Fruit Inspection :mag:
+The use of modern *Image Processing* and *Computer Vision* techniques is widely spread in the fruit supply chain as a way of guaranteeing quality and homogeneity of the final product to the end-users, whilst reducing both production costs and times.
+
+The present project, describes the implementation of an intelligent system capable of detecting imperfections and defects in fruits. Each fruit is acquired through a *NIR (Near Infra-Red)* and colour camera with little parallax effect.
+
+
+
+ | NIR example | Colour example |
+ |:---------------------------------------:|:--------------------------------------:|
+ |  |  |
+
+
+
+* For an in-depth description of the problem, read the [assignment](assignment.pdf) document.
+* For an in-depth description of the solution to the problem, read the [report](report.pdf) document.
+* For a visualization of the process to build the systems, see the notebooks:
+ * [First task](src/First%20task.ipynb)
+ * [Second task](src/Second%20task.ipynb)
+ * [Final challenge](src/Final%20challenge.ipynb)
+
+## Description
+The project includes three distinct tasks. In each of them a group of different colour images of fruits, along with their respective NIR version, is presented. The following requirements are expected to be achieved:
+
+* **First Task: Fruit Segmentation and Defect Detection.** Three images of apples are presented. The goal is to segment them from the background and locate imperfections caused by holes on their skin;
+* **Second Task: Russet Detection.** Two images of apples with unwanted reddish-brown parts (referred as russets) are observed. The aim is to identify these areas in the most precise way as possible;
+* **Final Challenge: Kiwi Inspection.** It is required to analyse five images of kiwis in order to locate their defects. Extra effort is required to pre-process them because of a great amount of noisy artefacts in the background of some of the given images.
+
+## Interface
+
+Three main scripts are provided to the user in order to test the defect detection systems.
+
+### Execute first task
+The [execute first task script](src/execute_first_task.py), provides a command line script to execute the task of detecting the defects of a fruit. It firstly masks the fruit, then it looks for the defects. If the task is run in `verbose` mode, the visualization of the defect regions of the fruit is plotted.
+
+The script positional arguments are:
+* `fruit-image-path`: The path of the colour image of the fruit.
+* `fruit-nir-image-path`: The path of the Near Infra-Red image of the fruit.
+* `image-name` (optional): The name of the image.
+
+The following optional non positional arguments are present:
+* `--tweak-factor`, `-tf` (default=0.3): Tweak factor for obtaining the binary mask.
+* `--sigma`, `-s` (default=1): Sigma to apply to the Gaussian Blur operation before Canny's algorithm.
+* `--threshold-1`, `-t1` (default=60): First threshold that is used in Canny's algorithm hysteresis process.
+* `--threshold-2`, `-t2` (default=120): Second threshold that is used in Canny's algorithm hysteresis process.
+* `--no-verbose`, `-nv` (default=False); Skip the visualization of the results.
+
+It returns:
+* Number of defect regions found in the fruit
+* Array of statistics about each defect region:
+ - The leftmost (x) coordinate which is the inclusive start of the bounding box in the horizontal direction;
+ - The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction;
+ - The horizontal size of the bounding box;
+ - The vertical size of the bounding box;
+ - The total area (in pixels) of the defect.
+* Array of centroid points about each defect region.
+
+### Execute second task
+The [execute second task script](src/execute_second_task.py), provides a command line script to execute the task of detecting the russet regions of a fruit.
+It firstly detects the class of the fruit, then it looks for the russet regions that can be present according to the class of the fruit. If the task is run in `verbose` mode, then the procedure of the detection of the fruit class is plotted along with the visualization of the russet regions in the fruit.
+
+The script positional arguments are:
+* `fruit-image-path`: The path of the colour image of the fruit.
+* `image-name` (optional): The name of the image.
+
+The following optional non positional arguments are present:
+* `--config-file-path`, `-cf`: The path of the configuration file.
+* `--data-folder-path`, `-d`: The path of the data folder.
+* `--tweak-factor`, `-tf` (default=0.4): Tweak factor for obtaining the binary mask.
+* `--class-threshold`, `-ct` (default=3): Distance threshold to compute the class of the fruit.
+* `--no-verbose`, `-nv` (default=False); Skip the visualization of the results.
+
+It returns:
+* Number of russet regions found in the fruit
+* Array of statistics about each russet region:
+ - The leftmost (x) coordinate which is the inclusive start of the bounding box in the horizontal direction;
+ - The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction;
+ - The horizontal size of the bounding box;
+ - The vertical size of the bounding box;
+ - The total area (in pixels) of the russet.
+* Array of centroid points about each russet region.
+
+### Execute final challenge
+The [execute final challenge script](src/execute_final_challenge.py), provides a command line script to execute the task of detecting the defects of a fruit in a very noisy environment. It firstly masks the fruit, then it looks for the defects. If the task is run in `verbose` mode, the visualization of the defect regions of the fruit is plotted.
+
+
+The script positional arguments are:
+* `fruit-image-path`: The path of the colour image of the fruit.
+* `fruit-nir-image-path`: The path of the Near Infra-Red image of the fruit.
+* `image-name` (optional): The name of the image.
+
+The following optional non positional arguments are present:
+* `--tweak-factor`, `-tf` (default=0.4): Tweak factor for obtaining the binary mask.
+* `--sigma`, `-s` (default=1): Sigma to apply to the Gaussian Blur operation before Canny's algorithm.
+* `--threshold-1`, `-t1` (default=50): First threshold that is used in Canny's algorithm hysteresis process.
+* `--threshold-2`, `-t2` (default=85): Second threshold that is used in Canny's algorithm hysteresis process.
+* `--mean-file-path`, `-m`: The path of the mean file of the colour of the kiwi region.
+* `--inv-cov-file-path`, `-inv-cov`: The path of the inverse covariance matrix file of the colour of the kiwi region.
+* `--roi-threshold`, `-t` (default=10): Distance threshold to segment the fruit from the sticker.
+* `--no-verbose`, `-nv` (default=False); Skip the visualization of the results.
+
+It returns:
+* Number of defect regions found in the fruit
+* Array of statistics about each defect region:
+ - The leftmost (x) coordinate which is the inclusive start of the bounding box in the horizontal direction;
+ - The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction;
+ - The horizontal size of the bounding box;
+ - The vertical size of the bounding box;
+ - The total area (in pixels) of the defect.
+* Array of centroid points about each defect region.
+
+
+## Usage
+
+### Execute first task
+The following shell command executes the defect detection system built for the first task on image `000001`.
+```sh
+python src/execute_first_task.py "images/first task/C1_000001.png" "images/first task/C0_000001.png" "image 1"
+```
+
+
+
+ | Detected defects | Detected defect areas |
+ |:---------------------------------------------------:|:------------------------------------------------------:|
+ |  |  |
+
+
+
+
+### Execute second task
+The following shell command executes the russet detection system built for the second task on image `000005`
+```sh
+ python src/execute_second_task.py "images/second task/C1_000005.png" "image 5"
+```
+
+
+
+ | Detected russets | Detected russet areas |
+ |:---------------------------------------------------:|:------------------------------------------------------:|
+ |  |  |
+
+
+
+
+### Execute final challenge
+The following shell command executes the defect detection system built for the final challenge on image `000007`.
+```sh
+ python src/execute_final_challenge.py "images/final challenge/C1_000007.png" "images/final challenge/C0_000007.png" "image 7"
+```
+
+
+
+ | Detected defects | Detected defect areas |
+ |:---------------------------------------------------:|:------------------------------------------------------:|
+ |  |  |
+
+
+
+## Repository structure
+
+ .
+ ├── images # Directory containing source Images of the fruits of which the defects have to be identified.
+ │ ├── extra
+ │ ├── final challenge
+ │ ├── first task
+ │ └── second task
+ ├── src
+ │ ├── config
+ │ │ └── config.json # Configuration JSON file that expresses the paths of files useful for the second task.
+ │ ├── data # Directory contining useful data files for the various tasks.
+ │ ├── utils
+ │ │ ├── __init__.py
+ │ │ ├── colour.py # Python module about colour related functions.
+ │ │ ├── colour_threshold.py # Python module about colour thresholding and segmentation functions.
+ │ │ ├── edge.py # Python module about edge detection functions.
+ │ │ ├── general.py # Python module about general plotting and image transformation functions.
+ │ │ └── threshold.py # Python module about thresholding and segmentation functions.
+ │ ├── Final challenge.ipynb # Notebook describing the process to solve the final challenge.
+ │ ├── First task.ipynb # Notebook describing the process to solve the first task.
+ │ ├── Second task.ipynb # Notebook describing the process to solve the second task.
+ │ ├── execute_final_challenge.py # Script to execute the system built to detect the defects in the final challenge.
+ │ ├── execute_first_task.py # Script to execute the system built to detect the defects in the first task.
+ │ └── execute_second_task.py # Script to execute the system built to detect the defects in the second task.
+ ├── assignment.pdf # Assignment of the project
+ ├── .gitattributes
+ ├── .gitignore
+ ├── LICENSE
+ ├── report.pdf # Report of the project
+ └── README.md
+
+## Dependencies
+- [OpenCV](https://pypi.org/project/opencv-python/)
+- [Matplotlib](https://matplotlib.org/)
+- [NumPy](https://numpy.org/)
+- [SciPy](https://scipy.org/)
+- [scikit-learn](https://scikit-learn.org/stable/)
+
+## Versioning
+
+Git is used for versioning.
+
+## Group members
+
+
+ | Name | Surname | Email | Username |
+ | :-------------: | :-------: | :---------------------------------: | :-----------------------------------------------------: |
+ | Facundo Nicolas | Maidana | `facundo.maidana@studio.unibo.it` | [_maidacundo_](https://github.com/maidacundo) |
+ | Riccardo | Spolaor | `riccardo.spolaor@studio.unibo.it` | [_RiccardoSpolaor_](https://github.com/RiccardoSpolaor) |
+
+
+
+## License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/assignment.pdf b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/assignment.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..5828b16b847736d679a1326f5595122dbc953bc3
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/assignment.pdf
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7d0a4234cf7d0f9a67aa9db9a297c7ef7ec86c7b782456c081f8ee62898b545b
+size 487194
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/extra/extra_russet.jpeg b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/extra/extra_russet.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..873c9ca0d27240ec7d322f66148dfd2aa9e9ab19
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/extra/extra_russet.jpeg differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000006.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000006.png
new file mode 100644
index 0000000000000000000000000000000000000000..6db3a1a2e841cd1310e42adc0eb332171d4d3f6a
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000006.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000007.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000007.png
new file mode 100644
index 0000000000000000000000000000000000000000..885b3c770c4f5d58c02b166e9f202e0d96c7aa1d
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000007.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000008.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000008.png
new file mode 100644
index 0000000000000000000000000000000000000000..44864312adb8c82692b9eae5b5fdde0de5d56440
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000008.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000009.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000009.png
new file mode 100644
index 0000000000000000000000000000000000000000..cc1142aa32f8c32de71201047b9cc0e1a01c57b3
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000009.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000010.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000010.png
new file mode 100644
index 0000000000000000000000000000000000000000..6a9d71bc2716d9e68a78c8370f269e0ddc8079a2
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C0_000010.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000006.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000006.png
new file mode 100644
index 0000000000000000000000000000000000000000..8411c418ea1356074631690832095316e5f8b1fa
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000006.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000007.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000007.png
new file mode 100644
index 0000000000000000000000000000000000000000..039b4a3fbee79d0abbc64fc2063c712277f84c17
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000007.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000008.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000008.png
new file mode 100644
index 0000000000000000000000000000000000000000..27279c5111694cc65a8c184227466f0cde194b4b
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000008.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000009.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000009.png
new file mode 100644
index 0000000000000000000000000000000000000000..44c6ab29345392f1d8a444185e640ee8c197ab06
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000009.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000010.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000010.png
new file mode 100644
index 0000000000000000000000000000000000000000..4a2a05dda23b1dc761746a63ad70a4e21d27c948
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/final challenge/C1_000010.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000001.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000001.png
new file mode 100644
index 0000000000000000000000000000000000000000..165f7554a3dee0c5bb1e0eb948ba0227ac8cd97a
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000001.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000002.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000002.png
new file mode 100644
index 0000000000000000000000000000000000000000..c5d01f47cb2a48803a7445f1d83088b1e5c315b8
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000002.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000003.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000003.png
new file mode 100644
index 0000000000000000000000000000000000000000..1b07c86fdfff6fc530ac86c6a303ec01476a1e0f
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C0_000003.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000001.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000001.png
new file mode 100644
index 0000000000000000000000000000000000000000..f534bf4bc8d37e41923f20bee2e40f5383629490
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000001.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000002.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000002.png
new file mode 100644
index 0000000000000000000000000000000000000000..503f7f3b6d4a7b2254a99d81793a76324e7b568b
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000002.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000003.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000003.png
new file mode 100644
index 0000000000000000000000000000000000000000..c9dece25725bf7ab7f647b7801d0a725faf652eb
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/first task/C1_000003.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/final-challenge-result-example-area.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/final-challenge-result-example-area.png
new file mode 100644
index 0000000000000000000000000000000000000000..c091e2277543de069c369b2553885a56a9772a65
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/final-challenge-result-example-area.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/final-challenge-result-example.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/final-challenge-result-example.png
new file mode 100644
index 0000000000000000000000000000000000000000..09d4997afe69486cd4af8f1b617cb7133ec44a59
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/final-challenge-result-example.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/first-task-result-example-area.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/first-task-result-example-area.png
new file mode 100644
index 0000000000000000000000000000000000000000..d43767d404c74829026a10e08300bcf802018cd6
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/first-task-result-example-area.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/first-task-result-example.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/first-task-result-example.png
new file mode 100644
index 0000000000000000000000000000000000000000..65f437d2be7040182698d1cc346489d2b63a7de7
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/first-task-result-example.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/second-task-result-example-area.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/second-task-result-example-area.png
new file mode 100644
index 0000000000000000000000000000000000000000..c0475f5e1d3bf29ab3f681b5a28933eb55b3b0bc
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/second-task-result-example-area.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/second-task-result-example.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/second-task-result-example.png
new file mode 100644
index 0000000000000000000000000000000000000000..043065d89fd6fdec95be8aa3324ebf3793fa0b10
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/samples/second-task-result-example.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C0_000004.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C0_000004.png
new file mode 100644
index 0000000000000000000000000000000000000000..8725ec04e5083f99fecf2ce6a6f54e585ec6c239
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C0_000004.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C0_000005.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C0_000005.png
new file mode 100644
index 0000000000000000000000000000000000000000..05dbe89ba61b9d02c29f674a7d1ee63d58983402
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C0_000005.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C1_000004.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C1_000004.png
new file mode 100644
index 0000000000000000000000000000000000000000..6728b2f7f6a2a391fec2a7349468c8ddad8a0e98
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C1_000004.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C1_000005.png b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C1_000005.png
new file mode 100644
index 0000000000000000000000000000000000000000..5581235415bcec4bb718b43bf70fdf314e9974b6
Binary files /dev/null and b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/images/second task/C1_000005.png differ
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/report.pdf b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/report.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..c9218cde6b82049efd0b6f36b92c47b127f78806
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/report.pdf
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b2e10233f90110d85e86df2e7f73abdf23705725515d3a2281a0041f6e8915a4
+size 31714288
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/Final challenge.ipynb b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/Final challenge.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..4ca0a8541b8fdaa164631a1120f61b2c465ebcc0
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/Final challenge.ipynb
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3b5f4c39889a143bc2be94f885867352c7f72d2e891440a6e8b99087f31668b3
+size 11865349
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/First task.ipynb b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/First task.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..432dc20357cca563c4552e96fcc0555f9dbc543a
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/First task.ipynb
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ea0858e1bdb7585e08b6bfaf149040fc13cc977ae8568cab136fd2c9deac7a30
+size 14977563
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/Second task.ipynb b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/Second task.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..2ebce44cd8ba5c6945204dfe96a1f21c05e5d690
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/Second task.ipynb
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:c83d645b08f4465a36c6fa2e2d82f6dd85fd0c4980948898ac96266a6ca137d4
+size 29188767
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/config/config.json b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/config/config.json
new file mode 100644
index 0000000000000000000000000000000000000000..d28e73cb7c88df6bf8f50448bb4c10155858c65a
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/config/config.json
@@ -0,0 +1,32 @@
+{
+ "healthy_fruit_means": [
+ "mean_healthy_fruit_0.npy",
+ "mean_healthy_fruit_1.npy"
+ ],
+ "healthy_fruit_inv_covs": [
+ "inv_cov_healthy_fruit_0.npy",
+ "inv_cov_healthy_fruit_1.npy"
+
+ ],
+ "roi_means": [
+ "mean_roi_0.npy",
+ "mean_roi_1.npy",
+ "mean_roi_2.npy"
+
+ ],
+ "roi_inv_covs": [
+ "inv_cov_roi_0.npy",
+ "inv_cov_roi_1.npy",
+ "inv_cov_roi_2.npy"
+ ],
+ "roi_thresholds": [
+ 7,
+ 1.5,
+ 7
+ ],
+ "roi_related_fruit": [
+ 0,
+ 0,
+ 1
+ ]
+}
\ No newline at end of file
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_final_challenge.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_final_challenge.npy
new file mode 100644
index 0000000000000000000000000000000000000000..edcbb614e3ba3794e247d85cdf4e2ec367ec0f91
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_final_challenge.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:32d886594b496cb7ea269d701467ac6f9357fcf981cc789ae19785dd3c9734e4
+size 160
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_healthy_fruit_0.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_healthy_fruit_0.npy
new file mode 100644
index 0000000000000000000000000000000000000000..df916392964a9ba793bc04b9333c6087ff54c7c7
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_healthy_fruit_0.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:ad8b7a7d6a19f18a3e78cea6f3a7e2f4305a9b33186f700abde11cda030261c8
+size 160
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_healthy_fruit_1.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_healthy_fruit_1.npy
new file mode 100644
index 0000000000000000000000000000000000000000..3d4140978318e731cae44902c02620c4ddf61a7f
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_healthy_fruit_1.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:38e1a7a9fd5c5f8eb00a4f995048169d7715c360b1e1f85f71e6bc2525a58bb2
+size 160
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_0.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_0.npy
new file mode 100644
index 0000000000000000000000000000000000000000..a14a1aa7e73dd7f7d239ada7708abb2decc1334b
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_0.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:17725e9ae46d59539aab7e835ab84dba69b8505a6c556e0c650223edb1e0aa46
+size 160
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_1.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_1.npy
new file mode 100644
index 0000000000000000000000000000000000000000..e7b51eae7ed0a70001b454d70a5b8e94158ad960
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_1.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:3abaaacae8abc1c0b6f3ec9a40dfb5e23921df970c187ab755b59d9838d2f2e8
+size 160
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_2.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_2.npy
new file mode 100644
index 0000000000000000000000000000000000000000..81a47229e47e2ac7d34e3bbc3c6cd855943643dc
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/inv_cov_roi_2.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f77122afcafa0ee0eefa4f2bb69a03fabc3abf590f6559f5598b05157952357d
+size 160
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_final_challenge.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_final_challenge.npy
new file mode 100644
index 0000000000000000000000000000000000000000..9397789f0cf976a87f69156ec13a6a09e44371a4
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_final_challenge.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f842f368649732b1dca2cc399acdb5e84e3d3effc5e1c4653c0f49658c338ed9
+size 144
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_healthy_fruit_0.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_healthy_fruit_0.npy
new file mode 100644
index 0000000000000000000000000000000000000000..6f159e37cb980ca5f16c1d80c0b08fcae1ce69eb
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_healthy_fruit_0.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:823ff42750c940df7d1a2b0dbeeb0bc9e5d24afb92614834e5590070a4b36983
+size 144
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_healthy_fruit_1.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_healthy_fruit_1.npy
new file mode 100644
index 0000000000000000000000000000000000000000..d8cc4d9ea0aec1a85113f5512db6e0bd822daff9
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_healthy_fruit_1.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:021c3039fcff4e8706e2935106a30646f2e192125fa70af1631bee1130ba857b
+size 144
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_0.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_0.npy
new file mode 100644
index 0000000000000000000000000000000000000000..2f34f46b312d60fe8b440fddde70727421d9a843
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_0.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e7883cd92a07d1dd572bdfd95a6ad92de4f757b19eb62cdf57f2d11c99bbf5e8
+size 144
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_1.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_1.npy
new file mode 100644
index 0000000000000000000000000000000000000000..9085d8a2dee09eaddcb9f3412c8de8605b266d88
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_1.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:9d0984c9bbfd0aca84cf99e58c86326b4ba4e883bebd377da00ab4c61c573975
+size 144
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_2.npy b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_2.npy
new file mode 100644
index 0000000000000000000000000000000000000000..6f717ce49968274346d3f4548a3bda2a882d7bbd
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/data/mean_roi_2.npy
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:fdd11aeb3f8ab99ee90b5435874f95a2a9d5acf5749016254be293d893da40ad
+size 144
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_final_challenge.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_final_challenge.py
new file mode 100644
index 0000000000000000000000000000000000000000..b34e3241ad404baa0b511683328dc035e67e8e8d
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_final_challenge.py
@@ -0,0 +1,209 @@
+import argparse
+import numpy as np
+import os
+import cv2 as cv
+
+from typing import Tuple
+
+from utils.edge import *
+from utils.colour import *
+from utils.colour_threshold import *
+from utils.threshold import *
+from utils.general import *
+
+
+def detect_defects(colour_image: np.ndarray, nir_image: np.ndarray, mean: np.ndarray, inv_cov: np.ndarray,
+ roi_threshold: int = 10, tweak_factor: float = .4,
+ sigma: float = 1., threshold_1: int = 50, threshold_2: int = 85,
+ image_name: str = '', verbose: bool = True) -> Tuple[int, np.ndarray, np.ndarray]:
+ """
+ Function that executes the task of detecting the defects of a fruit in a very noisy environment.
+
+ It firstly masks the fruit, then it looks for the defects.
+
+ If the task is run in `verbose` mode, the visualization of the defect regions of the fruit is plotted.
+
+ Parameters
+ ----------
+ colour_image: np.ndarray
+ Colour image of the fruit whose defects have to be detected
+ nir_image: np.ndarray
+ Near Infra-Red image of the same fruit represented in `colour_image`
+ mean: np.ndarray
+ Mean LAB colour value of the kiwi reference colour
+ inv_cov: np.ndarray
+ Inverse covariance matrices of the kiwi computed on the LAB colour space
+ roi_threshold: int, optional
+ Mahalanobis distance threshold. Pixels of the colour image having a Mahalanobis distance greater than it are not
+ considered part of the corresponding kiwi region (default = 10)
+ tweak_factor: float, optional
+ Tweak factor to apply to the "Tweaked Otsu's Algorithm" in order to obtain the binary segmentation mask
+ (default: 0.4)
+ sigma: float, optional
+ Value of sigma to apply to the Gaussian Blur operation before the use of Canny's algorithm (default: 1)
+ threshold_1: int, optional
+ Value of the first threshold that is used in Canny's algorithm (default: 50)
+ threshold_2: int, optional
+ Value of the second threshold that is used in Canny's algorithm (default: 85)
+ image_name: str, optional
+ Optional name of the image to visualize during the plotting operations
+ verbose: bool, optional
+ Whether to run the function in verbose mode or not (default: True)
+
+ Returns
+ -------
+ retval: int
+ Number of defect regions found in the fruit
+ stats: np.ndarray
+ Array of statistics about each defect region:
+ - The leftmost (x) coordinate which is the inclusive start of the bounding box in the horizontal direction;
+ - The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction;
+ - The horizontal size of the bounding box;
+ - The vertical size of the bounding box;
+ - The total area (in pixels) of the defect.
+ centroids: np.ndarray
+ Array of centroid points about each defect region.
+ """
+
+ # Filter the colour image by bilateral filter
+ f_img = cv.bilateralFilter(colour_image, d=5, sigmaColor=75, sigmaSpace=75)
+
+ # Filter the image by median blur with a 7 x 7 kernel
+ f_gray = cv.medianBlur(nir_image, 7)
+
+ # Get the fruit mask through Tweaked Otsu's algorithm
+ mask = get_fruit_segmentation_mask(f_gray, ThresholdingMethod.TWEAKED_OTSU, tweak_factor=tweak_factor)
+
+ # Perform two openings to clean up the mask
+ se1 = cv.getStructuringElement(cv.MORPH_ELLIPSE, (20, 5))
+ se2 = cv.getStructuringElement(cv.MORPH_ELLIPSE, (5, 20))
+ mask = cv.morphologyEx(mask, cv.MORPH_OPEN, se1)
+ mask = cv.morphologyEx(mask, cv.MORPH_OPEN, se2)
+
+ # Get largest blob corresponding to the fruit in the mask
+ mask = get_largest_blob_in_mask(mask)
+
+ # Apply the mask to the colour image
+ m_colour_image = apply_mask_to_image(f_img, mask)
+
+ # Turn BGR image to LAB and extract mask using Mahalanobis distance
+ lab_image = ColourSpace('LAB').bgr_to_colour_space(m_colour_image)
+ channels = (1, 2)
+
+ # Get the mask of the fruit without the sticker
+ roi_mask = get_mahalanobis_distance_segmented_image(lab_image, mean, inv_cov, roi_threshold, channels)
+
+ # Apply Opening operation to close small gaps in the ROI mask
+ element = cv.getStructuringElement(cv.MORPH_ELLIPSE, (10, 10))
+ roi_mask = cv.morphologyEx(roi_mask, cv.MORPH_OPEN, element)
+
+ # Apply mask to the filtered NIR image
+ m_nir_image = apply_mask_to_image(f_gray, roi_mask)
+
+ # Get the edge mask through Gaussian Blur and Canny's method
+ edge_mask = apply_gaussian_blur_and_canny(m_nir_image, sigma, threshold_1, threshold_2)
+
+ # Erode the mask to get rid of the edges of the bound of the fruit
+ erode_element = cv.getStructuringElement(cv.MORPH_RECT, (15, 15))
+ eroded_mask = cv.erode(mask, erode_element)
+
+ # Remove background edges from the edge mask
+ edge_mask = apply_mask_to_image(edge_mask, eroded_mask)
+
+ # Apply Closing operation to fill the defects according to the edges and obtain the defect mask
+ close_element = cv.getStructuringElement(cv.MORPH_ELLIPSE, (50, 50))
+ defect_mask = cv.morphologyEx(edge_mask, cv.MORPH_CLOSE, close_element)
+ defect_mask = cv.medianBlur(defect_mask, 7)
+
+ # Perform a connected components labeling to detect the defects
+ retval, labels, stats, centroids = cv.connectedComponentsWithStats(defect_mask)
+
+ if verbose:
+ print(f'Detected {retval - 1} defect{"" if retval - 1 == 1 else "s"} for image {image_name}.')
+
+ # Get highlighted defects on the fruit
+ highlighted_roi = get_highlighted_roi_by_mask(colour_image, defect_mask, 'red')
+
+ circled_defects = np.copy(colour_image)
+
+ for i in range(1, retval):
+ s = stats[i]
+ # Draw a red ellipse around the defect
+ cv.ellipse(circled_defects, center=tuple(int(c) for c in centroids[i]),
+ axes=(s[cv.CC_STAT_WIDTH] // 2 + 10, s[cv.CC_STAT_HEIGHT] // 2 + 10),
+ angle=0, startAngle=0, endAngle=360, color=(0, 0, 255), thickness=3)
+
+ plot_image_grid([highlighted_roi, circled_defects],
+ ['Detected defects ROI', 'Detected defects areas'],
+ f'Defects of the fruit {image_name}')
+ return retval - 1, stats[1:], centroids[1:]
+
+
+def _main():
+ parser = argparse.ArgumentParser(description='Script for defect location on a fruit.')
+
+ parser.add_argument('fruit-image-path', metavar='Fruit image path', type=str,
+ help='The path of the colour image of the fruit.')
+
+ parser.add_argument('fruit-nir-image-path', metavar='Fruit image path', type=str,
+ help='The path of the Near Infra-Red image of the fruit.')
+
+ parser.add_argument('image-name', metavar='Image name', type=str, help='The name of the image.', default='',
+ nargs='?')
+
+ parser.add_argument('--tweak-factor', '-tf', type=float, default=.4, nargs='?',
+ help='Tweak factor for obtaining the binary mask.', required=False)
+
+ parser.add_argument('--sigma', '-s', type=float, default=1., nargs='?',
+ help="Sigma to apply to the Gaussian Blur operation before Canny's algorithm",
+ required=False)
+
+ parser.add_argument('--threshold-1', '-t1', type=int, default=50, nargs='?',
+ help="First threshold that is used in Canny's algorithm.", required=False)
+
+ parser.add_argument('--threshold-2', '-t2', type=int, default=85, nargs='?',
+ help="Second threshold that is used in Canny's algorithm.", required=False)
+
+ parser.add_argument('--mean-file-path', '-m', type=str,
+ help='The path of the mean file of the colour of the kiwi region.',
+ default=os.path.join(os.path.dirname(__file__), 'data/mean_final_challenge.npy'), nargs='?',
+ required=False)
+
+ parser.add_argument('--inv-cov-file-path', '-inv-cov', type=str,
+ help='The path of the invverse covariance matrix file of the colour of the kiwi region.',
+ default=os.path.join(os.path.dirname(__file__), 'data/inv_cov_final_challenge.npy'), nargs='?',
+ required=False)
+
+ parser.add_argument('--roi-threshold', '-t', type=int, default=10, nargs='?',
+ help='Distance threshold to segment the fruit from the sticker.', required=False)
+
+ parser.add_argument('--no-verbose', '-nv', action='store_true', help='Skip the visualization of the results.')
+
+ arguments = parser.parse_args()
+
+ # Read colour image
+ fruit_image_path = vars(arguments)['fruit-image-path']
+ colour_image = cv.imread(fruit_image_path)
+
+ # Read NIR image
+ fruit_nir_image_path = vars(arguments)['fruit-nir-image-path']
+ nir_image = cv.imread(fruit_nir_image_path, cv.IMREAD_GRAYSCALE)
+
+ image_name = vars(arguments)['image-name']
+
+ tweak_factor = arguments.tweak_factor
+ sigma = arguments.sigma
+ threshold_1 = arguments.threshold_1
+ threshold_2 = arguments.threshold_2
+ roi_threshold = arguments.roi_threshold
+ verbose = not arguments.no_verbose
+
+ mean = np.load(arguments.mean_file_path)
+ inv_cov = np.load(arguments.inv_cov_file_path)
+
+ detect_defects(colour_image, nir_image, mean, inv_cov, roi_threshold, tweak_factor, sigma, threshold_1,
+ threshold_2, image_name, verbose)
+
+
+if __name__ == '__main__':
+ _main()
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_first_task.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_first_task.py
new file mode 100644
index 0000000000000000000000000000000000000000..728a17250aa8feca35d46d576e55025ad3e0f334
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_first_task.py
@@ -0,0 +1,154 @@
+import argparse
+import cv2 as cv
+import numpy as np
+from typing import Tuple
+
+from utils.edge import *
+from utils.general import *
+from utils.threshold import *
+
+
+def detect_defects(colour_image: np.ndarray, nir_image: np.ndarray, image_name: str = '', tweak_factor: float = .3,
+ sigma: float = 1., threshold_1: int = 60, threshold_2: int = 130,
+ verbose: bool = True) -> Tuple[int, np.ndarray, np.ndarray]:
+ """
+ Function that executes the task of detecting the defects of a fruit.
+
+ It firstly masks the fruit, then it looks for the defects.
+
+ If the task is run in `verbose` mode, the visualization of the defect regions of the fruit is plotted.
+
+ Parameters
+ ----------
+ colour_image: np.ndarray
+ Colour image of the fruit whose defects have to be detected
+ nir_image: np.ndarray
+ Near Infra-Red image of the same fruit represented in `colour_image`
+ image_name: str, optional
+ Optional name of the image to visualize during the plotting operations
+ tweak_factor: float, optional
+ Tweak factor to apply to the "Tweaked Otsu's Algorithm" in order to obtain the binary segmentation mask
+ (default: 0.3)
+ sigma: float, optional
+ Value of sigma to apply to the Gaussian Blur operation before the use of Canny's algorithm (default: 1)
+ threshold_1: int, optional
+ Value of the first threshold that is used in Canny's algorithm (default: 60)
+ threshold_2: int, optional
+ Value of the second threshold that is used in Canny's algorithm (default: 120)
+ verbose: bool, optional
+ Whether to run the function in verbose mode or not (default: True)
+
+ Returns
+ -------
+ retval: int
+ Number of defect regions found in the fruit
+ stats: np.ndarray
+ Array of statistics about each defect region:
+ - The leftmost (x) coordinate which is the inclusive start of the bounding box in the horizontal direction;
+ - The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction;
+ - The horizontal size of the bounding box;
+ - The vertical size of the bounding box;
+ - The total area (in pixels) of the defect.
+ centroids: np.ndarray
+ Array of centroid points about each defect region.
+ """
+ # Filter the NIR image by median blur
+ f_nir_image = cv.medianBlur(nir_image, 5)
+
+ # Get the fruit mask through Tweaked Otsu's algorithm
+ mask = get_fruit_segmentation_mask(f_nir_image, ThresholdingMethod.TWEAKED_OTSU, tweak_factor=tweak_factor)
+
+ # Apply the mask to the filtered NIR image
+ m_nir_image = apply_mask_to_image(f_nir_image, mask)
+
+ # Get the edge mask through Gaussian Blur and Canny's method
+ edge_mask = apply_gaussian_blur_and_canny(m_nir_image, sigma, threshold_1, threshold_2)
+
+ # Erode the mask to get rid of the edges of the bound of the fruit
+ erode_element = cv.getStructuringElement(cv.MORPH_RECT, (15, 15))
+ eroded_mask = cv.erode(mask, erode_element)
+
+ # Remove background edges from the edge mask
+ edge_mask = apply_mask_to_image(edge_mask, eroded_mask)
+
+ # Apply Closing operation to fill the defects according to the edges and obtain the defect mask
+ close_element = cv.getStructuringElement(cv.MORPH_ELLIPSE, (50, 50))
+ defect_mask = cv.morphologyEx(edge_mask, cv.MORPH_CLOSE, close_element)
+ defect_mask = cv.medianBlur(defect_mask, 7)
+
+ # Perform a connected components labeling to detect the defects
+ retval, labels, stats, centroids = cv.connectedComponentsWithStats(defect_mask)
+
+ if verbose:
+ print(f'Detected {retval - 1} defect{"" if retval - 1 == 1 else "s"} for image {image_name}.')
+
+ # Get highlighted defects on the fruit
+ highlighted_roi = get_highlighted_roi_by_mask(colour_image, defect_mask, 'red')
+
+ circled_defects = np.copy(colour_image)
+
+ for i in range(1, retval):
+ s = stats[i]
+ # Draw a red ellipse around the defect
+ cv.ellipse(circled_defects, center=tuple(int(c) for c in centroids[i]),
+ axes=(s[cv.CC_STAT_WIDTH] // 2 + 10, s[cv.CC_STAT_HEIGHT] // 2 + 10),
+ angle=0, startAngle=0, endAngle=360, color=(0, 0, 255), thickness=3)
+
+ plot_image_grid([highlighted_roi, circled_defects],
+ ['Detected defects ROI', 'Detected defects areas'],
+ f'Defects of the fruit {image_name}')
+ return retval - 1, stats[1:], centroids[1:]
+
+
+def _main():
+ parser = argparse.ArgumentParser(description='Script for applying defect detection on a fruit.')
+
+ parser.add_argument('fruit-image-path', metavar='Fruit image path', type=str,
+ help='The path of the colour image of the fruit.')
+
+ parser.add_argument('fruit-nir-image-path', metavar='Fruit image path', type=str,
+ help='The path of the Near Infra-Red image of the fruit.')
+
+ parser.add_argument('image-name', metavar='Image name', type=str, help='The name of the image.', default='',
+ nargs='?')
+
+ parser.add_argument('--tweak-factor', '-tf', type=float, default=.3, nargs='?',
+ help='Tweak factor for obtaining the binary mask.', required=False)
+
+ parser.add_argument('--sigma', '-s', type=float, default=1., nargs='?',
+ help="Sigma to apply to the Gaussian Blur operation before Canny's algorithm",
+ required=False)
+
+ parser.add_argument('--threshold-1', '-t1', type=int, default=60, nargs='?',
+ help="First threshold that is used in Canny's algorithm hysteresis process.", required=False)
+
+ parser.add_argument('--threshold-2', '-t2', type=int, default=130, nargs='?',
+ help="Second threshold that is used in Canny's algorithm hysteresis process.", required=False)
+
+ parser.add_argument('--no-verbose', '-nv', action='store_true', help='Skip the visualization of the results.')
+
+ # Initialize parser
+ arguments = parser.parse_args()
+
+ # Read colour image
+ fruit_image_path = vars(arguments)['fruit-image-path']
+ colour_image = cv.imread(fruit_image_path)
+
+ # Read NIR image
+ fruit_nir_image_path = vars(arguments)['fruit-nir-image-path']
+ nir_image = cv.imread(fruit_nir_image_path, cv.IMREAD_GRAYSCALE)
+
+ image_name = vars(arguments)['image-name']
+
+ tweak_factor = arguments.tweak_factor
+ sigma = arguments.sigma
+ threshold_1 = arguments.threshold_1
+ threshold_2 = arguments.threshold_2
+ verbose = not arguments.no_verbose
+
+ detect_defects(colour_image, nir_image, image_name=image_name, tweak_factor=tweak_factor, sigma=sigma,
+ threshold_1=threshold_1, threshold_2=threshold_2, verbose=verbose)
+
+
+if __name__ == '__main__':
+ _main()
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_second_task.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_second_task.py
new file mode 100644
index 0000000000000000000000000000000000000000..97acb1e9991178d62ebd014446364666e8d23a62
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/execute_second_task.py
@@ -0,0 +1,211 @@
+import argparse
+import cv2 as cv
+import json
+import numpy as np
+import os
+
+from typing import List, Tuple
+
+from utils.colour import *
+from utils.colour_threshold import *
+from utils.general import *
+from utils.threshold import *
+
+
+def detect_russet(image: np.ndarray, h_means: List[np.ndarray], h_inv_covs: List[np.ndarray],
+ roi_means: List[List[np.ndarray]], roi_inv_covs: List[List[np.ndarray]],
+ roi_thresholds: List[List[int]], class_threshold: float = 3, tweak_factor: float = .4,
+ image_name: str = '', verbose: bool = True) -> Tuple[int, np.ndarray, np.ndarray]:
+ """
+ Function that executes the task of detecting the russet regions of a fruit.
+
+ It firstly detects the class of the fruit, then it looks for the russet regions that can be present according to the
+ class of the fruit.
+
+ If the task is run in `verbose` mode, then the procedure of the detection of the fruit class is plotted along with
+ the visualization of the russet regions in the fruit.
+
+ Parameters
+ ----------
+ image: np.ndarray
+ Colour image of the fruit whose russet has to be detected
+ h_means: List[np.ndarray]
+ List of the mean LAB colour values of the healthy part of the fruits (one mean per fruit class)
+ h_inv_covs: List[np.ndarray]
+ List of inverse covariance matrices of the healthy fruit parts computed on the LAB colour space (one covariance
+ matrix per fruit class)
+ roi_means: List[List[np.ndarray]]
+ List of list of mean LAB colour values of the russet regions of the fruits (one or multiple per fruit class)
+ roi_inv_covs: List[List[np.ndarray]]
+ List of list of inverse covariance matrices of the russet regions of the fruits computed on the LAB colour space
+ (one or multiple per fruit class)
+ roi_thresholds: List[List[int]]
+ List of list of thresholds. Pixels of the colour image having a Mahalanobis distance greater than a certain
+ thresholds are not considered part of the corresponding russet region (one or multiple per fruit class)
+ class_threshold: float, optional
+ Threshold to compute the fruit class according to the colour distance from its healthy part. Pixels of the
+ colour image having a Mahalanobis distance greater than it are not considered part of the corresponding healthy
+ fruit region (default: 3)
+ image_name: str, optional
+ Optional name of the image to visualize during the plotting operations
+ tweak_factor: float, optional
+ Tweak factor to apply to the "Tweaked Otsu's Algorithm" in order to obtain the binary segmentation mask
+ (default: 0.4)
+ verbose: bool, optional
+ Whether to run the function in verbose mode or not (default: True)
+
+ Returns
+ -------
+ retval: int
+ Number of russet regions found in the fruit
+ stats: np.ndarray
+ Array of statistics about each russet region:
+ - The leftmost (x) coordinate which is the inclusive start of the bounding box in the horizontal direction;
+ - The topmost (y) coordinate which is the inclusive start of the bounding box in the vertical direction;
+ - The horizontal size of the bounding box;
+ - The vertical size of the bounding box;
+ - The total area (in pixels) of the russet.
+ centroids: np.ndarray
+ Array of centroid points about each russet region.
+ """
+ # Filter the image by bilateral filter
+ f_img = cv.bilateralFilter(image, d=5, sigmaColor=75, sigmaSpace=75)
+
+ # Convert the image to gray-scale and median blur it by a 5 x 5 kernel
+ f_gray = cv.medianBlur(cv.cvtColor(image, cv.COLOR_BGR2GRAY), 5)
+
+ # Get the fruit mask through Tweaked Otsu's algorithm
+ mask = get_fruit_segmentation_mask(f_gray, ThresholdingMethod.TWEAKED_OTSU, tweak_factor=tweak_factor)
+
+ # Apply the mask to the filtered colour image
+ m_image = cv.cvtColor(mask, cv.COLOR_GRAY2BGR) + f_img
+
+ # Turn BGR image to LAB
+ m_lab_image = ColourSpace('LAB').bgr_to_colour_space(m_image)
+ channels = (1, 2)
+
+ # Get the fruit class
+ fruit_class = get_fruit_class(m_lab_image, h_means, h_inv_covs, channels=channels, threshold=class_threshold,
+ display_image=image if verbose else None)
+
+ if verbose:
+ print(f'Class of fruit = {fruit_class}')
+
+ # Erode the mask to get rid of artefacts to the bound of the fruit after the russet detection is applied
+ element = cv.getStructuringElement(cv.MORPH_ELLIPSE, (15, 15))
+ eroded_mask = cv.erode(mask, element)
+
+ # Initialize the mask of the russet (ROI) as an array of 0s
+ roi_mask = np.zeros(image.shape[:2], dtype=np.uint8)
+
+ # Get the mask of each possible russet of the fruit and apply a bitwise
+ # OR between it and the previous ROI mask
+ for m, c, t in zip(roi_means[fruit_class], roi_inv_covs[fruit_class], roi_thresholds[fruit_class]):
+ roi_mask += get_mahalanobis_distance_segmented_image(m_lab_image, m, c, t, channels)
+
+ # Remove artifacts from the ROI mask
+ roi_mask = roi_mask & eroded_mask
+
+ # Apply median blur to de-noise the mask and smooth it
+ roi_mask = cv.medianBlur(roi_mask, 5)
+
+ # Apply Closing operation to close small gaps in the ROI mask
+ roi_mask = cv.morphologyEx(roi_mask, cv.MORPH_CLOSE, element)
+
+ # Perform a connected components labeling to detect defects
+ retval, labels, stats, centroids = cv.connectedComponentsWithStats(roi_mask)
+
+ if verbose:
+ print(f'Detected {retval - 1} defect{"" if retval - 1 == 1 else "s"} for image {image_name}.')
+
+ # Get highlighted russet on the fruit
+ highlighted_roi = get_highlighted_roi_by_mask(image, roi_mask)
+
+ circled_russets = np.copy(image)
+
+ for i in range(1, retval):
+ s = stats[i]
+ # Draw a red ellipse around the russet
+ cv.ellipse(circled_russets, center=tuple(int(c) for c in centroids[i]),
+ axes=(s[cv.CC_STAT_WIDTH] // 2 + 10, s[cv.CC_STAT_HEIGHT] // 2 + 10),
+ angle=0, startAngle=0, endAngle=360, color=(0, 0, 255), thickness=3)
+
+ plot_image_grid([highlighted_roi, circled_russets], ['Detected russets ROI', 'Detected russets areas'],
+ f'Russets of the fruit in image {image_name}')
+ return retval - 1, stats[1:], centroids[1:]
+
+
+def _main():
+ parser = argparse.ArgumentParser(description='Script for applying russet detection on a fruit.')
+
+ parser.add_argument('fruit-image-path', metavar='Fruit image path', type=str,
+ help='The path of the colour image of the fruit.')
+
+ parser.add_argument('image-name', metavar='Image name', type=str, help='The name of the image.', default='',
+ nargs='?')
+
+ parser.add_argument('--config-file-path', '-cf', type=str, help='The path of the configuration file.',
+ default=os.path.join(os.path.dirname(__file__), f'config/config.json'), nargs='?',
+ required=False)
+
+ parser.add_argument('--data-folder-path', '-d', type=str, help='The path of the data folder.',
+ default=os.path.join(os.path.dirname(__file__), f'data'), nargs='?', required=False)
+
+ parser.add_argument('--tweak-factor', '-tf', type=float, default=.4, nargs='?',
+ help='Tweak factor for obtaining the binary mask.', required=False)
+
+ parser.add_argument('--class-threshold', '-ct', type=float, default=3, nargs='?',
+ help='Distance threshold to compute the class of the fruit.', required=False)
+
+ parser.add_argument('--no-verbose', '-nv', action='store_true', help='Skip the visualization of the results.')
+
+ # Initialize parser
+ arguments = parser.parse_args()
+
+ # Read colour image
+ fruit_image_path = vars(arguments)['fruit-image-path']
+ colour_image = cv.imread(fruit_image_path)
+
+ image_name = vars(arguments)['image-name']
+
+ config_file_path = arguments.config_file_path
+ data_folder_path = arguments.data_folder_path
+ tweak_factor = arguments.tweak_factor
+ class_threshold = arguments.class_threshold
+ verbose = not arguments.no_verbose
+
+ # Get config file
+ with open(config_file_path, 'r') as j:
+ config_dictionary = json.load(j)
+
+ # Get means, inverse covariance matrices and other information from the config file
+ healthy_fruit_means = config_dictionary['healthy_fruit_means']
+ healthy_fruit_inv_covs = config_dictionary['healthy_fruit_inv_covs']
+ roi_means = config_dictionary['roi_means']
+ roi_inv_covs = config_dictionary['roi_inv_covs']
+ roi_thresholds = config_dictionary['roi_thresholds']
+ roi_related_fruit = config_dictionary['roi_related_fruit']
+
+ healthy_fruit_means = [np.load(os.path.join(data_folder_path, n)) for n in healthy_fruit_means]
+ healthy_fruit_inv_covs = [np.load(os.path.join(data_folder_path, n)) for n in healthy_fruit_inv_covs]
+ roi_means = [np.load(os.path.join(data_folder_path, n)) for n in roi_means]
+ roi_inv_covs = [np.load(os.path.join(data_folder_path, n)) for n in roi_inv_covs]
+
+ # Assign roi to each fruit
+ roi_means_sorted = [[] for _ in range(len(healthy_fruit_means))]
+ roi_inv_cov_sorted = [[] for _ in range(len(healthy_fruit_means))]
+ roi_thresholds_sorted = [[] for _ in range(len(healthy_fruit_means))]
+
+ for m, c, t, r in zip(roi_means, roi_inv_covs, roi_thresholds, roi_related_fruit):
+ roi_means_sorted[r].append(m)
+ roi_inv_cov_sorted[r].append(c)
+ roi_thresholds_sorted[r].append(t)
+
+ # Apply russet detection
+ detect_russet(colour_image, healthy_fruit_means, healthy_fruit_inv_covs, roi_means_sorted, roi_inv_cov_sorted,
+ roi_thresholds_sorted, class_threshold=class_threshold, tweak_factor=tweak_factor,
+ image_name=image_name, verbose=verbose)
+
+
+if __name__ == '__main__':
+ _main()
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/__init__.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..fc81c2b04d84f55362186a4b1da847a589195328
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/__init__.py
@@ -0,0 +1,5 @@
+"""
+Utils module
+"""
+from __future__ import absolute_import
+from . import colour, colour_threshold, edge, general, threshold
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/colour.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/colour.py
new file mode 100644
index 0000000000000000000000000000000000000000..918318988de1707d400cf6b8008c594869684aa4
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/colour.py
@@ -0,0 +1,196 @@
+"""
+Module about colour related functions.
+"""
+import cv2 as _cv
+import matplotlib.pyplot as _plt
+from matplotlib import colors as _colors
+import numpy as _np
+from typing import List as _List
+
+
+class ColourSpace:
+ """
+ Class of a colour space.
+
+ Parameters
+ ----------
+ colour_space : str
+ Name of the colour space from which the class is obtained
+
+ Attributes
+ ----------
+ name: str
+ Name of the colour space
+ channels: List[str]
+ Name of the channels of the colour space
+
+ Methods
+ -------
+ bgr_to_colour_space(img: ndarray) -> ndarray
+ Transform the image in the colour space instantiated by this class.
+ """
+
+ _COLOR_SPACE_IDS = {
+ 'BGR': None,
+ 'HSV': _cv.COLOR_BGR2HSV_FULL,
+ 'HLS': _cv.COLOR_BGR2HLS_FULL,
+ 'LUV': _cv.COLOR_BGR2Luv,
+ 'LAB': _cv.COLOR_BGR2LAB,
+ 'YCrCb': _cv.COLOR_BGR2YCrCb
+ }
+
+ _COLOR_SPACE_CHANNEL_NAMES = {
+ 'BGR': ['B', 'G', 'R'],
+ 'HSV': ['H', 'S', 'V'],
+ 'HLS': ['H', 'L', 'S'],
+ 'LUV': ['L', 'U', 'V'],
+ 'LAB': ['L', 'A', 'B'],
+ 'YCrCb': ['Y', 'Cr', 'Cb']
+ }
+
+ def __init__(self, colour_space: str) -> None:
+ self.name = colour_space
+ self.channels = self._COLOR_SPACE_CHANNEL_NAMES[self.name]
+
+ def bgr_to_colour_space(self, image) -> _np.ndarray:
+ """
+ Transform the image in the colour space instantiated by this class.
+
+ Parameters
+ ----------
+ image: ndarray
+ The image to transform in the colour space instantiated by the class
+
+ Returns
+ -------
+ transformed_image: ndarray
+ The image transformed in the given colour space
+ """
+ if self._COLOR_SPACE_IDS[self.name] is None:
+ return image
+ else:
+ return _cv.cvtColor(image, self._COLOR_SPACE_IDS[self.name])
+
+
+def plot_colour_distribution_3d(images: _List[_np.ndarray], images_names: _List[str], colour_space: ColourSpace,
+ masks: _List[_np.ndarray] = None, title: str = None) -> None:
+ """
+ Function to plot the colour distribution of a series of images onsidering the channels
+
+ Parameters
+ ----------
+ images: List[ndarray]
+ Images of which the colour distribution is plotted
+ images_names: List[str]
+ Names of the images of which the colour distribution is plotted
+ colour_space: ColourSpace
+ Colour space considered to plot the colour distribution of each image
+ masks: List[ndarray], optional
+ Optional list of masks that exclude pixels while plotting the colour distribution. By default no masks are
+ provided
+ title: str, optional
+ Optional title of the plot
+ """
+ fig = _plt.figure(figsize=(15, 5))
+
+ for idx, colour_img in enumerate(images):
+ # Turn the colored image into the defined colour space
+ img = colour_space.bgr_to_colour_space(colour_img)
+
+ # Get channels of the image and flatten them
+ channels = _cv.split(img)
+ channels = [ch.flatten() for ch in channels]
+
+ # Get channel names
+ channel_names = colour_space.channels
+
+ # Get RGB color of every pixel
+ pixel_colors = _cv.cvtColor(colour_img, _cv.COLOR_BGR2RGB).reshape((-1, 3))
+
+ # Remove masked pixels
+ if masks is not None:
+ mask = masks[idx].flatten()
+ channels = [ch[mask != 0] for ch in channels]
+ pixel_colors = pixel_colors[mask != 0]
+
+ # Normalize pixel colors
+ norm = _colors.Normalize(vmin=-1., vmax=1.)
+ norm.autoscale(pixel_colors)
+ pixel_colors = norm(pixel_colors).tolist()
+
+ # Plot a 3D scatter-plot if three channels are present
+ ax = fig.add_subplot(1, len(images), idx + 1, projection='3d')
+ ax.scatter(channels[0], channels[1], channels[2], facecolors=pixel_colors, marker=".")
+ ax.set_xlabel(f'Channel {channel_names[0]}')
+ ax.set_ylabel(f'Channel {channel_names[1]}')
+ ax.set_zlabel(f'Channel {channel_names[2]}')
+ ax.set_title(f'Color distribution for {images_names[idx]}')
+
+ if title is None:
+ fig.suptitle(f'Distribution of pixels in the {colour_space.name} colour space', fontsize=16)
+ else:
+ fig.suptitle(title, fontsize=16)
+ # Remove extra space between the sub-images
+ _plt.tight_layout()
+ _plt.show()
+
+
+def plot_colour_distribution_2d(image: _np.ndarray, image_name: str, colour_space: ColourSpace,
+ mask: _np.ndarray = None) -> None:
+ """
+ Function to plot the colour distributions of an image considering all different couples of channels
+
+ Parameters
+ ----------
+ image: ndarray
+ Image of which the colour distributions are plotted
+ image_name: str
+ Name of the image of which the colour distributions are plotted
+ colour_space: ColourSpace
+ Colour space considered to plot the colour distributions of the image
+ mask: List[ndarray], optional
+ Optional mask that exclude pixels while plotting the colour distributions. By default no mask is provided
+ """
+ fig, axes = _plt.subplots(1, 3, figsize=(15, 3))
+
+ channels_mapping = {idx: ch for idx, ch in enumerate(colour_space.channels)}
+
+ # Turn the colored image into the defined colour space
+ img = colour_space.bgr_to_colour_space(image)
+
+ for idx, channel_indices in enumerate([[0, 1], [0, 2], [1, 2]]):
+
+ # Get channels of the image, flatten them and remove masked pixels
+ channels = [img[:, :, ch] for ch in channel_indices]
+ channels = [ch.flatten() for ch in channels]
+
+ # Get RGB color of every pixel and remove the masked ones
+ pixel_colors = _cv.cvtColor(image, _cv.COLOR_BGR2RGB).reshape((-1, 3))
+
+ if mask is not None:
+ # Flatten the mask
+ mask = mask.flatten()
+ # Remove masked pixels from the channels and pixel_colors arrays
+ channels = [ch[mask != 0] for ch in channels]
+ pixel_colors = pixel_colors[mask != 0]
+
+ # Normalize pixel colors
+ norm = _colors.Normalize(vmin=-1., vmax=1.)
+ norm.autoscale(pixel_colors)
+ pixel_colors = norm(pixel_colors).tolist()
+
+ channel_x = channels_mapping[channel_indices[0]]
+
+ channel_y = channels_mapping[channel_indices[1]]
+
+ ax = axes[idx]
+
+ ax.scatter(channels[0], channels[1], facecolors=pixel_colors, marker=".")
+
+ ax.set_xlabel(f'Channel {channel_x}')
+ ax.set_ylabel(f'Channel {channel_y}')
+ ax.set_title(f'Color distribution for {channel_x} and {channel_y}')
+
+ fig.suptitle(f'Distribution of pixels of image {image_name} in the {colour_space.name} colour space', fontsize=16,
+ y=1.1)
+ _plt.show()
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/colour_threshold.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/colour_threshold.py
new file mode 100644
index 0000000000000000000000000000000000000000..8988cda7ed347cafd0756ee0516e49c728ef1fc1
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/colour_threshold.py
@@ -0,0 +1,347 @@
+"""
+Module about colour thresholding and segmentation functions.
+"""
+import cv2 as _cv
+import numpy as _np
+from scipy.spatial.distance import cdist as _cdist
+from sklearn.feature_extraction.image import extract_patches_2d as _extract_patches_2d
+from sklearn.mixture import GaussianMixture as _GaussianMixture
+from typing import List as _List, Tuple as _Tuple
+
+from .colour import ColourSpace as _ColourSpace
+from .general import get_highlighted_roi_by_mask as _get_highlighted_roi_by_mask, plot_image_grid as _plot_image_grid
+
+
+def get_k_means_segmented_image(image: _np.ndarray, channels: _Tuple[int, ...] = (0, 1, 2),
+ centers: int = 3) -> _np.ndarray:
+ """
+ Function that applies the K-Means algorithm to a given image in order to quantize the main colours and segment the
+ image accordingly.
+
+ It returns a grayscale segmented version of the image where the regions of the different colours are line-spaced
+ with values between 0 and 255.
+
+ Parameters
+ ----------
+ image: ndarray
+ The colour image to segment
+ channels: Tuple[int, ...]
+ The colour channels to use for quantizing the image
+ centers: int, optional
+ The number of centers to use for applying th K-Means algorithm. It also corresponds to the number of main region
+ of colours that will be found (default: 3)
+
+ Returns
+ -------
+ segmented_image: ndarray
+ The segmented grayscale version of `image`, where the region of different colours are line-spaced with values
+ between 0 and 255
+ """
+ # Set the criteria and the flags
+ criteria = (_cv.TERM_CRITERIA_EPS + _cv.TERM_CRITERIA_MAX_ITER, 10, 1.)
+ flags = _cv.KMEANS_RANDOM_CENTERS
+
+ # Transform the image in a flat float32 array
+ z = _np.copy(image)
+ z = z[:, :, channels]
+ z = z.reshape(-1, len(channels))
+ z = _np.float32(z)
+
+ # Get the labels from K-Means
+ _, labels, _ = _cv.kmeans(z, centers, None, criteria, 10, flags)
+
+ # Line-space the values of the labels between 0 and 255 for clear distinction
+ labels_map = list(_np.linspace(0, 255, num=centers, dtype=_np.uint8))
+ new_labels = _np.copy(labels)
+ for i, l in enumerate(_np.unique(labels)):
+ new_labels[labels == l] = labels_map[i]
+
+ # Get an image segmented according to K-Means
+ segmented_image = new_labels.reshape(image.shape[0], image.shape[1])
+ return segmented_image.astype(_np.uint8)
+
+
+def get_gaussian_mixture_segmented_image(image: _np.ndarray, channels: _List[int], components: int = 3,
+ seed: int = 42) -> _np.ndarray:
+ """
+ Function that applies the Gaussian Mixture algorithm to a given image in order to quantize the main colours and
+ segment the image accordingly.
+
+ It returns a grayscale segmented version of the image where the regions of the different colours are line-spaced
+ with values between 0 and 255.
+
+ Parameters
+ ----------
+ image: ndarray
+ The colour image to segment
+ channels: Tuple[int, ...]
+ The colour channels to use for quantizing the image
+ components: int, optional
+ The number of components to find. It corresponds to the number of main region of colours that will be found
+ (default: 3)
+ seed: int, optional
+ The seed to set for the random number generator of the algorithm (default: 42)
+
+ Returns
+ -------
+ segmented_image: ndarray
+ The segmented grayscale version of `image`, where the region of different colours are line-spaced with values
+ between 0 and 255
+ """
+ # Get the main channels and reshape the image
+ img_r = image[:, :, channels]
+ img_r = img_r.reshape(-1, len(channels))
+
+ # Get the Gaussian Mixture model and fit it on the image
+ gm_model = _GaussianMixture(n_components=components, covariance_type='tied', random_state=seed).fit(img_r)
+
+ # Predict the main colours of the image through the model
+ gmm_labels = gm_model.predict(img_r)
+
+ # Line-space the values of the labels between 0 and 255 for clear distinction
+ labels = gmm_labels.reshape(image.shape[0], image.shape[1])
+ labels_map = list(_np.linspace(0, 255, num=components, dtype=_np.uint8))
+ new_labels = _np.copy(labels)
+ for i, l in enumerate(_np.unique(labels)):
+ new_labels[labels == l] = labels_map[i]
+
+ # Get an image segmented according to the Gaussian Mixture model
+ segmented_image = new_labels.reshape(image.shape[0], image.shape[1])
+ return segmented_image.astype(_np.uint8)
+
+
+def get_roi_samples(roi: _np.ndarray, num_samples: int, patch_size: int, seed: int = 42) -> _List[_np.ndarray]:
+ """
+ Function that automatically samples a given number of squared patches from an image with a Region of Interest. The
+ Region of Interest of the image are the pixels different than 0.
+
+ Parameters
+ ----------
+ roi: ndarray
+ The image with the Region of Interest from which the patches are extracted
+ num_samples: int
+ The number of samples to obtain from the Region of Interest
+ patch_size: int, optional
+ The size of the samples on both dimensions
+ seed: int, optional
+ The seed to set for the random number generator of the algorithm (default: 42)
+
+ Returns
+ -------
+ roi_patches: List[ndarray]
+ The obtained list of samples
+ """
+ # Get all patches of size (`patch_size`, `patch_size`) from the image
+ patches = list(_extract_patches_2d(roi, (patch_size, patch_size), random_state=seed))
+ # Extract just the patches of the ROI (namely the ones where non 0 intensity pixels are present)
+ roi_patches = [p for p in patches if _np.all(p)]
+ # Get index of `num_samples` randomly chosen samples
+ samples_idx = _np.random.choice(_np.arange(len(roi_patches)), num_samples, replace=False)
+ # Get samples based on the obtained random indices
+ return [roi_patches[i] for i in samples_idx]
+
+
+def get_mean_and_inverse_covariance_matrix(samples: _List[_np.ndarray], colour_space: _ColourSpace,
+ channels: _Tuple[int, ...] = (0, 1, 2)) -> _Tuple[_np.ndarray, _np.ndarray]:
+ """
+ Function that computes the mean colour and the inverse covariance colour matrix by a list of samples in a specific
+ colour space and using the given channels.
+
+ Parameters
+ ----------
+ samples: List[ndarray]
+ The samples used to compute the mean colour and the inverse covariance colour matrix
+ colour_space: ColourSpace
+ The colour space the samples are turned to before computing the mean colour and inverse covariance colour matrix
+ on them
+ channels: Tuple[int, ...], optional
+ The channels of the colour space that are used to compute the mean colour and inverse covariance colour matrix
+ (default: all 3)
+
+ Returns
+ -------
+ mean: ndarray
+ The mean colour obtained by the samples
+ inverse_covariance: ndarray
+ The inverse covariance colour matrix obtained by the samples
+ """
+ colour_space_fun = colour_space.bgr_to_colour_space
+ # Get the number of channels
+ channel_num = len(channels)
+
+ # Set an array of 0s of the shape of the covariance matrix
+ covariance_tot = _np.zeros((channel_num, channel_num), dtype=_np.float32)
+ # Set an array of 0s of the shape of a mean vector of the color of the samples
+ mean_tot = _np.zeros((channel_num,), dtype=_np.float32)
+
+ for s in samples:
+ # Turn the sample patch in the selected colour space
+ s_colour_space = colour_space_fun(s)[:, :, channels]
+ # Reshape the sample patch
+ s_colour_space = s_colour_space.reshape(-1, channel_num)
+ # Obtain the covariance matrix and the mean for the patch
+ cov, mean = _cv.calcCovarMatrix(s_colour_space, None, _cv.COVAR_NORMAL + _cv.COVAR_ROWS + _cv.COVAR_SCALE)
+ # Add the obtained mean and the covariance to the ones of the previous patches
+ covariance_tot = _np.add(covariance_tot, cov)
+ mean_tot = _np.add(mean_tot, mean)
+
+ # Divide the sum of means by the number of samples
+ mean = mean_tot / len(samples)
+ # Divide the sum of covariances by the number of samples
+ covariance = covariance_tot / len(samples)
+
+ # Invert covariance with SVD decomposition
+ inv_cov = _cv.invert(covariance, _cv.DECOMP_SVD)[1]
+
+ return mean, inv_cov
+
+
+def get_mahalanobis_distance_segmented_image(image: _np.ndarray, mean: _np.ndarray,
+ inverse_covariance_matrix: _np.ndarray, threshold: float,
+ channels: _Tuple[int, ...] = (0, 1, 2)) -> _np.ndarray:
+ """
+ Function that computes the "Mahalanobis distance" of each pixel of an image from a certain colour according to its
+ mean and its inverse covariance matrix. It then sets at 0 all pixels that have a distance farther or equal to a
+ certain threshold and at 255 all pixels closer than threshold. It finally returns the obtained mask.
+
+ Parameters
+ ----------
+ image: ndarray
+ The image in a certain colour space from which the distance mask according to the "Mahalanobis distance" is
+ computed
+ mean: ndarray
+ The mean of the colour from which the "Mahalanobis distance" is computed
+ inverse_covariance_matrix: ndarray
+ The inverse covariance matrix of the colour from which the "Mahalanobis distance" is computed
+ threshold: float
+ Threshold used to set to 0 all pixels that have a "Mahalanobis distance" farther or equal to it and at 255 all
+ pixels with a distance lower than its value.
+ channels: Tuple[int, ...], optional
+ The channels of the colour space that are used to compute the "Mahalanobis distance" of the image (default: all
+ 3)
+
+ Returns
+ -------
+ mask: ndarray
+ Mask of the pixels of the image with "Mahalanobis distance" lower than threshold
+ """
+ # Get the number of channels of the image
+ channel_num = len(channels)
+ # Turn the mage in the selected colour space and get the requested channels
+ image = image[:, :, channels]
+
+ # Flatten the image and change the type to `float64`
+ img_flattened = image.reshape(-1, channel_num)
+ img_flattened = img_flattened.astype(_np.float64)
+
+ # Get the mahalanobis distance of each pixel
+ img_distances = _cdist(img_flattened, mean, metric='mahalanobis', VI=inverse_covariance_matrix)
+
+ # Reshape the flattened distance image
+ img_distances = img_distances.reshape(image.shape[0], image.shape[1])
+
+ # Obtain a distance mask where pixels more distant than `threshold` are masked
+ mask = _np.copy(img_distances).astype(_np.uint8)
+ mask[img_distances >= threshold] = 0
+ mask[img_distances < threshold] = 255
+ return mask
+
+
+def plot_mahalanobis_segmentation_comparisons(preprocessed_image: _np.ndarray, display_image: _np.ndarray,
+ mean: _np.ndarray, inverse_covariance_matrix: _np.ndarray,
+ thresholds: _List[float], title: str,
+ channels: _Tuple[int, ...] = (0, 1, 2)) -> None:
+ """
+ Function that plots the comparison of the "Mahalanobis distance" colour segmentation of an image given different
+ thresholds.
+
+ Parameters
+ ----------
+ preprocessed_image: ndarray
+ The image in a certain colour space from which the distance mask according to the "Mahalanobis distance" is
+ computed
+ display_image: ndarray
+ The image used to display the distance mask highlighted over it
+ mean: ndarray
+ The mean of the colour from which the "Mahalanobis distance" is computed
+ inverse_covariance_matrix: ndarray
+ The inverse covariance matrix of the colour from which the "Mahalanobis distance" is computed
+ thresholds: List[float]
+ List of thresholds to compare.
+ title: str
+ Title of the plot
+ channels: Tuple[int, ...], optional
+ The channels of the colour space that are used to compute the "Mahalanobis distance" of the image (default: all
+ 3)
+ """
+ highlighted_rois = []
+
+ for threshold in thresholds:
+ mask = get_mahalanobis_distance_segmented_image(preprocessed_image, mean, inverse_covariance_matrix, threshold,
+ channels)
+ highlighted_rois.append(_get_highlighted_roi_by_mask(display_image, mask))
+
+ _plot_image_grid(highlighted_rois, [f'Detected pixels for threshold {t}' for t in thresholds], title)
+
+
+def get_fruit_class(image: _np.ndarray, means: _List[_np.ndarray], inverse_covariance_matrices: _List[_np.ndarray],
+ channels: _Tuple[int, ...] = (1, 2, 3), threshold: float = 3,
+ display_image: _np.ndarray = None) -> int:
+ """
+ Function that computes the class of a fruit given the mean colour and inverse covariance colour matrix of each class
+ in two lists and displays the found pixel for each class if a display image is given.
+
+ The classes are ordinally sorted from 0 onwards and the corresponding colour means and inverse covariance colour
+ matrices are obtained at the corresponding class index in the respective lists (e.g.: `means[0]` and
+ `inverse_covariance_matrices[0]` correspond to the colour mean and inverse covariance colour matrix of the fruit
+ with class 0)
+
+ The number of classes is inferred by the length of the means and inverse covariance matrices lists (e.g.: if the two
+ lists have length 3, there are 3 fruit classes, namely: 0; 1 and 2)
+
+ The means and inverse covariance matrices should refer to the colour of the healthy part of a fruit.
+
+ Parameters
+ ----------
+ image: ndarray
+ The image of a fruit from which the class is computed
+ means: List[ndarray]
+ The mean of the colour from which the "Mahalanobis distance" is computed
+ inverse_covariance_matrices: List[ndarray]
+ The inverse covariance matrix of the colour from which the "Mahalanobis distance" is computed
+ channels: Tuple[int, ...], optional
+ The channels of the colour space that are used to compute the "Mahalanobis distance" of the image (default: all
+ 3)
+ threshold: float, optional
+ Threshold to compute the fruit class according to the colour distance from its healthy part. Pixels of the
+ colour image having a Mahalanobis distance greater than it are not considered part of the corresponding healthy
+ fruit region (default: 3)
+ channels: Tuple[int, ...], optional
+ The channels of the colour space that are used to compute the "Mahalanobis distance" of the image (default: all
+ 3)
+ display_image: ndarray, optional
+ The image used to display the found pixels of each class in `image` (default: None)
+
+ Returns
+ -------
+ class: int
+ The class of the fruit in the image
+ """
+ assert len(means) == len(inverse_covariance_matrices), \
+ 'The list of colour means and inverse covariance colour matrices must be of the same length'
+
+ # Get the masked distance matrices of each class and keep the pixels with distance less than 3
+ masks = [get_mahalanobis_distance_segmented_image(image, m, inv_cov, threshold, channels)
+ for m, inv_cov in zip(means, inverse_covariance_matrices)]
+
+ # Display the found pixels per class if the display image is provided
+ if display_image is not None:
+ _plot_image_grid([_get_highlighted_roi_by_mask(display_image, m) for m in masks],
+ [f'Pixels of class {idx}' for idx in range(len(masks))],
+ 'Detected pixels for each class')
+
+ # Count the number of found pixels per class
+ counts = [_np.count_nonzero(m) for m in masks]
+
+ # Return the class with more found pixels
+ return int(_np.argmax(counts))
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/edge.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/edge.py
new file mode 100644
index 0000000000000000000000000000000000000000..d54b252b9afd8e929daed90056fe92beae742e40
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/edge.py
@@ -0,0 +1,68 @@
+"""
+Module about edge detection functions.
+"""
+import cv2 as _cv
+import numpy as _np
+import math as _math
+
+from .general import get_highlighted_roi_by_mask
+
+
+def apply_gaussian_blur_and_canny(image: _np.ndarray, sigma: float, threshold_1: float,
+ threshold_2: float) -> _np.ndarray:
+ """
+ Function that blurs the image through Gaussian Blur and then applies Canny's edge detection algorithm on it.
+
+ Parameters
+ ----------
+ image: ndarray
+ Image to blur and apply edge detection on
+ sigma: float
+ Sigma value of the Gaussian Blur function
+ threshold_1: float
+ First threshold used for the Hysteresis step. If a pixel gradient value is below it, then it is rejected
+ threshold_2: float
+ Second threshold used for the Hysteresis step. If a pixel gradient is higher than it, the pixel is accepted as
+ an edge. If the pixel gradient is between the two thresholds, then it will be accepted only if it is connected
+ to a pixel that is above `threshold_2`
+
+ Returns
+ -------
+ edge_mask: ndarray
+ Grayscale image showing the edges of the input image
+ """
+ # Compute the kernel size through the rule-of-thumb
+ k = _math.ceil(3 * sigma)
+ kernel_size = (2 * k + 1, 2 * k + 1)
+
+ # Apply Gaussian Blur on the image
+ blur_image = _cv.GaussianBlur(image, kernel_size, sigma)
+
+ # Get the edges of the image through Canny's Algorithm
+ return _cv.Canny(blur_image, threshold_1, threshold_2)
+
+
+def get_highlighted_edges_on_image(image: _np.ndarray, edge_mask: _np.ndarray, size: int = 3,
+ highlight_channel: str = 'red') -> _np.ndarray:
+ """
+ Function that highlights edges on an image.
+
+ Parameters
+ ----------
+ image: ndarray
+ Image over which the edges are highlighted
+ edge_mask: ndarray
+ Grayscale image showing the edges of the input image
+ size: int, optional
+ The size of the edges to highlight (default: 3)
+ highlight_channel: str, optional
+ Colour of the highlighted edges: 'blue'; 'green' or 'red' (default: 'red')
+
+ Returns
+ -------
+ highlighted_edges: ndarray
+ Highlighted edges over the input image
+ """
+ element = _cv.getStructuringElement(_cv.MORPH_RECT, (size, size))
+ dilated_edge_mask = _cv.dilate(edge_mask, element)
+ return get_highlighted_roi_by_mask(image, dilated_edge_mask, highlight_channel)
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/general.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/general.py
new file mode 100644
index 0000000000000000000000000000000000000000..0c095fae1c4de8ceb4ea89ffaa277ddcce1fc585
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/general.py
@@ -0,0 +1,202 @@
+"""
+Module about general plotting and image transformation functions.
+"""
+import cv2 as _cv
+import numpy as _np
+import matplotlib.pyplot as _plt
+from matplotlib import ticker as _ticker
+from typing import List as _List
+
+from .colour import ColourSpace as _ColourSpace
+
+
+def plot_image_grid(images: _List[_np.ndarray], images_names: _List[str] = None, title: str = None) -> None:
+ """
+ Function that plots a series of images as a row grid.
+
+ Parameters
+ ----------
+ images: List[ndarray]
+ List of images to plot as a row grid
+ images_names: List[str], optional
+ List of the names of the images to plot
+ title: str, optional
+ Title of the plot
+ """
+
+ assert images_names is None or len(images_names) == len(images), \
+ '`images_names` must not be provided or it must have the same size as `images`.'
+
+ fig = _plt.figure(figsize=(15, 5), constrained_layout=True)
+ if title is not None:
+ fig.suptitle(title, fontsize=16)
+ else:
+ fig.suptitle('', fontsize=16)
+ for idx, img in enumerate(images):
+ # Add an ax to the plot
+ _plt.subplot(1, len(images), idx + 1)
+ # Remove the numerical axes from the image
+ _plt.axis('off')
+ # If the image has three dimensions plot it as a color image, otherwise as a grayscale one
+ if len(img.shape) == 3:
+ _plt.imshow(_cv.cvtColor(img, _cv.COLOR_BGR2RGB))
+ else:
+ _plt.imshow(img, cmap='gray', vmin=0, vmax=255)
+ if images_names is not None:
+ _plt.title(images_names[idx])
+ _plt.show()
+
+
+def plot_histogram_grid(images: _List[_np.ndarray], images_names: _List[str] = None, title: str = None) -> None:
+ """
+ Function that plots the histograms of a series of grayscale images as a row grid.
+
+ Parameters
+ ----------
+ images: List[ndarray]
+ List of grayscale images which histograms are plotted as a row grid
+ images_names: List[str], optional
+ List of the names of the images which histograms are plotted
+ title: str, optional
+ Title of the plot
+ """
+ assert images_names is None or len(images_names) == len(images), \
+ '`images_names` must not be provided or it must have the same size as `images`.'
+
+ fig = _plt.figure(figsize=(20, 13))
+ if title is not None:
+ fig.suptitle(title, fontsize=20)
+ for idx, img in enumerate(images):
+ # Add an ax to the plot
+ _plt.subplot(2, len(images), idx + 1)
+ # Obtain the gray-level histogram
+ hist, _ = _np.histogram(img.flatten(), 256, [0, 256])
+ # Plot the histogram
+ _plt.stem(hist, use_line_collection=True)
+ _plt.xlabel('gray levels', fontsize=13)
+ _plt.ylabel('pixels', fontsize=13)
+ if images_names is not None:
+ _plt.title(images_names[idx])
+ _plt.show()
+
+
+def get_highlighted_roi_by_mask(image: _np.ndarray, mask: _np.ndarray, highlight_channel: str = 'green') -> _np.ndarray:
+ """
+ Function that highlights a Region of Interest provided by a mask over an image with a given BGR colour.
+
+ Parameters
+ ----------
+ image: ndarray
+ Image on which the mask is highlighted
+ mask: ndarray
+ Mask illustrating the Region of Interest to highlight over the mage
+ highlight_channel: str, optional
+ Colour of the highlighted mask: 'blue'; 'green' or 'red' (default: 'green')
+
+ Returns
+ -------
+ highlighted_roi: ndarray
+ Highlighted Region of Interest over the input image
+ """
+ channel_map = {'blue': 0, 'green': 1, 'red': 2}
+ # Turn img into BGR image if img is a Grayscale image
+ if len(image.shape) == 2:
+ image = _cv.cvtColor(image, _cv.COLOR_GRAY2BGR)
+ # Turn mask into BGR image if img is a BGR image
+ mask = _cv.cvtColor(mask, _cv.COLOR_GRAY2BGR)
+ # Force the bits of every channel except the selected one at 0
+ mask[:, :, [i for i in range(3) if i != channel_map[highlight_channel]]] = 0
+ # Highlight the unmasked ROI
+ return _cv.addWeighted(mask, 0.3, image, 1, 0)
+
+
+def plot_image_histogram_2d(image: _np.ndarray, image_name: str, colour_space: _ColourSpace, bins: int = 32,
+ tick_spacing: int = 5) -> None:
+ """
+ Function that plots the 2D histograms of an image considering all different couples of channels.
+
+ Parameters
+ ----------
+ image: ndarray
+ Image of which the 2D histograms are plotted
+ image_name: str
+ Name of the image of which the 2D histograms are plotted
+ colour_space: ColourSpace
+ Colour space considered to plot the2D histograms of the image
+ bins: int, optional
+ bins to use in the histogram (default: 32)
+ tick_spacing: int, optional
+ Tick spacing of the axes of the histograms (default: 5)
+ """
+ fig, axes = _plt.subplots(1, 3, figsize=(15, 5))
+
+ channels_mapping = {idx: ch for idx, ch in enumerate(colour_space.channels)}
+
+ # Turn the colored image into the defined colour space
+ image = colour_space.bgr_to_colour_space(image)
+
+ for idx, channels in enumerate([[0, 1], [0, 2], [1, 2]]):
+ hist = _cv.calcHist([image], channels, None, [bins] * 2, [0, 256] * 2)
+
+ channel_x = channels_mapping[channels[0]]
+ channel_y = channels_mapping[channels[1]]
+
+ ax = axes[idx]
+ ax.set_xlim([0, bins - 1])
+ ax.set_ylim([0, bins - 1])
+
+ ax.set_xlabel(f'Channel {channel_x}')
+ ax.set_ylabel(f'Channel {channel_y}')
+ ax.set_title(f'2D Color Histogram for {channel_x} and '
+ f'{channel_y}')
+
+ ax.yaxis.set_major_locator(_ticker.MultipleLocator(tick_spacing))
+ ax.xaxis.set_major_locator(_ticker.MultipleLocator(tick_spacing))
+
+ im = ax.imshow(hist)
+
+ fig.colorbar(im, ax=axes.ravel().tolist(), orientation='horizontal')
+ fig.suptitle(f'2D Colour Histograms of image {image_name} with {bins} bins in colour space {colour_space.name}',
+ fontsize=16)
+ _plt.show()
+
+
+def get_largest_blob_in_mask(mask: _np.ndarray) -> _np.ndarray:
+ """
+ Function to get the largest blob in a binary mask.
+
+ Parameters
+ ----------
+ mask: ndarray
+ The mask from which the largest blob is extracted
+
+ Returns
+ -------
+ mask_with_largest_blob: ndarray
+ The mask with solely the largest blob
+ """
+ contours, _ = _cv.findContours(mask, _cv.RETR_EXTERNAL, _cv.CHAIN_APPROX_NONE)
+ max_contour = max(contours, key=_cv.contourArea)
+ out = _np.zeros(mask.shape, _np.uint8)
+ return _cv.drawContours(out, [max_contour], -1, 255, _cv.FILLED)
+
+
+def apply_mask_to_image(image: _np.ndarray, mask: _np.ndarray):
+ """
+ Function that applies a mask over an image
+
+ Parameters
+ ----------
+ image: ndarray
+ Image to apply the mask over
+ mask: ndarray
+ Mask to apply over the image
+
+ Returns
+ -------
+ masked_image: ndarray
+ The masked image
+ """
+ if len(image.shape) == 3:
+ mask = _cv.cvtColor(mask, _cv.COLOR_GRAY2BGR)
+ return image & mask
diff --git a/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/threshold.py b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/threshold.py
new file mode 100644
index 0000000000000000000000000000000000000000..cdaf732d354a1f6464816139a2cdb6e838f440cb
--- /dev/null
+++ b/Backend/Fruit_Freshness/Fruit-Inspection-main/Fruit-Inspection-main/src/utils/threshold.py
@@ -0,0 +1,388 @@
+"""
+Module about thresholding and segmentation functions.
+"""
+import cv2 as _cv
+from enum import Enum as _Enum
+import numpy as _np
+from time import time as _time
+from typing import Any as _Any, List as _List, Tuple as _Tuple, Union as _Union
+
+from .general import plot_image_grid as _plot_image_grid, get_highlighted_roi_by_mask as _get_highlighted_roi_by_mask
+
+
+class ThresholdingMethod(_Enum):
+ """Methods to use for binary thresholding"""
+ MANUAL = 0, "Manual Intensity binarization"
+ OTSU = 1, "Otsu's Algorithm"
+ TWEAKED_OTSU = 2, "Tweaked Otsu's Algorithm"
+ ADAPTIVE = 3, "Local Adaptive Thresholding"
+
+
+_THRESHOLDING_NAMES = {
+ ThresholdingMethod.MANUAL: 'Manual Intensity Binarization',
+ ThresholdingMethod.OTSU: "Otsu's Algorithm",
+ ThresholdingMethod.TWEAKED_OTSU: "Tweaked Otsu's Algorithm",
+ ThresholdingMethod.ADAPTIVE: "Adaptive Thresholding"
+}
+
+
+def _threshold_by_method(image: _np.ndarray, method: ThresholdingMethod,
+ **kwargs: _Any) -> _Tuple[_Union[float, None], _np.ndarray]:
+ """
+ Function that applies a binary thresholding function on an image given a specific method and eventual other named
+ parameters (`**kwargs`).
+
+ It returns in the given order the found threshold (just for global thresholding methods) and the segmentation mask
+ of the image obtained by applying the threshold over itself.
+ The "Local Adaptive" method returns `None` as a threshold since it does not find a global value for it.
+
+ Parameters
+ ----------
+ image: ndarray
+ The grayscale image from which the binary segmentation mask is obtained
+ method: ThresholdingMethod
+ Enum of the method to choose to apply the thresholding binarization of the image
+ **kwargs: Any
+ Keyword arguments that are passed to the thresholding functions described by method (`manual_threshold`,
+ `otsu_threshold`, `tweaked_otsu_threshold`, `adaptive_threshold_and_flood_fill_background`).
+ They include: `threshold` just for `MANUAL` method; `tweak_factor` just for `TWEAKED_OTSU` method; `block_size`
+ and `c` just for `ADAPTIVE` method
+
+ Returns
+ -------
+ threshold: Union[float, None]
+ The binarization threshold found by the algorithm
+ mask: ndarray
+ The binary segmentation mask of `image`
+ """
+ if method == ThresholdingMethod.MANUAL:
+ assert kwargs['threshold'] is not None, f'{_THRESHOLDING_NAMES[method]} needs parameter `threshold`.'
+ return manual_threshold(image, kwargs['threshold'])
+ elif method == ThresholdingMethod.OTSU:
+ return otsu_threshold(image)
+ elif method == ThresholdingMethod.TWEAKED_OTSU:
+ assert kwargs['tweak_factor'] is not None, \
+ f'{_THRESHOLDING_NAMES[method]} needs parameter `tweak_factor`.'
+ return tweaked_otsu_threshold(image, kwargs['tweak_factor'])
+ elif method == ThresholdingMethod.ADAPTIVE:
+ assert kwargs['block_size'] is not None and kwargs['c'] is not None, \
+ f'{_THRESHOLDING_NAMES[method]} needs parameters `block_size` and `c`.'
+ return adaptive_threshold_and_flood_fill_background(image, kwargs['block_size'], kwargs['c'])
+ else:
+ raise KeyError('Method is not valid')
+
+
+def get_fruit_segmentation_mask(image: _np.ndarray, method: ThresholdingMethod, **kwargs: _Any) -> _np.ndarray:
+ """
+ Function that returns a binary segmented mask on an image given a specific method and eventual other named
+ parameters (`**kwargs`), Then flood-fills it in order to fill the possible black holes inside of the white mask.
+
+ Parameters
+ ----------
+ image: ndarray
+ The grayscale image from which the binary segmentation mask is obtained
+ method: ThresholdingMethod
+ Enum of the method to choose to apply the thresholding segmentation masking of the image
+ **kwargs: Any
+ Keyword arguments that are passed to the thresholding functions described by method (`manual_threshold`,
+ `otsu_threshold`, `tweaked_otsu_threshold`, `adaptive_threshold_and_flood_fill_background`).
+ They include: `threshold` just for `MANUAL` method; `tweak_factor` just for `TWEAKED_OTSU` method; `block_size`
+ and `c` just for `ADAPTIVE` method
+
+ Returns
+ -------
+ mask: ndarray
+ The binary segmentation mask of `image` obtained according to a certain given or found threshold processed
+ through flood-filling
+ """
+ _, mask = _threshold_by_method(image, method, **kwargs)
+ return apply_flood_fill_to_segmentation_mask(mask)
+
+
+def manual_threshold(image: _np.ndarray, threshold: float) -> _Tuple[float, _np.ndarray]:
+ """
+ Function that applies a "Global Intensity Binarization" thresholding function on an image given a specific manual
+ threshold.
+
+ It returns in the given order the given threshold and the segmentation mask of the image obtained by applying the
+ threshold over itself.
+
+ Parameters
+ ----------
+ image: ndarray
+ The grayscale image from which the binary segmentation mask is obtained
+ threshold: float
+ The threshold to use to binarize the image
+
+ Returns
+ -------
+ threshold: float
+ The segmentation threshold given to the algorithm
+ mask: ndarray
+ The binary segmentation mask of `image` obtained according to `threshold`
+ """
+ return _cv.threshold(image, threshold, 255, _cv.THRESH_BINARY)
+
+
+def otsu_threshold(image: _np.ndarray) -> _Tuple[float, _np.ndarray]:
+ """
+ Function that applies "Otsu's Algorithm" to find a global threshold and obtain the binary segmentation mask of an
+ image according to it.
+
+ It returns in the given order the found threshold and the segmentation mask of the image obtained by applying the
+ threshold over itself.
+
+ Parameters
+ ----------
+ image: ndarray
+ The grayscale image from which the binary segmentation mask is obtained
+
+ Returns
+ -------
+ threshold: float
+ The segmentation threshold found by the algorithm
+ mask: ndarray
+ The binary segmentation mask of `image` obtained according to `threshold`
+ """
+ return _cv.threshold(image, 0, 255, _cv.THRESH_BINARY + _cv.THRESH_OTSU)
+
+
+def tweaked_otsu_threshold(image: _np.ndarray, tweak_factor: float) -> _Tuple[float, _np.ndarray]:
+ """
+ Function that applies "Otsu's Algorithm" to find a global threshold and then multiplies it by a "tweak factor" in
+ order to obtain a tweaked threshold and apply it to find the binary segmentation mask of an image according to it.
+
+ It returns in the given order the found tweaked threshold and the segmentation mask of the image obtained by
+ applying the threshold over itself.
+
+ Parameters
+ ----------
+ image: ndarray
+ The grayscale image from which the binary segmentation mask is obtained
+ tweak_factor: float
+ Value that will be multiplied to the value of the threshold obtained by "Otsu's Algorithm" in order to tweak it
+
+ Returns
+ -------
+ threshold: float
+ The segmentation threshold found by the algorithm
+ mask: ndarray
+ The binary mask of `image` obtained according to `threshold`
+ """
+ # Get threshold by Otsu
+ threshold, _ = _cv.threshold(image, 0, 255, _cv.THRESH_BINARY + _cv.THRESH_OTSU)
+ # Tweak the threshold
+ desired_threshold = threshold * tweak_factor
+ # Apply "Manual Intensity Binarization" using the new computed threshold
+ return _cv.threshold(image, desired_threshold, 255, _cv.THRESH_BINARY)
+
+
+def adaptive_threshold_and_flood_fill_background(image: _np.ndarray, block_size: int,
+ c: int) -> _Tuple[None, _np.ndarray]:
+ """
+ Function that applies a "Local Adaptive" thresholding method to obtain the binary segmentation mask of an image,
+ then applies flood-fill in order to get a full black background.
+
+ It returns in the given order `None`, since a global threshold is not computed, and the obtained segmentation mask
+ of the image.
+
+ Parameters
+ ----------
+ image: ndarray
+ The grayscale image from which the binary segmentation mask is obtained
+ block_size: int
+ The size of the window of pixel neighbours used to compute the threshold of each pixel through "Local Adaptive"
+ method
+ c: int
+ Constant subtracted from the mean computed by the "Local Adaptive" method for each pixel
+
+ Returns
+ -------
+ _: None
+ Since no global threshold can be found by the method, `None` is returned
+ mask: ndarray
+ The binary segmentation mask of `image` obtained after the "Local Adaptive" method and the flood-filling
+ """
+ mask = _cv.adaptiveThreshold(image, 255, _cv.ADAPTIVE_THRESH_MEAN_C, _cv.THRESH_BINARY, block_size, c)
+ mask = _np.pad(mask, 1, mode='constant', constant_values=255)
+ _cv.floodFill(mask, None, (0, 0), 0)
+ mask = mask[1:-1, 1:-1]
+ return None, mask
+
+
+def apply_flood_fill_to_segmentation_mask(image: _np.ndarray) -> _np.ndarray:
+ """
+ Function that applies a flood-filling on a binary segmentation mask in order to remove possible small holes inside
+ of it.
+
+ Parameters
+ ----------
+ image: ndarray
+ The binary segmentation mask to flood-fill
+
+ Returns
+ -------
+ mask: ndarray
+ The flood-filled segmentation mask
+ """
+ # Copy the threshold-ed image
+ img_flood_filled = image.copy()
+
+ # Pad image to guarantee that all the background is flood-filled
+ img_flood_filled = _np.pad(img_flood_filled, 1, mode='constant', constant_values=0)
+
+ # Mask used to flood filling
+ # The size needs to be 2 pixel larger than the image
+ h, w = img_flood_filled.shape[:2]
+ mask = _np.zeros((h + 2, w + 2), _np.uint8)
+
+ # Flood-fill from the upper-left corner (point (0, 0))
+ _cv.floodFill(img_flood_filled, mask, (0, 0), 255)
+
+ # Down-sample the image to its original size
+ img_flood_filled = img_flood_filled[1:-1, 1:-1]
+
+ # Invert the flood-filled image
+ img_copy_inv = ~img_flood_filled
+
+ # Combine the original and inverted flood-filled image to obtain the foreground
+ return image + img_copy_inv
+
+
+def plot_segmentation_process(gray_images: _List[_np.ndarray], display_images: _List[_np.ndarray],
+ images_names: _List[str], method: ThresholdingMethod, **kwargs: _Any) -> None:
+ """
+ Function that plots the binary segmentation masking process of a series of images given a specific thresholding
+ method and eventual other named parameters (`**kwargs`)
+
+ For each image it shows:
+ - The segmentation mask obtained by the method.
+ - The segmentation mask after flood-filling.
+ - The segmentation mask applied on a version of the initial image used for display purposes (For instance the
+ color version of the image)
+
+ Parameters
+ ----------
+ gray_images: List[ndarray]
+ The grayscale images for which the masking process is shown
+ display_images: List[ndarray]
+ Images corresponding to `gray_images`, used for displaying the computed binary segmentation masks over them.
+ images_names: List[str]
+ Names of the images from which the binary segmentation masks are computed
+ method: ThresholdingMethod
+ Enum of the method to choose to apply the thresholding segmentation masking of the images
+ **kwargs: Any
+ Keyword arguments that are passed to the thresholding functions described by method (`manual_threshold`,
+ `otsu_threshold`, `tweaked_otsu_threshold`, `adaptive_threshold_and_flood_fill_background`).
+ They include: `threshold` just for `MANUAL` method; `tweak_factor` just for `TWEAKED_OTSU` method; `block_size`
+ and `c` just for `ADAPTIVE` method
+ """
+ masks = []
+ thresholds = []
+
+ # Compute the mask and th threshold of each image
+ for image in gray_images:
+ threshold, mask = _threshold_by_method(image, method, **kwargs)
+ thresholds.append(threshold)
+ masks.append(mask)
+
+ # Flood fill the masks
+ flood_filled_masks = [apply_flood_fill_to_segmentation_mask(i) for i in masks]
+
+ # Highlight the masks over the display images
+ highlighted_images = [_get_highlighted_roi_by_mask(d, m) for d, m in zip(display_images, flood_filled_masks)]
+
+ # Plot the segmentation process of each image
+ for m, t, ffm, h, n in zip(masks, thresholds, flood_filled_masks, highlighted_images, images_names):
+ processed_images_names = [
+ f'Binary segmentation mask {f" (threshold = {t})" if t is not None else ""}',
+ 'Flood-filled segmentation mask',
+ 'Outlined fruit'
+ ]
+ _plot_image_grid([m, ffm, h], processed_images_names,
+ f'Outline of the fruits obtained through {_THRESHOLDING_NAMES[method]} for image {n}')
+
+
+# TODO: Remove Method
+def segment_fruit_and_plot(gray_images: _List[_np.ndarray], display_images: _List[_np.ndarray],
+ images_names: _List[str], method: ThresholdingMethod, title: str = None,
+ **kwargs: _Any) -> None:
+ masks = []
+ thresholds = []
+
+ for image in gray_images:
+ threshold, mask = _threshold_by_method(image, method, **kwargs)
+ thresholds.append(threshold)
+ masks.append(mask)
+
+ masks = [apply_flood_fill_to_segmentation_mask(i) for i in masks]
+
+ highlighted_images = [_get_highlighted_roi_by_mask(d, m) for d, m in zip(display_images, masks)]
+
+ processed_images_names = [f'Image {n} {f" (threshold = {t})" if t is not None else ""}'
+ for n, t in zip(images_names, thresholds)]
+
+ if title is None:
+ title = f'Outline of the fruits obtained through {_THRESHOLDING_NAMES[method]}'
+
+ _plot_image_grid(highlighted_images, processed_images_names, title)
+
+
+# TODO: Remove Method
+def plot_thresholding_on_light_and_dark_images(dark_images: _List[_np.ndarray], light_images: _List[_np.ndarray],
+ images_names: _List[str], method: ThresholdingMethod,
+ **kwargs: _Any) -> None:
+ segment_fruit_and_plot(dark_images, dark_images, images_names, method,
+ f'Outline of the fruits obtained through {_THRESHOLDING_NAMES[method]} on darker images',
+ **kwargs)
+ segment_fruit_and_plot(light_images, light_images, images_names, method,
+ f'Outline of the fruits obtained through {_THRESHOLDING_NAMES[method]} on lighter images',
+ **kwargs)
+
+
+def get_segmentation_time(images: _List[_np.ndarray], method: ThresholdingMethod, repeats: int = 1_000,
+ **kwargs: _Any) -> _Tuple[float, float]:
+ """
+ Function that computes the total time needed to apply segmentation and flood-filling on a series of images with a
+ given number of repetitions. Moreover, the mean time per image is obtained by the function.
+
+ Additionally, the functions prints the total and mean segmentation times.
+
+ Parameters
+ ----------
+ images: List[ndarray]
+ The grayscale images for which the time of the segmentation process is computed
+ method: ThresholdingMethod
+ Enum of the method to choose to apply the thresholding segmentation of the images
+ repeats: int, optional
+ Number of time the segmentation process is repeated for each image (default: 1,000)
+ **kwargs: Any
+ Keyword arguments that are passed to the thresholding functions described by method (`manual_threshold`,
+ `otsu_threshold`, `tweaked_otsu_threshold`, `adaptive_threshold_and_flood_fill_background`).
+ They include: `threshold` just for `MANUAL` method; `tweak_factor` just for `TWEAKED_OTSU` method; `block_size`
+ and `c` just for `ADAPTIVE` method
+
+ Returns
+ -------
+ total_time: float
+ Total time needed for the segmentation process of the images with the given repetitions
+ mean_time: float
+ Mean time needed to segment an image
+ """
+ # Compute the initial time
+ s = _time()
+
+ # Mask the images with repetitions
+ for img in images * repeats:
+ get_fruit_segmentation_mask(img, method, **kwargs)
+
+ # Get total time according to the initial time and mean time per image
+ total_time = _time() - s
+ mean_time = total_time / (len(images) * repeats)
+
+ # Print the total and mean time
+ print(f'Total time to perform {_THRESHOLDING_NAMES[method]} on {repeats * len(images)} ',
+ f'images = {total_time:.6f}')
+ print(f'Mean time per instance to perform {_THRESHOLDING_NAMES[method]} = {mean_time:.6f}')
+
+ return total_time, mean_time
diff --git a/Backend/OCR/Dynamic/VideoOCR.py b/Backend/OCR/Dynamic/VideoOCR.py
new file mode 100644
index 0000000000000000000000000000000000000000..f28cc1e46464ce98495249f258d7afc71688ddcb
--- /dev/null
+++ b/Backend/OCR/Dynamic/VideoOCR.py
@@ -0,0 +1,168 @@
+# Import necessary libraries
+import cv2
+from paddleocr import PaddleOCR, draw_ocr
+
+import os
+import csv
+import numpy as np
+import gradio as gr
+import google.generativeai as genai
+import pandas as pd
+
+
+# Define paths
+ocr = PaddleOCR(use_angle_cls=True, lang='en')
+GOOGLE_API_KEY = os.getenv("GEMINI_API")
+genai.configure(api_key=GOOGLE_API_KEY)
+
+
+# Function to add branding to a frame
+def add_branding(frame, text="Abhinav Video OCR", position=(50, 50), font_scale=2, font_thickness=3,
+ text_color=(255, 255, 255), bg_color=(0, 0, 0)):
+ overlay = frame.copy()
+ alpha = 0.6 # Transparency factor
+
+ # Get the width and height of the text box
+ (text_width, text_height), _ = cv2.getTextSize(text, cv2.FONT_HERSHEY_SIMPLEX, font_scale, font_thickness)
+ x, y = position
+
+ # Draw a rectangle and put the text on it
+ cv2.rectangle(overlay, (x, y + 10), (x + text_width, y - text_height - 10), bg_color, -1)
+ cv2.addWeighted(overlay, alpha, frame, 1 - alpha, 0, frame)
+ cv2.putText(frame, text, position, cv2.FONT_HERSHEY_SIMPLEX, font_scale, text_color, font_thickness)
+
+ return frame
+
+# Function to preprocess the frame for OCR
+def preprocess_frame(frame, resize_width=600):
+ resized = cv2.resize(frame, (resize_width, int(frame.shape[0] * (resize_width / frame.shape[1]))))
+ gray = cv2.cvtColor(resized, cv2.COLOR_BGR2GRAY)
+ return gray, resized
+def parse_gemini_response(response_text):
+ parsed_data = {
+ "Manufacturing Date": "",
+ "Expiry Date": "",
+ "MRP Details": ""
+ }
+ for line in response_text.split("\n"):
+ if line.startswith("Manufacturing Date:"):
+ parsed_data["Manufacturing Date"] = line.split("Manufacturing Date:")[1].strip()
+ elif line.startswith("Expiry Date:"):
+ parsed_data["Expiry Date"] = line.split("Expiry Date:")[1].strip()
+ elif line.startswith("MRP Details:"):
+ parsed_data["MRP Details"] = line.split("MRP Details:")[1].strip()
+ return parsed_data
+
+# Function to call Gemini LLM for date predictions
+def call_gemini_llm_for_dates(text):
+ # Use the previously set up Gemini model for predictions
+ model = genai.GenerativeModel('models/gemini-1.5-flash')
+ prompt = f"""
+ You are provided with extracted words from a product's packaging. Based on this text, your task is to predict the manufacturing and expiry dates of the product.
+
+ Please follow these rules:
+ - If only one date is present, consider it to be the expiry date.
+ - Ignore any noise or irrelevant information.
+ - Predict the most logical manufacturing and expiry dates based on the context provided.
+ - Output the dates strictly in the format:
+ Manufacturing Date: DD/MM/YYYY
+ Expiry Date: DD/MM/YYYY
+ - Do not generate any other information or text besides the two dates.
+
+ Here is the extracted text:
+ {text}
+ """
+
+ # Send the prompt to Gemini model and get the response
+ response = model.generate_content(prompt)
+ print(response.text)
+
+ return response.text.strip()
+
+
+
+# Gradio function to process the video
+def gradio_video_ocr_processing(video_file):
+ input_video_path = video_file
+ output_video_path = "annotated_video.mp4"
+ output_text_file = "detected_words.csv"
+
+ print("[DEBUG] Starting video processing.")
+ cap = cv2.VideoCapture(input_video_path)
+ if not cap.isOpened():
+ print("[ERROR] Cannot open video file.")
+ return None, "Error: Cannot open video file."
+
+ input_frame_rate = cap.get(cv2.CAP_PROP_FPS)
+ print(f"[DEBUG] Input video frame rate: {input_frame_rate} FPS.")
+
+ fourcc = cv2.VideoWriter_fourcc(*'mp4v')
+ out = None
+ frame_skip = 2
+ resize_width = 600
+ detected_words = [["Frame", "Word", "Confidence", "X", "Y", "Width", "Height"]]
+ frame_count = 0
+
+ while cap.isOpened():
+ ret, frame = cap.read()
+ if not ret:
+ print("[DEBUG] End of video stream.")
+ break
+
+ if frame_count % frame_skip != 0:
+ frame_count += 1
+ continue
+
+ # Preprocess frame
+ gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+ resized_frame = cv2.resize(gray, (resize_width, int(frame.shape[0] * resize_width / frame.shape[1])))
+ print(f"[DEBUG] Processing frame {frame_count}.")
+
+ # OCR processing with PaddleOCR
+ # OCR processing with PaddleOCR
+ results = ocr.ocr(resized_frame)
+ if results[0] is not None:
+ for line in results[0]:
+ word, confidence = line[1][0], float(line[1][1])
+ if confidence > 0.7:
+ bbox = line[0]
+ x_min, y_min = int(bbox[0][0]), int(bbox[0][1])
+ x_max, y_max = int(bbox[2][0]), int(bbox[2][1])
+ detected_words.append([frame_count, word, confidence, x_min, y_min, x_max - x_min, y_max - y_min])
+
+ # Annotate the frame
+ frame = cv2.rectangle(frame, (x_min, y_min), (x_max, y_max), (0, 255, 0), 2)
+ frame = cv2.putText(frame, f"{word} ({confidence:.2f})", (x_min, y_min - 10),
+ cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
+ else:
+ print(f"[DEBUG] No text detected in frame {frame_count}.")
+
+ frame = add_branding(frame)
+ if out is None:
+ out = cv2.VideoWriter(output_video_path, fourcc, input_frame_rate // frame_skip,
+ (frame.shape[1], frame.shape[0]))
+ out.write(frame)
+ frame_count += 1
+
+ cap.release()
+ if out is not None:
+ out.release()
+ cv2.destroyAllWindows()
+
+ # Save detected words to CSV
+ with open(output_text_file, 'w', newline='', encoding='utf-8') as file:
+ writer = csv.writer(file)
+ writer.writerows(detected_words)
+ print(f"[INFO] Detected words saved to {output_text_file}.")
+ print(f"[INFO] Annotated video saved to {output_video_path}.")
+
+ # Generate Gemini response
+ ocr_results_df = pd.read_csv(output_text_file)
+ detected_text = " ".join(ocr_results_df['Word'].dropna())
+ gemini_response = call_gemini_llm_for_dates(detected_text)
+ parsed_output = parse_gemini_response(gemini_response)
+
+ print("[DEBUG] Gemini response generated.")
+ return output_video_path, gemini_response, parsed_output
+
+
diff --git a/Backend/OCR/Static/ImageOCR.py b/Backend/OCR/Static/ImageOCR.py
new file mode 100644
index 0000000000000000000000000000000000000000..64867432349dabf55099fe0024a9a5825ed95173
--- /dev/null
+++ b/Backend/OCR/Static/ImageOCR.py
@@ -0,0 +1,801 @@
+<<<<<<< HEAD
+import os
+import cv2
+import numpy as np
+from PIL import Image
+import matplotlib.pyplot as plt
+from paddleocr import PaddleOCR
+import gradio as gr
+import google.generativeai as genai
+
+GOOGLE_API_KEY = os.getenv("GEMINI_API")
+
+def new_draw_bounding_boxes(image):
+ """Draw bounding boxes around detected text in the image and display it."""
+ try:
+ # Check the input type and load the image
+ if isinstance(image, str):
+ img = Image.open(image)
+ np_img = np.array(img) # Convert to NumPy array
+ print("[DEBUG] Loaded image from file path.")
+ elif isinstance(image, Image.Image):
+ np_img = np.array(image) # Convert PIL Image to NumPy array
+ print("[DEBUG] Converted PIL Image to NumPy array.")
+ else:
+ raise ValueError("Input must be a file path or a PIL Image object.")
+
+ # Perform OCR on the array
+ ocr_result = ocr.ocr(np_img, cls=True) # Ensure this line is error-free
+ print("[DEBUG] OCR Result:\n", ocr_result)
+
+ # Create a figure to display the image
+ plt.figure(figsize=(10, 10))
+ plt.imshow(image)
+ ax = plt.gca()
+ all_text_data = []
+
+ # Iterate through the OCR results and draw boxes
+ for idx, line in enumerate(ocr_result[0]):
+ box = line[0] # Get the bounding box coordinates
+ text = line[1][0] # Extracted text
+ print(f"[DEBUG] Box {idx + 1}: {text}") # Debug print
+ all_text_data.append(text)
+
+ # Draw the bounding box
+ polygon = plt.Polygon(box, fill=None, edgecolor='red', linewidth=2)
+ ax.add_patch(polygon)
+
+ # Add text label with a small offset for visibility
+ x, y = box[0][0], box[0][1]
+ ax.text(x, y - 5, f"{idx + 1}: {text}", color='blue', fontsize=12, ha='left')
+
+ plt.axis('off') # Hide axes
+ plt.title("Detected Text with Bounding Boxes", fontsize=16) # Add a title
+ plt.show()
+
+ return all_text_data
+
+ except Exception as e:
+ print(f"[ERROR] Error in new_draw_bounding_boxes: {e}")
+ return []
+
+
+
+def gemini_context_correction(text):
+ """Use Gemini API to refine noisy OCR results and extract MRP details."""
+ model = genai.GenerativeModel('models/gemini-1.5-flash')
+
+ response = model.generate_content(
+ f"Identify and extract manufacturing, expiration dates, and MRP from the following text. "
+ f"The dates may be written in dd/mm/yyyy format or as or . "
+ f"The text may contain noise or unclear information. If only one date is provided, assume it is the Expiration Date. "
+ f"Additionally, extract the MRP (e.g., 'MRP: ₹99.00', 'Rs. 99/-'). "
+ f"Format the output as:\n"
+ f"Manufacturing Date: Expiration Date: MRP: "
+ f"Here is the text: {text}"
+ )
+
+ return response.text
+
+def validate_dates_with_gemini(mfg_date, exp_date):
+ """Use Gemini API to validate and correct the manufacturing and expiration dates."""
+ model = genai.GenerativeModel('models/gemini-1.5-flash')
+ response = model.generate_content = (
+ f"Input Manufacturing Date: {mfg_date}, Expiration Date: {exp_date}. "
+ f"If either date is '-1', leave it as is. "
+ f"1. If the expiration date is earlier than the manufacturing date, swap them. "
+ f"2. If both dates are logically incorrect, suggest new valid dates based on typical timeframes. "
+ f"Always respond ONLY in the format:\n"
+ f"Manufacturing Date: , Expiration Date: "
+ )
+
+ # Check if the response contains valid parts
+ if response.parts:
+ # Process the response to extract final dates
+ final_dates = response.parts[0].text.strip()
+ return final_dates
+
+ # Return a message or a default value if no valid parts are found
+ return "Invalid response from Gemini API."
+
+from datetime import datetime
+
+def extract_and_validate_with_gemini(refined_text):
+ """
+ Use Gemini API to extract, validate, correct, and swap dates in 'yyyy/mm/dd' format if necessary.
+ """
+ model = genai.GenerativeModel('models/gemini-1.5-flash')
+
+ # Generate content using Gemini with the refined prompt
+ response = model.generate_content(
+ f"The extracted text is:\n'{refined_text}'\n\n"
+ f"1. Extract the 'Manufacturing Date', 'Expiration Date', and 'MRP' from the above text. "
+ f"Ignore unrelated data.\n"
+ f"2. If a date or MRP is missing or invalid, return -1 for that field.\n"
+ f"3. If the 'Expiration Date' is earlier than the 'Manufacturing Date', swap them.\n"
+ f"4. Ensure both dates are in 'dd/mm/yyyy' format. If the original dates are not in this format, convert them. "
+ f"However, if the dates are in 'mm/yyyy' format (without a day), leave them as is and return in 'mm/yyyy' format. "
+ f"If the dates do not have a day, return them in 'mm/yyyy' format.\n"
+ f"5. MRP should be returned in the format 'INR '. If not found or invalid, return 'INR -1'.\n"
+ f"Respond ONLY in this exact format:\n"
+ f"Manufacturing Date: \n"
+ f"Expiration Date: \n"
+ f"MRP: "
+ )
+
+ # Validate the response and extract dates
+ if hasattr(response, 'parts') and response.parts:
+ final_dates = response.parts[0].text.strip()
+ print(f"[DEBUG] Gemini Response: {final_dates}")
+
+ # Extract the dates from the response
+ mfg_date_str, exp_date_str, mrp_str = parse_gemini_response(final_dates)
+
+ # Process and swap if necessary
+ if mfg_date_str != "-1" and exp_date_str != "-1":
+ # Handle dates with possible 'mm/yyyy' format
+ mfg_date = parse_date(mfg_date_str)
+ exp_date = parse_date(exp_date_str)
+
+ # Swap if Expiration Date is earlier than Manufacturing Date
+ swapping_statement = ""
+ if exp_date < mfg_date:
+ print("[DEBUG] Swapping dates.")
+ mfg_date, exp_date = exp_date, mfg_date
+ swapping_statement = "Corrected Dates: \n"
+
+ # Return the formatted swapped dates
+ return swapping_statement + (
+ f"Manufacturing Date: {format_date(mfg_date)}, "
+ f"Expiration Date: {format_date(exp_date)}\n"
+ f"MRP: {mrp_str}"
+ )
+
+ # If either date is -1, return them as-is
+ return final_dates
+
+ # Handle invalid responses gracefully
+ print("[ERROR] Invalid response from Gemini API.")
+ return "Invalid response from Gemini API."
+
+def parse_gemini_response(response_text):
+ """
+ Helper function to extract Manufacturing Date and Expiration Date from the response text.
+ """
+ try:
+ # Split and extract the dates and MRP
+ parts = response_text.split(", ")
+ mfg_date_str = parts[0].split(": ")[1].strip()
+ exp_date_str = parts[1].split(": ")[1].strip()
+ mrp_str = parts[2].split(": ")[1].strip() if len(parts) > 2 else "INR -1" # Extract MRP
+ return mfg_date_str, exp_date_str, mrp_str
+ except IndexError:
+ print("[ERROR] Failed to parse Gemini response.")
+ return "-1", "-1", "INR -1"
+
+def parse_date(date_str):
+ """Parse date string to datetime object considering possible formats."""
+ if '/' in date_str: # If the date has slashes, we can parse it
+ parts = date_str.split('/')
+ if len(parts) == 3: # dd/mm/yyyy
+ return datetime.strptime(date_str, "%d/%m/%Y")
+ elif len(parts) == 2: # mm/yyyy
+ return datetime.strptime(date_str, "%m/%Y")
+ return datetime.strptime(date_str, "%d/%m/%Y") # Default fallback
+
+def format_date(date):
+ """Format date back to string."""
+ if date.day == 1: # If day is defaulted to 1, return in mm/yyyy format
+ return date.strftime('%m/%Y')
+ return date.strftime('%d/%m/%Y')
+
+
+def extract_date(refined_text, date_type):
+ """Extract the specified date type from the refined text."""
+ if date_type in refined_text:
+ try:
+ # Split the text and find the date for the specified type
+ parts = refined_text.split(',')
+ for part in parts:
+ if date_type in part:
+ return part.split(':')[1].strip() # Return the date value
+ except IndexError:
+ return '-1' # Return -1 if the date is not found
+ return '-1' # Return -1 if the date type is not in the text
+
+
+
+import re
+
+def extract_details_from_validated_output(validated_output):
+ """Extract manufacturing date, expiration date, and MRP from the validated output."""
+ # Pattern to match the specified format exactly
+ pattern = (
+ r"Manufacturing Date:\s*([\d\/]+)\s*"
+ r"Expiration Date:\s*([\d\/]+)\s*"
+ r"MRP:\s*INR\s*([\d\.]+)"
+ )
+
+ print("[DEBUG] Validated Output:", validated_output) # Debug print for input
+
+ match = re.search(pattern, validated_output)
+
+ if match:
+ mfg_date = match.group(1) # Extract Manufacturing Date
+ exp_date = match.group(2) # Extract Expiration Date
+ mrp = f"INR {match.group(3)}" # Extract MRP with INR prefix
+
+ print("[DEBUG] Extracted Manufacturing Date:", mfg_date) # Debug print for extracted values
+ print("[DEBUG] Extracted Expiration Date:", exp_date)
+ print("[DEBUG] Extracted MRP:", mrp)
+ else:
+ print("[ERROR] No match found for the specified pattern.") # Debug print for errors
+ mfg_date, exp_date, mrp = "Not Found", "Not Found", "INR -1"
+
+ return [
+ ["Manufacturing Date", mfg_date],
+ ["Expiration Date", exp_date],
+ ["MRP", mrp]
+ ]
+
+def new_draw_bounding_boxes(image):
+ """Draw bounding boxes around detected text in the image and display it."""
+ # If the input is a string (file path), open the image
+ if isinstance(image, str):
+ img = Image.open(image)
+ np_img = np.array(img) # Convert to NumPy array
+ ocr_result = ocr.ocr(np_img, cls=True) # Perform OCR on the array
+ elif isinstance(image, Image.Image):
+ np_img = np.array(image) # Convert PIL Image to NumPy array
+ ocr_result = ocr.ocr(np_img, cls=True) # Perform OCR on the array
+ else:
+ raise ValueError("Input must be a file path or a PIL Image object.")
+
+ # Create a figure to display the image
+ plt.figure(figsize=(10, 10))
+ plt.imshow(image)
+ ax = plt.gca()
+ all_text_data = []
+
+ # Iterate through the OCR results and draw boxes
+ for idx, line in enumerate(ocr_result[0]):
+ box = line[0] # Get the bounding box coordinates
+ text = line[1][0] # Extracted text
+ print(f"[DEBUG] Box {idx + 1}: {text}") # Debug print
+ all_text_data.append(text)
+
+ # Draw the bounding box
+ polygon = plt.Polygon(box, fill=None, edgecolor='red', linewidth=2)
+ ax.add_patch(polygon)
+
+ # Add text label with a small offset for visibility
+ x, y = box[0][0], box[0][1]
+ ax.text(x, y - 5, f"{idx + 1}: {text}", color='blue', fontsize=12, ha='left')
+
+ plt.axis('off') # Hide axes
+ plt.title("Detected Text with Bounding Boxes", fontsize=16) # Add a title
+ plt.show()
+
+ return all_text_data
+# Initialize PaddleOCR
+ocr = PaddleOCR(use_angle_cls=True, lang='en')
+
+def detect_and_ocr(image):
+ model = YOLO('/content/drive/MyDrive/OCR_Using_model/Yolo_Dataset/Yolo_Checkpoints/improved-model/improved_Model3/weights/best.pt')
+
+ """Detect objects using YOLO, draw bounding boxes, and perform OCR."""
+ # Convert input image from PIL to OpenCV format
+ image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
+
+ # Run inference using YOLO model
+ results = model(image)
+ boxes = results[0].boxes.xyxy.cpu().numpy() # Extract bounding box coordinates
+
+ extracted_texts = []
+ for (x1, y1, x2, y2) in boxes:
+ # Draw bounding box on the original image
+ cv2.rectangle(image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
+
+ # Perform OCR on the detected region using the original image and bounding box coordinates
+ region = image[int(y1):int(y2), int(x1):int(x2)]
+ ocr_result = ocr.ocr(region, cls=True)
+
+ # Check if ocr_result is None or empty
+ if ocr_result and isinstance(ocr_result, list) and ocr_result[0]:
+ for idx, line in enumerate(ocr_result[0]):
+ box = line[0] # Get the bounding box coordinates
+ text = line[1][0] # Extracted text
+ print(f"[DEBUG] Box {idx + 1}: {text}") # Debug output
+ extracted_texts.append(text)
+ else:
+ # Handle case when OCR returns no result
+ print(f"[DEBUG] No OCR result for region: ({x1}, {y1}, {x2}, {y2}) or OCR returned None")
+ extracted_texts.append("No OCR result found") # Append a message to indicate no result
+
+ # Convert image to RGB for Gradio display
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
+
+ # Join all extracted texts into a single string
+ result_text = "\n".join(str(text) for text in extracted_texts)
+
+ # Call the Gemini context correction function
+ refined_text = gemini_context_correction(result_text)
+ print("[DEBUG] Gemini Refined Text:\n", refined_text)
+
+ # Validate and correct dates
+ validated_output = extract_and_validate_with_gemini(refined_text)
+
+ print("[DEBUG] Validated Output from Gemini:\n", validated_output)
+
+ # Return image with bounding boxes and results
+ return image_rgb, result_text, refined_text, validated_output
+
+def further_processing(image, previous_result_text):
+ bounding_boxes_list = new_draw_bounding_boxes(image)
+ print("[DEBUG] ", bounding_boxes_list, type(bounding_boxes_list))
+ combined_text = previous_result_text
+ for text in bounding_boxes_list:
+ combined_text += text
+ combined_text += "\n"
+ print("[DEBUG] combined text", combined_text)
+ # Call Gemini for context correction and refinement
+ refined_output = gemini_context_correction(combined_text)
+ print("[DEBUG] Gemini Refined Output:\n", refined_output)
+
+ return refined_output # Return refined output for display
+
+def handle_processing(validated_output):
+ """Decide whether to proceed with further processing."""
+ # Extract the manufacturing date, expiration date, and MRP from the string
+ try:
+ mfg_date_str = validated_output.split("Manufacturing Date: ")[1].split("\n")[0].strip()
+ exp_date_str = validated_output.split("Expiration Date: ")[1].split("\n")[0].strip()
+ mrp_str = validated_output.split("MRP: ")[1].strip()
+
+ # Check for invalid manufacturing date formats
+ if mfg_date_str == "-1":
+ mfg_date = -1
+ else:
+ # Attempt to parse the manufacturing date
+ if '/' in mfg_date_str: # If it's in dd/mm/yyyy or mm/yyyy format
+ mfg_date = mfg_date_str
+ else:
+ mfg_date = -1
+
+ # Check for invalid expiration date formats
+ if exp_date_str == "-1":
+ exp_date = -1
+ else:
+ # Attempt to parse the expiration date
+ if '/' in exp_date_str: # If it's in dd/mm/yyyy or mm/yyyy format
+ exp_date = exp_date_str
+ else:
+ exp_date = -1
+
+ # Check MRP validity
+ if mrp_str == "INR -1":
+ mrp = -1
+ else:
+ # Ensure MRP is in the correct format
+ if mrp_str.startswith("INR "):
+ mrp = mrp_str.split("INR ")[1].strip()
+ else:
+ mrp = -1
+
+ print("Further processing: ", mfg_date, exp_date, mrp)
+
+ except IndexError as e:
+ print(f"[ERROR] Failed to parse validated output: {e}")
+ return gr.update(visible=False) # Hide button on error
+
+ # Check if all three values are invalid (-1)
+ if mfg_date == -1 and exp_date == -1 and mrp == -1:
+ print("[DEBUG] Showing the 'Further Processing' button.") # Debug print
+ return gr.update(visible=True) # Show 'Further Processing' button
+
+ print("[DEBUG] Hiding the 'Further Processing' button.") # Debug print
+ return gr.update(visible=False) # Hide button if all values are valid
+
+
+
+=======
+import os
+import cv2
+import numpy as np
+from PIL import Image
+import matplotlib.pyplot as plt
+from paddleocr import PaddleOCR
+import gradio as gr
+import google.generativeai as genai
+from ultralytics import YOLO
+from datetime import datetime
+import re
+
+GOOGLE_API_KEY = os.getenv("GEMINI_API")
+
+def new_draw_bounding_boxes(image):
+ """Draw bounding boxes around detected text in the image and display it."""
+ try:
+ # Check the input type and load the image
+ if isinstance(image, str):
+ img = Image.open(image)
+ np_img = np.array(img) # Convert to NumPy array
+ print("[DEBUG] Loaded image from file path.")
+ elif isinstance(image, Image.Image):
+ np_img = np.array(image) # Convert PIL Image to NumPy array
+ print("[DEBUG] Converted PIL Image to NumPy array.")
+ else:
+ raise ValueError("Input must be a file path or a PIL Image object.")
+
+ # Perform OCR on the array
+ ocr_result = ocr.ocr(np_img, cls=True) # Ensure this line is error-free
+ print("[DEBUG] OCR Result:\n", ocr_result)
+
+ # Create a figure to display the image
+ plt.figure(figsize=(10, 10))
+ plt.imshow(image)
+ ax = plt.gca()
+ all_text_data = []
+
+ # Iterate through the OCR results and draw boxes
+ for idx, line in enumerate(ocr_result[0]):
+ box = line[0] # Get the bounding box coordinates
+ text = line[1][0] # Extracted text
+ print(f"[DEBUG] Box {idx + 1}: {text}") # Debug print
+ all_text_data.append(text)
+
+ # Draw the bounding box
+ polygon = plt.Polygon(box, fill=None, edgecolor='red', linewidth=2)
+ ax.add_patch(polygon)
+
+ # Add text label with a small offset for visibility
+ x, y = box[0][0], box[0][1]
+ ax.text(x, y - 5, f"{idx + 1}: {text}", color='blue', fontsize=12, ha='left')
+
+ plt.axis('off') # Hide axes
+ plt.title("Detected Text with Bounding Boxes", fontsize=16) # Add a title
+ plt.show()
+
+ return all_text_data
+
+ except Exception as e:
+ print(f"[ERROR] Error in new_draw_bounding_boxes: {e}")
+ return []
+
+
+
+def gemini_context_correction(text):
+ """Use Gemini API to refine noisy OCR results and extract MRP details."""
+ model = genai.GenerativeModel('models/gemini-1.5-flash')
+
+ response = model.generate_content(
+ f"Identify and extract manufacturing, expiration dates, and MRP from the following text. "
+ f"The dates may be written in dd/mm/yyyy format or as or . "
+ f"The text may contain noise or unclear information. If only one date is provided, assume it is the Expiration Date. "
+ f"Additionally, extract the MRP (e.g., 'MRP: ₹99.00', 'Rs. 99/-'). "
+ f"Format the output as:\n"
+ f"Manufacturing Date: Expiration Date: MRP: "
+ f"Here is the text: {text}"
+ )
+
+ return response.text
+
+def validate_dates_with_gemini(mfg_date, exp_date):
+ """Use Gemini API to validate and correct the manufacturing and expiration dates."""
+ model = genai.GenerativeModel('models/gemini-1.5-flash')
+ response = model.generate_content = (
+ f"Input Manufacturing Date: {mfg_date}, Expiration Date: {exp_date}. "
+ f"If either date is '-1', leave it as is. "
+ f"1. If the expiration date is earlier than the manufacturing date, swap them. "
+ f"2. If both dates are logically incorrect, suggest new valid dates based on typical timeframes. "
+ f"Always respond ONLY in the format:\n"
+ f"Manufacturing Date: , Expiration Date: "
+ )
+
+ # Check if the response contains valid parts
+ if response.parts:
+ # Process the response to extract final dates
+ final_dates = response.parts[0].text.strip()
+ return final_dates
+
+ # Return a message or a default value if no valid parts are found
+ return "Invalid response from Gemini API."
+
+
+def extract_and_validate_with_gemini(refined_text):
+ """
+ Use Gemini API to extract, validate, correct, and swap dates in 'yyyy/mm/dd' format if necessary.
+ """
+ model = genai.GenerativeModel('models/gemini-1.5-flash')
+
+ # Generate content using Gemini with the refined prompt
+ response = model.generate_content(
+ f"The extracted text is:\n'{refined_text}'\n\n"
+ f"1. Extract the 'Manufacturing Date', 'Expiration Date', and 'MRP' from the above text. "
+ f"Ignore unrelated data.\n"
+ f"2. If a date or MRP is missing or invalid, return -1 for that field.\n"
+ f"3. If the 'Expiration Date' is earlier than the 'Manufacturing Date', swap them.\n"
+ f"4. Ensure both dates are in 'dd/mm/yyyy' format. If the original dates are not in this format, convert them. "
+ f"However, if the dates are in 'mm/yyyy' format (without a day), leave them as is and return in 'mm/yyyy' format. "
+ f"If the dates do not have a day, return them in 'mm/yyyy' format.\n"
+ f"5. MRP should be returned in the format 'INR '. If not found or invalid, return 'INR -1'.\n"
+ f"Respond ONLY in this exact format:\n"
+ f"Manufacturing Date: \n"
+ f"Expiration Date: \n"
+ f"MRP: "
+ )
+
+ # Validate the response and extract dates
+ if hasattr(response, 'parts') and response.parts:
+ final_dates = response.parts[0].text.strip()
+ print(f"[DEBUG] Gemini Response: {final_dates}")
+
+ # Extract the dates from the response
+ mfg_date_str, exp_date_str, mrp_str = parse_gemini_response(final_dates)
+
+ # Process and swap if necessary
+ if mfg_date_str != "-1" and exp_date_str != "-1":
+ # Handle dates with possible 'mm/yyyy' format
+ mfg_date = parse_date(mfg_date_str)
+ exp_date = parse_date(exp_date_str)
+
+ # Swap if Expiration Date is earlier than Manufacturing Date
+ swapping_statement = ""
+ if exp_date < mfg_date:
+ print("[DEBUG] Swapping dates.")
+ mfg_date, exp_date = exp_date, mfg_date
+ swapping_statement = "Corrected Dates: \n"
+
+ # Return the formatted swapped dates
+ return swapping_statement + (
+ f"Manufacturing Date: {format_date(mfg_date)}, "
+ f"Expiration Date: {format_date(exp_date)}\n"
+ f"MRP: {mrp_str}"
+ )
+
+ # If either date is -1, return them as-is
+ return final_dates
+
+ # Handle invalid responses gracefully
+ print("[ERROR] Invalid response from Gemini API.")
+ return "Invalid response from Gemini API."
+
+def parse_gemini_response(response_text):
+ """
+ Helper function to extract Manufacturing Date and Expiration Date from the response text.
+ """
+ try:
+ # Split and extract the dates and MRP
+ parts = response_text.split(", ")
+ mfg_date_str = parts[0].split(": ")[1].strip()
+ exp_date_str = parts[1].split(": ")[1].strip()
+ mrp_str = parts[2].split(": ")[1].strip() if len(parts) > 2 else "INR -1" # Extract MRP
+ return mfg_date_str, exp_date_str, mrp_str
+ except IndexError:
+ print("[ERROR] Failed to parse Gemini response.")
+ return "-1", "-1", "INR -1"
+
+def parse_date(date_str):
+ """Parse date string to datetime object considering possible formats."""
+ if '/' in date_str: # If the date has slashes, we can parse it
+ parts = date_str.split('/')
+ if len(parts) == 3: # dd/mm/yyyy
+ return datetime.strptime(date_str, "%d/%m/%Y")
+ elif len(parts) == 2: # mm/yyyy
+ return datetime.strptime(date_str, "%m/%Y")
+ return datetime.strptime(date_str, "%d/%m/%Y") # Default fallback
+
+def format_date(date):
+ """Format date back to string."""
+ if date.day == 1: # If day is defaulted to 1, return in mm/yyyy format
+ return date.strftime('%m/%Y')
+ return date.strftime('%d/%m/%Y')
+
+
+def extract_date(refined_text, date_type):
+ """Extract the specified date type from the refined text."""
+ if date_type in refined_text:
+ try:
+ # Split the text and find the date for the specified type
+ parts = refined_text.split(',')
+ for part in parts:
+ if date_type in part:
+ return part.split(':')[1].strip() # Return the date value
+ except IndexError:
+ return '-1' # Return -1 if the date is not found
+ return '-1' # Return -1 if the date type is not in the text
+
+
+
+
+def extract_details_from_validated_output(validated_output):
+ """Extract manufacturing date, expiration date, and MRP from the validated output."""
+ # Pattern to match the specified format exactly
+ pattern = (
+ r"Manufacturing Date:\s*([\d\/]+)\s*"
+ r"Expiration Date:\s*([\d\/]+)\s*"
+ r"MRP:\s*INR\s*([\d\.]+)"
+ )
+
+ print("[DEBUG] Validated Output:", validated_output) # Debug print for input
+
+ match = re.search(pattern, validated_output)
+
+ if match:
+ mfg_date = match.group(1) # Extract Manufacturing Date
+ exp_date = match.group(2) # Extract Expiration Date
+ mrp = f"INR {match.group(3)}" # Extract MRP with INR prefix
+
+ print("[DEBUG] Extracted Manufacturing Date:", mfg_date) # Debug print for extracted values
+ print("[DEBUG] Extracted Expiration Date:", exp_date)
+ print("[DEBUG] Extracted MRP:", mrp)
+ else:
+ print("[ERROR] No match found for the specified pattern.") # Debug print for errors
+ mfg_date, exp_date, mrp = "Not Found", "Not Found", "INR -1"
+
+ return [
+ ["Manufacturing Date", mfg_date],
+ ["Expiration Date", exp_date],
+ ["MRP", mrp]
+ ]
+
+def new_draw_bounding_boxes(image):
+ """Draw bounding boxes around detected text in the image and display it."""
+ # If the input is a string (file path), open the image
+ if isinstance(image, str):
+ img = Image.open(image)
+ np_img = np.array(img) # Convert to NumPy array
+ ocr_result = ocr.ocr(np_img, cls=True) # Perform OCR on the array
+ elif isinstance(image, Image.Image):
+ np_img = np.array(image) # Convert PIL Image to NumPy array
+ ocr_result = ocr.ocr(np_img, cls=True) # Perform OCR on the array
+ else:
+ raise ValueError("Input must be a file path or a PIL Image object.")
+
+ # Create a figure to display the image
+ plt.figure(figsize=(10, 10))
+ plt.imshow(image)
+ ax = plt.gca()
+ all_text_data = []
+
+ # Iterate through the OCR results and draw boxes
+ for idx, line in enumerate(ocr_result[0]):
+ box = line[0] # Get the bounding box coordinates
+ text = line[1][0] # Extracted text
+ print(f"[DEBUG] Box {idx + 1}: {text}") # Debug print
+ all_text_data.append(text)
+
+ # Draw the bounding box
+ polygon = plt.Polygon(box, fill=None, edgecolor='red', linewidth=2)
+ ax.add_patch(polygon)
+
+ # Add text label with a small offset for visibility
+ x, y = box[0][0], box[0][1]
+ ax.text(x, y - 5, f"{idx + 1}: {text}", color='blue', fontsize=12, ha='left')
+
+ plt.axis('off') # Hide axes
+ plt.title("Detected Text with Bounding Boxes", fontsize=16) # Add a title
+ plt.show()
+
+ return all_text_data
+# Initialize PaddleOCR
+ocr = PaddleOCR(use_angle_cls=True, lang='en')
+
+def detect_and_ocr(image):
+ model = YOLO('Weights/kitkat_s.pt')
+
+ """Detect objects using YOLO, draw bounding boxes, and perform OCR."""
+ # Convert input image from PIL to OpenCV format
+ image = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
+
+ # Run inference using YOLO model
+ results = model(image)
+ boxes = results[0].boxes.xyxy.cpu().numpy() # Extract bounding box coordinates
+
+ extracted_texts = []
+ for (x1, y1, x2, y2) in boxes:
+ # Draw bounding box on the original image
+ cv2.rectangle(image, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
+
+ # Perform OCR on the detected region using the original image and bounding box coordinates
+ region = image[int(y1):int(y2), int(x1):int(x2)]
+ ocr_result = ocr.ocr(region, cls=True)
+
+ # Check if ocr_result is None or empty
+ if ocr_result and isinstance(ocr_result, list) and ocr_result[0]:
+ for idx, line in enumerate(ocr_result[0]):
+ box = line[0] # Get the bounding box coordinates
+ text = line[1][0] # Extracted text
+ print(f"[DEBUG] Box {idx + 1}: {text}") # Debug output
+ extracted_texts.append(text)
+ else:
+ # Handle case when OCR returns no result
+ print(f"[DEBUG] No OCR result for region: ({x1}, {y1}, {x2}, {y2}) or OCR returned None")
+ extracted_texts.append("No OCR result found") # Append a message to indicate no result
+
+ # Convert image to RGB for Gradio display
+ image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
+
+ # Join all extracted texts into a single string
+ result_text = "\n".join(str(text) for text in extracted_texts)
+
+ # Call the Gemini context correction function
+ refined_text = gemini_context_correction(result_text)
+ print("[DEBUG] Gemini Refined Text:\n", refined_text)
+
+ # Validate and correct dates
+ validated_output = extract_and_validate_with_gemini(refined_text)
+
+ print("[DEBUG] Validated Output from Gemini:\n", validated_output)
+
+ # Return image with bounding boxes and results
+ return image_rgb, result_text, refined_text, validated_output
+
+def further_processing(image, previous_result_text):
+ bounding_boxes_list = new_draw_bounding_boxes(image)
+ print("[DEBUG] ", bounding_boxes_list, type(bounding_boxes_list))
+ combined_text = previous_result_text
+ for text in bounding_boxes_list:
+ combined_text += text
+ combined_text += "\n"
+ print("[DEBUG] combined text", combined_text)
+ # Call Gemini for context correction and refinement
+ refined_output = gemini_context_correction(combined_text)
+ print("[DEBUG] Gemini Refined Output:\n", refined_output)
+
+ return refined_output # Return refined output for display
+
+def handle_processing(validated_output):
+ """Decide whether to proceed with further processing."""
+ # Extract the manufacturing date, expiration date, and MRP from the string
+ try:
+ mfg_date_str = validated_output.split("Manufacturing Date: ")[1].split("\n")[0].strip()
+ exp_date_str = validated_output.split("Expiration Date: ")[1].split("\n")[0].strip()
+ mrp_str = validated_output.split("MRP: ")[1].strip()
+
+ # Check for invalid manufacturing date formats
+ if mfg_date_str == "-1":
+ mfg_date = -1
+ else:
+ # Attempt to parse the manufacturing date
+ if '/' in mfg_date_str: # If it's in dd/mm/yyyy or mm/yyyy format
+ mfg_date = mfg_date_str
+ else:
+ mfg_date = -1
+
+ # Check for invalid expiration date formats
+ if exp_date_str == "-1":
+ exp_date = -1
+ else:
+ # Attempt to parse the expiration date
+ if '/' in exp_date_str: # If it's in dd/mm/yyyy or mm/yyyy format
+ exp_date = exp_date_str
+ else:
+ exp_date = -1
+
+ # Check MRP validity
+ if mrp_str == "INR -1":
+ mrp = -1
+ else:
+ # Ensure MRP is in the correct format
+ if mrp_str.startswith("INR "):
+ mrp = mrp_str.split("INR ")[1].strip()
+ else:
+ mrp = -1
+
+ print("Further processing: ", mfg_date, exp_date, mrp)
+
+ except IndexError as e:
+ print(f"[ERROR] Failed to parse validated output: {e}")
+ return gr.update(visible=False) # Hide button on error
+
+ # Check if all three values are invalid (-1)
+ if mfg_date == -1 and exp_date == -1 and mrp == -1:
+ print("[DEBUG] Showing the 'Further Processing' button.") # Debug print
+ return gr.update(visible=True) # Show 'Further Processing' button
+
+ print("[DEBUG] Hiding the 'Further Processing' button.") # Debug print
+ return gr.update(visible=False) # Hide button if all values are valid
+
+
+>>>>>>> e5d15d9f20f81ec00c665c918a7ff8559300ccf3
diff --git a/Database/mongodb.py b/Database/mongodb.py
new file mode 100644
index 0000000000000000000000000000000000000000..7df900f3940ee3c6ac864d9b8ff36d2e4843b8ea
--- /dev/null
+++ b/Database/mongodb.py
@@ -0,0 +1,409 @@
+from pymongo.mongo_client import MongoClient
+from pymongo.server_api import ServerApi
+from datetime import datetime, timedelta
+import json
+
+uri = "mongodb+srv://transyltoonia:meradatabase@transyltoonia.xdrsx1s.mongodb.net/?retryWrites=true&w=majority&appName=transyltoonia"
+
+class DatabaseManager:
+ def __init__(self, uri=uri, db_name='FlipkartGrid_DB'):
+ """
+ Comprehensive Database Management System
+ Combines basic and advanced database operations
+
+ """
+
+ client = MongoClient(uri, server_api=ServerApi('1'))
+
+ try:
+ client.admin.command('ping')
+ print("Pinged your deployment. You successfully connected to MongoDB!")
+ except Exception as e:
+ print("An error occurred while connecting to MongoDB: ", e)
+ try:
+ # Database Connection
+ self.client = MongoClient(uri)
+ self.db = self.client[db_name]
+
+ # Collections
+ self.brand_collection = self.db['brand_recognition']
+ self.ocr_collection = self.db['ocr']
+ self.freshness_collection = self.db['freshness']
+
+ # Create performance indexes
+ self._create_indexes()
+ except Exception as e:
+ print(f"Database connection error: {e}")
+ raise
+
+ def _create_indexes(self):
+ """
+ Create performance and unique indexes
+ """
+ self.brand_collection.create_index([("brand", 1)], unique=True)
+ self.ocr_collection.create_index([("brand", 1), ("expiry_date", 1)])
+ self.freshness_collection.create_index([("produce", 1)])
+
+ # Original Basic Methods
+ from datetime import datetime
+
+ def add_brand_record(self, brand, count):
+ """
+ Add or update a brand record with validation.
+ If the brand exists, increment its count. Otherwise, add a new record.
+ """
+ try:
+ # Input validation
+ if not brand or not isinstance(brand, str):
+ return "Invalid brand name"
+ if not isinstance(count, (int, float)) or count < 0:
+ return "Invalid count value"
+
+ # Prepare the brand name
+ brand = brand.strip().title()
+
+ # Check if the brand already exists
+ existing_record = self.brand_collection.find_one({"brand": brand})
+
+ if existing_record:
+ # Increment the count if the brand exists
+ new_count = existing_record["count"] + count
+ self.brand_collection.update_one(
+ {"brand": brand},
+ {"$set": {"count": new_count, "last_updated": datetime.now()}}
+ )
+ return f"Updated brand record: Brand = {brand}, New Count = {new_count}"
+ else:
+ # Add a new record if the brand does not exist
+ record = {
+ "S.No": self.brand_collection.count_documents({}) + 1,
+ "timestamp": datetime.now(),
+ "brand": brand,
+ "count": count,
+ "last_updated": datetime.now()
+ }
+ self.brand_collection.insert_one(record)
+ return f"Added brand record: Brand = {brand}, Count = {count}"
+ except Exception as e:
+ return f"Error adding brand record: {e}"
+
+
+ def get_brand_records(self, filter_criteria=None, sort_by='timestamp', ascending=False):
+ """
+ Retrieve brand records with flexible filtering and sorting
+ """
+ try:
+ filter_criteria = filter_criteria or {}
+ sort_direction = 1 if ascending else -1
+
+ records = self.brand_collection.find(filter_criteria).sort(sort_by, sort_direction)
+
+ return [
+ {
+ "S.No": record['S.No'],
+ "Brand": record['brand'],
+ "Count": record['count'],
+ "Timestamp": record['timestamp']
+ } for record in records
+ ]
+ except Exception as e:
+ return f"Error retrieving brand records: {e}"
+
+ def add_ocr_record(self, brand, expiry_date, manufacture_date, mrp):
+ """
+ Add OCR record with comprehensive validation
+ """
+ try:
+ # Date validation helper
+ def validate_date(date_str):
+ try:
+ return datetime.strptime(date_str, "%Y-%m-%d")
+ except ValueError:
+ return None
+
+ exp_date = validate_date(expiry_date)
+ man_date = validate_date(manufacture_date)
+
+ if not exp_date or not man_date:
+ return "Invalid date format. Use YYYY-MM-DD"
+
+ # Check expiry date is after manufacture date
+ if exp_date <= man_date:
+ return "Expiry date must be after manufacture date"
+
+ # Validate MRP
+ try:
+ mrp = float(mrp)
+ if mrp <= 0:
+ return "MRP must be a positive number"
+ except ValueError:
+ return "Invalid MRP value"
+
+ record = {
+ "S.No": self.ocr_collection.count_documents({}) + 1,
+ "timestamp": datetime.now(),
+ "brand": brand.strip().title(),
+ "expiry_date": exp_date,
+ "manufacture_date": man_date,
+ "mrp": mrp,
+ "days_to_expiry": (exp_date - datetime.now().date()).days
+ }
+ self.ocr_collection.insert_one(record)
+ return f"Added OCR record: Brand = {brand}, Expiry Date = {expiry_date}"
+ except Exception as e:
+ return f"Error adding OCR record: {e}"
+
+
+ def get_ocr_records(self, filter_criteria=None, sort_by='timestamp', ascending=False):
+ """
+ Retrieve OCR records with flexible filtering and sorting
+ """
+ try:
+ filter_criteria = filter_criteria or {}
+ sort_direction = 1 if ascending else -1
+
+ records = self.ocr_collection.find(filter_criteria).sort(sort_by, sort_direction)
+
+ return [
+ {
+ "S.No": record['S.No'],
+ "Brand": record['brand'],
+ "Expiry Date": record['expiry_date'],
+ "Manufacture Date": record['manufacture_date'],
+ "MRP": record['mrp']
+ } for record in records
+ ]
+ except Exception as e:
+ return f"Error retrieving OCR records: {e}"
+
+
+ def add_freshness_record(self, produce, shelf_life, characteristics, eatable):
+ """
+ Add freshness record with enhanced validation
+ """
+ try:
+ # Input validations
+ if not produce or not isinstance(produce, str):
+ return "Invalid produce name"
+
+ # Convert to boolean or validate eatable status
+ if isinstance(eatable, str):
+ eatable = eatable.lower() in ['true', 'yes', '1']
+
+ record = {
+ "S.No": self.freshness_collection.count_documents({}) + 1,
+ "timestamp": datetime.now(),
+ "produce": produce.strip().title(),
+ "Shelf-Life": shelf_life,
+ "Characteristics": characteristics,
+ "Eatable": bool(eatable)
+ }
+ self.freshness_collection.insert_one(record)
+ return f"Added freshness record: Produce = {produce}, Shelf-Life = {shelf_life}"
+ except Exception as e:
+ return f"Error adding freshness record: {e}"
+
+ # Advanced Analysis Methods
+ def analyze_brand_trends(self, time_period=30):
+ """
+ Analyze brand trends over a specified time period
+ """
+ try:
+ cutoff_date = datetime.now() - timedelta(days=time_period)
+
+ pipeline = [
+ {"$match": {"timestamp": {"$gte": cutoff_date}}},
+ {"$group": {
+ "_id": "$brand",
+ "total_count": {"$sum": "$count"},
+ "avg_count": {"$avg": "$count"},
+ "first_seen": {"$min": "$timestamp"},
+ "last_seen": {"$max": "$timestamp"}
+ }},
+ {"$sort": {"total_count": -1}}
+ ]
+
+ trends = list(self.brand_collection.aggregate(pipeline))
+
+ # Enrich the results
+ for trend in trends:
+ trend['brand'] = trend.pop('_id')
+ trend['first_seen'] = trend['first_seen'].strftime('%Y-%m-%d %H:%M:%S')
+ trend['last_seen'] = trend['last_seen'].strftime('%Y-%m-%d %H:%M:%S')
+ trend['total_count'] = round(trend['total_count'], 2)
+ trend['avg_count'] = round(trend['avg_count'], 2)
+
+ return trends
+ except Exception as e:
+ return f"Error analyzing brand trends: {e}"
+
+ # Additional methods from previous implementations
+ def get_all_brand_records(self):
+ """
+ Retrieve all brand records
+ """
+ try:
+ records = self.brand_collection.find()
+ result = [
+ f"S.No: {record['S.No']}, Brand: {record['brand']}, Count: {record['count']}"
+ for record in records
+ ]
+ return "\n".join(result) if result else "No brand records found."
+ except Exception as e:
+ return f"An error occurred while fetching brand records: {e}"
+
+ def get_all_ocr_records(self):
+ """
+ Retrieve all OCR records
+ """
+ try:
+ records = self.ocr_collection.find()
+ result = [
+ f"S.No: {record['S.No']}, Brand: {record['brand']}, Expiry Date: {record['expiry_date']}, "
+ f"Manufacture Date: {record['manufacture_date']}, MRP: {record['mrp']}"
+ for record in records
+ ]
+ return "\n".join(result) if result else "No OCR records found."
+ except Exception as e:
+ return f"An error occurred while fetching OCR records: {e}"
+
+ def get_all_freshness_records(self):
+ """
+ Retrieve all freshness records
+ """
+ try:
+ records = self.freshness_collection.find()
+ result = [
+ f"S.No: {record['S.No']}, Produce: {record['produce']}, Shelf-Life: {record['Shelf-Life']}, "
+ f"Characteristics: {record['Characteristics']}, Eatable: {record['Eatable']}"
+ for record in records
+ ]
+ return "\n".join(result) if result else "No freshness records found."
+ except Exception as e:
+ return f"An error occurred while fetching freshness records: {e}"
+
+ def get_freshness_records(self, filter_criteria=None, sort_by='timestamp', ascending=False):
+ """
+ Retrieve freshness records with flexible filtering and sorting
+ """
+ try:
+ filter_criteria = filter_criteria or {}
+ sort_direction = 1 if ascending else -1
+
+ records = self.freshness_collection.find(filter_criteria).sort(sort_by, sort_direction)
+
+ return [
+ {
+ "S.No": record['S.No'],
+ "Produce": record['produce'],
+ "Shelf-Life": record['Shelf-Life'],
+ "Characteristics": record['Characteristics'],
+ "Eatable": record['Eatable']
+ } for record in records
+ ]
+ except Exception as e:
+ return f"Error retrieving freshness records: {e}"
+
+
+
+ # Advanced Search and Filtering
+ def advanced_search(self, collection_name, search_criteria=None, projection=None):
+ """
+ Advanced search method with flexible filtering
+ """
+ try:
+ collection_map = {
+ 'brand': self.brand_collection,
+ 'ocr': self.ocr_collection,
+ 'freshness': self.freshness_collection
+ }
+
+ if collection_name not in collection_map:
+ return "Invalid collection name"
+
+ search_criteria = search_criteria or {}
+ projection = projection or {}
+
+ results = list(collection_map[collection_name].find(search_criteria, projection))
+
+ # Convert ObjectId to string for JSON serialization
+ for result in results:
+ if '_id' in result:
+ result['_id'] = str(result['_id'])
+
+ return results
+ except Exception as e:
+ return f"Error performing advanced search: {e}"
+
+ # More Advanced Methods (Export, Statistical Analysis, etc.)
+ def export_collection_to_json(self, collection_name, filename=None):
+ """
+ Export a collection to a JSON file
+ """
+ try:
+ collection_map = {
+ 'brand': self.brand_collection,
+ 'ocr': self.ocr_collection,
+ 'freshness': self.freshness_collection
+ }
+
+ if collection_name not in collection_map:
+ return "Invalid collection name"
+
+ documents = list(collection_map[collection_name].find())
+
+ for doc in documents:
+ doc['_id'] = str(doc['_id'])
+
+ if not filename:
+ filename = f"{collection_name}_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
+
+ with open(filename, 'w') as f:
+ json.dump(documents, f, indent=2, default=str)
+
+ return f"Successfully exported {len(documents)} documents to {filename}"
+ except Exception as e:
+ return f"Error exporting collection: {e}"
+
+ def close_connection(self):
+ """
+ Properly close the MongoDB connection
+ """
+ try:
+ self.client.close()
+ print("MongoDB connection closed successfully")
+ except Exception as e:
+ print(f"Error closing connection: {e}")
+
+# Example usage
+def main():
+ try:
+ # Initialize database manager
+ db_manager = DatabaseManager()
+
+ # Example of using various methods
+ print(db_manager.add_brand_record("Nike", 150))
+ print(db_manager.add_ocr_record("Adidas", "2024-12-31", "2023-06-01", 75.50))
+ print(db_manager.add_freshness_record("Apple", "14 days", "Red, crisp", True))
+
+ # Retrieve records
+ print("\nBrand Trends:")
+ print(db_manager.analyze_brand_trends())
+
+ # Advanced search example
+ print("\nAdvanced Search:")
+ search_results = db_manager.advanced_search('brand',
+ search_criteria={'count': {'$gt': 100}},
+ projection={'brand': 1, 'count': 1}
+ )
+ print(json.dumps(search_results, indent=2))
+
+ except Exception as e:
+ print(f"An error occurred: {e}")
+ finally:
+ db_manager.close_connection()
+
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/Frontend/BrandRecongnition/Image.py b/Frontend/BrandRecongnition/Image.py
new file mode 100644
index 0000000000000000000000000000000000000000..a2185b5c6c8720b6a670a09768d5ffef4741f89b
--- /dev/null
+++ b/Frontend/BrandRecongnition/Image.py
@@ -0,0 +1,34 @@
+import gradio as gr
+from Backend.BrandRecognition.Static.Brand_Count_Img import detect_grocery_items
+from Backend.BrandRecognition.Static.Brand_Count_Img import batch_detect_grocery_items
+
+## Layout for Image interface
+def create_image_interface():
+
+ """
+ Create an interface for object detection in an image.
+
+ The interface allows users to upload an image, and the model will return an annotated image, item quantities, and average confidence scores.
+
+ Parameters
+ ----------
+ None
+
+ Returns
+ -------
+ gr.Interface
+ An Interface object that can be launched to accept user input.
+
+ """
+ return gr.Interface(
+ fn=detect_grocery_items,
+ inputs=gr.Image(label="Upload Image", height=400, width=400),
+ outputs=[
+ gr.Image(label="Image with Bounding Boxes", height=400, width=400),
+ gr.Dataframe(headers=["Item", "Quantity", "Avg Confidence"], label="Detected Items and Quantities", elem_id="summary_table"),
+ gr.Textbox(label="Status", elem_id="status_message")
+ ],
+ title="Grocery Item Detection in an Image",
+ description="Upload an image for object detection. The model will return an annotated image, item quantities, and average confidence scores.",
+ css=".gr-table { font-size: 16px; text-align: left; width: 50%; margin: auto; } #summary_table { margin-top: 20px; }"
+ )
diff --git a/Frontend/BrandRecongnition/Integration_BR.py b/Frontend/BrandRecongnition/Integration_BR.py
new file mode 100644
index 0000000000000000000000000000000000000000..89bf1f4aae941892911439bf3676be07b24acf51
--- /dev/null
+++ b/Frontend/BrandRecongnition/Integration_BR.py
@@ -0,0 +1,27 @@
+import gradio as gr
+from Frontend.BrandRecongnition.Image import create_image_interface
+from Frontend.BrandRecongnition.Video import create_video_interface
+
+def create_brand_recog_interface():
+ """
+ Create an interface for brand recognition in images and videos.
+
+ The interface uses gradio Tabs to switch between an image and video interface.
+ The image interface accepts an image and returns an annotated image, item quantities, and average confidence scores.
+ The video interface accepts a video and returns an annotated video with bounding boxes and item quantities.
+
+ Returns:
+ gr.Interface
+ An Interface object that can be launched to accept user input.
+ """
+ with gr.Blocks() as demo:
+ gr.Markdown("# Flipkart Grid Robotics Track - Brand Recognition Interface")
+
+ with gr.Tabs():
+ with gr.Tab("Image"):
+ create_image_interface()
+ with gr.Tab("Video"):
+ create_video_interface()
+ return demo
+
+Brand_recog = create_brand_recog_interface()
diff --git a/Frontend/BrandRecongnition/Video.py b/Frontend/BrandRecongnition/Video.py
new file mode 100644
index 0000000000000000000000000000000000000000..f513fb75b8c5178a058c6e08b2b5d3a2bc0f4bf3
--- /dev/null
+++ b/Frontend/BrandRecongnition/Video.py
@@ -0,0 +1,31 @@
+import gradio as gr
+from Backend.BrandRecognition.Dynamic.Brand_Count_Vid import annotate_video
+
+
+def create_video_interface():
+ """
+ Create an interface for object detection in a video.
+
+ The interface allows users to upload a video, and the model will return an annotated video with bounding boxes and item quantities.
+
+ Returns:
+ gr.Interface: A Gradio interface object.
+ """
+ return gr.Interface(
+ fn=annotate_video,
+ inputs=gr.Video(label="Upload Video"),
+ outputs=[
+ gr.Video(label="Annotated Video"), # Display the annotated video
+ gr.Dataframe(headers=["Item", "Quantity"], label="Detected Items and Quantities"), # Display detected items
+ gr.Textbox(label="Status") # Display status message
+ ],
+ title="Grocery Item Detection in Video",
+ description=(
+ "Upload a video for grocery item detection. The model will process the video "
+ "and return an annotated version with bounding boxes and detected item quantities."
+ ),
+ examples=None,
+ allow_flagging="never",
+ live=False,
+ )
+
diff --git a/Frontend/FruitFreshness/Image.py b/Frontend/FruitFreshness/Image.py
new file mode 100644
index 0000000000000000000000000000000000000000..733ec19369642ae21d00ecb4e762c9b6952ece2f
--- /dev/null
+++ b/Frontend/FruitFreshness/Image.py
@@ -0,0 +1,16 @@
+
+import gradio as gr
+from Backend.Fruit_Freshness.Freshness_main import freshness
+
+
+def image_freshness_interface():
+ return gr.Interface(
+ fn=freshness,
+ inputs=gr.Image(type="pil", label="Upload an Image"), # Removed tool argument
+ #textbox outputs
+ outputs="text",
+ title="Banana Freshness Classifier",
+ description="Upload an image of a banana to classify its freshness.",
+ css="#component-0 { width: 300px; height: 300px; }" # Keep your CSS for fixe
+ )
+
diff --git a/Frontend/FruitFreshness/Integration_FR.py b/Frontend/FruitFreshness/Integration_FR.py
new file mode 100644
index 0000000000000000000000000000000000000000..370154c13ac7074d55d54ddce40e5c73a9c2c03b
--- /dev/null
+++ b/Frontend/FruitFreshness/Integration_FR.py
@@ -0,0 +1,14 @@
+import gradio as gr
+from Frontend.FruitFreshness.Image import image_freshness_interface
+
+
+def create_fruit_interface():
+ with gr.Blocks() as demo:
+ gr.Markdown("# Flipkart Grid Robotics Track - Fruits Interface")
+ with gr.Tabs():
+ with gr.Tab("Image Freshness"):
+ image_freshness_interface() # Call the image freshness interface
+ return demo
+
+
+Fruit = create_fruit_interface()
diff --git a/Frontend/OCR/ImageOCR.py b/Frontend/OCR/ImageOCR.py
new file mode 100644
index 0000000000000000000000000000000000000000..fb1d4941ddc7eeb77595fba35d7efed790d1de0c
--- /dev/null
+++ b/Frontend/OCR/ImageOCR.py
@@ -0,0 +1,71 @@
+import gradio as gr
+from Backend.OCR.Static.ImageOCR import detect_and_ocr, extract_details_from_validated_output, further_processing,handle_processing
+
+def createStaticOcrInterface():
+ with gr.Blocks() as ocr_interface:
+ gr.Markdown("# Flipkart Grid Robotics Track - OCR Interface")
+
+ with gr.Tabs():
+ # Upload and Detection Tab
+ with gr.TabItem("Upload & Detection"):
+ with gr.Row():
+ input_image = gr.Image(type="pil", label="Upload Image", height=400, width=400)
+ output_image = gr.Image(label="Image with Bounding Boxes", height=400, width=400)
+
+ btn = gr.Button("Analyze Image & Extract Text")
+
+ # OCR Results Tab
+ with gr.TabItem("OCR Results"):
+ with gr.Row():
+ extracted_textbox = gr.Textbox(label="Extracted OCR Text", lines=5)
+ with gr.Row():
+ refined_textbox = gr.Textbox(label="Refined Text from Gemini", lines=5)
+ with gr.Row():
+ validated_textbox = gr.Textbox(label="Validated Output", lines=5)
+
+ # Data table for Manufacturing Date, Expiration Date, and MRP
+ with gr.Row():
+ detail_table = gr.Dataframe(
+ headers=["Label", "Value"],
+ value=[["", ""], ["", ""], ["", ""]], # Initialize with empty values
+ label="Manufacturing, Expiration Dates & MRP",
+ datatype=["str", "str"],
+ interactive=False,
+ )
+
+ further_button = gr.Button("Comprehensive OCR", visible=False)
+
+ # Detect and OCR button click event
+ btn.click(
+ detect_and_ocr,
+ inputs=[input_image],
+ outputs=[output_image, extracted_textbox, refined_textbox, validated_textbox]
+ )
+
+ # Update the table when validated_textbox changes
+ validated_textbox.change(
+ lambda validated_output: extract_details_from_validated_output(validated_output),
+ inputs=[validated_textbox],
+ outputs=[detail_table]
+ )
+
+ # Further processing button click event
+ further_button.click(
+ further_processing,
+ inputs=[input_image, extracted_textbox],
+ outputs=refined_textbox
+ )
+
+ # Monitor validated output to control button visibility
+ refined_textbox.change(
+ handle_processing,
+ inputs=[validated_textbox],
+ outputs=[further_button]
+ )
+
+ further_button.click(
+ lambda: gr.update(visible=False),
+ outputs=[validated_textbox]
+ )
+
+ return ocr_interface
\ No newline at end of file
diff --git a/Frontend/OCR/Integration_OCR.py b/Frontend/OCR/Integration_OCR.py
new file mode 100644
index 0000000000000000000000000000000000000000..4d2ea2c38d0e1985d357315ad47259ab66a328db
--- /dev/null
+++ b/Frontend/OCR/Integration_OCR.py
@@ -0,0 +1,28 @@
+import gradio as gr
+from Frontend.OCR.ImageOCR import createStaticOcrInterface
+from Frontend.OCR.VideoOCR import createVideoOcrInterface
+
+def create_OCR_Interface():
+ """
+ Create an interface for OCR in an image or video.
+
+ The interface allows users to upload an image or video, and the model will return the detected text.
+
+ Returns:
+ gr.Interface: A Gradio interface object.
+ """
+ with gr.Blocks() as ocr_interface:
+ gr.Markdown("# Flipkart Grid Robotics Track - OCR Interface")
+
+ with gr.Tabs():
+ # Image OCR Tab
+ with gr.TabItem("Image OCR"):
+ createStaticOcrInterface()
+
+ # Video OCR Tab
+ with gr.TabItem("Video OCR"):
+ createVideoOcrInterface()
+
+ return ocr_interface
+
+Ocr = create_OCR_Interface()
\ No newline at end of file
diff --git a/Frontend/OCR/VideoOCR.py b/Frontend/OCR/VideoOCR.py
new file mode 100644
index 0000000000000000000000000000000000000000..62a4679ab47fccbf5f27f2427a5d2404f451f65e
--- /dev/null
+++ b/Frontend/OCR/VideoOCR.py
@@ -0,0 +1,27 @@
+import gradio as gr
+from Backend.OCR.Dynamic.VideoOCR import gradio_video_ocr_processing
+def createVideoOcrInterface():
+ """
+ Create an interface for OCR in a video.
+
+ The interface allows users to upload a video, and the model will return an annotated video with bounding boxes and detected text.
+ """
+ return gr.Interface(
+ fn=gradio_video_ocr_processing,
+ inputs=gr.Video(label="Upload Video File (.mp4)"),
+ outputs=[
+ gr.Video(label="Annotated Video"),
+ gr.Textbox(label="Gemini Full Response"),
+ gr.JSON(label="Parsed Output")
+ ],
+ title="OCR in Video",
+ description=(
+ "Upload a video for OCR. The model will process the video "
+ "and return an annotated version with bounding boxes and detected text."
+ "It will also process the text with Gemini LLM for manufacturing, expiry date and MRP predictions."
+ ),
+ examples=None,
+ allow_flagging="never",
+ live=False,
+ )
+
diff --git a/Frontend/db/db.py b/Frontend/db/db.py
new file mode 100644
index 0000000000000000000000000000000000000000..bcc1a7dd30af2ee3c5db504cb2ed980640b29196
--- /dev/null
+++ b/Frontend/db/db.py
@@ -0,0 +1,162 @@
+import gradio as gr
+import json
+from Database.mongodb import DatabaseManager
+import traceback
+
+def create_gradio_interface():
+
+ db_manager = DatabaseManager()
+
+ def safe_execute(func, *args, **kwargs):
+ """
+ Wrapper to handle exceptions gracefully
+ """
+ try:
+ return func(*args, **kwargs)
+ except Exception as e:
+ return f"Error occurred: {str(e)}\n\nTraceback:\n{traceback.format_exc()}"
+ # Brand Record Methods
+
+ def get_brand_records(filter_brand='', sort_by='timestamp', ascending=False):
+ filter_criteria = {}
+ if filter_brand:
+ filter_criteria['brand'] = {'$regex': filter_brand, '$options': 'i'}
+
+ return safe_execute(db_manager.get_brand_records, filter_criteria, sort_by, ascending)
+
+ def get_freshness_records(filter_freshness='', sort_by='timestamp', ascending=False):
+ filter_criteria = {}
+ if filter_freshness:
+ filter_criteria['Eatable'] = {'$regex': filter_freshness, '$options': 'i'}
+
+ return safe_execute(db_manager.get_freshness_records, filter_criteria, sort_by, ascending)
+
+
+ # Analysis Methods
+ def analyze_brand_trends(time_period):
+ return safe_execute(db_manager.analyze_brand_trends, int(time_period))
+
+ # Advanced Search
+ def perform_advanced_search(collection, search_criteria, projection):
+ try:
+ # Parse search criteria and projection as JSON
+ search_dict = json.loads(search_criteria) if search_criteria else {}
+ proj_dict = json.loads(projection) if projection else {}
+
+ return safe_execute(db_manager.advanced_search, collection, search_dict, proj_dict)
+ except json.JSONDecodeError:
+ return "Invalid JSON format for search criteria or projection"
+
+ # Export Methods
+ def export_collection(collection_name):
+ return safe_execute(db_manager.export_collection_to_json, collection_name)
+
+ # Gradio Interface Construction
+ with gr.Blocks(title="Database Management System", theme=gr.themes.Soft()) as demo:
+ gr.Markdown("# 📊 Advanced Database Management System")
+
+ with gr.Tab("Brand Records"):
+ with gr.Row():
+
+ with gr.Column():
+ gr.Markdown("## 📋 Get Brand Records")
+ filter_brand = gr.Textbox(label="Filter by Brand (optional)")
+ sort_by = gr.Dropdown(
+ ["timestamp", "count"],
+ label="Sort By",
+ value="timestamp"
+ )
+ ascending = gr.Checkbox(label="Ascending Order")
+ get_brands_btn = gr.Button("Retrieve Brand Records")
+ brand_records_output = gr.JSON(label="Brand Records")
+
+
+ get_brands_btn.click(
+ get_brand_records,
+ inputs=[filter_brand, sort_by, ascending],
+ outputs=brand_records_output
+ )
+
+
+
+ with gr.Tab("Freshness Records"):
+ with gr.Row():
+ with gr.Column():
+ gr.Markdown("## 🍎 Get Freshness Record")
+ filter_freshness = gr.Textbox(label="Filter by Freshness (optional)")
+ sort_by = gr.Dropdown(
+ ["timestamp", "count"],
+ label="Sort By",
+ value="timestamp"
+ )
+ ascending = gr.Checkbox(label="Ascending Order")
+ get_freshness_btn = gr.Button("Retrieve Freshness Records")
+ freshness_records_output = gr.JSON(label="Freshness Records")
+
+ get_freshness_btn.click(
+ get_freshness_records,
+ inputs=[filter_freshness, sort_by, ascending],
+ outputs=freshness_records_output
+ )
+
+
+
+ with gr.Tab("Analytics & Search"):
+ with gr.Row():
+ with gr.Column():
+ gr.Markdown("## 📈 Brand Trend Analysis")
+ time_period = gr.Number(label="Time Period (Days)", value=30)
+ analyze_trends_btn = gr.Button("Analyze Brand Trends")
+ trends_output = gr.JSON(label="Brand Trends")
+
+ with gr.Column():
+ gr.Markdown("## 🔬 Advanced Search")
+ collection_dropdown = gr.Dropdown(
+ ["brand", "ocr", "freshness"],
+ label="Collection"
+ )
+ search_criteria = gr.Textbox(
+ label="Search Criteria (JSON)",
+ placeholder='e.g., {"count": {"$gt": 100}}'
+ )
+ projection = gr.Textbox(
+ label="Projection (JSON)",
+ placeholder='e.g., {"brand": 1, "count": 1}'
+ )
+ search_btn = gr.Button("Perform Search")
+ search_output = gr.JSON(label="Search Results")
+
+ # Analytics Interactions
+ analyze_trends_btn.click(
+ analyze_brand_trends,
+ inputs=time_period,
+ outputs=trends_output
+ )
+ search_btn.click(
+ perform_advanced_search,
+ inputs=[collection_dropdown, search_criteria, projection],
+ outputs=search_output
+ )
+
+ with gr.Tab("Export"):
+ with gr.Row():
+ with gr.Column():
+ gr.Markdown("## 📤 Export Collections")
+ export_collection_dropdown = gr.Dropdown(
+ ["brand", "ocr", "freshness"],
+ label="Select Collection to Export"
+ )
+ export_btn = gr.Button("Export to JSON")
+ export_output = gr.Textbox(label="Export Result")
+
+ # Export Interactions
+ export_btn.click(
+ export_collection,
+ inputs=export_collection_dropdown,
+ outputs=export_output
+ )
+
+ return demo
+
+
+db_interface = create_gradio_interface()
\ No newline at end of file
diff --git a/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.03 (1).jpeg b/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.03 (1).jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..fb441dd5a63db7a045e492a54873292f91ee288f
Binary files /dev/null and b/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.03 (1).jpeg differ
diff --git a/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.03.jpeg b/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.03.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..95b222fe34f6a96fff9129fd0919c1457e503439
Binary files /dev/null and b/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.03.jpeg differ
diff --git a/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.04.jpeg b/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.04.jpeg
new file mode 100644
index 0000000000000000000000000000000000000000..687d13492e65c329d6fae0373858f07689881164
Binary files /dev/null and b/Tests/Images/BrandRecognition/WhatsApp Image 2024-12-06 at 21.15.04.jpeg differ
diff --git a/Tests/Images/Freshness/Photos/Fresh_1.png b/Tests/Images/Freshness/Photos/Fresh_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..193916cd91556a5562bdf9913b9ca5a5de79e83f
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Fresh_1.png differ
diff --git a/Tests/Images/Freshness/Photos/Fresh_2.png b/Tests/Images/Freshness/Photos/Fresh_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..98ced8d972b4f3a4106f151c2bdc4734e96626d2
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Fresh_2.png differ
diff --git a/Tests/Images/Freshness/Photos/Fresh_3.png b/Tests/Images/Freshness/Photos/Fresh_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..ccbc38433ae69896e1aa795b2e56d0b9a7657018
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Fresh_3.png differ
diff --git a/Tests/Images/Freshness/Photos/Fresh_4.png b/Tests/Images/Freshness/Photos/Fresh_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..f2fcb1467c5d7a6b9b9e0ea385c2225c8dce9aee
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Fresh_4.png differ
diff --git a/Tests/Images/Freshness/Photos/Fresh_5.png b/Tests/Images/Freshness/Photos/Fresh_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..747583a96394428ade2105bbe9c623d1f3b9403c
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Fresh_5.png differ
diff --git a/Tests/Images/Freshness/Photos/Rotten_1.png b/Tests/Images/Freshness/Photos/Rotten_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..cd179fff58ef1ae7222862756b6a7a0e66b8956f
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Rotten_1.png differ
diff --git a/Tests/Images/Freshness/Photos/Rotten_2.png b/Tests/Images/Freshness/Photos/Rotten_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..9a779971c9cbcc14e84e70ca0e1306607bd05a2c
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Rotten_2.png differ
diff --git a/Tests/Images/Freshness/Photos/Rotten_3.png b/Tests/Images/Freshness/Photos/Rotten_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..9fd08da64beeba23067a22f2642ae2d3aeac1edf
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Rotten_3.png differ
diff --git a/Tests/Images/Freshness/Photos/Rotten_4.png b/Tests/Images/Freshness/Photos/Rotten_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..4d22b9ba50c68a454d87204ade73daa849ee8b2f
Binary files /dev/null and b/Tests/Images/Freshness/Photos/Rotten_4.png differ
diff --git a/Tests/Images/Freshness/Pictures/1.png b/Tests/Images/Freshness/Pictures/1.png
new file mode 100644
index 0000000000000000000000000000000000000000..39fc564041134507e8282e1cdaa53a5a015f2909
Binary files /dev/null and b/Tests/Images/Freshness/Pictures/1.png differ
diff --git a/Tests/Images/Freshness/Pictures/2.png b/Tests/Images/Freshness/Pictures/2.png
new file mode 100644
index 0000000000000000000000000000000000000000..87e019be012795e111a127fd56dadefceb9e712b
Binary files /dev/null and b/Tests/Images/Freshness/Pictures/2.png differ
diff --git a/Tests/Images/Freshness/Pictures/4.png b/Tests/Images/Freshness/Pictures/4.png
new file mode 100644
index 0000000000000000000000000000000000000000..46f1942cb125df5de5d1b576d1583fa3826320e8
Binary files /dev/null and b/Tests/Images/Freshness/Pictures/4.png differ
diff --git a/Tests/Images/Freshness/Pictures/5.png b/Tests/Images/Freshness/Pictures/5.png
new file mode 100644
index 0000000000000000000000000000000000000000..9fd5a54d25b6480b82db7d426f3f929253b0bd2f
Binary files /dev/null and b/Tests/Images/Freshness/Pictures/5.png differ
diff --git a/Tests/Images/Freshness/Pictures/6.png b/Tests/Images/Freshness/Pictures/6.png
new file mode 100644
index 0000000000000000000000000000000000000000..e1a12ac2e9c31150ed841bc62e3bf3b3ab0fa7c8
Binary files /dev/null and b/Tests/Images/Freshness/Pictures/6.png differ
diff --git a/Tests/Images/Freshness/Pictures/7.png b/Tests/Images/Freshness/Pictures/7.png
new file mode 100644
index 0000000000000000000000000000000000000000..0303d8cb90d00541d6f2a8f6a78d145104bead5b
Binary files /dev/null and b/Tests/Images/Freshness/Pictures/7.png differ
diff --git a/Tests/Images/Freshness/Pictures/8.png b/Tests/Images/Freshness/Pictures/8.png
new file mode 100644
index 0000000000000000000000000000000000000000..989df489f30b940620f2eceec6c978030ffae149
Binary files /dev/null and b/Tests/Images/Freshness/Pictures/8.png differ
diff --git a/Tests/Images/Freshness/Pictures/Image_3.png b/Tests/Images/Freshness/Pictures/Image_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..926242dc01f277b4d1087338a6c5cdb2c540f38d
Binary files /dev/null and b/Tests/Images/Freshness/Pictures/Image_3.png differ
diff --git a/Tests/videos/video.mp4 b/Tests/videos/video.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..1bb0d1ae6b6c23e0aac5e127be2ade772bf2def6
--- /dev/null
+++ b/Tests/videos/video.mp4
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:45ff50cee978b747a6406568635afa2ffaff50f7e2dd6ee0a9fe4f39996a42d2
+size 1143874
diff --git a/Tests/videos/video_for_ocr.mp4 b/Tests/videos/video_for_ocr.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..97ba022312b144487075b24c013ccf13ea66da65
--- /dev/null
+++ b/Tests/videos/video_for_ocr.mp4
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:e3d8248a76bccc7ac6ce55c559d3201122bfe678f4c38fca319bf91b2ad8734b
+size 2131228
diff --git a/Weights/freshness.pt b/Weights/freshness.pt
new file mode 100644
index 0000000000000000000000000000000000000000..bbc3c5c65db42c01fb37bb1dd5fb60cca48576ee
--- /dev/null
+++ b/Weights/freshness.pt
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f665e360f8797d486077d003a1ee563b2f41e04cf7ddff3b035db0f0495adb16
+size 22495523
diff --git a/Weights/kitkat_s.pt b/Weights/kitkat_s.pt
new file mode 100644
index 0000000000000000000000000000000000000000..1e51f4b6de4f611286177576be83390c05084c94
--- /dev/null
+++ b/Weights/kitkat_s.pt
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:a771157224c10ab4c8e8fdf7f19005629ef67e2f57664bffe0173927d9865815
+size 19961007
diff --git a/annotated_output.mp4 b/annotated_output.mp4
new file mode 100644
index 0000000000000000000000000000000000000000..3e282849ce48f77b3c66dee0d93c07d5570f80e3
--- /dev/null
+++ b/annotated_output.mp4
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:7665369482e46f927eb1b59f1e41756b6d9c6f78ef4fd02ccb5197b367e3449a
+size 1599160
diff --git a/main.py b/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..11a0e09c78952ae33a142737fed3e3852576a5ee
--- /dev/null
+++ b/main.py
@@ -0,0 +1,31 @@
+import gradio as gr
+from Frontend.BrandRecongnition.Integration_BR import Brand_recog
+from Frontend.FruitFreshness.Integration_FR import Fruit
+from Frontend.db.db import db_interface
+from Frontend.OCR.Integration_OCR import Ocr
+
+# Define custom CSS to enlarge elements
+custom_css = """
+* {
+ font-size: 18px !important; /* Increase font size globally */
+}
+button {
+ font-size: 20px !important; /* Enlarge button text */
+}
+.gr-container {
+ transform: scale(1.5); /* Scale entire interface */
+}
+"""
+
+def create_tabbed_interface():
+ return gr.TabbedInterface(
+ [Brand_recog, Fruit, Ocr, db_interface],
+ ["Brand Recognition", "Freshness Detection", "OCR Interface", "Database Records"],
+ )
+
+with gr.Blocks(css=custom_css) as tabbed_interface:
+ create_tabbed_interface()
+
+if __name__ == "__main__":
+ tabbed_interface.queue()
+ tabbed_interface.launch(debug=True)
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..26ca073bf81c902fa842124a74f878b3b2d81460
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,15 @@
+gradio==5.8.0
+matplotlib==3.8.4
+numpy==2.2.0
+opencv_contrib_python==4.10.0.84
+opencv_python==4.9.0.80
+opencv_python_headless==4.10.0.84
+paddleocr==2.9.1
+paddleocr.egg==info
+pandas==2.2.3
+Pillow==11.0.0
+protobuf==5.29.1
+pymongo==4.10.1
+scikit_learn==1.4.2
+scipy==1.14.1
+ultralytics==8.3.15