6
$\begingroup$

In the picture below there are some regions which are very bright (i.e. more white). Some bright regions are wide and some are narrow or thin. The red box covers one such wide bright spot, and blue box covers one thin bright spot. Thin bright spots are called edges and wide bright spots are called hot-spots.

I want to remove all the hot-spots from the image (i.e. make them black), but no edge should be removed.

My question is how to write Python code using OpenCV to remove all hot-spots but no edge?

enter image description here

$\endgroup$

2 Answers 2

4
$\begingroup$

Based on this answer's algorithm I have written my code which is working as intended.

Here's a breakdown of the coding steps:

  1. Otsu's thresholding is applied to the grayscale image1 using cv2.threshold() with the cv2.THRESH_BINARY + cv2.THRESH_OTSU flag to obtain image2.

  2. Erosion is performed on image2 using cv2.erode() with a square kernel to obtain image3.

  3. The threshold distance K is defined.

  4. You then compare to 0 for pixels where image2 is larger than 0. So you can combine the result of the two full-image comparisons with the logical and(&) operator, and use the result to index into the output image.

  5. The final image is displayed using cv2.imshow().

Note that a square region with side 2*K is used instead of a circular mask in this implementation. The choice between a circular or square area can be adjusted by modifying the mask variable in the code. Feel free to adjust the threshold distance K and experiment with different shapes and sizes of the neighborhood mask to suit your specific requirements.

import cv2
import numpy as np


# Load the image
image1 = cv2.imread('orange.jpg', cv2.IMREAD_GRAYSCALE)


# Otsu's thresholding
_, image2 = cv2.threshold(image1, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)


# Erosion
kernel = np.ones((5, 5), np.uint8)
image3 = cv2.erode(image2, kernel, iterations=1)


# Define the threshold distance K
K = 2


# Iterate over image1 pixels and generate the final image
final_image = np.copy(image1)
final_image[(cv2.blur(image3,[2*K+1, 2*K+1]) > 0) & (image2 > 0)] = 0



# Display the original and final image
cv2.imshow('Original image', image1)
cv2.imshow('Final Image', final_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Output:

enter image description here

$\endgroup$
4
  • 2
    $\begingroup$ Nice. Can you also add the image result? That way it will be easy for people to see whether this could be applicable also to their situation? $\endgroup$
    – Jon Nordby
    Commented Jun 3, 2023 at 18:06
  • 1
    $\begingroup$ @JonNordby Please check my updated answer. And give comments. $\endgroup$
    – S. M.
    Commented Jun 4, 2023 at 11:03
  • $\begingroup$ Is it me or mask is not used in the algorithm? $\endgroup$ Commented Jun 5, 2023 at 14:35
  • 1
    $\begingroup$ @SébastienVincent see my updated answer which is very concise. $\endgroup$
    – S. M.
    Commented Jun 6, 2023 at 6:59
2
$\begingroup$

Can you try the following approach using OpenCV

The logic behind this is:

  1. Convert the image to grayscale.

  2. Apply a Gaussian blur to the image to smooth out the edges.

  3. Threshold the image to create a binary image where the hot-spots are white and the rest of the image is black.

  4. Dilate the binary image to fill in any small holes in the hot-spots.

  5. Find the contours in the dilated image.

  6. Iterate over the contours and remove any that are not large enough.

  7. Fill in all of the remaining contours with black.

      import cv2
    
      def remove_hotspots(image):
      # Convert the image to grayscale
          gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    
      # Apply a Gaussian blur to the image to smooth out the edges
      blur = cv2.GaussianBlur(gray, (5, 5), 0)
    
      # Threshold the image to create a binary image where the hot-spots are white and the rest of the image is black
      threshold = cv2.threshold(blur, 128, 255, cv2.THRESH_BINARY)[1]
    
      # Dilate the binary image to fill in any small holes in the hot-spots
      dilated = cv2.dilate(threshold, None, iterations=2)
    
      # Find the contours in the dilated image
      contours, hierarchy = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
      # Iterate over the contours and remove any that are not large enough
      for i in range(len(contours)):
          if cv2.contourArea(contours[i]) < 100:
              continue
    
          # Fill in the contour with black
          cv2.drawContours(image, contours, i, 0, -1)
    
      return image
    
    
      if __name__ == "__main__":
      # Load the image
      image = cv2.imread("image.jpg")
    
      # Remove the hot-spots
      new_image = remove_hotspots(image)
    
      # Display the original and new images
      cv2.imshow("Original", image)
      cv2.imshow("New", new_image)
      cv2.waitKey(0)
      cv2.destroyAllWindows()
    
$\endgroup$
1
  • 1
    $\begingroup$ Your code doesn't even close proximity to my intended result. You could delete your answer. $\endgroup$
    – S. M.
    Commented Jun 3, 2023 at 7:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.