/ / opencv findContours perde alguma área. [não obtém todas as caixas delimitadoras corretas] - python, opencv, processamento de imagem, extração, reconhecimento de imagem

opencv findContours perde alguma área. [não obtém todas as caixas delimitadoras corretas] - python, opencv, processamento de imagem, extração, reconhecimento de imagem

Eu sou novo no opencv, comece a aprender extraindo char do captcha simples. Depois de algum esforço, consegui findContours e algum método para limpar a imagem, às vezes funcionava, mas não com mais frequência.

Por exemplo:

  1. Eu tenho uma imagem original (já dimensionada para um tamanho grande): insira a descrição da imagem aqui

  2. converter em escala de cinza e usar cv2.threshold limpar \ limpo: insira a descrição da imagem aqui

  3. usar cv2.findContours para obter caixas delimitadoras:

insira a descrição da imagem aqui W cobrir apenas metade e não ficar b.

Meu código:

from StringIO import StringIO
import string

from PIL import Image
import requests
import cv2
import numpy as np
import matplotlib.pyplot as plt

def get_ysdm_captcha():
url = "http://www.ysdm.net/common/CleintCaptcha"
r = requests.get(url)
img = Image.open(StringIO(r.content))
return img

def scale_image(img, ratio):
return img.resize((int(img.width*ratio), int(img.height*ratio)))

def draw_rect(im):
im = np.array(im)

if len(im.shape) == 3 and im.shape[2] == 3:
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
else:
imgray = im

#plt.imshow(Image.fromarray(imgray), "gray")
pilimg = Image.fromarray(imgray)
ret,thresh = cv2.threshold(imgray,127,255,0)

threimg = Image.fromarray(thresh)

plt.figure(figsize=(4,3))
plt.imshow(threimg, "gray")
plt.xticks([]), plt.yticks([])

contours, hierarchy = cv2.findContours(np.array(thresh),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
areas = []

for c in contours:
rect = cv2.boundingRect(c)
area = cv2.contourArea(c)
areas.append(area)
x,y,w,h = rect

if area > 2000 or area < 200 : continue

cv2.rectangle(thresh,(x,y),(x+w,y+h),(0,255,0),1)
plt.figure(figsize=(1,1))
plt.imshow(threimg.crop((x,y,x+w,y+h)), "gray")
plt.xticks([]), plt.yticks([])

plt.figure(figsize=(10,10))

plt.figure()
plt.imshow(Image.fromarray(thresh), "gray")
plt.xticks([]), plt.yticks([])


image = get_ysdm_captcha()
im = scale_image(image, 3)
im = np.array(im)

imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
imgray = cv2.GaussianBlur(imgray,(5,5),0)
# im = cv2.medianBlur(imgray,9)
# im = cv2.bilateralFilter(imgray,9,75,75)

draw_rect(imgray)

Eu tentei o meu melhor para escrever o código acima. As soluções que imagino são:

  1. encontrar havia alguma maneira de dizer cv2.findContours eu preciso 4 caixas delimitadoras em algum tamanho
  2. tentei algum parâmetro diferente (tentei de tudo http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours , mas ainda não funciona)

Agora estou preso, não tenho ideia de como melhorar cv2.findContours...

Respostas:

2 para resposta № 1

Você pode usar operações morfológicas para modificar sua imagem e preencher as lacunas, por exemplo erode e dilate

Veja aqui: http://docs.opencv.org/2.4/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html

Original:

insira a descrição da imagem aqui

Dilatado:

insira a descrição da imagem aqui

A propósito: Eu implementaria uma etapa de separação HSV na imagem original, removendo todo o conteúdo "branco / cinza / preto" (baixa saturação). Isso reduzirá o número de manchas. Faça isso antes de converter em escala de cinza.

Aqui está o resultado filtrando: saturação> 90 insira a descrição da imagem aqui

Resultado final: (adicionada uma etapa de desfoque antes)

insira a descrição da imagem aqui

Além disso, se sempre houver um gradiente, você poderá detectar isso e filtrar ainda mais cores. Mas isso é um pouco demais se você acabou de iniciar o processamento de imagens;)


0 para resposta № 2

O findCountours funciona corretamente, pois encontra todoscomponente conectado à sua imagem. Sua condição de área é o que provavelmente está evitando que você obtenha uma caixa delimitadora em torno da letra b, por exemplo. Obviamente, se você colocar uma caixa delimitadora em torno de cada componente conectado, você não acabará com uma caixa delimitadora em torno de cada caractere, pois possui muitas falhas nas letras.

Se você deseja segmentar as letras, primeirotente brincar com as operações de abertura (porque suas letras são pretas em fundo branco, seria fechado se fosse o contrário) para preencher os buracos que você tem nas suas letras. Então eu projetava verticalmente os pixels e analisava a forma que você obtém. Se você encontrar os pontos do vale nessa forma projetada, obterá os limites verticais entre os caracteres. Você pode fazer o mesmo horizontalmente para obter os limites superior e inferior de seus caracteres. Essa abordagem só funcionará se o texto for horizontal. Caso contrário, você deve encontrar o ângulo do eixo principal da sua corda e girar a imagem de acordo. Para encontrar o ângulo do eixo principal, você pode ajustar uma elipse ao texto e encontrar o ângulo do eixo principal ou continuar girando sua imagem em um determinado ângulo até que sua projeção horixontal seja máxima.