Archivo para la categoría Visión Artificial

Playing with Qt and OpenCv

In this project I’m going to capture the image from a USB camera, using openCV, and showing all in a QT window.

Let’s started:

The first thing that we have to do, once we have created the project, is to edit the *.pro file, and add our OpenCv paths.

QT       += core gui
 TARGET = untitled
 TEMPLATE = app
 INCLUDEPATH += /home/opencv_source/trunk/opencv/include/opencv
 LIBS += -L/home/opencv_source/trunk/opencv/release/lib -lml -lcvaux -lhighgui -lcv -lcxcore
 SOURCES += capture.cpp\
 main.cpp\
 mainwindow.cpp

HEADERS  +=  capture.h\
 mainwindow.h

FORMS    += mainwindow.ui

I had a problem,  “undefined recerence to vtable” ,that I could fix placing on top capture.h and capture.cpp files.

Once we have ready our environment I’ll explain the content of the files:

– capture: Is the most important file, this class runs in other thread that the GUI, and all that it does is emitting a signal when has a new IplImage from the cam.

Create a new Thread in QT is so easy, all that we have to do is derivate from QThread and implement the virtual method void run()

class Captura : public QThread
 {
 Q_OBJECT              //We need this macro for use Signals mechanism
 public:
 void run();
 signals:
 void newImgAvailable(QImage*);
 };

void Capture::run()

{
 CvCapture * cap = cvCaptureFromCAM(0);
 if(cap == NULL)
 {
 cout << "There were troubles .. " << endl;
 }
 else
 {
 cout << "Ok" << endl;
 IplImage* imgDisplay;
 while(1){
 imgDisplay = cvQueryFrame(cap);
 QImage* image = IplImage2QImage(imgDisplay);
 emit newImgAvailable(image);
 QThread::msleep(10);
 }
 }
 }
<pre>

– In mainwindow we are going to create the instance of capture, start it, and connect with our own slots wich will set the image in a QLabel using setPixMap property.

The header:

class MainWindow : public QMainWindow
 {
 Q_OBJECT

public:
 explicit MainWindow(QWidget *parent = 0);
 ~MainWindow();

public slots:
 void getImg(QImage*);
 private:
 Ui::MainWindow *ui;
 };

and the cpp:

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent),  ui(new Ui::MainWindow)
 {
 ui->setupUi(this);
 Capture* cap = new Capture();               //Create the Thread wich deals with opencv
 connect(cap, SIGNAL(newImgAvailable(QImage*)),this, SLOT(getImg(QImage*)));
 cap->start();  //starting the thread...
 }

void MainWindow::getImg(QImage* img)   //This code will update the image
 {
 ui->label->setPixmap(QPixmap::fromImage(*img));
 delete img;
 }

To avoid memory leaks we have to bear in mind that getImg has to delete the QImage.

Important: We mustn’t release the IplImage* in the loop, because this  is made internally and it would be a mistake

Anuncios

1 comentario

Porque no emplear cvSet2D. Why we shouldn’t use cvSet2D

Trás implementar la clase para el cambio de espacio de color he querido comprobar cuanta diferencia había entre los distintos métodos:

JETMAP: ha tardado: 9.7 milisegundos
JETMAPFAST: ha tardado: 1.555 milisegundos
HsvMap: ha tardado: 9.702 milisegundos
HsvMapFast: ha tardado: 1.556 milisegundos
HotMap: ha tardado: 9.735 milisegundos
HotMapFast: ha tardado: 1.555 milisegundos
CoolMap: ha tardado: 9.727 milisegundos
CoolMapFast: ha tardado: 1.556 milisegundos
SpringMap: ha tardado: 9.726 milisegundos
SpringMapFast: ha tardado: 1.569 milisegundos
SummerMap: ha tardado: 9.672 milisegundos
SummerMapFast: ha tardado: 1.568 milisegundos
AutumnMap: ha tardado: 9.789 milisegundos
AutumnMapFast: ha tardado: 1.554 milisegundos
WinterMap: ha tardado: 10.007 milisegundos
WinterMapFast: ha tardado: 1.555 milisegundos
GrayMap: ha tardado: 9.924 milisegundos
GrayMapFast: ha tardado: 1.554 milisegundos
BoneMap: ha tardado: 9.714 milisegundos
BoneMapFast: ha tardado: 1.555 milisegundos
CopperMap: ha tardado: 9.961 milisegundos
CopperMapFast: ha tardado: 1.564 milisegundos
PinkMap: ha tardado: 9.681 milisegundos
PinkMapFast: ha tardado: 1.556 milisegundos
LinesMap: ha tardado: 9.96 milisegundos
LinesMapFast: ha tardado: 1.568 milisegundos

Trás ver la evidente ventaja, a continuación expongo como sería el método rápido:

int alto    = entrada->height;
int ancho   = entrada->width;
int step    = entrada->widthStep;
int canales = entrada->nChannels;
uchar* data      = (uchar *)entrada->imageData;

for(int i=0; i < alto;i++)
for(int j=0; j <ancho;j++)
for(int k=0; k < canales;k++)
data[i*step+j*canales+k]= pink[data[i*step+j*canales+k]*3 +2-k];

After develop the class for space color changes, I wanted check the differences between both methods:

JETMAP: takes: 9.7 miliseconds
JETMAPFAST: takes: 1.555 miliseconds
HsvMap: takes: 9.702 miliseconds
HsvMapFast: takes: 1.556 miliseconds
HotMap: takes: 9.735 miliseconds
HotMapFast: takes: 1.555 miliseconds
CoolMap: takes: 9.727 miliseconds
CoolMapFast: takes: 1.556 miliseconds
SpringMap: takes: 9.726 miliseconds
SpringMapFast: takes: 1.569 miliseconds
SummerMap: takes: 9.672 miliseconds
SummerMapFast: takes: 1.568 miliseconds
AutumnMap: takes: 9.789 miliseconds
AutumnMapFast: takes: 1.554 miliseconds
WinterMap: takes: 10.007 miliseconds
WinterMapFast: takes: 1.555 miliseconds
GrayMap: takes: 9.924 miliseconds
GrayMapFast: takes: 1.554 miliseconds
BoneMap: takes: 9.714 miliseconds
BoneMapFast: takes: 1.555 miliseconds
CopperMap: takes: 9.961 miliseconds
CopperMapFast: takes: 1.564 miliseconds
PinkMap: takes: 9.681 miliseconds
PinkMapFast: takes: 1.556 miliseconds
LinesMap: takes: 9.96 miliseconds
LinesMapFast: takes: 1.568 miliseconds

Once we see the advantages of using pointers, I write the code for the fastest way:

int alto    = entrada->height;
int ancho   = entrada->width;
int step    = entrada->widthStep;
int canales = entrada->nChannels;
uchar* data      = (uchar *)entrada->imageData;

for(int i=0; i < alto;i++)
for(int j=0; j <ancho;j++)
for(int k=0; k < canales;k++)
data[i*step+j*canales+k]= pink[data[i*step+j*canales+k]*3 +2-k];

1 comentario

Protegido: Supresión de fondos

Este contenido está protegido por contraseña. Para verlo introduce tu contraseña a continuación:

1 comentario

Sistema de detección de clases de objetos utilizando modelos de partes deformables

En este proyecto se ha implementado un detector de clases genéricas de objetos utilizando una aproximación piramidal

y detectores de gradientes orientados (HOG).

Está desarrollado en C++ y hace uso de modelos ya entrenados existentes en workspaces de MATLAB.

A continuación unas imágenes del detector funcionando y un video.

Deja un comentario

Detección de bordes

La detección de bordes se basa en los cambios de intensidad entre un pixel y su vecindario.
Para ello empleamos un filtro de matriz. Las matrices más usadas corresponden a la matriz de Laplace y su aproximación
Una matriz de Laplace, tiene la siguiente forma:

1 1 1
1 -8 1
1 1 1

Ahora tenemos que tener en cuenta que el color blanco se corresponde a 25 y el ne  gro a 0, y tenemos algo tal que:

255 255 255 Que lo multiplicamos por la matriz 255 255 255
255 255 255 255 -2040 255
0 0 0 0 0 0

Una vez hayamos hecho esto, sumamos todos los valores, y hayamos su valor absoluto, 765 en este caso.
El cual umbralizaremos (lo normal es entre 20 y 30) y diremos que el punto denota un borde

La info la he extraido y resumido a partir de aquí:
http://vidaartificial.com/index.php?title=Una_introduccion_a_la_Vision_Artificial_%28Generation5.org%29

#include "program.h"
#include <fstream>
#include <vector>

using namespace std;

/***********************************************
        Detector de Bordes:
                                1   1   1
Aplicamos una mascara tal que:  1  -8   1
                                1   1   1

sumamos los puntos y si esta por encima de un umbral
ese punto nos mola.

OpenCv usa un puntero, lo cual nos complica un poco la cosa
mi idea es, defino la matriz del mismo tamañao, y la inicializo
y entonces ya puedo acceder dentro de un bucle for
***********************************************/

int main (int argc, char **argv)
{

 IplImage *entrada = cvLoadImage(argv[1]);              //Leemos la entrada

 int alto    = entrada->height;                         //guardamos las propiedades
 int ancho   = entrada->width;
 int canales = entrada->nChannels;

 vector <int> columna;                                   //en cada columna vamos metiendo los datos, y luego todos los metemos en una fila
 vector <vector <int> > fila;                            //Luego la fila se compone de elementos columnas
 vector <vector <vector <int> > > img_canales;           //y un conjunto de filasxcolumnas, forman un canal

for(int z = 0; z < canales; z++)
{
     for(int f = 0; f < alto ;f++)
     {
        for(int c = 0; c < ancho ; c++)              {               columna.push_back(c);              }         fila.push_back(columna);         columna.clear();      }      img_canales.push_back(fila);    fila.clear();     }     /*      AHORA QUEDA COPIAR LOS DATOS EN LA MATRIZ  El parametro widthStep, indica el número de bytes utilizados para representar cada fila de una imagen.  Una imagen de anchura 101 píxeles, de tipo byte con un widthStep igual a 104, codificará cada fila como una ristra de 104 bytes, de los cuales los 101 primeros se corresponderán con los píxeles de cada fila. ¿Y los 3 restantes, en este ejemplo? OpenCv los rellena con ‘/0′. En OpenCV, el campo widthStep siempre tiene que ser múltiplo de 4. Siempre. Así pues, una imagen (tanto en color como en escala de grises) de tipo byte con anchura de 102 píxeles tendrá un widthStep con valor 104, exactamente el mismo que para otra imagen diferente de anchura 103 ó 104. Esto es así porque la mínima cantidad de memoria que se puede reservar es de 4 bytes en algunos formatos de imagen. */  /*          este trozo de codigo invierte una imagen*/ int step      = entrada->widthStep;
uchar* data      = (uchar *)entrada->imageData;

  for(int i=0;i<alto;i++)
     for(int j=0;j<ancho;j++)
        for(int k=0;k<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span><canales;k++)
            data[i*step+j*canales+k]= 255-data[i*step+j*canales+k];

 cvNamedWindow("kk");
 cvShowImage("kk",entrada);
 cvWaitKey(0);

 return 0;
}

Deja un comentario