O documento apresenta técnicas de visão computacional com MATLAB, incluindo detecção de objetos através de features, criação de imagens panorâmicas, análise de movimento por fluxo ótico e classificação de imagens por bag of features. É descrito o processo de detecção de objetos em imagens usando features, extração de descritores e correspondência de pontos. Também são explicados métodos para estimar fluxo ótico em vídeos e criar um classificador de imagens de comida usando bag of features.
3. Pág.
Computer Vision com MATLAB
3
Detecção de Objetos através de Features
Criação de Imagens Panorâmicas
Análise de Movimento por Fluxo Ótico
Classificação por Bag of Features
4. Pág.
Detecção através de Features
4
Problema: encontrar um objeto
específico em uma imagem com
muitos objetos
y
x
5. Pág. 5
Detecção através de Features
featX=detectMSERFeatures(rgb2gray(x),...
'RegionAreaRange',[30 5000]);
featY=detectMSERFeatures(rgb2gray(y),'RegionAreaRange',[30 5000]);
descX=extractFeatures(rgb2gray(x),featX);
descY=extractFeatures(rgb2gray(y),featY);
matched=matchFeatures(descX,descY,'MatchThreshold',5,'MaxRatio',0.95, ‘Unique’,true);
6. Pág. 6
Detecção através de Features
[Tr,pointsX,pointsY]=estimateGeometricTransform(featX(matched(:,1)),featY(matched(:,2)),'affine’);
figure, showMatchedFeatures(x,y,pointsX,pointsY,'montage');
7. Pág. 7
Detecção através de Features
mask=ones(size(x,1),size(x,2));
ref=imref2d(size(y));
maskW=imwarp(mask,Tr,'OutputView',ref);
yBlend=repmat((maskW+0.6*(~maskW)),1,1,3).*im2double(y);
yBlend
9. Pág. 9
Imagens Panorâmicas
hBlender=vision.AlphaBlender('Operation','Binary Mask','MaskSource','Input port’);
reset(vid);
while ~isDone(vid)
frame=vid();
W=imwarp(frame,Tr{k},'OutputView', panoramaView);
Wmask=(imwarp(ones(size(frame)),Tr{k},'OutputView',panoramaView)==1);
panorama=hBlender(panorama,double(W),Wmask);
end
imshow(panorama,[])
10. Pág.
Fluxo Ótico
𝐼 𝑥 𝑢+ 𝐼 𝑦 𝑣+ 𝐼𝑡 = 0
(𝑢, 𝑣) → Fluxo Ótico (velocidades)
(𝐼 𝑥, 𝐼 𝑦, 𝐼𝑡) → Derivadas da imagem no espaço e no tempo
opticalFlowHS
Método de Horn-Schunck
opticalFlowLK
Método de Lucas-Kanade
opticalFlowLKDoG
opticalFlowFarneBack
Método de Farneback
• Assume que fluxo é suave sobre a
imagem inteira;
• Aplica filtros de Sobel para calcular as
derivadas espaciais, e filtro [-1 1] para a
derivada temporal;
• Resolve iterativamente para u e v de
forma a minimizar a equação de erro.
• Divide a imagem em seções e assume
velocidades constantes em cada uma;
• Aplica filtros [-1 8 0 -8 1]/12 para calcular
as derivadas espaciais, e filtro [-1 1] para
a temporal;
• Calcula u e v em cada seção por mínimos
quadrados.
• Variante do método de Lucas-Kanade que
utiliza filtros gaussianos e de derivadas de
gaussianas ao invés dos citados acima.
• Divide a imagem em seções e ajusta
polinômio quadrático sobre cada seção;
• Aplica translações sobre os polinômios
ajustados e, observando como os
polinômios se transformam, estima as
velocidades dos pontos da imagem;
• Baixo erro comparado a outros métodos
(Two-Frame Motion Estimation Based on
Polynomial Expansion).
17. Pág. 17
Problema: criar um classificador
de imagens de comidas
Classificação de Imagens por
Bag of Features
Fonte do dataset: grebvm2.epfl.ch/lin/food/Food-11.zip
18. Pág. 18
Dataset:
1.16GB
Mais de 16 mil imagens
Pré-separadas em 11 categorias:
Bread
Dessert
Diary
Egg
Fried
Meat
Pasta
Rice
Seafood
Soup
Veggies
Classificação de Imagens por
Bag of Features
19. Pág. 19
Algoritmo:
Separação de imagens para treino e teste
Extraçao de Features das Imagens de treino
Qual algoritmo de detecção de features?
Clustering das features, criando o “vocabulário visual”
Qual o critério de corte das features a serem usadas?
Quantas “palavras” (número de clusters)?
Qual método de clustering? Kmeans, outro, quais parâmetros?
Treino do classificador
Qual algoritmo de classificação? KNN, Naive Bayes, SVM...?
Avaliação do resultado (matriz de confusão)
Classificação de Imagens por
Bag of Features
20. Pág. 20
Classificação de Imagens por
Bag of Features
ds=imageDatastore('./foods2’,...
'IncludeSubfolders',true,...
'LabelSource','foldernames');
ds=shuffle(ds);
dsTrain=partition(ds,5,1);
dsTest=partition(ds,5,2);
istrained=false;
if ~istrained
Q=bagOfFeatures(dsTrain,'VocabularySize’,20000);
save('foodBag.mat','Q’);
classifier=trainImageCategoryClassifier(dsTrain,Q);
confmat=evaluate(classifier,dsTest);
save('foodModel.mat','classifier');
else
load('foodBag.mat’);
load('foodModel.mat');
end
~10 mil imagens
~2 mil imagens cada
Bom dia Pessoal, meu nome é Daniel Vieira, sou Pesquisador Científico daqui da Opencadd. Obrigada por estar conosco nesta manhã.
Neste Webinar mostrarei para vocês algumas ferramentas de visão computacional para detecção de objetos, identificação de objetos e análise de movimento.
Com o apoio neste webinar, aqui ao meu lado está o .... Caso vocês possuam dúvidas, peço que nos envie através do item “Questões” que aparece para vocês.
No primeiro exemplo mostrarei uma forma simples de encontrar objetos conhecidos em uma imagem contendo muitos objetos. Como exemplo, imagine que quero que o algoritmo encontre o caderno da foto à esquerda numa imagem como a da foto direita. Note a diferença de ângulo e iluminação entre as duas fotos, e o acobertamento parcial do caderno na segunda.
Um dos métodos mais simples para realizar esta tarefa é através de Feature Matching. Primeiro se aplica tanto no template quanto na imagem uma função de detecção de Features; aqui escolhi detectMSERFeatures - Maximally Stable Extremal Regions - que detecta regiões aproximadamente constantes na imagem e retorna aproximações elípticas de cada uma. Em seguida se transforma as features detectadas em descritores, e utiliza-se estes para dar match entre as features das duas imagens - através das funções extractFeatures e matchFeatures respectivamente. Notem que foram especificados alguns parâmetros para cada função, há um certo trabalho experimental até encontrar os parâmetros mais adequados para a tarefa.
Com o match entre as features de cada imagem é possível estimar a transformação geométrica entre as duas imagens e ressaltar os pontos utilizados.
Por fim podemos usar a transformação calculada para ressaltar o objeto na imagem, utilizando as funções imref2d para settar um referencial adequado e imwarp para aplicar a transformação.
Este método é bastante simples e nem sempre suficientemente preciso
A função vision.VideoFileReader cria um objeto leitor de vídeos. Percorre-se o vídeo inteiro até o final (verificado com o método isDone) e a cada frame se segue o mesmo procedimento do exemplo anterior: detecta features, extrai descritores, match features destre frame com o frame anterior, estima transformação geométrica.
Ao final do vídeo, aplica-se correções que jular necessárias às transformações obtidas, utiliza-se o tamanho dos frames e as transformações obtidas para calcular o tamanho da imagem panorâmica final (outputLimits) e cria referencial (imref2d)...
Por último, se percorre o vídeo novamente aplicando as transformações em cada frame (imwarp) e “colando” numa imagem de saída (objeto criado com vision.AlphaBlender).
O fluxo ótico (u,v) é definido resolvendo esta equação, onde Ix e Iy são as derivadas da imagem nos sentidos dos eixos x e y, e It é a derivada no tempo (de um frame para outro). A solução exata não é computacionalmente eficiente, então há diversos métodos para isso. O MATLAB possui 4 funções que resolvem este problema por diferentes métodos.
<explicar Horn-Schunck>
<explicar Lucas-Kanade>
<explicar Lucas-Kanade DoG>
<explicar Farneback>
Esta é a estrutura geral de como calcular o fluxo ótico no MATLAB. A função de cálculo de fluxo ótico escolhida cria um objeto que analisa cada frame do vídeo em comparação ao anterior utilizando o método estimateFlow. Cada função tem seus próprios parâmetros. Como o primeiro frame não tem anterior seu resultado deve ser desconsiderado (aplicando estimateFlow e descartando o resultado). A cada frame após o primeiro se aplica estimateFlow novamente, utilizando-se o resultado como precisar. O resultado de cada avaliação é dado em um objeto (Q) com as propriedades Vx e Vy (velocidades nos eixos x e y em todos os pontos do frame), Orientation e Magnitude (direção e comprimento do vetor velocidade em todos os pontos do frame).
Aqui temos um exemplo de visualização do fluxo ótico obtido com o método Farneback em um dos frames do vídeo. Sobre cada ponto do frame foi plotada uma seta vermelha mostrando a direção e intensidade do fluxo, como vemos nesse zoom...
Resultado obtido por outros métodos...
Video do fluxo ótico no vídeo inteiro usando o método de Lucas-Kanade.
No primeiro exemplo mostrei como detectar objetos específicos conhecidos; aqui mostrarei como identificar objetos entre muitas possibilidades, utilizando o algoritmo de Bag of Features.
Sobre o dataset utilizado.
Sobre o Algoritmo...
Extração de Features: a função do MATLAB bagOfFeatures usa features tipo SURF (Speeded-Up Robust Features), que são pontos aproximadamente invariantes por transformações geométricas pequenas (e portanto bons pontos de referência).
Clustering: a função utiliza as N features mais “fortes” de cada categoria de forma que N seja 80% do número de features da categoria com menor quantidade de features; em seguida aplica kmeans para criar o vocabulário visual; o usuário determina o número de “palavras” no vocabulário visual
Classificador: o algoritmo padrão usado pela função do MATLAB é SVM (Support Vector Machine)
Uma vantagem deste método é que ele se aplica mesmo que suas imagens não estejam com tamanho padronizado (diferente de outros métodos como Deep Learning).
Uma desvantagem é que este método desconsidera a distribuição espacial das caracteristicas; ele apenas conta features e agrupa por similaridade, mas a informação de onde a feature está é perdida por isso o nome “Bag” of Features).
A função imageDatastore cria um objeto armazenando uma lista com todas as imagens da pasta selecionada. A opção IncludeSubfolders permite incluir as imagens dentro as subpastas, e a opção LabelSource no modo foldernames significa que cada imagem receberá um label de acordo com o nome da subpasta em que está. Isso permite interpretar com facilidade o dataset, facilitando o treino do classificador depois.
Os métodos shuffle e partition embaralham e separam o dataset, respectivamente. Aqui 1/5 foi usado para treinar o algoritmo e outro 1/5 para testar sua performance.
As funções bagOfFeatures e trainCategoryClassifier criam o vocabulário visual e treinam o classificador respectivamente. Aqui a única opção customizada foi o número de palavras (20mil).
Como o treino pode ser bastante demorado, foi colocada a condição istrained; se já estiver treinado é só escolher esta opção como true, e ao invés de treinar novamente o algoritmo meramente carrega o modelo pré-treinado de um arquivos .mat
Por fim o método evaluate utiliza a partição de teste para avaliar o desempenho do algoritmo através da matriz de confusão.
Durante o treino a função mostra as diversas etapas (é possível desativar essa visualização). O treino completo nessa configuração levou cerca de 12h.
Aqui vemos um exemplo de uma das imagens do dataset representada em termos do vocabulário visual obtido.
E por fim aqui o resultado final da avaliação de performance. Sendo 10 categorias um classificador totalmente incompetente acertaria 1/10 de cada categoria. Vemos que algumas categorias são notoriamente difíceis (Bread, Dessert, Egg), enquanto outras são mais fáceis (Diary, Pasta, Rice, Soup).
Isso é entendido intuitivamente lembrando que algumas dessas categorias tem características muito bem definidas enquanto outras são muito genéricas. Por exemplo, toda imagem de “arroz” deve conter pequenos grãos alongados de cor clara, toda imagem de “sopa” deve conter uma região grande, arredondada de cor aproximadamente constante (prato cheio de liquido), quase toda imagem de “macarrão” deve conter quantidades grandes de “fios beges emaranhados”. Enquanto isso, não é fácil dizer que formas e cores definem uma “sobremesa” ou uma “fritura”, são categorias bastante variadas. Se treinarmos de novo usando apenas as categorias mais fáceis...
Vemos que com um problema mais simples o algoritmo funciona muito melhor.
Mais exemplos...
Uma outra fonte dos erros do algoritmo é que este dataset é bastante complexo. Estas duas imagens por exemplo, ambas estão na categoria sopa. Mas a primeira contém também um pão, e foi classificada errada como arroz (possivelmente por causa dos “grãos” contidos”). A segunda é um ramen: uma sopa que contém macarrão, carne, e frutos do mar (e foi classificada como laticínio). Erros são esperados!