问题
I have this code, that draws contours in my image, but I need only the external contours:
import cv2
import numpy as np
camino= "C:/Users/Usuario/Documents/Deteccion de Objetos/123.jpg"
img = cv2.imread("C:/Users/Usuario/Documents/Deteccion de Objetos/123.jpg")
grises= cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
bordes= cv2.Canny(grises, 100, 250)
ctns = cv2.findContours(bordes, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
ctns = ctns[0] if len(ctns)==2 else ctns[1]
for c in ctns:
cv2.drawContours(img,[c], -1,(0,0,255),2)
print ('Numero de contornos es ', len(ctns))
texto= 'Contornos encontrados ' + str(len(ctns))
cv2.putText(img, texto, (10, 20), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
(255, 0, 0), 1)
cv2.imshow('Bordes', bordes)
cv2.imshow('Imagen', img)
cv2.waitKey(0)
cv2.destroyAllWindows().
This is my original image:
This is the obtained image with the contours:
In this case I just only need to detect 10 contours 1 for each entity, but it detects 450 contours.
回答1:
Here's an approach using thresholding + morphological operations + contour filtering
First we convert to grayscale then Otsu's threshold for a binary image (left) then remove dotted lines using contour area filtering (right)
From here we perform morph close to remove the text then invert the image (left). We find contours and fill all contours smaller than a threshold to black (right)
Next we invert again and perform morph open with a large rectangle kernel to remove the small edges and spikes
Finally we find contours to get our result
import cv2
image = cv2.imread('1.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5,5), 0)
thresh = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]
# Remove dotted lines
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 5000:
cv2.drawContours(thresh, [c], -1, (0,0,0), -1)
# Fill contours
close_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = 255 - cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, close_kernel, iterations=6)
cnts = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
area = cv2.contourArea(c)
if area < 15000:
cv2.drawContours(close, [c], -1, (0,0,0), -1)
# Smooth contours
close = 255 - close
open_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (20,20))
opening = cv2.morphologyEx(close, cv2.MORPH_OPEN, open_kernel, iterations=3)
# Find contours and draw result
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
cv2.drawContours(image, [c], -1, (36,255,12), 3)
cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image)
cv2.waitKey()
回答2:
You can try flood fill combined with some morph operators.
来源:https://stackoverflow.com/questions/58920162/obtain-only-external-contours-in-image