-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathmain.cpp
307 lines (235 loc) · 8.79 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
/**
Video Resumen Open Source
2015
Authors:
Ponzoni Nelson, npcuadra <at> gmail.com
Olivera Jose, joseolivera123 <at> gmail.com
Oliva Eduardo, edumoliva <at> gmail.com
Facultad de Ingenieria y Ciencias Hidricas
Universidad Nacional del Litoral
Procesamiento Digital de Imagenes, 2015
please replace <at> for arroba
**/
#include "opencv2/opencv.hpp"
#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <vector>
/**
PARAMETROS:
DEBUG := visualizar la segmentacion y etiqutado
MAS_INFO := visualizar mas informacion (numeros en la etiquetas de los blobs...)
FONDO_PASOS_SEG := cada cuanto se quiere que se actualize el fondo
FONDO_MERGE := alfa de mezclado entre el frame actual y el que estaba (fondo)
MOSTRAR_FONDO := muestra los pasos intermedios del calculo del fondo
FONDO_NOMBRE := nombre del archivo donde se guarda el fondo
TAM_MIN_OBJETOS := tamanio minimo (en pixeles) que deben de tener los objetos para participar como eventos en la escena
TAM_MAX_OBJETOS := tamanio maximo (en pixeles) que deben de tener los objetos para participar como eventos en la escena
TASA_APRENDIZAJE := tasa de aprendizaje para el MOG2, con cuanto se quiere que reconozca el fondo
SEG_ROJO_AZUL := dejar solo los objetos rojos (true) o los objetos azules (false)
DELAY_EVENTOS := espera (en frames) de visualizacion para agregar nuevos eventos a la escena
MOSTRAR_RESULTADO := para ver el resultado de la compilacion en video final
CANTIDAD_EVENTOS := cantidad de objetos a visualizar juntos en la escena final
ENTRADA_NOMBRE := nombre del video de entrada (.AVI)
SALIDA_NOMBRE := nombre del video de salida (.AVI)
RATIO := factor de escala para achicar el video o salida. (=2.0 mas rapido; =1.0 mas lento)
**/
//
#define DEBUG false
#define MAS_INFO false
// fondo
#define FONDO_PASOS_SEG 1
#define FONDO_MERGE 0.90
#define FONDO_MOSTRAR true
#define FONDO_NOMBRE "FONDO.jpg"
// segmentacion
#define TAM_MAX_OBJETOS 5000 // estaba en 30000
#define TAM_MIN_OBJETOS 40 // estaba en 110
#define TASA_APRENDIZAJE 0.001f
#define SEG_ROJO_AZUL true
// mostrar
#define DELAY_EVENTOS 10
#define MOSTRAR_RESULTADO true
#define CANTIDAD_EVENTOS 30
#define EVENTOS_SEG false
#define EVENTOS_SEGUNDOS true
// videos
#define ENTRADA_NOMBRE "video2.avi"
//#define ENTRADA_NOMBRE "video_casa.mp4"
#define SALIDA_NOMBRE "salida2.avi"
#define RATIO 2
//#define FPS 30
//
/// Funciones, dejar abajo de los define
#include "Functions.h"
//
using namespace cv;
using namespace std;
/// Funcion Principal
int main()
{
Mat frame, //current frame
morpho, //dilated fgMaskMOG
frame2,
first_frame, //primer frame del video
src, //frame resizeado
mascara,
threshold_output, //binary output from ConvexHull
output, //output from ConvexHull
element,
threshold_output_centers, //threshold_output with centers on obejects
colored_output,
fgMaskMOG; //fg mask generated by MOG method
vector< BlobCenter > blobs_frame, //blobs del frame actual (ver en Functions.h el struct BlobCenter)
blobs_frame_old; //blobs del frame anterior
// un vector de pares (un elemento del vector por objeto), cada par tiene
// primero>> un vector de vectores con el centro cx cy y el frame donde cada uno aparece
// segundo>> un vector con cada frame del objeto
vector <pair < vector<vector <int> > , vector<Mat> > > Objects, //cada elemento es un vector de imagenes con un objeto particular
Objects_copia;
vector< vector<double> > etiquetas; // vector que contiene la relacion entre ids del frame actual y el anterior
int morph_elem = 1, // rectangular
morph_size = 2,
// ratio = 2,
next_id = 1; //id único global para cada objeto que sea detectado en el video
bool flag = true;
// detectores de objetos
Ptr< BackgroundSubtractor> pMOG2; //MOG Background subtractor
pMOG2 = new BackgroundSubtractorMOG2();
// archivo
char fileName[100] = ENTRADA_NOMBRE;
// char fileName[100] = argv[1];
// video de entrada
VideoCapture stream(fileName); //0 is the id of video device.0 if you have only one camera
int n = 0; // contador de frames del video
// para el fondo
VideoCapture stream_fondo(fileName);
Mat frame_fondo;
if(!(stream_fondo.read(frame_fondo))) cout << "No se puede Abrir el archivo de entrada"; //obtener un solo frame del video
Mat fondo_temporal;
resize(frame_fondo, fondo_temporal, Size(frame_fondo.size().width/RATIO, frame_fondo.size().height/RATIO) );
// para la salida a video
Size S = Size((int) stream.get(CV_CAP_PROP_FRAME_WIDTH)/RATIO, (int) stream.get(CV_CAP_PROP_FRAME_HEIGHT)/RATIO);
int codec = static_cast<int>(stream.get(CV_CAP_PROP_FOURCC));
double framenum = stream.get(CV_CAP_PROP_FPS);
VideoWriter outputVideo(SALIDA_NOMBRE, codec, framenum, S, true);
int fondo_pasos_frames = framenum * FONDO_PASOS_SEG;
while (true) {
if(!(stream.read(frame2))) //get one frame form video
break;
/**
S E G M E N T A C I O N
**/
///filtro gaussiano
GaussianBlur( frame2, frame, Size( 9, 9 ), 0, 0 );
resize(frame, src, Size(frame.size().width/RATIO, frame.size().height/RATIO) );
pMOG2->operator()(src, fgMaskMOG,TASA_APRENDIZAJE);
GaussianBlur( fgMaskMOG, fgMaskMOG, Size( 9, 9 ), 0, 0 );
threshold( fgMaskMOG, fgMaskMOG, 200, 255,0 );
element = getStructuringElement( morph_elem, Size( 2*morph_size + 1, 2*morph_size + 1), Point( morph_size, morph_size ) );
dilate(fgMaskMOG,morpho,element);
/// pasa a tres canales lo mismo
mascara = src;
for(int i = 0; i < 3; i++)
for (int x=0; x<mascara.cols; x++)
for (int y=0; y<mascara.rows; y++)
mascara.at<Vec3b>(y,x)[i] = morpho.at<uchar>(y,x);
/**
C O N V E X H U L L
**/
ConvexHull(mascara,src, frame2, output, threshold_output);
/**
F O N D O
**/
Mat frame_actual;
resize(frame2, frame_actual, Size(frame.size().width/RATIO, frame.size().height/RATIO) );
// salida2 el frame leido pequeño
// calcula el fondo, cada # frames actualiza el valor
if ( !(n % fondo_pasos_frames) )
{
Mat salida_fondo;
extraerFondo(frame_actual,threshold_output,fondo_temporal,salida_fondo);
salida_fondo.copyTo(fondo_temporal);
}
#if FONDO_MOSTRAR
imshow("Calculando fondo...",fondo_temporal);
#endif
/**
E T I Q U E T A D O
**/
///extraigo los blobs con sus respectivos centros
Img2Blob(threshold_output, blobs_frame, n);
if(flag && (blobs_frame.size() > 0) ){
flag = false;
for(int t=0; t<blobs_frame.size(); t++){
blobs_frame[t].id = next_id;
next_id++;
}
}
else if(blobs_frame.size() > 0){
correspondencias_id(blobs_frame_old, blobs_frame, etiquetas);
reEtiquetado(blobs_frame, etiquetas, next_id);
#if DEBUG
///-.-.-.-.-VISUALIZAR SEGUIMIENTO-.-.-.-.-
colored_output = Mat::zeros(threshold_output.size(), CV_8UC3);
double time = n/framenum;
paintBlobs(blobs_frame, colored_output,time);
imshow("out", output);
imshow("colored_out", colored_output);
imshow("frame", frame_actual);
/// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
#endif
}
if(blobs_frame.size() > 0){
FillObjects(src, blobs_frame, Objects); //cargo en Objects las imagenes con cada objeto por separado
}
blobs_frame_old = blobs_frame;
blobs_frame.clear();
etiquetas.clear();
if (waitKey(10) >= 0)
break;
// if(n==500)
// break;
n++;
}
#if FONDO_MOSTRAR
imshow("EXTRACCION DEL FONDO",fondo_temporal);
waitKey(0);
#endif
// guardo el fondo a disco
imwrite(FONDO_NOMBRE,fondo_temporal);
//elimino los objetos que aparecen por menos de 10 frames
Objects_copia = Objects;
Objects.clear();
for(int i=0; i<Objects_copia.size(); i++){
if(Objects_copia[i].second.size() > 10){
Objects.push_back(Objects_copia[i]);
}
}
Mat fondo = imread(FONDO_NOMBRE,3);
#if EVENTOS_SEG
// seleeciono los videos con algun criterio
vector <pair < vector<vector <int> > , vector<Mat> > > Objects_aux;
seleccionar(Objects,Objects_aux);
Objects = Objects_aux;
#endif
// junta todos los objetos y los guarda en video
mostrar(Objects,fondo,CANTIDAD_EVENTOS, outputVideo,framenum);
//
/**
Visualizacion de los parametros
**/
cout << "\n\n";
cout << "\n calculo del fondo cada X segundos: \t" << FONDO_PASOS_SEG;
cout << "\n alfa merging fondo: \t" << FONDO_MERGE;
cout << "\n tamanio minimo de los objetos a considerar (pixeles): " << TAM_MIN_OBJETOS;
cout << "\n tamanio maximo de los objetos a considerar (pixeles): " << TAM_MAX_OBJETOS;
cout << "\n tasa de aprendizaje: \t" << TASA_APRENDIZAJE;
cout << "\n frames entre eventos: \t" << DELAY_EVENTOS;
cout << "\n ratio del proceso: \t" << RATIO;
cout << "\n cantidad de objetos a visualizar juntos p/frame: " << CANTIDAD_EVENTOS;
waitKey(0);
///-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-
return 0;
}