detectar contorno de imagens

Discussão em 'Dicas e tutoriais' iniciado por kodo no kami, 8 Outubro 2019.

  1. kodo no kami
    Offline

    kodo no kami Membro Conhecido

    Afiliado:
    16 Dezembro 2015
    Mensagens:
    237
    Sexo:
    Masculino
    Avaliações:
    +321 / -0
    Então galera nesse tutorial vamos aprender a detectar os contornos de uma imagem usando um algoritimo bem simples, nesse tutorial vamos utilizar o python com o modulo PIL (pillow) embora possa ser feito em qualquer outra linguagem de sua preferencia ja que vamos fazer na mão. Para começar importamos o modulo pil (não vou abordar a instalação do mesmo)

    Código (Forge Crash):
    #!/usr/bin/python3

    from PIL import Image
    podemos carregar a imagem usando o metodo open da classe Image (Image.open), podemos inclusive exibir ela com o metodo show

    Código (Forge Crash):
    #!/usr/bin/python3

    from PIL import Image

    img = Image.open("mikan.jpg")
    img.show()
    [​IMG]

    transformamos a imagem em preto e branco para ter apenas duas cores a ser manipulada, criamos um novo objeto de imagem com o metodo new com o mesmo tamanho da imagem atual para receber a imagem preto e branco, depois basta ler pixel a pixel da imagem original tirar uma media das 3 cores RGB e por comparar essa media com um valor (esse valor pode ser uma variavel ~ no caso chamei ela de nivel), caso a media seja maior a gente desenha um pixel branco e caso seja menor a gente desenha um pixel preto

    Código (Forge Crash):
    #!/usr/bin/python3

    from PIL import Image

    img = Image.open("mikan.jpg")
    tam = img.size

    imgMono = Image.new("RGB",tam)

    nivel = 127
    contx = 0
    while contx < tam[0]:
       conty = 0
       while conty < tam[1]:
         r, g, b = img.getpixel((contx, conty))
         
         media = (r + g + b) // 3
         
         if media > nivel:
           imgMono.putpixel((contx, conty),(255,255,255))
         else:
           imgMono.putpixel((contx, conty),(0,0,0))
         
         conty += 1
       contx += 1

    imgMono.show()
     
    [​IMG]

    as bordas são os limites de uma superficie no caso contorno dela, existe uma pequena diferença na sua coloração entre a borda e depois dela, sendo que é essa diferença que vamos utilizar para detectar elas. A logica em cima disso é bastante simples bastando ler a imagem preto e branco pixel a pixel, caso a imagem tenha o pixel preto a gente ignora, caso tenha o pixel branco a gente pinta um pixel na imagem (no caso uma imagem nova), se tiver outro pixel branco seguido do anterior a gente ignora ate o proximo pixel preto (para fazer isso usamos uma variavel para indicar se o pixel anterior é branco ou não, caso detecte o pixel branco setamos a variavel como verdadeiro e com isso não permitindo desenhar na imagem outro pixel branco, caso detecte um pixel preto ele atribui falso naquela variavel permitindo desenhar o proximo pixel branco e com isso ficando nesse loop)

    Código (Forge Crash):
    #!/usr/bin/python3

    from PIL import Image

    img = Image.open("mikan.jpg")
    tam = img.size

    imgMono = Image.new("RGB",tam)
    imgBorda = Image.new("RGB",tam)

    nivel = 127
    contx = 0
    while contx < tam[0]:
       conty = 0
       while conty < tam[1]:
         r, g, b = img.getpixel((contx, conty))
         
         media = (r + g + b) // 3
         
         if media > nivel:
           imgMono.putpixel((contx, conty),(255,255,255))
         else:
           imgMono.putpixel((contx, conty),(0,0,0))
         
         conty += 1
       contx += 1

    contx = 0
    desenhado = False
    while contx < tam[0]:
       conty = 0
       while conty < tam[1]:
         
         r, g, b = imgMono.getpixel((contx, conty))
         
         if (desenhado == False) and (r == 255):
           imgBorda.putpixel((contx, conty),(255,255,255))
           desenhado = True
         else:
           if r == 0:
             desenhado = False
             
         conty += 1
       contx += 1

    imgBorda.show()
    [​IMG]

    se a gente tentar pegar as bordas de um quadrado de uma unica cor usando esse script vai gera apenas uma linha T.T

    [​IMG]

    para uma precisão maior é necessario ler a imagem pixel a pixel da direita para a esquerda, depois da esquerda para direita, depois de cima para baixo e por fim de baixo para cima (não necessarimente nessa ordem), obs: esse mesmo codigo poderia ser melhorado de varias formas possiveis por exemplo usando apenas um loop para aumentar a performance

    Código (Forge Crash):
    #!/usr/bin/python3

    from PIL import Image

    img = Image.open("quadrado.jpg")
    tam = img.size

    imgMono = Image.new("RGB",tam)
    imgBorda = Image.new("RGB",tam)

    nivel = 127
    contx = 0
    while contx < tam[0]:
       conty = 0
       while conty < tam[1]:
         r, g, b = img.getpixel((contx, conty))
         
         media = (r + g + b) // 3
         
         if media > nivel:
           imgMono.putpixel((contx, conty),(255,255,255))
         else:
           imgMono.putpixel((contx, conty),(0,0,0))
         
         conty += 1
       contx += 1

    contx = 0
    desenhado = False
    while contx < tam[0]:
       conty = 0
       while conty < tam[1]:
         r, g, b = imgMono.getpixel((contx, conty))
         
         if (desenhado == False) and (r == 255):
           imgBorda.putpixel((contx, conty),(255,255,255))
           desenhado = True
         else:
           if r == 0:
             desenhado = False
             
         conty += 1
       contx += 1

    conty = 0
    desenhado = False
    while conty < tam[1]:
       contx = 0
       while contx < tam[0]:
         r, g, b = imgMono.getpixel((contx, conty))
         
         if (desenhado == False) and (r == 255):
           imgBorda.putpixel((contx, conty),(255,255,255))
           desenhado = True
         else:
           if r == 0:
             desenhado = False
             
         contx += 1
       conty += 1

    contx = tam[0] -1
    desenhado = False
    while contx >= 0:
       conty = tam[1] -1
       while conty >= 0:
         r, g, b = imgMono.getpixel((contx, conty))
         
         if (desenhado == False) and (r == 255):
           imgBorda.putpixel((contx, conty),(255,255,255))
           desenhado = True
         else:
           if r == 0:
             desenhado = False
             
         conty -= 1
       contx -= 1

    conty = tam[1] -1
    desenhado = False
    while conty >= 0:
       contx = tam[0] -1
       while contx >= 0:
         r, g, b = imgMono.getpixel((contx, conty))
         
         if (desenhado == False) and (r == 255):
           imgBorda.putpixel((contx, conty),(255,255,255))
           desenhado = True
         else:
           if r == 0:
             desenhado = False
             
         contx -= 1
       conty -= 1

    img.show()
    imgBorda.show()
     
    [​IMG]

    outro exemplo com a foto da mikan e como seria no exemplo anterior

    [​IMG]

    outra coisa que a gente pode fazer é mexer naquela variavel nivel para tentar pegar alguns outros contornos mais escuros ou ignorar os mais escuros (isso pode variar de imagem para imagem), ex: em 240 pegamos apenas uma parte dos olhos da mikan ignorando todo o resto

    Código (Forge Crash):
    nivel = 240
    [​IMG]

    bom galera é isso, ate o proximo tutorial sobre computação grafica \o

    by kodo no kami
     
    • Gostei Gostei x 2
    • Top Top x 2
    • Informativo Informativo x 1
    • Útil Útil x 1

Compartilhe esta Página