Reputation: 370
I have a number of grayscale images as the left one below. I only want to keep the outer edges of the object in the image using python, preferably OpenCV. I have tried OpenCV erosion and then get the right image below. However, as seen in the image there is still brighter areas inside of the object. I want to remove those and only keep the outer edge. What would be an efficient way to achieve this? Simple thresholding will not work, because the bright "stripes" inside the object may sometimes be brighter than the edges. Edge detection will detect edges also inside the "main" edges.
The right image - "eroded_areas" is achieved by the following code:
im = cv2.imread(im_path, cv2.IMREAD_GRAYSCALE)
im_eroded = copy.deepcopy(im)
kernel_size=3
kernel = np.ones((kernel_size, kernel_size), np.uint8)
im_eroded = cv2.erode(im_eroded, kernel, iterations=1)
eroded_areas = im - im_eroded
plt.imshow(eroded_areas)
Upvotes: 0
Views: 1451
Reputation: 53089
Here is one approach in Python/OpenCV.
Input:
import cv2
import numpy as np
# read the input as grayscale
img = cv2.imread('long_blob.png', cv2.IMREAD_GRAYSCALE)
# threshold
thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
# get contours and filter out small defects
result = np.zeros_like(img)
contours = cv2.findContours(thresh , cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
for cntr in contours:
area = cv2.contourArea(cntr)
if area > 20:
cv2.drawContours(result, [cntr], 0, 255, 1)
# save results
cv2.imwrite('long_blob_contours.png', result)
# show results
cv2.imshow('thresh', thresh)
cv2.imshow('result', result)
cv2.waitKey(0)
Result:
Upvotes: 1
Reputation: 81
Did you try canny edge detection on it? It has a non-max suppression step in that algorithm that removes those lighter tones. I believe the canny edge detector is built into open cv but if not, heres a guide of it https://en.wikipedia.org/wiki/Canny_edge_detector
Open cv document https://docs.opencv.org/4.x/da/d22/tutorial_py_canny.html
Code ex
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
edges = cv.Canny(img,100,200)
plt.subplot(121),plt.imshow(img,cmap = 'gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(edges,cmap = 'gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
This should work from the first image since the grey scale gradually changes to the lighter and darker tones.
If this still doesnt work, maybe you can try first making the high tones higher while low tones lower using just pixel wise multiplications, then running a threshold after doing the 'im_eroded = cv2.erode(im_eroded, kernel, iterations=1)' step.
I just had a more simple solution that probably only works for your current example image. Since you have it masked perfectly, you could just change everything that is not pure black to pure white, and then run an edge detector on it. It should be able to get the main outline and those little holes and ignore those lighter stripes.
There might be a better way to do this, but this is the best Ive got for now.
Upvotes: 0