Como criar aplicação visão computacional para detecção de imagens

Bernardo Caldas
7 min readJan 29, 2020

Post sobre como realizar aplicação de visão computacional para dataset customizado de frutas.

dataset frutas tropicais

Visão computacional

Visão computacional é a ciência e tecnologia das máquinas que enxergam.[1] Ela desenvolve teoria e tecnologia para a construção de sistemas artificiais que obtém informação de imagens ou quaisquer dados multidimensionais. Exemplos de aplicações incluem o controle de processos (como robôs industriais ou veículos autônomos), detecção de eventos, organização de informação, modelagem de objetos ou ambientes e interação (atrelado a interação humano-computador).

A visão computacional também pode ser descrita como um complemento da visão biológica. Na visão biológica, a percepção visual dos humanos e outros animais é estudada, resultando em modelos em como tais sistemas operam em termos de processos fisiológicos. Por outro lado, a visão computacional estuda e descreve sistemas de visão artificial implementados por hardware ou software.

Sub campos de pesquisa incluem reconstrução de cena, detecção de eventos, reconhecimento de objetos, aprendizagem de máquina e restauração de imagens

https://pt.wikipedia.org/wiki/Vis%C3%A3o_computacional

Aplicações recentes com uso de visão computacional;

  • Restauração de imagens
  • Reconhecimento
  • Identificação
  • Detecção

Alguns exemplos;

detecção e contagem de objetos

Segmentação de imagens

O resultado da segmentação de imagens é um conjunto de regiões/objetos ou um conjunto de contornos extraídos da imagem (ver detecção de borda). Como resultado, cada um dos pixels em uma mesma região é similar com referência a alguma característica ou propriedade computacional, tais como cor, intensidade, textura ou continuidade. Regiões adjacentes devem possuir diferenças significativas com respeito a mesma característica(s).

Tipos de segmentação baseadas em Formatos;

Mask RCNN

Mask R-CNN (rede neural convolucional regional) é uma estrutura de dois estágios: o primeiro estágio digitaliza a imagem e gera propostas (áreas que provavelmente contêm um objeto). E o segundo estágio classifica as propostas e gera caixas delimitadoras e máscaras.
Foi introduzido no ano passado através do artigo Mask R-CNN para estender seu antecessor, Faster R-CNN, pelos mesmos autores. O R-CNN mais rápido é uma estrutura popular para detecção de objetos, e o Mask R-CNN o estende com segmentação de instância, entre outras coisas.

Criando uma aplicação de segmentação de imagens a partir de um dataset customizado

Para esta tarefa, há uma ferramenta muito boa para baixar imagens do google images chamado OIDv4_ToolKit, depois de clonar o repositório e instalar os pacotes necessários com a linha de comando abaixo, podemos baixar as imagens, se quiser dar uma conferida segue lá.

Open Images Dataset V5 ( Orange class segmentation object)
python3 main.py downloader --classes Pineapple Orange --type_csv validation

1. Anotando imagens

usando a ferramenta VIA, podemos anotar as imagens no conjunto de dados que foram baixadas previamente como na imagem abaixo, essa ferramenta é somente uma entre várias disponíveis para segmentar objetos para um dataset.

https://www.robots.ox.ac.uk/~vgg/software/via/via-1.0.6.html

depois de anotar todas as imagens, precisamos gerar um arquivo json com todas as coordenadas para usar no projeto, como padrão 'via_region_data.json'.

2. Configurando o ambiente

Neste próximo passo deveremos clonar o repositório ( matterport/maskrcnn);

  • Instalar dependencias e pacotes
  • rodar o arquivo setup.py do projeto
pip3 install -r requirements.txtpython3 setup.py install

Faça uma cópia do diretório ‘samples / balloon’ e renomeie com o nome do seu projeto, neste caso ‘samples / tropical’
crie uma pasta ‘train’ e ‘val’ dentro dessa estrutura e mova seus arquivos anotados anteriormente com o arquivo json; considere dividir os arquivos de 80% de train e 20% de validação em sua estrutura.
Projeto de estrutura
-tropical
|
|
ballonn.py
pasta train
|
file1.png
file2.png
.
.
via_region_data.json
|
|
pasta -val
|
file1.png
file2.png
.
.
via_region_data.json

3.Configurando código

vamos configurar o código em ‘samples / tropical / balloon.py’, primeiro renomeie esse arquivo do conjunto de dados personalizado, neste caso ‘samples / tropical / fruits.py’.

Agora, dentro do arquivo, fruits.py, vamos fazer algumas alterações, como segue abaixo.

class fruitConfig(Config):
"""Configuration for training on the toy dataset.
Derives from the base Config class and overrides some values.
"""
# Give the configuration a recognizable name
NAME = "fruits"
# We use a GPU with 12GB memory, which can fit two images.
# Adjust down if you use a smaller GPU.
IMAGES_PER_GPU = 2
# Number of classes (including background)
NUM_CLASSES = 1 + 2 # Background + pineapple + Orange
# Number of training steps per epoch
STEPS_PER_EPOCH = 100
# Skip detections with < 90% confidence
DETECTION_MIN_CONFIDENCE = 0.9
############################################################
# Dataset
############################################################
class fruitsDataset(utils.Dataset):def load_fruits(self, dataset_dir, subset):
"""Load a subset of the Balloon dataset.
dataset_dir: Root directory of the dataset.
subset: Subset to load: train or val
"""
# Add classes. We have two class to add.
self.add_class("fruits", 1, "orange")
self.add_class("fruits", 2, "pineapple")

4. Usando transfer learning e treinando o modelo

Usando um dos códigos abaixo, podemos treinar o modelo usando pesos do modelo MS COCO ou imagenet do arquivo 'samples/tropical/fruits.py'.

# Train a new model starting from pre-trained COCO weights
python3 fruits.py train --dataset=/path/to/balloon/dataset --weights=coco
# Resume training a model that you had trained earlier
python3 fruits.py train --dataset=/path/to/balloon/dataset --weights=last
# Train a new model starting from ImageNet weights
python3 fruits.py train --dataset=/path/to/balloon/dataset --weights=imagenet

para cada epoch treinado será salvo na pasta de logs os modelos correspondentes, podemos ver os resultados e as métricas do nosso modelo usando o tensorboard, digite:


# tensorboard — logdir = caminho/para/logs
tensorboard

Agora que temos o modelo treinado vamos executar, o jupyter notebook chamado inspect_balloon_model.ipynb dentro da pasta, configure para ver os resultados;

função para prever arquivos em uma única função:

def predictSingle(image):
# Load image
image = skimage.io.imread(image)
# If grayscale. Convert to RGB for consistency.
if image.ndim != 3:
image = skimage.color.gray2rgb(image)
# If has an alpha channel, remove it for consistency
if image.shape[-1] == 4:
image = image[..., :3]
# return image
# Run object detection
results = model.detect([image], verbose=1)
# Display results
ax = get_ax(1)
r = results[0]
a = visualize.display_instances(image, r['rois'], r['masks'], r['class_ids'],
dataset.class_names, r['scores'], ax=ax,
title="Predictions")
print("{} detections: {}".format(
det_count, np.array(dataset.class_names)[det_class_ids]))

# Show coordinates
print ("Coordinates from bounding box")
for i in (r['rois']):
print (i)

Resultados

Foto original
Previsão
Original
Previsão

Conclusão

O modelo precisa de algumas melhorias para corrigir, esse modo foi treinado com apenas 76 imagens, talvez possamos definir mais epochs e mais imagens para obter bons resultados e ver usando o tensorboard a perda de treinamento e perda de validação
No ‘mrcnn / config.py’, podemos definir algumas configurações para melhorar nosso modelo.


STEPS_PER_EPOCH = 1000
# Number of validation steps to run at the end of every training epoch.
# A bigger number improves accuracy of validation stats, but slows
# down the training.
VALIDATION_STEPS = 50
# Backbone network architecture
# Supported values are: resnet50, resnet101.
# You can also provide a callable that should have the signature
# of model.resnet_graph. If you do so, you need to supply a callable
# to COMPUTE_BACKBONE_SHAPE as well
BACKBONE = "resnet101"
# Only useful if you supply a callable to BACKBONE. Should compute
# the shape of each layer of the FPN Pyramid.
# See model.compute_backbone_shapes
COMPUTE_BACKBONE_SHAPE = None
# The strides of each layer of the FPN Pyramid. These values
# are based on a Resnet101 backbone.
BACKBONE_STRIDES = [4, 8, 16, 32, 64]
# Size of the fully-connected layers in the classification graph
FPN_CLASSIF_FC_LAYERS_SIZE = 1024
# Size of the top-down layers used to build the feature pyramid
TOP_DOWN_PYRAMID_SIZE = 256
# Number of classification classes (including background)
NUM_CLASSES = 1 # Override in sub-classes
# Length of square anchor side in pixels
RPN_ANCHOR_SCALES = (32, 64, 128, 256, 512)

Bom espero que esse post possa contribuir com o aprendizado nessa área com uma boa e simples aplicação, sinta-se livre por sugestões.

--

--

Bernardo Caldas

Developer | AI | Driving innovation with development tools and AI. Making technology meaningful