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:
Eu tenho uma imagem original (já dimensionada para um tamanho grande):
converter em escala de cinza e usar
cv2.threshold
limpar \ limpo:usar
cv2.findContours
para obter caixas delimitadoras:
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:
- encontrar havia alguma maneira de dizer
cv2.findContours
eu preciso4
caixas delimitadoras em algum tamanho - 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 № 1Você 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:
Dilatado:
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
Resultado final: (adicionada uma etapa de desfoque antes)
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.