-
Notifications
You must be signed in to change notification settings - Fork 0
/
carCounter.h
387 lines (313 loc) · 13.3 KB
/
carCounter.h
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
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
#define USE_BACKGROUND 0
#define USE_ORGINAL_FRAME 1
#define USE_RESIZED_WITH_OVERLAYS_FRAME 2
#define USE_SUBTRACTED 3
#define DETECT_SHADOWS_ON true
#define DETECT_SHADOWS_OFF false
#define SHOW_LAST_CAR_ON true
#define SHOW_LAST_CAR_OFF false
#define SHOW_PREDICTION_ON true
#define SHOW_PREDICTION_OFF false
#define SHOW_LATEST_PATHS_ON true
#define SHOW_LATEST_PATHS_OFF false
#define SHOW_TRANSIT_LEDGER_ON true
#define SHOW_TRANSIT_LEDGER_OFF false
#define SHOW_BOUNDBOX_ON true
#define SHOW_BOUNDBOX_OFF false
#define SHOW_REGION_MONITORS_ON true
#define SHOW_REGION_MONITORS_OFF false
#define SHOW_PATH_OF_CAR_X_OFF -1
#define RUN_ONLINE true
#define RUN_OFFLINE false
#define USE_MOG2_ON true
#define USE_MOG2_OFF false
#define _VARIADIC_MAX 10
#ifndef CARCOUNTER_H
#include <stdio.h>
#include <iostream>
#include <ctime>
#include <thread>
#include <limits>
#include <vector>
#include <queue>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/opencv.hpp>
#include "sqlite3.h"
#include "DPAdaptiveMedianBGS.h"
#include "FrameDifferenceBGS.h"
/* Frame datatype */
/* Holistic representation of all the objects captured in the given frame. */
struct Frame
{
// Geometric description
cv::vector<cv::vector<cv::Point>> contour;
cv::vector<cv::Rect> boundRect;
cv::vector<cv::Point2f> center;
cv::vector<float> radius;
// Instantaneous metrics (based on current frame and the last)
cv::vector<double> velocity;
cv::vector<double> velocityX;
cv::vector<double> velocityY;
// Average metrics (based on the entire known history of the object)
cv::vector<double> speed;
cv::vector<double> speedX;
cv::vector<double> speedY;
cv::vector<double> distance;
cv::vector<double> distanceX;
cv::vector<double> distanceY;
// Meta-data
cv::vector<int> time;
cv::vector<int> id;
cv::vector<int> tIdx;
cv::vector<bool> p;
cv::vector<bool> checked;
cv::vector<cv::Point2f> start_loc;
// Calculated prediction of where the object should be in the future
cv::vector<std::vector<cv::Point2f>> pTraj;
};
/* Object datatype */
/* Representation of object. */
struct Object
{
// Target data
int id;
int count;
cv::Point2f start_loc;
cv::vector<cv::Point2f> trajectory;
cv::vector<int> area;
cv::vector<int> frames;
cv::vector<int> ulx;
cv::vector<int> uly;
cv::vector<int> lrx;
cv::vector<int> lry;
cv::Mat img;
// Simple flags
bool checked;
bool hasSibling;
bool headlight;
bool miss;
// Headlight sibling
int siblingID;
// Variables to track last know state of object.
int last_seen;
cv::vector<std::vector<cv::Point2f>> trajectories_before_disappearing;
cv::vector<cv::Point> contour_before_disappearing;
cv::Rect boundbox_before_disappearing;
cv::Point2f center_when_last_seen;
double velocity_when_last_seen;
double velocityX_when_last_seen;
double velocityY_when_last_seen;
double speed_when_last_seen;
double speedX_when_last_seen;
double speedY_when_last_seen;
double distance_when_last_seen;
double distanceX_when_last_seen;
double distanceY_when_last_seen;
int time_when_last_seen;
// Buffer index
int bIdx;
// Transit index
int tIdx;
// Set default boolean values
Object() {
checked = false;
hasSibling = false;
headlight = false;
miss = false;
}
};
/* An instance of carCounter can run the algorithm.
* carCounter also stores result data on cars and all
* processed frames. An alternative to getting the data
* from program memory is to pull it from a database. A
* carCounter will keep table data updated as the algorithm
* runs.
*
* note: Anything marked with (*) is specific to night time mode only.
*
* while(true)
* - obtainframe < (opencv)
* - obtainBoundBoxes
* - createFrame
* - threshold < (opencv)
* - selectBackgroundSubtraction
* - MOG2 < (opencv) || - Adaptive Median < (BGS) || - (*) FrameDifference < (BGS)
* - dilate < (opencv)
* - erode < (opencv)
* - medianblur < (opencv)
* - removeShadow
* - persistenceCheck
* - checkTransitLedgerUsingMomentAndCenter
* - startRegionMonitor
* - safetyChecks
* - histogramCalcAndFindStd
* - calcHistogram
* - findStd
* - checkMissing
* - endRegionMonitor
* - safetyChecks
* - histogramClacAndFindStd
* - calcHistogram
* - findStd
* - (*) detectCarBoxForNight
* - drawResult
*
*/
class carCounter{
private:
// Identifier
int id;
// Counters
int frame_counter;
int object_counter;
int car_counter;
// Flow control (If nighttime is selected algorithm will take a slightly alternate path each cycle)
bool nightTime;
// Temporal Workspace
std::deque<Frame> buffer;
std::deque<Object> transit;
// Result
std::deque<Object> carArchive;
std::deque<Frame> frameArchive;
// Testing
std::clock_t start; // timer
double duration; // timer
cv::Mat test; // isn't used in calc, output to this to see what something looks like
// Frame
cv::Mat frame; // current frame
cv::Mat resizeF; // current frame resized
cv::Mat resizeFgray; // current frame resized (grayscale)
// Display Matrix
cv::Mat display; // can use this to draw whatever you want on it.
// Foreground Matrices
cv::Mat mask; // fg mask generated by MOG2/Adaptive Median or Threshold for night time.
cv::Mat3b maskrgb; // fg mask with 3 channels.
cv::Mat extraMask; // fg mask generated by frame difference (during night time).
cv::Mat3b extraMaskrgb; // fg mask with 3 channels.
// Background Matrix
cv::Mat background;
cv::vector<cv::vector<cv::Point>> contours;
cv::vector<cv::Vec4i> hierarchy;
cv::vector<cv::Vec3f> vecCircles;
cv::vector<cv::Vec3f>::iterator itrCircles;
cv::BackgroundSubtractorMOG2 MOG2; // MOG Background subtractor.
IBGS *bgsAdaptiveMedian;
IBGS *bgsFrameDifference;
// db variables
sqlite3 *db;
int rc;
/* Initializes the frame object once background subtraction is done. */
void createFrame(Frame &data, cv::vector<cv::vector<cv::Point>> &contours,
cv::vector<cv::vector<cv::Point>> &contours_poly,
cv::vector<cv::Rect> &boundRect,
cv::vector<cv::Point2f> ¢er,
cv::vector<float> &radius, int minObjectSize);
/* Select and apply BackgroundSubtraction.
For daytime use either MOG2 or a modified DP Adaptive Median.
For nighttime we use frame difference. (currently not implemented) */
void carCounter::selectBackgroundSubtraction(bool useMOG2, bool nightTime,
cv::Mat &resizeF,cv::Mat &mask,
int nmixtures, double backgroundratio, bool detectShadows);
/* Checks what objects in the current frame correspond to the ones
in the previous. Will check against the transit ledger and properly update
the most current frame object in the buffer. */
void persistenceCheck(int &frame_counter,int type,std::deque<Frame> &buffer, std::deque<Object> &transit,int expectedDist);
/* This method keeps tabs on objects that may have went missing.
If object transit ledger is updated with information from current frame.
Else the object is simply marked as missing and the transit ledger
will store info from the previous time the object was seen. */
void checkMissing(int &frame_counter,
std::deque<Frame> &buffer,std::deque<Object> &transit);
/* Checks for new objects entering the transit region.
Objects in the transit region are suspected cars, if they enter they should also leave
at some point. When this happens they are identified as being cars. In the start region objects
are assigned their initial values. During night time we attempt to "match" multiple objects to one
another since we look at headlights. (2 headlights belong to 1 car)*/
void startRegionMonitor(cv::Mat &frame,cv::Mat &background, cv::Mat &subtract,
std::deque<Frame> &buffer,std::deque<Object> &transit,
cv::vector<cv::Point> startRegion,
int horizontalBandWidth);
/* Checks for objects exiting the transit region. We flush all objects up to
the last one that exited. If A,B, and C entered the transit region in
that order and C ends up crossing first then A and B are disregarded.*/
void endRegionMonitor(cv::Mat &frame,cv::Mat &background,cv::Mat &subtract, cv::Mat &subtract2, int minObjectSize,
int &car_counter,
std::deque<Frame> &buffer,std::deque<Object> &transit,std::deque<Object> &carArchive,
cv::vector<cv::Point> endRegion);
/* Internal functionality for endRegionMonitor */
void detectCarBoxForNight(cv::Mat &subtract,cv::Rect &boundRect,int minObjectSize);
/* Internal functionality for persistenceCheck */
void checkTransitLedgerUsingMomentAndCenter(int &frame_counter,std::deque<Frame> &buffer,std::deque<Object> &transit,int expectDist);
/* Internal functionality for startRegionMonitor and endRegionMonitor */
bool safetyChecks(cv::Mat &frame,cv::Mat &background,cv::Mat &subtract,
std::deque<Frame> &buffer,
int boundBoxNum,double thresh);
/* Internal functionality for safetyChecks */
double histogramCalcAndFindStd(cv::Mat &frame,cv::Mat &background,cv::Mat &subtract,
std::deque<Frame> &buffer,int boundBoxNum);
/* Internal functionality for histogramCalcAndFindMax */
cv::vector<cv::Mat> calcHistogram(cv::Mat& img,cv::Mat& mask);
double findStd(cv::vector<cv::Mat> &hist, int channel);
/* Visualization */
void drawResult(int &car_counter, int &object_counter, cv::Mat &frame, cv::vector<cv::Vec4i> &hierarchy, std::deque<Frame> &buffer,std::deque<Object> &transit,
bool showLastCar, bool boundBoxesOn, bool predictionOn, bool latestPathsOn, bool displayTransitLedger, bool displayFocusRegions, int showPathofId,
cv::vector<cv::Point> startRegion,
cv::vector<cv::Point> endRegion);
/* Custom Utility */
int obtainBoundBoxes(cv::vector<cv::vector<cv::Point>> &contours,cv::vector<cv::vector<cv::Point>> &contours_poly,
cv::vector<cv::Rect> &boundRect,
cv::vector<cv::Point2f> ¢er,cv::vector<float> &radius, int minObjectSize);
/* Applies median blur, dilate/erode and shadow removal */
void cleanNoise(cv::Mat &mask, cv::Mat &extraMask,cv::Mat3b &maskrgb, cv::Mat3b &extraMaskrgb);
/* Internal to clean noise, can remove shadows if MOG2 shadow detection is being used*/
void removeShadow(cv::Mat &subtract,cv::Mat3b &subtractrgb);
/* DB functions */
void openDB(int expID,char dataBase[200]);
void closeDB();
/* Async method for filling the database */
void exportCarsToDB(int expID,char fileName[100], char saveImgTo[200], std::deque<Object> &carArchive, int fps);
public:
// constructor
carCounter(int expID,bool night);
/* Start the counter
* NAME: :DESCRIPTION :UNITS (IF APPLICABLE)
* bufferSize: Local workspace (how many of the latest frames of the video to store)
* minObjectSizeDay: Minimum required size for an object to be considered (ignore things that are too small to be a car) Pixels Squared
(*) minObjectSizeNight: Minimum required size for an object to be considered (ignore things that are too small to be a headlight) Pixels Squared
* skip: Skips frames from video (potential performance improvement) Frames
* learningTime: Give time for BGS to settle Frames
* fileName: Video filename that you want run the algorithm on.
* saveImgTo: Directory in which cropped images of counted cars will be saved.
* dataBase The local sqlite database to which you want to save data. (absolute location)
* fps: Ignore this for now (set the frames per second of this video. Can be used to track how many seconds into the video the car is detect) Frames/second
* expectedDist: Tells the algorithm the threshold on how far along in pixels the object will be next frame. Pixels
* horizontalBandWidth: If looking for a sibling headlight object this tells the algorithm how wide the search area band should be horizontally. Pixels
* online: Whether to display frames
* ppt,ppt2,npt,npt2: Set an overlay mask on the video (optional)
* useMOG2: Choose between MOG2 or Adaptive Median for background subtraction
(Adaptive median is more primitive but is able to handle stationary objects).
Check MOG2 for details.
* startRegion: Set points for start Region.
* endRegion: Set points for end Region.
Other parameters are settings for displaying if online mode is chosen.
*
* note: Anything marked with (*) is specific to night time mode only.
*/
void run(int bufferSize, int minObjectSizeDay, int minObjectSizeNight, int skip, int learningTime,
char fileName[100], char saveImgTo[200], char dataBase[200],
int fps,
int expectedDist, int horizontalBandWidth,
bool online, const cv::Point* ppt, const cv::Point* ppt2,int* npt,int* npt2, bool useMOG2,
int nmixtures, double backgroundratio, bool detectShadows, bool showLastCar,
bool boundBoxesOn, bool predictionOn, bool latestPathsOn,
bool displayTransitLedger, bool displayFocusRegions, int showPathofId,
int displayType,
cv::vector<cv::Point> startRegion,
cv::vector<cv::Point> endRegion);
/* Getters for the results */
void getFrameArchiveData(int* frames);
void getCarArchiveData(int* cars);
};
static int callback(void *NotUsed, int argc, char **argv, char **azColName);
#endif