Obtain only external contours in image

為{幸葍}努か 提交于 2019-12-24 03:44:25

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!