Ya tenemos la manera de ver la imagen de la máquina recreativa con el Galaga, pero ahora vamos salvar esas imágenes para poder obtener esa información
El objetivo: Detectar elementos y grabarlos
Para “detectar” objetos pero aún no estamos en el nivel de entender lo que ve, solo necesitamos dar lo que en filosofía sería la “idea” de nave de marciano.
Para esto se necesitan esas imágenes y como detectarlas, para openCV este proceso es muy sencillo y muy común
- Obtener el área de interés Rect rectROI(POS_X,POS_Y,ANCHO,ALTO)
- Nos creará un rectángulo de la imagen con la que trabajaremos
- Pasar la imagen a gris cvtColor(origina,imgGris,COLOR_BGR2GRAY)
- No necesitamos colores
- obtener imagen binaria (threshold,imgGris,imgGris,50,200,THRESH_BINARY)
- Nos crea imagen de 0 (negro) 1(blanco) solo con dos valores
- Crear un vector para los contornos y su jerarquía
- vector<vector<Point> > contornos;
- vector<Vec4i> jerarquia;
- Buscar los contornos
- findContours(imgGris,contornos,jerarquia,RETR_LIST,CHAIN_APPROX_SIMPLE);
- Buscamos los contornos y los ajustamos a un polígono
- vector<vector<Point> > contornosPoly(contornos.size());
- Luego hay que usar funciones para que nuestros puntos se aproximen a un polígono que tenga cierto sentido matemático, es decir puntos adyacentes y que no tengan saltos, de esta manera separa los elementos para que tengan continuidad.
Bueno todo esto sobre el papel lo aguanta todo, pero aquí va el código. Ya subiré el código al GIT y una documentación detallada para los que apoyen el patreon 😉
#include <opencv2/core.hpp>
#include <opencv2/opencv.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include "../000_include/tools.h"
using namespace cv;
using namespace std;
bool grabar=false;
int main (int argc, char **argv)
{
Mat frame;
Mat original;
Mat marciano;
Mat imgGris;
Mat img1, img2,img3,img4,img5;
Mat imgCanny;
Mat dst;
VideoCapture cap;
int deviceID =2;
int apiID = cv::CAP_ANY;
cap.open(deviceID, apiID);
if (!cap.isOpened())
{
cerr << "Error abriendo la camara" << endl;
return -1;
}
cap.set(CAP_PROP_FRAME_WIDTH,1280);
cap.set(CAP_PROP_FRAME_HEIGHT,720);
Rect rectROI(320, 0, 640, 720);
while (cap.read(frame))
{
int64_t flag=getTickCount();
if (frame.empty())
{
cerr << "Error fotograma en blanco" << endl;
return -1;
}
//Área de interes (ROI)
original = frame(rectROI).clone();
cvtColor(original,imgGris,COLOR_BGR2GRAY);
imshow("Atenea",frame);
imshow("gris",imgGris);
threshold(imgGris,imgGris,50,200,THRESH_BINARY);
imshow("thresh",imgGris);
dst = Mat::zeros(imgGris.rows,imgGris.cols,CV_8UC3);
vector<vector<Point> > contornos;
vector<Vec4i> jerarquia;
findContours(imgGris,contornos,jerarquia,RETR_LIST,CHAIN_APPROX_SIMPLE);
vector<vector<Point> > contornosPoly(contornos.size());
vector<Rect> boundRect(contornos.size());
vector<Point2f>centros(contornos.size());
vector<float>radios(contornos.size());
Scalar rojo=Scalar(255,255,255);
char buffer[25];
uint64_t tiempo = getTick(flag);
sprintf(buffer,"Obj: %d timpo: %d",contornos.size(),tiempo);
putText(dst,buffer,Point(10,40),FONT_HERSHEY_SIMPLEX,1,rojo,1);
for (size_t idx=0;idx < contornos.size();idx++)
{
double area=contourArea(contornos[idx]);
if (area >10 )
{
approxPolyDP(contornos[idx],contornosPoly[idx],3,true);
boundRect[idx]= boundingRect(contornosPoly[idx]);
if (grabar)
{
char nombre[24];
sprintf (nombre,"./marcianos/marciano%03d.jpg",idx );
cout << nombre << endl;
marciano = original(boundRect[idx]).clone();
imwrite(nombre,marciano);
}
minEnclosingCircle(contornosPoly[idx],centros[idx],radios[idx]);
if (radios[idx]>=3 && radios[idx]<=16 || (radios[idx]>=20 && radios[idx]<=30))
{
circle(dst,centros[idx],(int)radios[idx],Scalar(0,0,255),1);
drawContours(dst,contornos,idx,rojo);
sprintf(buffer,"%d",(int)radios[idx]);
putText(dst,buffer,centros[idx],FONT_HERSHEY_SIMPLEX,0.4,rojo,1);
}
}
}
imshow("contornos",dst);
char C = waitKey(5);
switch (C)
{
case 'q':
return 0 ;
break;
case 's':
grabar=!grabar;
break;
}
}
return 0;
}