I have to detect an object very close to ground. It has most area similar to road surface in terms of grey scale, but visually it has a proper shape. I tried with manual thresholding, image filling and contours. But no good results. Contours are worst. My aim is to get a binary image with the object as foreground (white).
-
1[Edge-detection](https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_canny/py_canny.html#canny-edge-detection-in-opencv) might work. Can you add the image? We'll be able to help you better. – J.D. Jan 19 '19 at 11:31
-
Using a similar approach as I demonstrated [here](https://stackoverflow.com/questions/44176667/image-processing-segmentation-in-matlab/44180934#44180934) may work. – m7913d Jan 19 '19 at 20:59
-
Thanks J.D. and m7913d. But, both of your answers do not seem to fit in this problem. I have attached the image link above. I believe, a systematic sequential basic image preprocessing should be our answer. But, I am unable to find that sweet spot (:- – user2580731 Jan 20 '19 at 06:10
1 Answers
That is a small image :p
This is how I approached your problem: first I detected the edges in the image. Next I used morphological closing to join lines that are close together. This works very well on the outer edges, the outline of the shape. Then the contour of this shape could be detected (cv2.RETR_EXTERNAL returns only the outermost contour). Because of some noise I added a size threshold, and the remaining contour is drawn filled on a new image.
I added a second option, that is more efficient, but might not work for the rest of your project, because it is less flexible for other images. Here the edges are taken and a large morphological closing is done, which joins together the entire shape. To remove the noise a smaller morphological opening is then performed. As you can see below, the results are nearly identical, though the difference may be bigger for other images.
Final note: if this mask is too crude, you can use the mask to cut out the relevant area of your image and use this to create a better mask.
Result:
Code:
import numpy as np
import cv2
# load image
image = cv2.imread("image.png")
# detect edges in image
edges = cv2.Canny(image,100,100)
#option 1: use contours
# solidify / join edges
kernel = np.ones((10,10),np.uint8)
mask = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel)
# create black image with the size of image
result = np.zeros(image.shape[:2])
# detect contours in the mask (outer edges only)
im, contours, hierarchy = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# draw contour
for cnt in contours:
if cv2.contourArea(cnt) > 100:
# draw filled contour in white on result
cv2.drawContours(result, [cnt], 0, (255), -1)
# draw outline of contour in red on original image
cv2.drawContours(image, [cnt], 0, (0,0,255), 2)
#option 2: morphology only
# solidify / join edges
kernel2 = np.ones((20,20),np.uint8)
mask2 = cv2.morphologyEx(edges, cv2.MORPH_CLOSE, kernel2)
# remove noise
kernel3 = np.ones((5,5),np.uint8)
result2 = cv2.morphologyEx(mask2, cv2.MORPH_OPEN, kernel3)
# show image and results
cv2.imshow("image", image)
cv2.imshow("edges", edges)
cv2.imshow("Result_option1", result)
cv2.imshow("Result_option2", result2)
# release recourses
cv2.waitKey(0)
cv2.destroyAllWindows()

- 4,511
- 2
- 7
- 20