diff --git a/.gitignore b/.gitignore index 3c376992c637b36d09a851de4354488e043144a6..12a9eb27814870fb520e00cd9545e3dbf29385f1 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,6 @@ __pycache__/ # Ignore all migrations directories migrations/ + +/media/ +media/ \ No newline at end of file diff --git a/MisplaceAI/MisplaceAI/__pycache__/settings.cpython-310.pyc b/MisplaceAI/MisplaceAI/__pycache__/settings.cpython-310.pyc index b7655d4edfc9a06ebba39bc17462088eb74dbd78..35c5da5b4fd5d421b404460cb3cdf37b3220e3ae 100644 Binary files a/MisplaceAI/MisplaceAI/__pycache__/settings.cpython-310.pyc and b/MisplaceAI/MisplaceAI/__pycache__/settings.cpython-310.pyc differ diff --git a/MisplaceAI/MisplaceAI/__pycache__/urls.cpython-310.pyc b/MisplaceAI/MisplaceAI/__pycache__/urls.cpython-310.pyc index 5bc9500af69bbc23baeceebb12d89e00ba5686c3..3956f0b2d86625453804480eab685b35352ca45c 100644 Binary files a/MisplaceAI/MisplaceAI/__pycache__/urls.cpython-310.pyc and b/MisplaceAI/MisplaceAI/__pycache__/urls.cpython-310.pyc differ diff --git a/MisplaceAI/MisplaceAI/urls.py b/MisplaceAI/MisplaceAI/urls.py index 72133439728ebff809a22214688c13b243b9e63f..9d2cb18ff6cf93edbe2139e41f7e68789d9d3c5d 100644 --- a/MisplaceAI/MisplaceAI/urls.py +++ b/MisplaceAI/MisplaceAI/urls.py @@ -12,15 +12,10 @@ urlpatterns = [ path('auth/', include('authentication.urls')), path('admin-app/', include('admin_app.urls')), path('process_misplaced_manager/', include('process_misplaced_manager.urls', namespace='process_misplaced_manager')), # Ensure namespace is included correctly - path('item_detector/', include('item_detector.urls', namespace='item_detector')), # Include item_detector URLs with namespace - path('placement_rules/', include('placement_rules.urls', namespace='placement_rules')), # Include placement_rules URLs with namespace - path('results_viewer/', include('results_viewer.urls', namespace='results_viewer')), - - - + + + path('results_viewer/', include('results_viewer.urls', namespace='results_viewer')), # Include results_viewer URLs with namespace ] - - if settings.DEBUG: - urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) \ No newline at end of file + urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) diff --git a/MisplaceAI/item_detector/admin.py b/MisplaceAI/item_detector/admin.py deleted file mode 100644 index 8c38f3f3dad51e4585f3984282c2a4bec5349c1e..0000000000000000000000000000000000000000 --- a/MisplaceAI/item_detector/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/MisplaceAI/item_detector/apps.py b/MisplaceAI/item_detector/apps.py index 9f89fa27ed3f499c0c0a6f3cbde4ce0fadeb8469..28e4c480515a24823b6f07082d4c3b67aaf5812f 100644 --- a/MisplaceAI/item_detector/apps.py +++ b/MisplaceAI/item_detector/apps.py @@ -1,5 +1,7 @@ +# item_detector/apps.py + from django.apps import AppConfig class ItemDetectorConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' name = 'item_detector' - verbose_name = 'Item Detector' diff --git a/MisplaceAI/item_detector/models.py b/MisplaceAI/item_detector/models.py index 38fc6067d96dcf66c07181616568db6236d6d8d3..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/MisplaceAI/item_detector/models.py +++ b/MisplaceAI/item_detector/models.py @@ -1,13 +0,0 @@ -#item_detector/models.py -from django.db import models - -class DetectedObject(models.Model): - class_name = models.CharField(max_length=255) - ymin = models.FloatField() - xmin = models.FloatField() - ymax = models.FloatField() - xmax = models.FloatField() - image = models.ForeignKey('process_misplaced_manager.UploadedImage', on_delete=models.CASCADE) - - def __str__(self): - return f"{self.class_name} ({self.ymin}, {self.xmin}, {self.ymax}, {self.xmax})" diff --git a/MisplaceAI/item_detector/templates/item_detector/results.html b/MisplaceAI/item_detector/templates/item_detector/results.html deleted file mode 100644 index 6619f9b233e082608503689fa93cfed53a47dea2..0000000000000000000000000000000000000000 --- a/MisplaceAI/item_detector/templates/item_detector/results.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends 'core/base.html' %} -{% load static %} - -{% block content %} -<div class="container mt-5"> - <h1>Detected Objects</h1> - <img src="{{ output_image_url }}" alt="Detected Objects" class="img-fluid"> - <h2>Details</h2> - <ul> - {% for obj in detected_objects %} - <li>{{ obj.class_name }}: [{{ obj.ymin }}, {{ obj.xmin }}, {{ obj.ymax }}, {{ obj.xmax }}]</li> - {% endfor %} - </ul> - {% if misplaced_objects %} - <h2>Misplaced Objects</h2> - <ul> - {% for obj in misplaced_objects %} - <li>{{ obj.class_name }} is misplaced. It should be on {{ obj.allowed_locations|join:", " }}.</li> - {% endfor %} - </ul> - {% endif %} - <h2>Annotated Image with Misplaced Items</h2> - <img src="{{ annotated_image_url }}" alt="Annotated Image" class="img-fluid"> -</div> -{% endblock %} \ No newline at end of file diff --git a/MisplaceAI/item_detector/urls.py b/MisplaceAI/item_detector/urls.py deleted file mode 100644 index fa4f4b8b4e475cf7a58dab6dd6e78d74b51d7b08..0000000000000000000000000000000000000000 --- a/MisplaceAI/item_detector/urls.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.urls import path -from .views import detect_items - -app_name = 'item_detector' - -urlpatterns = [ - path('detect/<int:image_id>/', detect_items, name='detect_items'), -] diff --git a/MisplaceAI/item_detector/utils.py b/MisplaceAI/item_detector/utils.py index 98bd2503e1dbbb5cb577c83e27a7c288ce906f8b..db00dde7265a5e25c7b3249e31f7e80f8d55d86b 100644 --- a/MisplaceAI/item_detector/utils.py +++ b/MisplaceAI/item_detector/utils.py @@ -1,84 +1,85 @@ +import os +import glob import numpy as np -from PIL import Image, ImageDraw, ImageFont -from io import BytesIO import tensorflow as tf -import os +from PIL import Image +from io import BytesIO +from object_detection.utils import ops as utils_ops, label_map_util +# Patch tf1 functions into `utils.ops` for compatibility +utils_ops.tf = tf.compat.v1 -from object_detection.utils import label_map_util, ops as utils_ops +# Patch the location of gfile for TensorFlow file operations +tf.gfile = tf.io.gfile -os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2" +def load_model(model_path): + """Load the object detection model from the specified path.""" + model = tf.saved_model.load(model_path) + return model -MAX_DIMENSION = 1024 +def create_category_index_from_labelmap(label_map_path, use_display_name=True): + """Create a category index from a label map file.""" + return label_map_util.create_category_index_from_labelmap(label_map_path, use_display_name=use_display_name) def load_image_into_numpy_array(path): + """Load an image from file into a numpy array.""" img_data = tf.io.gfile.GFile(path, "rb").read() image = Image.open(BytesIO(img_data)) (im_width, im_height) = image.size return np.array(image.getdata()).reshape((im_height, im_width, 3)).astype(np.uint8) -def load_model(model_path): - return tf.saved_model.load(model_path) +def run_inference(model, category_index, image_path): + """Run inference on a single image.""" + print("-----------------------------------") + print("DEBUG-MESSAGE--FROM-BATCH-INTERFACE") -def create_category_index_from_labelmap(label_map_path, use_display_name=True): - return label_map_util.create_category_index_from_labelmap(label_map_path, use_display_name) + image_np = load_image_into_numpy_array(image_path) + output_dict = run_inference_for_single_image(model, image_np) + + dataLocation = [] + print(f"Detected objects in {image_path}:") + for i, box in enumerate(output_dict["detection_boxes"]): + if output_dict["detection_scores"][i] > 0.5: + ymin, xmin, ymax, xmax = box + class_id = output_dict["detection_classes"][i] + class_name = category_index[class_id]["name"] if class_id in category_index else "N/A" + print(f"Object {i+1} ({class_name}): [{ymin:.2f}, {xmin:.2f}, {ymax:.2f}, {xmax:.2f}]") + dataLocation.append({ + "Object": i, + "class_name": class_name, + "ymin": ymin, + "xmin": xmin, + "ymax": ymax, + "xmax": xmax, + }) -def resize_image(image): - width, height = image.size - if width > MAX_DIMENSION or height > MAX_DIMENSION: - if width > height: - new_width = MAX_DIMENSION - new_height = int((MAX_DIMENSION / width) * height) - else: - new_height = MAX_DIMENSION - new_width = int((MAX_DIMENSION / height) * width) - return image.resize((new_width, new_height), Image.ANTIALIAS) - return image + print("-----------------------------------") + return dataLocation -def run_inference(model, category_index, image_path): - image_np = load_image_into_numpy_array(image_path) - input_tensor = tf.convert_to_tensor(image_np) +def run_inference_for_single_image(model, image): + """Run inference on a single image and return the output dictionary.""" + # Convert image to tensor and add batch dimension + input_tensor = tf.convert_to_tensor(image) input_tensor = input_tensor[tf.newaxis, ...] + + # Run inference output_dict = model(input_tensor) + + # Process output tensors num_detections = int(output_dict.pop("num_detections")) output_dict = {key: value[0, :num_detections].numpy() for key, value in output_dict.items()} output_dict["num_detections"] = num_detections output_dict["detection_classes"] = output_dict["detection_classes"].astype(np.int64) - detected_objects = [] - for i in range(num_detections): - if output_dict['detection_scores'][i] > 0.5: - ymin, xmin, ymax, xmax = output_dict['detection_boxes'][i] - class_id = output_dict['detection_classes'][i] - class_name = category_index[class_id]['name'] if class_id in category_index else 'N/A' - detected_objects.append({ - 'class_name': class_name, - 'ymin': ymin, - 'xmin': xmin, - 'ymax': ymax, - 'xmax': xmax - }) - - return detected_objects - -def visualize_boxes(image_path, detected_objects, output_path): - image = Image.open(image_path) - image = resize_image(image) # Resize the image if necessary - draw = ImageDraw.Draw(image) - font = ImageFont.load_default() - - for obj in detected_objects: - ymin = obj['ymin'] * image.height - xmin = obj['xmin'] * image.width - ymax = obj['ymax'] * image.height - xmax = obj['xmax'] * image.width - - draw.rectangle([(xmin, ymin), (xmax, ymax)], outline="red", width=3) - draw.text((xmin, ymin), obj['class_name'], fill="red", font=font) - - image.save(output_path) - -def run_inference_and_visualize(model, category_index, image_path, output_path): - detected_objects = run_inference(model, category_index, image_path) - visualize_boxes(image_path, detected_objects, output_path) - return detected_objects + # Process masks, if available + if "detection_masks" in output_dict: + detection_masks_reframed = utils_ops.reframe_box_masks_to_image_masks( + output_dict["detection_masks"], + output_dict["detection_boxes"], + image.shape[0], + image.shape[1], + ) + detection_masks_reframed = tf.cast(detection_masks_reframed > 0.5, tf.uint8) + output_dict["detection_masks_reframed"] = detection_masks_reframed.numpy() + + return output_dict diff --git a/MisplaceAI/item_detector/views.py b/MisplaceAI/item_detector/views.py deleted file mode 100644 index 0cbfdce64158f7acfb142ad431efaa572b801fd3..0000000000000000000000000000000000000000 --- a/MisplaceAI/item_detector/views.py +++ /dev/null @@ -1,43 +0,0 @@ -from django.shortcuts import render, get_object_or_404 -from .models import DetectedObject -from process_misplaced_manager.models import UploadedImage -from .utils import run_inference, load_model, create_category_index_from_labelmap, run_inference_and_visualize -from placement_rules.utils import PlacementRules -from results_viewer.utils import visualize_misplaced_objects # Import the visualization function -import os - -MODEL_PATH = "models/research/object_detection/faster_rcnn_resnet50_v1_1024x1024_coco17_tpu-8/saved_model" -LABEL_MAP_PATH = "models/research/object_detection/data/mscoco_label_map.pbtxt" - -detection_model = load_model(MODEL_PATH) -category_index = create_category_index_from_labelmap(LABEL_MAP_PATH) - -def detect_items(request, image_id): - image = get_object_or_404(UploadedImage, id=image_id) - image_path = image.image.path - output_image_name = "detected_" + os.path.basename(image_path) - output_image_path = os.path.join("media", output_image_name) - detected_objects = run_inference_and_visualize(detection_model, category_index, image_path, output_image_path) - - for obj in detected_objects: - DetectedObject.objects.create( - class_name=obj['class_name'], - ymin=obj['ymin'], - xmin=obj['xmin'], - ymax=obj['ymax'], - xmax=obj['xmax'], - image=image - ) - - placement_rules = PlacementRules() - misplaced_objects = placement_rules.check_placement(detected_objects) - - annotated_image_path = visualize_misplaced_objects(image_path, detected_objects, misplaced_objects) - - return render(request, 'item_detector/results.html', { - 'detected_objects': detected_objects, - 'image': image, - 'output_image_url': "/media/" + output_image_name, - 'annotated_image_url': "/media/" + os.path.basename(annotated_image_path), - 'misplaced_objects': misplaced_objects - }) diff --git a/MisplaceAI/media/annotated_c_s1KC3iy.jpg b/MisplaceAI/media/annotated_c_s1KC3iy.jpg deleted file mode 100644 index 5dd24ad54a519568232d04d730e5049bc92c4108..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/annotated_c_s1KC3iy.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_1265_8dCYFrT.jpg b/MisplaceAI/media/detected_1265_8dCYFrT.jpg deleted file mode 100644 index ba2a60116c41303b7907c1d222b81881fffd58ad..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_1265_8dCYFrT.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_1265_SqbKUM7.jpg b/MisplaceAI/media/detected_1265_SqbKUM7.jpg deleted file mode 100644 index 08a8b6febef360e4d82675ebe8643dbf1085c38b..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_1265_SqbKUM7.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_1265_Ut88mRj.jpg b/MisplaceAI/media/detected_1265_Ut88mRj.jpg deleted file mode 100644 index 08a8b6febef360e4d82675ebe8643dbf1085c38b..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_1265_Ut88mRj.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_1265_WZU8Jas.jpg b/MisplaceAI/media/detected_1265_WZU8Jas.jpg deleted file mode 100644 index ba2a60116c41303b7907c1d222b81881fffd58ad..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_1265_WZU8Jas.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_1265_qlFQMla.jpg b/MisplaceAI/media/detected_1265_qlFQMla.jpg deleted file mode 100644 index ba2a60116c41303b7907c1d222b81881fffd58ad..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_1265_qlFQMla.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_c.jpg b/MisplaceAI/media/detected_c.jpg deleted file mode 100644 index 867a5bdc7641d25505bed97b51541164d21c6cad..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_c.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_c_Q8DkqzK.jpg b/MisplaceAI/media/detected_c_Q8DkqzK.jpg deleted file mode 100644 index 867a5bdc7641d25505bed97b51541164d21c6cad..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_c_Q8DkqzK.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_c_oyoy0lB.jpg b/MisplaceAI/media/detected_c_oyoy0lB.jpg deleted file mode 100644 index 867a5bdc7641d25505bed97b51541164d21c6cad..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_c_oyoy0lB.jpg and /dev/null differ diff --git a/MisplaceAI/media/detected_c_s1KC3iy.jpg b/MisplaceAI/media/detected_c_s1KC3iy.jpg deleted file mode 100644 index 867a5bdc7641d25505bed97b51541164d21c6cad..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/detected_c_s1KC3iy.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265.jpg b/MisplaceAI/media/uploads/1265.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_5PkHAAR.jpg b/MisplaceAI/media/uploads/1265_5PkHAAR.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_5PkHAAR.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_8dCYFrT.jpg b/MisplaceAI/media/uploads/1265_8dCYFrT.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_8dCYFrT.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_CAwc2WF.jpg b/MisplaceAI/media/uploads/1265_CAwc2WF.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_CAwc2WF.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_SqbKUM7.jpg b/MisplaceAI/media/uploads/1265_SqbKUM7.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_SqbKUM7.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_Ut88mRj.jpg b/MisplaceAI/media/uploads/1265_Ut88mRj.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_Ut88mRj.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_WZU8Jas.jpg b/MisplaceAI/media/uploads/1265_WZU8Jas.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_WZU8Jas.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_htc3TW1.jpg b/MisplaceAI/media/uploads/1265_htc3TW1.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_htc3TW1.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_qlFQMla.jpg b/MisplaceAI/media/uploads/1265_qlFQMla.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_qlFQMla.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/1265_vaU7bAC.jpg b/MisplaceAI/media/uploads/1265_vaU7bAC.jpg deleted file mode 100644 index cfbe598652ec99461c5dbf29ceb3fdc3de194d15..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/1265_vaU7bAC.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/c.jpg b/MisplaceAI/media/uploads/c.jpg deleted file mode 100644 index 17bcf8a104f5eee456def3de25ff0219de68b4f1..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/c.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/c_Q8DkqzK.jpg b/MisplaceAI/media/uploads/c_Q8DkqzK.jpg deleted file mode 100644 index 17bcf8a104f5eee456def3de25ff0219de68b4f1..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/c_Q8DkqzK.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/c_oyoy0lB.jpg b/MisplaceAI/media/uploads/c_oyoy0lB.jpg deleted file mode 100644 index 17bcf8a104f5eee456def3de25ff0219de68b4f1..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/c_oyoy0lB.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/c_s1KC3iy.jpg b/MisplaceAI/media/uploads/c_s1KC3iy.jpg deleted file mode 100644 index 17bcf8a104f5eee456def3de25ff0219de68b4f1..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/c_s1KC3iy.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/download.png b/MisplaceAI/media/uploads/download.png deleted file mode 100644 index 7494af61e1cfb51e8825af72c07b164f377e2a7f..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/download.png and /dev/null differ diff --git a/MisplaceAI/media/uploads/download_uzsTYmc.png b/MisplaceAI/media/uploads/download_uzsTYmc.png deleted file mode 100644 index 7494af61e1cfb51e8825af72c07b164f377e2a7f..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/download_uzsTYmc.png and /dev/null differ diff --git a/MisplaceAI/media/uploads/imageedit_1_7276535462.jpg b/MisplaceAI/media/uploads/imageedit_1_7276535462.jpg deleted file mode 100644 index a99320e269270fe4dfba128c1598beb721ea1ad3..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/imageedit_1_7276535462.jpg and /dev/null differ diff --git a/MisplaceAI/media/uploads/logoNB.png b/MisplaceAI/media/uploads/logoNB.png deleted file mode 100644 index 682f1a7d46d887273abea70367053172525b1242..0000000000000000000000000000000000000000 Binary files a/MisplaceAI/media/uploads/logoNB.png and /dev/null differ diff --git a/MisplaceAI/placement_rules/apps.py b/MisplaceAI/placement_rules/apps.py index eb135fda56dfe177cf9f6dcfc6bc017c97de12c9..478b1f3f8565f263c62dc2eff473b10e49e3d9a0 100644 --- a/MisplaceAI/placement_rules/apps.py +++ b/MisplaceAI/placement_rules/apps.py @@ -1,5 +1,5 @@ from django.apps import AppConfig class PlacementRulesConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' name = 'placement_rules' - verbose_name = 'Placement Rules' diff --git a/MisplaceAI/placement_rules/models.py b/MisplaceAI/placement_rules/models.py index eafd21265fbf5058f8b8043bc013fada3cf328d5..bd488e2cd6f19fbc01d27f67873d1c138ff6e5e9 100644 --- a/MisplaceAI/placement_rules/models.py +++ b/MisplaceAI/placement_rules/models.py @@ -1,9 +1,8 @@ from django.db import models -# Assuming we have models similar to the ones in the rules app. class PlacementRule(models.Model): - item = models.ForeignKey('rules.Item', on_delete=models.CASCADE) - location = models.ForeignKey('rules.Location', on_delete=models.CASCADE) + object_name = models.CharField(max_length=100) + allowed_locations = models.JSONField() def __str__(self): - return f"Rule: {self.item.name} should be on {self.location.name}" + return self.object_name diff --git a/MisplaceAI/placement_rules/templates/placement_rules/placement_rules.html b/MisplaceAI/placement_rules/templates/placement_rules/placement_rules.html deleted file mode 100644 index 2278edd2c8d537dd1cff1c5ae6229bb4f807c308..0000000000000000000000000000000000000000 --- a/MisplaceAI/placement_rules/templates/placement_rules/placement_rules.html +++ /dev/null @@ -1,17 +0,0 @@ -{% extends 'core/base.html' %} - -{% block title %}Check Placement{% endblock %} - -{% block content %} -<div class="container mt-5"> - <h1>Check Placement</h1> - <form method="post"> - {% csrf_token %} - <div class="form-group"> - <label for="dataLocation">Data Location</label> - <textarea id="dataLocation" name="dataLocation" class="form-control" rows="5"></textarea> - </div> - <button type="submit" class="btn btn-primary">Check Placement</button> - </form> -</div> -{% endblock %} \ No newline at end of file diff --git a/MisplaceAI/placement_rules/templates/placement_rules/results.html b/MisplaceAI/placement_rules/templates/placement_rules/results.html deleted file mode 100644 index fe67ff331097224630ae1754a3acbff90d05abfc..0000000000000000000000000000000000000000 --- a/MisplaceAI/placement_rules/templates/placement_rules/results.html +++ /dev/null @@ -1,27 +0,0 @@ -{% extends 'core/base.html' %} -{% load static %} - -{% block title %}Detected Objects{% endblock %} - -{% block content %} -<div class="container mt-5"> - <h1>Detected Objects</h1> - <img src="{{ output_image_url }}" alt="Detected Objects" class="img-fluid"> - <ul> - {% for obj in detected_objects %} - <li>{{ obj.class_name }}: [{{ obj.ymin }}, {{ obj.xmin }}, {{ obj.ymax }}, {{ obj.xmax }}]</li> - {% endfor %} - </ul> - - <h2>Misplaced Objects</h2> - {% if misplaced_objects %} - <ul> - {% for obj in misplaced_objects %} - <li>{{ obj.class_name }} is misplaced. It should be on {{ obj.allowed_locations|join:", " }}.</li> - {% endfor %} - </ul> - {% else %} - <p>No misplaced objects detected.</p> - {% endif %} -</div> -{% endblock %} \ No newline at end of file diff --git a/MisplaceAI/placement_rules/urls.py b/MisplaceAI/placement_rules/urls.py deleted file mode 100644 index cbde3cefe1a1e09709c6bd061cb4cff8d3f779da..0000000000000000000000000000000000000000 --- a/MisplaceAI/placement_rules/urls.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.urls import path -from .views import check_placement_view - -app_name = 'placement_rules' -urlpatterns = [ - path('check/', check_placement_view, name='check_placement'), -] diff --git a/MisplaceAI/placement_rules/utils.py b/MisplaceAI/placement_rules/utils.py index d9de5b65f169377589ee6198fff351f95b37c92c..3b5d2e0d37baf8e47630b50102642edf71cd5e56 100644 --- a/MisplaceAI/placement_rules/utils.py +++ b/MisplaceAI/placement_rules/utils.py @@ -2,46 +2,51 @@ from rules.models import Rule class PlacementRules: def __init__(self): - self.rules = self.load_rules() + self.rules = self.load_rules_from_db() - def load_rules(self): - rules = {} - for rule in Rule.objects.all(): + def load_rules_from_db(self): + rules_dict = {} + rules = Rule.objects.all() + for rule in rules: item_name = rule.item.name - if item_name not in rules: - rules[item_name] = [] - for location in rule.locations.all(): - rules[item_name].append(location.name) - return rules + allowed_locations = list(rule.locations.values_list('name', flat=True)) + rules_dict[item_name] = allowed_locations + return rules_dict - def check_placement(self, data_location): + def check_placement(self, dataLocation): """Check the placement of each object based on the rules.""" misplaced_objects = [] print("-----------------------------------") print("--CHECK-PLACEMENT-FOR-EACH-OBJECT--") - for obj in data_location: + for obj in dataLocation: object_name = obj["class_name"] allowed_locations = self.rules.get(object_name, []) is_placed_correctly = False print(f"Checking {object_name}, allowed on: {allowed_locations}") for location in allowed_locations: - is_on_top, _ = self.is_on_top_of(data_location, object_name, location) + is_on_top, _ = self.is_on_top_of(dataLocation, object_name, location) if is_on_top: is_placed_correctly = True break if not is_placed_correctly and allowed_locations: - print(f"{object_name} is misplaced. It should be on {', '.join(allowed_locations)}.") - obj["allowed_locations"] = allowed_locations + print( + f"{object_name} is misplaced. It should be on {', '.join(allowed_locations)}." + ) + obj["allowed_locations"] = allowed_locations # Add allowed locations to obj misplaced_objects.append(obj) print("-----------------------------------") return misplaced_objects - def is_on_top_of(self, data_location, top_object_name, bottom_object_name): + def is_on_top_of(self, dataLocation, top_object_name, bottom_object_name): # Filter objects by class_name - top_objects = [obj for obj in data_location if obj["class_name"] == top_object_name] - bottom_objects = [obj for obj in data_location if obj["class_name"] == bottom_object_name] + top_objects = [ + obj for obj in dataLocation if obj["class_name"] == top_object_name + ] + bottom_objects = [ + obj for obj in dataLocation if obj["class_name"] == bottom_object_name + ] # Define a function to check if two objects have horizontal overlap def has_horizontal_overlap(a, b): @@ -52,6 +57,9 @@ class PlacementRules: for bottom in bottom_objects: if has_horizontal_overlap(top, bottom): if top["ymax"] <= bottom["ymax"] and top["ymax"] >= bottom["ymin"]: - return True, f"Object {top['Object']} ({top['class_name']}) is on top of Object {bottom['Object']} ({bottom['class_name']})" + return ( + True, + f"Object {top['Object']} ({top['class_name']}) is on top of Object {bottom['Object']} ({bottom['class_name']})", + ) return False, f"No {top_object_name} is on top of any {bottom_object_name}." diff --git a/MisplaceAI/placement_rules/views.py b/MisplaceAI/placement_rules/views.py deleted file mode 100644 index c83f0c25fcf8567c306eda37aee9b22733ddcd2c..0000000000000000000000000000000000000000 --- a/MisplaceAI/placement_rules/views.py +++ /dev/null @@ -1,13 +0,0 @@ -from django.shortcuts import render -from .utils import PlacementRules - -def check_placement_view(request): - if request.method == 'POST': - # Assuming dataLocation is passed in the POST request body - data_location = request.POST.get('dataLocation') - placement_rules = PlacementRules() - misplaced_objects = placement_rules.check_placement(data_location) - return render(request, 'placement_rules/results.html', {'misplaced_objects': misplaced_objects}) - else: - # Render a form to accept dataLocation input - return render(request, 'placement_rules/input.html') diff --git a/MisplaceAI/process_misplaced_manager/admin.py b/MisplaceAI/process_misplaced_manager/admin.py deleted file mode 100644 index 8c38f3f3dad51e4585f3984282c2a4bec5349c1e..0000000000000000000000000000000000000000 --- a/MisplaceAI/process_misplaced_manager/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/MisplaceAI/process_misplaced_manager/forms.py b/MisplaceAI/process_misplaced_manager/forms.py index 94c8d440219eedcc65fbd5c9a3e77b1e9a74a5fd..fa7edd5c2e61e3302d2667a786bde1b0f51b0aa0 100644 --- a/MisplaceAI/process_misplaced_manager/forms.py +++ b/MisplaceAI/process_misplaced_manager/forms.py @@ -1,6 +1,7 @@ -# forms.py in process_misplaced_manager - from django import forms +from .models import UploadedImage -class ImageUploadForm(forms.Form): - image = forms.ImageField(label='Select an image to upload') +class ImageUploadForm(forms.ModelForm): + class Meta: + model = UploadedImage + fields = ['image'] diff --git a/MisplaceAI/process_misplaced_manager/models.py b/MisplaceAI/process_misplaced_manager/models.py index af3dc0b53bd21b2945076bc0adbda3943a028552..1d73a62583f25455d02930af8b3a7a2470581e90 100644 --- a/MisplaceAI/process_misplaced_manager/models.py +++ b/MisplaceAI/process_misplaced_manager/models.py @@ -2,3 +2,7 @@ from django.db import models class UploadedImage(models.Model): image = models.ImageField(upload_to='uploads/') + uploaded_at = models.DateTimeField(auto_now_add=True) + + def __str__(self): + return f"Image {self.id} uploaded at {self.uploaded_at}" diff --git a/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/display_image.html b/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/display_image.html deleted file mode 100644 index 336861e5d870fe9807bb4d2cf59e625ce258a9e4..0000000000000000000000000000000000000000 --- a/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/display_image.html +++ /dev/null @@ -1,12 +0,0 @@ -<!-- display_image.html in process_misplaced_manager/templates/process_misplaced_manager --> - -{% extends 'core/base.html' %} - -{% block content %} -<h2>Uploaded Image</h2> -{% if image %} -<img src="{{ image.image.url }}" alt="Uploaded Image"> -{% else %} -<p>No image found.</p> -{% endif %} -{% endblock %} \ No newline at end of file diff --git a/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/display_results.html b/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/display_results.html new file mode 100644 index 0000000000000000000000000000000000000000..0ddd16070dfadb4a17688609ef603bd224667906 --- /dev/null +++ b/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/display_results.html @@ -0,0 +1,13 @@ +{% extends 'core/base.html' %} + +{% block content %} +<h1>Detection Results</h1> +<img src="{{ output_image_url }}" alt="Detected Objects"> +<h2>Misplaced Objects</h2> +<ul> + {% for obj in misplaced_objects %} + <li>{{ obj.class_name }} is misplaced. Allowed locations: {{ obj.allowed_locations }}</li> + {% endfor %} +</ul> +<a href="{% url 'process_misplaced_manager:upload_image' %}">Upload another image</a> +{% endblock %} \ No newline at end of file diff --git a/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/upload_image.html b/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/upload_image.html index 9d51f87bd1a349cccf15f7a311cbafc4b850de97..7de40c0ff8da259433f2f03dfbc89a98ff3eb31e 100644 --- a/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/upload_image.html +++ b/MisplaceAI/process_misplaced_manager/templates/process_misplaced_manager/upload_image.html @@ -1,9 +1,7 @@ -<!-- upload_image.html in process_misplaced_manager/templates/process_misplaced_manager --> - {% extends 'core/base.html' %} {% block content %} -<h2>Upload an Image</h2> +<h1>Upload Image</h1> <form method="post" enctype="multipart/form-data"> {% csrf_token %} {{ form.as_p }} diff --git a/MisplaceAI/process_misplaced_manager/urls.py b/MisplaceAI/process_misplaced_manager/urls.py index 751d9ff97187677467ee5f3928877710dc8f984a..d8e6e973a6319274b60d5d28f171c538fab5d43e 100644 --- a/MisplaceAI/process_misplaced_manager/urls.py +++ b/MisplaceAI/process_misplaced_manager/urls.py @@ -1,11 +1,9 @@ -# process_misplaced_manager/urls.py - from django.urls import path -from .views import upload_image, display_image +from .views import upload_image, display_results -app_name = 'process_misplaced_manager' +app_name = 'process_misplaced_manager' urlpatterns = [ - path('upload-image/', upload_image, name='upload_image'), - path('display-image/<int:image_id>/', display_image, name='display_image'), + path('upload/', upload_image, name='upload_image'), + path('results/<int:image_id>/', display_results, name='display_results'), ] diff --git a/MisplaceAI/process_misplaced_manager/views.py b/MisplaceAI/process_misplaced_manager/views.py index d3dbecc0a13029fbd61d1fec8890f8fe7991f185..356319757c5f42f31c00e53a6e9514f0a9f6494a 100644 --- a/MisplaceAI/process_misplaced_manager/views.py +++ b/MisplaceAI/process_misplaced_manager/views.py @@ -1,22 +1,47 @@ -# process_misplaced_manager/views.py - from django.shortcuts import render, redirect, get_object_or_404 from .forms import ImageUploadForm from .models import UploadedImage +from item_detector.utils import run_inference, load_model, create_category_index_from_labelmap +from placement_rules.utils import PlacementRules +from results_viewer.utils import visualize_misplaced_objects - +import os + +# Load the model and category index for object detection +MODEL_PATH = "models/research/object_detection/faster_rcnn_resnet50_v1_1024x1024_coco17_tpu-8/saved_model" +LABEL_MAP_PATH = "models/research/object_detection/data/mscoco_label_map.pbtxt" + +detection_model = load_model(MODEL_PATH) +category_index = create_category_index_from_labelmap(LABEL_MAP_PATH) -def display_image(request, image_id): - image = get_object_or_404(UploadedImage, id=image_id) - return render(request, 'process_misplaced_manager/display_image.html', {'image': image}) - def upload_image(request): if request.method == 'POST': form = ImageUploadForm(request.POST, request.FILES) if form.is_valid(): - new_image = UploadedImage(image=request.FILES['image']) - new_image.save() - return redirect('item_detector:detect_items', image_id=new_image.id) + new_image = form.save() + return redirect('process_misplaced_manager:display_results', image_id=new_image.id) else: form = ImageUploadForm() return render(request, 'process_misplaced_manager/upload_image.html', {'form': form}) + +def display_results(request, image_id): + image = get_object_or_404(UploadedImage, id=image_id) + image_path = image.image.path + + # Run object detection + detected_objects = run_inference(detection_model, category_index, image_path) + print(f"Detected objects: {detected_objects}") # Debugging + + # Check placement rules + placement_rules = PlacementRules() + misplaced_objects = placement_rules.check_placement(detected_objects) + print(f"Misplaced objects: {misplaced_objects}") # Debugging + + # Visualize results + output_image_path = visualize_misplaced_objects(image_path, detected_objects, misplaced_objects) + + return render(request, 'process_misplaced_manager/display_results.html', { + 'image': image, + 'output_image_url': "/media/" + os.path.basename(output_image_path), + 'misplaced_objects': misplaced_objects + }) diff --git a/MisplaceAI/results_viewer/apps.py b/MisplaceAI/results_viewer/apps.py index 288ce625805d1a19e49a70316611db3eedfc6602..062e2d41c9a5d20d0903fd987475e55f019be59e 100644 --- a/MisplaceAI/results_viewer/apps.py +++ b/MisplaceAI/results_viewer/apps.py @@ -1,5 +1,5 @@ from django.apps import AppConfig class ResultsViewerConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' name = 'results_viewer' - verbose_name = 'Results Viewer' diff --git a/MisplaceAI/results_viewer/urls.py b/MisplaceAI/results_viewer/urls.py index c02aa0fd76319c4bae4d1ae11abee4f5c8cac4d0..da720e4baa2bf256151bc7db2d3bcecefc5cab59 100644 --- a/MisplaceAI/results_viewer/urls.py +++ b/MisplaceAI/results_viewer/urls.py @@ -1,7 +1,8 @@ from django.urls import path -from .views import visualize_results +from .views import generate_annotated_image app_name = 'results_viewer' + urlpatterns = [ - path('visualize/<int:image_id>/', visualize_results, name='visualize_results'), + path('generate/<int:image_id>/', generate_annotated_image, name='generate_annotated_image'), ] diff --git a/MisplaceAI/results_viewer/utils.py b/MisplaceAI/results_viewer/utils.py index 5cb8fba89ad99552daf3315a226545bceba9e077..4ffcdf0423fa1d7e3e5972b4dbcf11128567f31f 100644 --- a/MisplaceAI/results_viewer/utils.py +++ b/MisplaceAI/results_viewer/utils.py @@ -1,9 +1,9 @@ -import os from PIL import Image import matplotlib.pyplot as plt import matplotlib.patches as patches +import os -def visualize_misplaced_objects(image_path, dataLocation, misplaced_objects): +def visualize_misplaced_objects(image_path, detected_objects, misplaced_objects): """Visualize misplaced objects with annotations.""" image = Image.open(image_path) width, height = image.size @@ -14,8 +14,9 @@ def visualize_misplaced_objects(image_path, dataLocation, misplaced_objects): ax = plt.gca() misplaced_names = [obj["class_name"] for obj in misplaced_objects] + print(f"Misplaced object names: {misplaced_names}") # Debugging - for obj in dataLocation: + for obj in detected_objects: ymin, xmin, ymax, xmax = [ obj["ymin"] * height, obj["xmin"] * width, @@ -28,24 +29,25 @@ def visualize_misplaced_objects(image_path, dataLocation, misplaced_objects): xmax - xmin, ymax - ymin, linewidth=2, - edgecolor="red" if obj["class_name"] in misplaced_names else "green", + edgecolor="green" if obj["class_name"] not in misplaced_names else "red", facecolor="none", ) ax.add_patch(rect) - if obj["class_name"] in misplaced_names: - ax.text( - xmin, - ymin, - f"Misplaced: {obj['class_name']}", - color="red", - fontsize=12, - verticalalignment="bottom", - ) + ax.text( + xmin, + ymin, + f"{'Misplaced: ' if obj['class_name'] in misplaced_names else ''}{obj['class_name']}", + color="red" if obj["class_name"] in misplaced_names else "green", + fontsize=12, + verticalalignment="bottom", + ) plt.axis("off") - output_annotated_image_path = os.path.join("media", "annotated_" + os.path.basename(image_path)) - plt.savefig(output_annotated_image_path, bbox_inches='tight', pad_inches=0.0) + + output_image_path = os.path.join("media", os.path.splitext(os.path.basename(image_path))[0] + "_annotated.png") + plt.savefig(output_image_path, bbox_inches='tight', pad_inches=0.0) plt.close() - return output_annotated_image_path + print(f"Output image saved at: {output_image_path}") # Debugging + return output_image_path diff --git a/MisplaceAI/results_viewer/views.py b/MisplaceAI/results_viewer/views.py index 2ab9500e6d098c1fd3cc0f990a846c65e4de5486..4518dc0c219851f6f1b719c19c3e26f5cdbb8720 100644 --- a/MisplaceAI/results_viewer/views.py +++ b/MisplaceAI/results_viewer/views.py @@ -1,35 +1,20 @@ -from django.shortcuts import render, get_object_or_404 -from process_misplaced_manager.models import UploadedImage -from item_detector.models import DetectedObject +# results_viewer/views.py + +from django.http import JsonResponse from .utils import visualize_misplaced_objects import os -def visualize_results(request, image_id): - image = get_object_or_404(UploadedImage, id=image_id) - image_path = image.image.path - - detected_objects = DetectedObject.objects.filter(image=image) - - data_location = [ - { - "class_name": obj.class_name, - "ymin": obj.ymin, - "xmin": obj.xmin, - "ymax": obj.ymax, - "xmax": obj.xmax, - } - for obj in detected_objects - ] - - # Here you would get the misplaced objects - # For now, assuming misplaced_objects is available - misplaced_objects = [] # Replace with actual misplaced objects +def generate_annotated_image(request): + if request.method == 'POST': + image_path = request.POST.get('image_path') + misplaced_objects = request.POST.get('misplaced_objects') - visualize_misplaced_objects(image_path, data_location, misplaced_objects) + if not image_path or not misplaced_objects: + return JsonResponse({'error': 'Invalid input data'}, status=400) - return render(request, 'results_viewer/visualize_results.html', { - 'image': image, - 'output_image_url': "/media/" + os.path.basename(image_path), - 'detected_objects': detected_objects, - 'misplaced_objects': misplaced_objects, - }) + output_image_path = os.path.join("media", "annotated_" + os.path.basename(image_path)) + visualize_misplaced_objects(image_path, misplaced_objects, output_image_path) + + return JsonResponse({'annotated_image_path': output_image_path}) + else: + return JsonResponse({'error': 'Invalid request method'}, status=400) diff --git a/README.md b/README.md index 4f9ad88d7ff2af3c82632fc943142fff1c81edf6..00459617fd07615054a22b220f08db79f9cfc44f 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ create superuser: ``` bash - docker-compose exec web python manage.py createsuperusers + docker-compose exec web python manage.py createsuperuser ```