Adaptive Object Detection and Image Processing - Carleton-SRCL/SPOT GitHub Wiki

ADPT_HA.py

Click here for raw code
  import cv2
  import numpy as np
  from datetime import datetime
  import os
  
  output_file_path = r'C:\images'
  scale_percent = 34
  
  def middleBoxCheck(boxes):
      # frame width hard set to 1280*2
      thres = 100
      N_boxes = len(boxes)
      mark_box = np.array([])
      for ib in range(N_boxes):
          if abs(2208*2 - boxes[ib][0]) < thres:
              return boxes
          elif abs(2208 - boxes[ib][0]) < thres:
              mark_box  = np.array([ib])
      # if none are at the right edge, remove that box
      if mark_box.size == 0:
          return boxes
      else:
          del boxes[mark_box[0]]
          return boxes
  
  def save_image(image, filename_prefix):
      timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
      filename = f"{filename_prefix}_{timestamp}.jpg"
      output_path = os.path.join(output_file_path, filename)
      cv2.imwrite(output_path, image)
      print(f"Saved: {output_path}")
  
  def resize_for_display(image, scale_percent):
      width = int(image.shape[1] * scale_percent / 100)
      height = int(image.shape[0] * scale_percent / 100)
      dim = (width, height)
      # Resize the image to the specified dimensions for display
      resized_image = cv2.resize(image, dim, interpolation=cv2.INTER_AREA)
      return resized_image
  
  def process_img_adaptive(img_to_process, kernol_size_blur, blockSize_adaptive, C_adaptive, kernol_size_morph_open, kernol_size_morph_close, min_contour_area, show_images_q, save_images_q):
  
      # B, G, R = cv2.split(img_to_process)
      # B = cv2.equalizeHist(B)
      # G = cv2.equalizeHist(G)
      # R = cv2.equalizeHist(R)
      # img_to_process = cv2.merge((B, G, R))
  
  
      img = cv2.cvtColor(img_to_process, cv2.COLOR_RGB2HSV)[:, :, 1]
  
      if show_images_q:
          cv2.imshow('HSV image', resize_for_display(img, scale_percent))
          cv2.waitKey(0)
          cv2.destroyAllWindows()
      if save_images_q:
          save_image(img, "HSV image (2)")
  
      # Apply Gaussian blur
      img = cv2.GaussianBlur(img, (kernol_size_blur, kernol_size_blur), cv2.BORDER_DEFAULT)
  
      if show_images_q:
          cv2.imshow('Gaussian Blur', resize_for_display(img, scale_percent))
          cv2.waitKey(0)
          cv2.destroyAllWindows()
      if save_images_q:
          save_image(img, "Gaussian Blur  (3)")
  
      # apply threshold
      thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, blockSize_adaptive, C_adaptive)
  
      if show_images_q:
          cv2.imshow('Adaptive Threshold', resize_for_display(thresh, scale_percent))
          cv2.waitKey(0)
          cv2.destroyAllWindows()
      if save_images_q:
          save_image(thresh, "Adaptive Threshold (4)")
  
      # Apply morphology open and close to fill interior regions in the mask and remove external noise
      kernel_open = np.ones((kernol_size_morph_open, kernol_size_morph_open), np.uint8)
      opening_morph = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel_open)
  
      if show_images_q:
          cv2.imshow('opening_morph', resize_for_display(opening_morph, scale_percent))
          cv2.waitKey(0)
          cv2.destroyAllWindows()
      if save_images_q:
          save_image(opening_morph, "opening_morph (5)")
  
      kernel_close = np.ones((kernol_size_morph_close, kernol_size_morph_close), np.uint8)
      opening_and_closing_morph = cv2.morphologyEx(opening_morph, cv2.MORPH_CLOSE, kernel_close)
  
      if show_images_q:
          cv2.imshow('opening_and_closing_morph', resize_for_display(opening_and_closing_morph, scale_percent))
          cv2.waitKey(0)
          cv2.destroyAllWindows()
      if save_images_q:
          save_image(opening_and_closing_morph, "opening_and_closing_morph (6)")
  
      # Contour filtering to remove small regions
      contours, _ = cv2.findContours(opening_and_closing_morph, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
      filtered_contours = [cnt for cnt in contours if cv2.contourArea(cnt) > min_contour_area]
      # Create a black image to draw the filtered contours
      filtered_img = np.zeros_like(opening_and_closing_morph)
  
      drawn = cv2.drawContours(filtered_img, filtered_contours, -1, 255, thickness = cv2.FILLED)
  
      if show_images_q:
          cv2.imshow('Filtered Contours (maybe same as Processed Image)', resize_for_display(drawn, scale_percent))
          # cv2.waitKey(0)
          # cv2.destroyAllWindows()
      if save_images_q:
          save_image(drawn, "Filtered Contours (maybe same as Processed Image) (7)")
  
      # cv2.imshow("", )
  
      output_img = filtered_img
  
      return output_img
  
  def RatioChecker(box):
      x, y, x2, y2 = box
      w = x2 - x
      h = y2 - y
      ratioDet = w/h
      if ratioDet > 5.5:
          return 1
      else:
          return box
  
  def overlappedBox(boxes,frame, show_images, save_images_q):
      # bring boxes into same area
      boxes = np.array(boxes)
      if len(boxes) < 2:
          return boxes
      boxes_copy = [boxes[0],boxes[1]]
      shftover =  int(frame.shape[1]//2 - 0.024*frame.shape[1])
      for ip in range(len(boxes)):
          if boxes[ip][0] > frame.shape[1]//2:
              boxReform = [int(boxes[ip][0] - shftover),boxes[ip][1],int(boxes[ip][2] - shftover),boxes[ip][3]]
          else:
              boxReform = boxes[ip]
          boxes[ip] = boxReform
  
      box_right = boxes[0] # right
      box_left = tuple(boxes[1]) # left
  
      # now they're in the same area, see which parts overlap
      x_overlap = max(0, min(box_left[2], box_right[2]) - max(box_left[0], box_right[0]))
      y_overlap = max(0, min(box_left[3], box_right[3]) - max(box_left[1], box_right[1]))
      if x_overlap == 0 or y_overlap == 0:
          return boxes_copy  # No overlap
      overlap = tuple([max(box_right[0], box_left[0]),max(box_right[1], box_left[1]), min(box_right[2], box_left[2]), min(box_right[3], box_left[3])])
  
      frame = frame[:, :frame.shape[1]//2, :]
      x, y, x2, y2 = box_right
  
      line_thickness = 8
  
      cv2.rectangle(frame, (x, y), (x2, y2), (0, 0, 255), line_thickness) # red
      x, y, x2, y2 = box_left
      cv2.rectangle(frame, (x, y), (x2, y2), (255, 0, 0), line_thickness) # blue
      x, y, x2, y2 = overlap
      cv2.rectangle(frame, (x, y), (x2, y2), (0, 255, 0), line_thickness) # green
      resized_cropped_img_with_merged_boxes = frame
      # Display the image with merged bounding boxes
  
      print(type(resized_cropped_img_with_merged_boxes))
  
      if show_images:
          cv2.imshow("TEST TEST TEST", resize_for_display(resized_cropped_img_with_merged_boxes, scale_percent))
          cv2.waitKey(0)
          cv2.destroyAllWindows()
      if save_images_q:
          save_image(resized_cropped_img_with_merged_boxes, "TEST TEST TEST (18)")
  
  
      # compare size of overlap, if its small just don't
      box_right_size = abs(box_right[0] - box_right[2])*abs(box_right[1]- box_right[3])
      box_left_size = abs(box_left[0] - box_left[2])*abs(box_left[1]- box_left[3])
      overlap_size = abs(overlap[0] - overlap[2])*abs(overlap[1]- overlap[3])
      # box_diff_L = abs(overlap_size - box_left_size)
      # box_diff_R = abs(overlap_size - box_right_size)
  
      if  overlap_size >= 80000: #box_diff_L <= 40000 and box_diff_R <= 40000:
          shfted_overlap = [overlap[0] + shftover,overlap[1],overlap[2] + shftover,overlap[3]]
          overlap_boxes = [shfted_overlap,overlap]
          return tuple(overlap_boxes)
      else:
          return tuple(boxes_copy)

Purpose

  • This code is an image processing program focused on object detection. It includes preprocessing steps like adaptive thresholding and Gaussian blur. Object detection is performed through functions adjusting bounding boxes and filtering based on aspect ratio. Overlapping bounding boxes are visualized. Utility functions handle image saving and resizing for display.

Inputs

  • Image
    • The main input is an image or a frame from a video feed. This image contains the objects that need to be detected or analyzed.
  • Parameters
    • Various parameters are required for the image processing operations, such as kernel size for Gaussian blur, block size and constant for adaptive thresholding, kernel sizes for morphological operations, and minimum contour area.
  • Bounding Boxes
    • Detected bounding boxes within the image generated previously.
  • Boolean Flags
    • These indicate whether to show intermediate images during processing and whether to save generated images.

Outputs

  • Processed Image
    • The main output is the processed image after undergoing these image processing operations (adaptive thresholding, Gaussian blur, and morphological operations).
  • Filtered Bounding Boxes
    • An output set of filtered bounding boxes representing the detected objects within the image. These bounding boxes are typically represented as arrays containing the coordinates of the bounding box (e.g., (x, y, width, height)).
  • Visualizations
    • The code may generate overlapping bounding boxes or intermediate results of the image processing. These visualizations aid in understanding the processing steps and validating the accuracy of the object detection.
  • Saved Images
    • If Boolean Flags set to save images, the code saves intermediate and final images to the specified output directory.

Click here to go BACK

⚠️ **GitHub.com Fallback** ⚠️