-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmotioncalibrate.cpp
More file actions
274 lines (232 loc) · 8.18 KB
/
motioncalibrate.cpp
File metadata and controls
274 lines (232 loc) · 8.18 KB
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
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector> // for vectors
#include <utility> // pairs
#include <tuple> // I don't think I actuall need this
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include "opencv2/objdetect.hpp"
// #include motiondetect.cpp I am being lazy and not making this a header file
using namespace std;
using namespace cv;
//KEYBINDS
#define YES_KEY (89)
#define YES_KEY_LOWER (121)
#define NO_KEY (78)
#define NO_KEY_LOWER (110)
#define ENTER_KEY (13)
#define ESCAPE_KEY (27)
//data-struct of tuples each rectangle is comprised of a pair of points
vector<pair<tuple<int, int>, tuple<int, int>>> exclusion_collection;
tuple<int, int> tl(-1,-1); //top right
tuple<int, int> br(-1,-1); //bot left
void exclusionzone(tuple<int, int> top_left,tuple<int, int> bottom_right, Mat in_mat, Mat &ex_mat);
void populatezones(vector<pair<tuple<int, int>, tuple<int, int>>> exclusion_collection, Mat in, Mat &out);
bool motiondetect(int sensitivity, Mat prev_frame, Mat curr_frame);
int sliderValue = 0;
int sensitivity = 1;
//SLIDER BAR
void onTrackbar(int pos, void*) {
sensitivity = pos;
}
//MOUSE CAP FUNCTION
void onmouse(int action, int x, int y, int, void*){
if(action == EVENT_LBUTTONDOWN){
cout << "click detected (" << x << ", " << y << ")" << endl;
//mouse click
tl = make_tuple(x,y);
}else if(action == EVENT_LBUTTONUP){
cout << "unclick detected (" << x << ", " << y << ")" << endl;
//unclick
br = make_tuple(x,y);
cout << "keep? (y/n/enter/esc)" << endl;
}
}
//CREATE A CALIBRATION
int motioncalibrate(){
//OVERWRITE WARNING ESC TO QUIT
cout << "WARNING this program will overwrite any existing config files in the default directory" << endl;
//sensitivity num
Mat frame, exclusions;
bool done = false;
//start capture from cam
VideoCapture cam0(0);
namedWindow("exclusion selection");
//TODO: write on the window instructions "click and drag a square to exclude area"
//capture frame
cam0.read(frame);
exclusions = frame.clone();
//loop
//void cv::setMouseCallback (const String &winname, MouseCallback onMouse, void * userdata = 0 )
cout << "click and drag to select top left then bottom right of the exclusion" << endl;
bool skip_switch = false;
int key = -1;
//GET EXCLUSION ZONES
while(1){
//wait for bottom left point to populate
while(get<1>(br) == -1 && get<1>(tl) == -1){
imshow("exclusion selection", exclusions);
//draw exclusion with mouse
setMouseCallback("exclusion selection", onmouse);
char input;
if((input = waitKey(1)) == ESCAPE_KEY){
return -1;
}else if(input == ENTER_KEY){
skip_switch = true;
done = true;
break;
}
}
//TODO:swap points if not ---> direction
if(!skip_switch){
key = waitKey(1);
}
pair<tuple<int, int>, tuple<int, int>> pair;
switch(key){
//keep (y/n)
case YES_KEY:
case YES_KEY_LOWER:
//write
cout << "yes" << endl;
cout << "(" << get<0>(tl) << ", " << get<1>(tl) << ") ; (" << get<0>(br) << ", " << get<1>(br) << ")" << endl;
pair = make_pair(tl,br);
exclusion_collection.push_back(pair);
//update mat
exclusionzone(tl, br, exclusions, exclusions);
tl = make_tuple(-1,-1);
br = make_tuple(-1,-1);
break;
case NO_KEY:
case NO_KEY_LOWER:
cout << "no" << endl;
tl = make_tuple(-1,-1);
br = make_tuple(-1,-1);
cout << "click and drag again, enter to continue, esc to quit" << endl;
break;
//done? (enter)
case ENTER_KEY:
done = true;
break;
//exit (esc)
case ESCAPE_KEY:
return -1;
break;//useless but looks nice
case -1:
continue;
default:
break;
}
if(done){
break;
}
}
//show camera with sensitivity bar
Mat ex2, ex1, f1;
ex2 = exclusions.clone();
bool capture = false;
sensitivity = 1;
destroyWindow("exclusion selection");
//SENSITIVITY CALIBRATE
while(1){
//press enter to save value
//TODO: toggle exclusions (space?)
//create window
namedWindow("sensitivity calibration");
//read cam
cam0.read(frame);
//exclude selection(s)
populatezones(exclusion_collection, frame, ex1);
//create slider
createTrackbar("sensitivity", "sensitivity calibration", nullptr, (frame.rows * frame.cols * 5), onTrackbar);
//check motion
capture = motiondetect(sensitivity, ex2, ex1);
//write if detect is true on f1
string text = (capture) ? "motion detected! (" : "no motion (";
text.append(to_string(sensitivity));
text.append(")");
f1 = ex1.clone();
putText(f1, text, Point(20, 20), 1, 1, Scalar(50,50,50), 2);
//show frame
imshow("sensitivity calibration", f1);
key = waitKey(1);
//exit if enter or esc
if (key == ESCAPE_KEY){
return -1;
}else if(key == ENTER_KEY){
break;
}
ex2 = ex1.clone();
}
//press enter to save value
//TODO: toggle exclusions (space?)
//write sensitivity with tuple datastruct to file
return 0;
}
void populatezones(vector<pair<tuple<int, int>, tuple<int, int>>> exclusion_collection, Mat in, Mat &out){
//loop through collection
out = in.clone();
for (auto& [p1, p2] : exclusion_collection){
exclusionzone(p1, p2, out, out);
}
}
//motiondetect
bool motiondetect(int sensitivity, Mat prev_frame, Mat curr_frame){
/*
sensitivity: the minimum difference needed for motion detection to trigger
prev_frame: the previous frame captured from the camera
curr_frame: the most recent capture from the camera
motion detection will return true if the absolute difference detected is above the given threshold
TODO: a default should be determined if the sensitivity is not given or zero is given
*/
int diff_value;
Mat diff_frame;
//for now we will just do a color diff not a grayscale
absdiff(prev_frame, curr_frame, diff_frame);
diff_value = (unsigned int)cv::sum(diff_frame)[0]; //add up only the blue frame
cout << diff_value << " ;;; " << sensitivity << endl;
if (diff_value > sensitivity){
//motion detected
return true;
}
return false;
}
void exclusionzone(tuple<int, int> top_left, tuple<int, int> bottom_right, Mat in_mat, Mat &ex_mat){
/*
example mat is 250x250
example inputs
x y
topleft = (34, 27)
topright = (123, 238)
*/
//this program will draw a white box over an area in the mat which excludes it from motion detection.
//get the coordinates of the tuples for top right and lower left
int x1 = get<0>(top_left);
int y1 = get<1>(top_left);
int x2 = get<0>(bottom_right);
int y2 = get<1>(bottom_right);
//clone in_mat to ex_mat
ex_mat = in_mat.clone();
if (x1 > x2) swap(x1, x2);
if (y1 > y2) swap(y1, y2);
//loop through ex_mat and overwrite pixels
// cout << ex_mat
for(int y = 0; y < ex_mat.rows; y++){
if(y >= y1 && y <=y2){
//if row is in range
for(int x = 0; x < ex_mat.cols; x++){
//if col is in range
if(x >= x1 && x <=x2){
ex_mat.at<Vec3b>(y,x)[0] = 0;
ex_mat.at<Vec3b>(y,x)[1] = 0;
ex_mat.at<Vec3b>(y,x)[2] = 0;
//pixel == 255
}
}
}
}
}
int main(){
return motioncalibrate();
}