38 static Mat
shift_frame(Mat in_frame,
int shiftx,
int shifty) {
39 Mat zero_mask = Mat::zeros(in_frame.size(), in_frame.type());
43 LOGGING <<
"SHIFT_X: " << shiftx << std::endl <<
"SHIFT_Y: " << shifty << std::endl;
47 if ((shiftx < 0) && (shifty < 0)) {
50 LOGGING <<
"shifting case 1 - move right and down" << std::endl;
54 .copyTo(zero_mask(Rect(abs(shiftx), abs(shifty),
BOXSIZE-abs(shiftx),
BOXSIZE-abs(shifty))));
55 }
else if (shiftx < 0) {
58 LOGGING <<
"shifting case 2 - move right and maybe up" << std::endl;
61 in_frame(Rect(0, abs(shifty),
BOXSIZE-abs(shiftx),
BOXSIZE-abs(shifty)))
62 .copyTo(zero_mask(Rect(abs(shiftx), 0,
BOXSIZE-abs(shiftx),
BOXSIZE-abs(shifty))));
63 }
else if (shifty < 0) {
66 LOGGING <<
"shifting case 3 - move down and maybe left" << std::endl;
69 in_frame(Rect(abs(shiftx), 0,
BOXSIZE-abs(shiftx),
BOXSIZE-abs(shifty)))
70 .copyTo(zero_mask(Rect(0, abs(shifty),
BOXSIZE-abs(shiftx),
BOXSIZE-abs(shifty))));
74 LOGGING <<
"shifting case 4 - move up and left" << std::endl;
77 in_frame(Rect(abs(shiftx), abs(shifty),
BOXSIZE-abs(shiftx),
BOXSIZE-abs(shifty)))
78 .copyTo(zero_mask(Rect(0, 0,
BOXSIZE-abs(shiftx),
BOXSIZE-abs(shifty))));
101 static Mat
corner_matching(Mat in_frame, vector<Point> contour,
int plusx,
int plusy) {
163 in_frame =
shift_frame(in_frame, shiftx/2, shifty/2);
177 static vector <int>
test_edges(Mat in_frame, vector<Point> contour,
int te_ret) {
182 Rect rect = boundingRect(contour);
196 if ((te_ret == 1) || (te_ret == 3) || (te_ret == 7)) {
198 plusx = rect.br().x -
ORIG_BR.x;
199 plusy = rect.br().y -
ORIG_BR.y;
200 }
else if ((te_ret == 2) || (te_ret == 6) || (te_ret == 8)) {
202 plusx = rect.tl().x -
ORIG_TL.x;
203 plusy = rect.tl().y -
ORIG_TL.y;
204 }
else if (te_ret == 4) {
208 }
else if (te_ret == 5) {
211 plusy = -(
ORIG_BR.y - rect.height);
216 LOGGING << plusx <<
", " << plusy << std::endl;
220 vector <int> outplus;
221 outplus.push_back(plusx);
222 outplus.push_back(plusy);
234 BOXSIZE = min(in_frame.rows, in_frame.cols);
250 vector <int> local_vec;
252 Rect box = boundingRect(contour);
253 int top = box.tl().y;
254 int bot = box.br().y;
258 for (
size_t i = 0; i<contour.size(); i++) {
259 if (contour[i].y == top) {
262 if (contour[i].y == bot) {
267 local_vec.push_back(topout);
268 local_vec.push_back(botout);
280 vector <int> local_vec;
282 Rect box = boundingRect(contour);
283 int lef = box.tl().x;
284 int rig = box.br().x;
288 for (
size_t i = 0; i<contour.size(); i++) {
289 if (contour[i].y == lef) {
292 if (contour[i].y == rig) {
297 local_vec.push_back(lefout);
298 local_vec.push_back(rigout);
321 Rect image_rect = Rect({}, in_frame.size());
324 Point roi_tl = Point(box.tl().x - ((
BOXSIZE - box.width)/2),
325 (box.tl().y- (
BOXSIZE - box.height)/2));
326 Point roi_br = Point(((
BOXSIZE - box.width)/2) + box.br().x,
327 ((
BOXSIZE - box.height)/2) + box.br().y);
329 if (roi_br.x - roi_tl.x >
BOXSIZE) {
330 oldvalue = (roi_br.x - roi_tl.x) -
BOXSIZE;
331 roi_br = Point(roi_br.x - oldvalue, roi_br.y);
332 }
else if (roi_br.x - roi_tl.x <
BOXSIZE) {
333 oldvalue =
BOXSIZE - (roi_br.x - roi_tl.x);
334 roi_br = Point(roi_br.x + oldvalue, roi_br.y);
336 if (roi_br.y - roi_tl.y >
BOXSIZE) {
337 oldvalue = (roi_br.y - roi_tl.y) -
BOXSIZE;
338 roi_br = Point(roi_br.x, roi_br.y - oldvalue);
339 }
else if (roi_br.y - roi_tl.y <
BOXSIZE) {
340 oldvalue =
BOXSIZE - (roi_br.y - roi_tl.y);
341 roi_br = Point(roi_br.x, roi_br.y + oldvalue);
345 oldvalue = -(roi_tl.x);
346 roi_tl = Point(0, roi_tl.y);
347 roi_br = Point(roi_br.x - oldvalue, roi_br.y);
350 oldvalue = -(roi_tl.y);
351 roi_tl = Point(roi_tl.x, 0);
352 roi_br = Point(roi_br.x, roi_br.y - oldvalue);
354 if (roi_br.x > in_frame.cols) {
355 oldvalue = roi_br.x - in_frame.cols;
356 roi_tl = Point(roi_tl.x - oldvalue, roi_tl.y);
357 roi_br = Point(roi_br.x - oldvalue, roi_br.y);
359 if (roi_br.y > in_frame.rows) {
360 oldvalue = roi_br.y - in_frame.rows;
361 roi_tl = Point(roi_tl.x, roi_tl.y - oldvalue);
362 roi_br = Point(roi_br.x, roi_br.y - oldvalue);
365 Rect roi = Rect(roi_tl, roi_br);
367 Rect intersection = image_rect & roi;
369 intersection = Rect(Point(intersection.x, intersection.y), Size(
BOXSIZE,
BOXSIZE));
371 Rect inter_roi = intersection - roi.tl();
374 Mat precrop = in_frame(intersection);
377 if ((inter_roi.x > 0) || (inter_roi.y > 0)) {
379 Mat zero_mask = Mat::zeros(Size(
BOXSIZE,
BOXSIZE), in_frame.type());
381 precrop(Rect(Point(0, 0),
387 Point(inter_roi.x, inter_roi.y),
392 in_frame = zero_mask;
424 Rect box = boundingRect(contour);
426 if (box.tl().x == 0) {
427 if (box.tl().y == 0) {
429 }
else if (box.br().y == in_frame.rows) {
434 }
else if (box.br().x == in_frame.cols) {
435 if (box.tl().y == 0) {
437 }
else if (box.br().y == in_frame.rows) {
443 if (box.tl().y == 0) {
445 }
else if (box.br().y == in_frame.rows) {
458 Mat mask(Size(in_frame.rows, in_frame.cols), in_frame.type(), Scalar(0));
459 Mat zero_mask(Size(
BOXSIZE,
BOXSIZE), in_frame.type(), Scalar(0));
461 Mat item(in_frame(box));
464 drawContours(mask, contours, largest, 255, FILLED);
467 item.copyTo(item, mask(box));
471 Rect center_box(center.x - box.width/2, center.y - box.height/2, box.width, box.height);
474 item.copyTo(zero_mask(center_box));
477 in_frame = zero_mask;
501 threshold(in_frame.clone(), temp_frame,
BLACKOUT_THRESH, 255, THRESH_TOZERO);
508 <<
"Number of detected contours in ellipse frame: " 516 drawContours(in_frame, contours, largest_contour_index, 255, 2, LINE_8);
519 Rect box = boundingRect(contours[largest_contour_index]);
521 ORIG_PERI = arcLength(contours[largest_contour_index],
true);
532 <<
"box width: " << box.width << std::endl
533 <<
"box height: " << box.height << std::endl
534 <<
"box x: " << box.x << std::endl
535 <<
"box y: " << box.y << std::endl
536 <<
"box area: " << box.area() << std::endl;
654 threshold(in_frame.clone(), temp_frame,
BLACKOUT_THRESH, 255, THRESH_TOZERO);
657 Rect box = boundingRect(contours[largest]);
669 LOGGING <<
"Activating Corner Matching" << std::endl;
672 vector <int> outplus =
test_edges(in_frame, contours[largest], te_ret);
673 in_frame =
shift_frame(in_frame, outplus[0], outplus[1]);
674 if ((outplus[0] > 0) || (outplus[0] < 0)) {
675 vector <int> local_edge =
edge_width(contours[largest]);
676 edge_top = local_edge[0];
677 edge_bot = local_edge[1];
679 if ((outplus[1] > 0) || (outplus[1] < 0)) {
680 vector <int> local_edge =
edge_height(contours[largest]);
681 edge_lef = local_edge[0];
682 edge_rig = local_edge[1];
684 }
else if (te_ret == 0) {
687 LOGGING <<
"Centering Traditionally" << std::endl;
693 std::cerr <<
"WARNING: Returned improper value when testing touching edges" << std::endl;
703 std::ofstream outell;
708 << box.x + (box.width/2)
710 << box.y + (box.height/2)
728 HNC_FRAME = in_frame;
740 std::cerr <<
"Caught ctrl+c interrupt signal: " << std::endl;
758 vector <vector <Point>> contours;
759 contours.push_back(contour);
760 drawContours(in_frame, contours, 0, 0, maskwidth, LINE_8);
772 int largest_contour_index = -1;
773 int largest_area = 0;
776 for(
size_t i = 0; i< contours.size(); i++ ) {
777 double area = contourArea(contours[i]);
779 if (area > largest_area) {
781 largest_contour_index = i;
784 return largest_contour_index;
795 vector <vector<Point>> contours;
796 vector<Vec4i> hierarchy;
797 findContours(in_frame, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE);
812 threshold(in_frame.clone(), in_frame,
BLACKOUT_THRESH, 255, THRESH_TOZERO);
819 <<
"Number of detected contours in ellipse frame: " 825 if (contours.size() < 1) {
832 BF_BOX = boundingRect(contours[largest_contour_index]);
848 std::ofstream outfile;
849 outfile.open(
BOXDATA, std::ios_base::app);
860 << box.area() << std::endl;
873 std::cerr <<
"Usage: " <<
" <option(s)> \t\tSOURCES\tDescription\n" 875 <<
"\t-h,--help\t\t\tShow this help message\n" 876 <<
"\t-v,--version\t\t\tPrint version info to STDOUT\n" 877 <<
"\t-i,--input\t\tINPUT\tSpecify path to input video\n" 878 <<
"\t-c,--config-file \tINPUT\tSpecify config file (default settings.cfg)\n" 879 <<
"\t-osf,--osf-path \tINPUT\tSpeify path to osf video\n" 892 GaussianBlur(in_frame.clone(), in_frame,
898 threshold(in_frame.clone(), in_frame, 1, 255, THRESH_BINARY);
899 vector <vector <Point>> local_contours =
contours_only(in_frame);
901 if (largest_contour_index < 0) {
902 vector <Point> empty;
903 empty.push_back(Point(-1, -1));
906 vector <Point> bigone = local_contours[largest_contour_index];
921 static vector <vector<Point>>
quiet_halo_elim(vector <vector<Point>> contours, vector <Point> bigone) {
923 vector <vector<Point>> out_contours;
925 bool caught_mask =
false;
927 for (
size_t i = 0; i < contours.size(); i++) {
933 Moments M = moments(contours[i]);
934 int x_cen = (M.m10/M.m00);
935 int y_cen = (M.m01/M.m00);
936 if ((x_cen < 0) || (y_cen < 0)) {
937 x_cen = contours[i][0].x;
938 y_cen = contours[i][0].y;
940 for (
size_t j = 0; j < bigone.size(); j++) {
941 distance = sqrt(pow((x_cen - bigone[j].x), 2) + pow((y_cen - bigone[j].y), 2));
948 out_contours.push_back(contours[i]);
964 int tier_one(
int framecnt, Mat in_frame, vector <Point> bigone) {
968 std::ofstream outfile;
969 adaptiveThreshold(in_frame.clone(), in_frame,
971 ADAPTIVE_THRESH_GAUSSIAN_C,
980 if (contours.size() > 1) {
986 <<
"Number of contours in tier 1 pass for frame " 994 if (largest_contour_index > -1) {
995 minEnclosingCircle(contours[largest_contour_index], center, bigradius);
997 outfile.open(
TIER1FILE, std::ios_base::app);
999 for (
auto vec : contours) {
1001 if (vec.size() > 1) {
1002 minEnclosingCircle(vec, center, radius);
1003 if (radius != bigradius) {
1008 <<
static_cast<int>(center.x)
1010 << static_cast<int>(center.y)
1022 <<
"Found too few contours for frame " << framecnt <<
" Tier " 1024 <<
"skipping this tier for this frame." 1042 int tier_two(
int framecnt, Mat in_frame, vector <Point> bigone) {
1045 float bigradius = 0;
1046 std::ofstream outfile;
1047 adaptiveThreshold(in_frame.clone(), in_frame,
1049 ADAPTIVE_THRESH_GAUSSIAN_C,
1057 if (contours.size() > 1) {
1063 <<
"Number of contours in tier 2 pass for frame " 1071 if (largest_contour_index > -1) {
1072 minEnclosingCircle(contours[largest_contour_index], center, bigradius);
1074 outfile.open(
TIER2FILE, std::ios_base::app);
1076 for (
auto vec : contours) {
1078 if (vec.size() > 1) {
1079 minEnclosingCircle(vec, center, radius);
1080 if (radius != bigradius) {
1085 <<
static_cast<int>(center.x)
1087 << static_cast<int>(center.y)
1099 <<
"Found too few contours for frame " << framecnt <<
" Tier " 1101 <<
"skipping this tier for this frame." 1122 int tier_three(
int framecnt, Mat in_frame, Mat old_frame, vector <Point> bigone) {
1125 float bigradius = 0;
1126 std::ofstream outfile;
1130 Laplacian(in_frame.clone(), in_frame, CV_32F,
1136 Laplacian(old_frame.clone(), old_frame, CV_32F,
1142 GaussianBlur(in_frame.clone(), in_frame,
1148 GaussianBlur(old_frame.clone(), old_frame,
1154 scaleframe = in_frame.clone() - old_frame.clone();
1159 vector <vector<Point>> contours =
contours_only(scaleframe);
1160 if (contours.size() > 0) {
1166 <<
"Number of contours in tier 3 pass for frame " 1174 if (largest_contour_index > -1) {
1175 minEnclosingCircle(contours[largest_contour_index], center, bigradius);
1177 outfile.open(
TIER3FILE, std::ios_base::app);
1179 for (
auto vec : contours) {
1181 if (vec.size() > 1) {
1182 minEnclosingCircle(vec, center, radius);
1183 if (radius != bigradius) {
1188 <<
static_cast<int>(center.x)
1190 << static_cast<int>(center.y)
1202 <<
"Found too few contours for frame " << framecnt <<
" Tier " 1204 <<
"skipping this tier for this frame." 1229 int tier_four(
int framecnt, Mat in_frame, Mat old_frame, vector <Point> bigone) {
1232 float bigradius = 0;
1233 std::ofstream outfile;
1238 subtract(in_frame.clone(), old_frame.clone(), in_frame);
1239 adaptiveThreshold(in_frame.clone(), in_frame,
1241 ADAPTIVE_THRESH_GAUSSIAN_C,
1247 Sobel(in_frame.clone(), ix1, CV_32F, 1, 0);
1248 Sobel(in_frame.clone(), iy1, CV_32F, 0, 1);
1252 sqrt(ii1.clone(), ii1);
1253 convertScaleAbs(ii1.clone(), ii1);
1254 GaussianBlur(ii1.clone(), ii1,
1260 ximgproc::thinning(ii1.clone(), scaleframe,
T4_THINNING);
1266 vector <vector<Point>> contours =
contours_only(scaleframe);
1267 if (contours.size() > 0) {
1273 <<
"Number of contours in tier 4 pass for frame " 1281 if (largest_contour_index > -1) {
1282 minEnclosingCircle(contours[largest_contour_index], center, bigradius);
1284 outfile.open(
TIER4FILE, std::ios_base::app);
1286 for (
auto vec : contours) {
1288 if (vec.size() > 1) {
1289 minEnclosingCircle(vec, center, radius);
1290 if (radius != bigradius) {
1295 <<
static_cast<int>(center.x)
1297 << static_cast<int>(center.y)
1310 <<
"Found too few contours for frame " << framecnt <<
" Tier " 1312 <<
"skipping this tier for this frame." 1330 if (name ==
"DEBUG_COUT" 1331 || name ==
"DEBUG_FRAMES" 1332 || name ==
"OUTPUT_FRAMES" 1333 || name ==
"EMPTY_FRAMES" 1334 || name ==
"GEN_SLIDESHOW" 1335 || name ==
"SIMP_ELL" 1336 || name ==
"CONCAT_TIERS" 1337 || name ==
"TIGHT_CROP" 1341 if (value ==
"true" || value ==
"True" || value ==
"TRUE") {
1343 }
else if (value ==
"false" || value ==
"False" || value ==
"FALSE") {
1346 std::cerr <<
"Invalid boolean value in settings.cfg item: " << name << std::endl;
1350 if (name ==
"DEBUG_COUT") {
1352 }
else if (name ==
"DEBUG_FRAMES") {
1354 }
else if (name ==
"OUTPUT_FRAMES") {
1356 }
else if (name ==
"EMPTY_FRAMES") {
1358 }
else if (name ==
"GEN_SLIDESHOW") {
1360 }
else if (name ==
"SIMP_ELL") {
1362 }
else if (name ==
"CONCAT_TIERS") {
1364 }
else if (name ==
"TIGHT_CROP") {
1370 name ==
"EDGETHRESH" 1371 || name ==
"QHE_WIDTH" 1372 || name ==
"BLACKOUT_THRESH" 1373 || name ==
"CONVERT_FPS" 1374 || name ==
"NON_ZERO_START" 1375 || name ==
"T1_AT_BLOCKSIZE" 1376 || name ==
"T1_DYMASK" 1377 || name ==
"T2_AT_BLOCKSIZE" 1378 || name ==
"T2_DYMASK" 1379 || name ==
"T3_LAP_KERNEL" 1380 || name ==
"T3_GB_KERNEL_X" 1381 || name ==
"T3_GB_KERNEL_Y" 1382 || name ==
"T3_CUTOFF_THRESH" 1383 || name ==
"T3_DYMASK" 1384 || name ==
"T4_AT_BLOCKSIZE" 1385 || name ==
"T4_GB_KERNEL_X" 1386 || name ==
"T4_GB_KERNEL_Y" 1387 || name ==
"T4_THINNING" 1388 || name ==
"T4_DYMASK" 1389 || name ==
"QHE_GB_KERNEL_X" 1390 || name ==
"QHE_GB_KERNEL_Y" 1393 int result = std::stoi(value);
1394 if (name ==
"EDGETHRESH") {
1396 }
else if (name ==
"QHE_WIDTH") {
1398 }
else if (name ==
"BLACKOUT_THRESH") {
1400 }
else if (name ==
"CONVERT_FPS") {
1402 }
else if (name ==
"NON_ZERO_START") {
1404 }
else if (name ==
"T1_AT_BLOCKSIZE") {
1406 }
else if (name ==
"T1_DYMASK") {
1408 }
else if (name ==
"T2_AT_BLOCKSIZE") {
1410 }
else if (name ==
"T2_DYMASK") {
1412 }
else if (name ==
"T3_LAP_KERNEL") {
1414 }
else if (name ==
"T3_GB_KERNEL_X") {
1416 }
else if (name ==
"T3_GB_KERNEL_Y") {
1418 }
else if (name ==
"T3_CUTOFF_THRESH") {
1420 }
else if (name ==
"T3_DYMASK") {
1422 }
else if (name ==
"T4_AT_BLOCKSIZE") {
1424 }
else if (name ==
"T4_GB_KERNEL_X") {
1426 }
else if (name ==
"T4_GB_KERNEL_Y") {
1428 }
else if (name ==
"T4_THINNING") {
1430 }
else if (name ==
"T4_DYMASK") {
1432 }
else if (name ==
"QHE_GB_KERNEL_X") {
1434 }
else if (name ==
"QHE_GB_KERNEL_Y") {
1442 || name ==
"T1_AT_CONSTANT" 1443 || name ==
"T2_AT_MAX" 1444 || name ==
"T2_AT_CONSTANT" 1445 || name ==
"T3_LAP_SCALE" 1446 || name ==
"T3_LAP_DELTA" 1447 || name ==
"T3_GB_SIGMA_X" 1448 || name ==
"T3_GB_SIGMA_Y" 1449 || name ==
"T4_AT_MAX" 1450 || name ==
"T4_AT_CONSTANT" 1451 || name ==
"T4_POWER" 1452 || name ==
"T4_GB_SIGMA_X" 1453 || name ==
"T4_GB_SIGMA_Y" 1454 || name ==
"QHE_GB_SIGMA_X" 1455 || name ==
"QHE_GB_SIGMA_Y" 1458 double result = std::stod(value);
1459 if (name ==
"T1_AT_MAX") {
1461 }
else if (name ==
"T1_AT_CONSTANT") {
1463 }
else if (name ==
"T2_AT_MAX") {
1465 }
else if (name ==
"T2_AT_CONSTANT") {
1467 }
else if (name ==
"T3_LAP_SCALE") {
1469 }
else if (name ==
"T3_LAP_DELTA") {
1471 }
else if (name ==
"T3_GB_SIGMA_X") {
1473 }
else if (name ==
"T3_GB_SIGMA_Y") {
1475 }
else if (name ==
"T4_AT_MAX") {
1477 }
else if (name ==
"T4_AT_CONSTANT") {
1479 }
else if (name ==
"T4_POWER") {
1481 }
else if (name ==
"T4_GB_SIGMA_X") {
1483 }
else if (name ==
"T4_GB_SIGMA_Y") {
1485 }
else if (name ==
"QHE_GB_SIGMA_X") {
1487 }
else if (name ==
"QHE_GB_SIGMA_Y") {
1492 name ==
"OSFPROJECT" 1493 || name ==
"OUTPUTDIR" 1496 if (name ==
"OSFPROJECT") {
1498 }
else if (name ==
"OUTPUTDIR") {
1502 std::cerr <<
"Did not recognize entry " << name <<
" in config file, skipping" << std::endl;
1514 std::stringstream outstream;
1515 outstream <<
OUTPUTDIR <<
"frames/" << std::setw(10) << std::setfill(
'0') << framecnt <<
".png";
1516 std::string outstring = outstream.str();
1527 std::string outstring;
1528 for (
int i = 0; i < instring.size(); i++) {
1529 if (instring[i] ==
' ') {
1533 outstring += instring[i];
1541 std::string temp_loc =
OUTPUTDIR +
"data/temp.csv";
1542 vector <std::string> tfiles;
1554 for (
auto i : tfiles) {
1555 std::ifstream infile(i);
1556 if (!infile.is_open()) {
1558 <<
"WARNING: Could not open tier file: " 1565 if (infile.good()) {
1567 std::getline(infile, line);
1571 std::ofstream outputfile(temp_loc);
1574 LOGGING <<
"opened file: " << temp_loc << std::endl;
1577 if (outputfile.good()) {
1579 <<
"frame number,x pos,y pos,radius" 1583 <<
"Could not open temp.csv output file" 1593 outputfile.open(temp_loc, std::ios_base::app);
1594 while (std::getline(infile, line)) {
1596 std::stringstream ss(line);
1602 while (std::getline(ss, token,
',')) {
1606 token = std::to_string(val);
1607 outputfile << token <<
",";
1608 }
else if (col == 2) {
1610 token = std::to_string(val);
1611 outputfile << token <<
",";
1612 }
else if (col == 3) {
1613 outputfile << token << std::endl;
1616 outputfile << token <<
",";
1620 if (ss.peek() ==
',') {
1628 if (std::remove(i.c_str()) != 0) {
1629 std::cerr <<
"Failure to remove file " <<
space_space(i) <<
" with error " << strerror(errno) << std::endl;
1633 LOGGING <<
"rm\'d " << i << std::endl
1634 <<
"mv\'ing " << temp_loc <<
" to " << i << std::endl;
1637 if (std::rename(temp_loc.c_str(), i.c_str()) < 0) {
1638 std::cerr <<
"Could not move temp.csv to Tier location using rename with error: " << strerror(errno) << std::endl;
1654 std::ifstream box_file(
BOXDATA);
1655 if (!box_file.is_open()) {
1657 <<
"WARNING: Could not open box file" 1663 int running_size = 0;
1666 if (box_file.good()) {
1668 std::getline(box_file, line);
1671 while (std::getline(box_file, line)) {
1673 std::stringstream ss(line);
1679 while (std::getline(ss, token,
',')) {
1683 if (running_size < std::stoi(token)) {
1684 running_size = std::stoi(token);
1686 }
else if (col == 8) {
1687 if (running_size < std::stoi(token)) {
1688 running_size = std::stoi(token);
1690 }
else if (col == 9) {
1694 if (ss.peek() ==
',') {
1702 return running_size;
1708 std::string temppath =
OUTPUTDIR +
"temp.mp4";
1709 std::string outpath =
OUTPUTDIR +
"output.mp4";
1710 std::string command;
1711 command =
"ffmpeg -y -hide_banner -loglevel warning -framerate 30 -i " + framepath +
"%10d.png " + framepath +
"../output.mp4";
1714 LOGGING <<
"Beginning slideshow generation" << std::endl;
1717 system(command.c_str());
1720 LOGGING <<
"Slideshow created" << std::endl;
1727 std::cerr <<
"Max ellipse apparently is 0. Something is wrong." << std::endl;
1732 LOGGING <<
"Max Box: " << max_box << std::endl;
1739 command =
"ffmpeg -y -hide_banner -loglevel warning -i " + framepath +
"../output.mp4 -vf \"crop=" + std::to_string(
TC_W) +
":" + std::to_string(
TC_H) +
":" + std::to_string(center_x) +
":" + std::to_string(center_y) +
"\" " + framepath +
"../temp.mp4";
1747 system(command.c_str());
1750 LOGGING <<
"Slideshow given a tight crop" << std::endl;
1753 if (fs::file_size(
"./Birdtracker_Output/temp.mp4") > 0) {
1754 if (std::rename(temppath.c_str(), outpath.c_str()) != 0) {
1755 std::cerr <<
"Failed to move temp.mp4 to output.mp4 with error: " 1756 << strerror(errno) << std::endl;
1759 if (std::remove(temppath.c_str()) != 0) {
1760 std::cerr <<
"Failed to remove old temp.mp4 file with error: " 1761 << strerror(errno) << std::endl;
1777 if (!t1_file.is_open()) {
1779 <<
"Could not open Tier 1 data" 1785 if (!t2_file.is_open()) {
1787 <<
"Could not open Tier 2 data" 1793 if (!t3_file.is_open()) {
1795 <<
"Could not open Tier 3 data" 1801 if (!t4_file.is_open()) {
1803 <<
"Could not open Tier 4 data" 1809 std::string mix_loc =
OUTPUTDIR +
"data/mixed_tiers.csv";
1810 std::ofstream outputfile(mix_loc);
1811 outputfile.open(mix_loc);
1818 if ((t1_file.good()) && (t2_file.good()) && (t3_file.good()) && (t4_file.good())) {
1820 std::getline(t1_file, line);
1821 std::getline(t2_file, line);
1822 std::getline(t3_file, line);
1823 std::getline(t4_file, line);
1827 outputfile.open(mix_loc);
1828 if (outputfile.good()) {
1830 <<
"frame number,x pos,y pos,radius,tier" 1835 <<
"Could not open mixed_tiers.csv output file" 1840 vector <std::ifstream *> tfiles;
1841 tfiles.push_back(&t1_file);
1842 tfiles.push_back(&t2_file);
1843 tfiles.push_back(&t3_file);
1844 tfiles.push_back(&t4_file);
1846 outputfile.open(mix_loc, std::ios_base::app);
1847 for (
auto i : tfiles) {
1850 LOGGING <<
"Concat begin on file: " << tcnt << std::endl;
1853 while (std::getline(*i, line)) {
1854 line = line +
"," + std::to_string(tcnt);
1864 std::string commandstr;
1865 commandstr =
"(head -n 1 " 1869 +
" | sort --field-separator=',' -n -k 1,1)" 1875 LOGGING <<
"Concat command string: " << commandstr << std::endl;
1878 if (system(commandstr.c_str()) != 0) {
1879 std::cerr <<
"WARNING: Failed to concat tiers with error: " 1880 << strerror(errno) << std::endl;
1884 if (std::rename((
OUTPUTDIR +
"data/temp.csv").c_str(), mix_loc.c_str()) != 0) {
1885 std::cerr <<
"WARNING: Failed to move temporary file to mixed_tiers.csv with error: " 1886 << strerror(errno) << std::endl;
1902 if (!ellipse_file.is_open()) {
1904 <<
"Could not open ellipse file" 1910 std::string simp_loc =
OUTPUTDIR +
"data/offscreen_moon.csv";
1911 std::ofstream outputfile(simp_loc);
1912 outputfile.open(simp_loc);
1919 if (ellipse_file.good()) {
1921 std::getline(ellipse_file, line);
1925 outputfile.open(simp_loc);
1926 if (outputfile.good()) {
1928 <<
"frame number,points on top edge,points on bot edge,points on left edge,points on right edge" 1933 <<
"Could not open offscreen_moon.csv output file" 1939 while (std::getline(ellipse_file, line)) {
1941 std::stringstream ss(line);
1945 std::string out_string;
1948 bool offscreen =
false;
1950 while (std::getline(ss, token,
',')) {
1953 if ((col == 6) || (col == 7) || (col == 8) || (col == 9)) {
1954 if (std::stoi(token) != 0) {
1958 if ((col == 0) || (col == 6) || (col == 7) || (col == 8)) {
1959 out_string += token +
',';
1960 }
else if (col == 9) {
1961 out_string += token +
'\n';
1963 outputfile.open(simp_loc, std::ios_base::app);
1973 if (ss.peek() ==
',') {
1979 ellipse_file.close();
1996 <<
"ERROR: Failed to generate frame slideshow, retaining frame files and exiting" 2003 <<
"ERROR: Failed to edit contours to match tight crop requirements" 2012 <<
"Removing png files from frames/ directory" 2022 <<
"WARNING: Something went wrong stacking the Tier files" 2029 <<
"WARNING: Something went wrong simplifying the ellipse screen edges" 2042 std::string
tail(std::string
const& source,
size_t const length) {
2043 if (length >= source.size()) {
2046 return source.substr(source.size() - length);
2069 vector <string> sources;
2070 std::string osf_file =
"";
2071 std::string input_file =
"";
2072 std::string config_file =
"settings.cfg";
2074 for (
int i = 1; i < argc; ++i) {
2075 string arg = argv[i];
2076 if ((arg ==
"-h") || (arg ==
"--help")) {
2080 }
else if ((arg ==
"-v") || (arg ==
"--version")) {
2082 <<
"LunAero Frame Extractor" 2086 <<
"Compiled: " << __TIMESTAMP__
2088 <<
"Copyright (C) 2020, GPL-3.0" 2090 <<
"Wesley T. Honeycutt, Oklahoma Biological Survey" 2093 }
else if ((arg ==
"-c") || (arg ==
"--config-file")) {
2095 config_file = argv[++i];
2097 std::cerr <<
"--config-file option requires one argument" << std::endl;
2100 }
else if ((arg ==
"-osf") || (arg ==
"--osf-path")) {
2104 osf_file = argv[++i];
2106 std::cerr <<
"--osf-path option requires one argument." << std::endl;
2109 }
else if ((arg ==
"-i") || (arg ==
"--input")) {
2113 input_file = argv[++i];
2115 std::cerr <<
"--input option requires one argument." << std::endl;
2119 sources.push_back(argv[i]);
2124 if (osf_file.length() > 0 && input_file.length() > 0) {
2125 std::cerr <<
"Either use an input file or an OSF file, not both" << std::endl;
2127 }
else if (osf_file.length() == 0 && input_file.length() == 0) {
2128 std::cerr <<
"You must give frame_extraction an input file or an OSF path" << std::endl;
2130 }
else if (osf_file.length() > 0) {
2131 if (!(osf_file.substr(0, 10) ==
"osfstorage")) {
2133 <<
"The path to the OSF video must look like \"osfstorage/path/to/file.mp4\"" 2137 if (!((osf_file.substr(osf_file.size() - 3) ==
"mp4") || (osf_file.substr(osf_file.size() - 4) ==
"h264"))) {
2139 <<
"Input OSF file must end with mp4 or h264" 2143 if (system(
"osf --version > /dev/null 2>&1")) {
2144 std::cerr <<
"OSFClient is not available on this system. Install using \"pip3 install osfclient --user\"" << std::endl;
2151 std::ifstream config_stream (config_file);
2152 if (config_stream.is_open()) {
2154 while(getline(config_stream, line)) {
2155 line.erase(std::remove_if(line.begin(), line.end(), isspace), line.end());
2156 if(line[0] ==
'#' || line.empty()) {
2159 auto delimiter_pos = line.find(
"=");
2160 std::string name = line.substr(0, delimiter_pos);
2161 std::string value = line.substr(delimiter_pos + 1);
2167 std::cerr <<
"Couldn't open config file for reading." << std::endl;
2174 <<
"Config File Loaded from" << config_file << std::endl
2175 <<
"Using input file: " << input_file << std::endl;
2182 std::string localpath;
2183 localpath = fs::current_path();
2185 localpath = OUTPUTDIR +
"data";
2186 fs::create_directories(localpath);
2187 std::ofstream outfile;
2189 LOGOUT = OUTPUTDIR +
"data/log.log";
2194 localpath = OUTPUTDIR +
"frames";
2195 fs::create_directories(localpath);
2199 TIER1FILE = OUTPUTDIR +
"data/Tier1.csv";
2200 TIER2FILE = OUTPUTDIR +
"data/Tier2.csv";
2201 TIER3FILE = OUTPUTDIR +
"data/Tier3.csv";
2202 TIER4FILE = OUTPUTDIR +
"data/Tier4.csv";
2204 METADATA = OUTPUTDIR +
"data/metadata.csv";
2206 BOXDATA = OUTPUTDIR +
"data/boxes.csv";
2255 std::ofstream outell;
2264 <<
"moon x diameter" 2266 <<
"moon y diameter" 2268 <<
"moon enclosing box area" 2270 <<
"points on top edge" 2272 <<
"points on bot edge" 2274 <<
"points on left edge" 2276 <<
"points on right edge" 2282 if (!osf_file.empty()) {
2283 std::string osfcommand =
"osf -p ";
2285 osfcommand.append(
" fetch ");
2286 osfcommand.append(osf_file);
2287 if (osf_file.substr(osf_file.size() - 3) ==
"mp4") {
2288 osfcommand.append(
" ./local.mp4");
2289 input_file =
"local.mp4";
2291 osfcommand.append(
" ./local.h264");
2292 input_file =
"local.h264";
2297 <<
"Downloading OSF file: " 2299 <<
" to local drive with name: " 2301 <<
" using the the command: " 2306 if (system(osfcommand.c_str())) {
2307 std::cerr <<
"ERROR: There was a problem while downloading the OSF file." << std::endl;
2313 if (!std::experimental::filesystem::exists(input_file)) {
2314 std::cerr <<
"Input file (" << input_file <<
") not found. Aborting." << std::endl;
2320 std::string file_ending;
2322 file_ending =
tail(input_file, 3);
2323 if (file_ending ==
"mp4") {
2327 <<
"Input file has mp4 filetype ending, proceeding" << std::endl;
2330 }
else if (file_ending ==
"264") {
2334 <<
"Input file has h264 filetype ending, converting video" << std::endl;
2337 std::string convert_command =
"ffmpeg -y -hide_banner -r ";
2339 convert_command +=
" -i ";
2341 convert_command +=
" -c copy ./converted.mp4";
2342 input_file =
"converted.mp4";
2343 system(convert_command.c_str());
2347 <<
"Video converted and stored at ./converted.mp4" << std::endl;
2351 std::cerr <<
"ERROR: Unrecognized input video filetype ending, mp4 or h264 required" 2357 auto delimiter_pos = input_file.find(
'.');
2358 if (input_file.substr(delimiter_pos + 1) !=
"mp4") {
2362 <<
") does not end with \"mp4\". Assuming the input file is incompatible" 2370 std::ofstream metafile;
2372 if (!osf_file.empty()) {
2373 metafile <<
"video:," << osf_file << std::endl;
2375 metafile <<
"video:," << input_file << std::endl;
2379 metafile << std::endl <<
"settings values:," << config_file << std::endl;
2382 if (config_stream.is_open()) {
2383 config_stream.clear();
2384 config_stream.seekg(0);
2386 while(getline(config_stream, line)) {
2387 line.erase(std::remove_if(line.begin(), line.end(), isspace), line.end());
2388 if(line[0] ==
'#' || line.empty()) {
2391 delimiter_pos = line.find(
"=");
2392 std::string name = line.substr(0, delimiter_pos);
2393 std::string value = line.substr(delimiter_pos + 1);
2394 metafile << name <<
":," << value << std::endl;
2397 std::cerr <<
"Couldn't open config file reporting metadata." << std::endl;
2402 std::string ffmeta_path = localpath +
"/fftemp.txt";
2403 std::string command;
2404 if (!osf_file.empty()) {
2405 command =
"ffprobe -hide_banner -i " 2407 +
" -show_format -show_streams -print_format default > " 2410 command =
"ffprobe -hide_banner -i " 2412 +
" -show_format -show_streams -print_format default > " 2418 LOGGING <<
"Recording video metadata using command: " 2423 system(command.c_str());
2426 metafile << std::endl <<
"ffprobe metadata," << std::endl;
2429 std::ifstream ffmeta_stream(ffmeta_path);
2430 if (ffmeta_stream.is_open()) {
2432 while(getline(ffmeta_stream, line)) {
2433 line.erase(std::remove_if(line.begin(), line.end(), isspace), line.end());
2434 if(line[0] ==
'[' || line.empty()) {
2437 delimiter_pos = line.find(
"=");
2438 std::string name = line.substr(0, delimiter_pos);
2439 std::string value = line.substr(delimiter_pos + 1);
2440 metafile << name <<
":," << value << std::endl;
2443 std::cerr <<
"Unable to open ff metadata temporary file" << std::endl;
2448 if (std::remove(ffmeta_path.c_str()) != 0) {
2449 std::cerr <<
"Failed to remove old fftemp.txt file with error: " 2450 << strerror(errno) << std::endl;
2489 auto *mm_killed = static_cast <
bool *>(mmap(NULL,
sizeof(
bool), \
2490 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2491 auto *mm_frameavail = static_cast <
bool *>(mmap(NULL,
sizeof(
bool), \
2492 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2493 auto *mm_gotframe1 = static_cast <
bool *>(mmap(NULL,
sizeof(
bool), \
2494 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2495 auto *mm_gotframe2 = static_cast <
bool *>(mmap(NULL,
sizeof(
bool), \
2496 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2497 auto *mm_gotframe3 = static_cast <
bool *>(mmap(NULL,
sizeof(
bool), \
2498 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2499 auto *mm_tier1 = static_cast <
bool *>(mmap(NULL,
sizeof(
bool), \
2500 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2501 auto *mm_tier2 = static_cast <
bool *>(mmap(NULL,
sizeof(
bool), \
2502 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2503 auto *mm_tier3 = static_cast <
bool *>(mmap(NULL,
sizeof(
bool), \
2504 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2505 auto *mm_frmcount = static_cast <
int *>(mmap(NULL,
sizeof(
int), \
2506 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0));
2513 int frame_fd = open(
"/tmp/file", O_CREAT|O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
2514 int frame_fd2 = open(
"/tmp/file2", O_CREAT|O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
2521 VideoCapture cap(input_file);
2522 if (!cap.isOpened())
2526 bool running =
true;
2529 if (frame.empty()) {
2530 std::cerr <<
"ERROR: Could not find a frame without the moon touching the edge. Exiting" 2532 <<
"If the video looks good to you and you see this message, increase the value of " 2533 <<
"BLACKOUT_THRESH in the settings.cfg file, and re-run." 2539 cvtColor(frame.clone(), frame, COLOR_BGR2GRAY);
2540 threshold(frame.clone(), temp_frame,
BLACKOUT_THRESH, 255, THRESH_TOZERO);
2541 vector <vector<Point>> contours =
contours_only(temp_frame);
2553 LOGGING <<
"passed first frame, used frame " << *mm_frmcount <<
" as corners" << std::endl;
2559 cap.open(input_file);
2560 if (!cap.isOpened())
2573 cvtColor(frame, frame, COLOR_BGR2GRAY);
2579 imwrite(output_loc, frame);
2582 LOGGING <<
"frame saved at " << output_loc << std::endl;
2591 const size_t shmem_size = frame.total() * frame.elemSize();
2596 <<
"frame dimensions: " 2597 << frame.size().width
2599 << frame.size().height
2612 if (ftruncate(frame_fd, shmem_size) != 0) {
2613 std::cerr <<
"failed to truncate resize file descriptor" << std::endl;
2617 if (ftruncate(frame_fd2, shmem_size) != 0) {
2618 std::cerr <<
"failed to truncate resize file descriptor 2" << std::endl;
2623 unsigned char *buf = static_cast <
unsigned char*>(mmap(NULL, shmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, frame_fd, 0));
2624 memcpy(buf, frame.ptr(), shmem_size);
2627 LOGGING <<
"memcpy'd buf1 with size:" <<
sizeof(*buf) << std::endl;
2631 unsigned char *buf2 = static_cast <
unsigned char*>(mmap(NULL, shmem_size, PROT_READ|PROT_WRITE, MAP_SHARED, frame_fd2, 0));
2632 memcpy(buf2, frame.ptr(), shmem_size);
2635 LOGGING <<
"memcpy'd buf2 with size:" <<
sizeof(*buf2) << std::endl;
2640 memcpy(buf, frame.ptr(), shmem_size);
2641 *mm_frameavail =
true;
2650 *mm_frameavail =
true;
2660 while (cap.isOpened()) {
2667 while ((*mm_tier1 ==
false) || (*mm_tier2 ==
false) || (*mm_tier3 ==
false)) {
2670 *mm_frameavail =
false;
2677 memcpy(buf2, buf, shmem_size);
2680 if (frame.empty()) {
2682 LOGGING <<
"Reached end of frames. Exiting" << std::endl;
2691 <<
"----------------------- frame number: " 2698 cvtColor(frame, frame, COLOR_BGR2GRAY);
2700 std::cerr <<
"ERROR: Encountered empty frame. Ending this run. " 2701 <<
"If you believe the moon is refound later in the video, break video into parts" 2702 <<
" and re-run each part" << std::endl;
2711 <<
"frame dimensions: " 2712 << frame.size().width
2714 << frame.size().height
2723 memcpy(buf, frame.ptr(), shmem_size);
2726 *mm_frameavail =
true;
2730 imwrite(output_loc, frame);
2733 LOGGING <<
"frame saved at " << output_loc << std::endl;
2739 imshow(
"fg_mask", frame);
2748 while (*mm_killed ==
false) {
2749 while ((*mm_frameavail ==
false) || (*mm_tier1 ==
true) || (*mm_tier2 ==
true) || (*mm_tier3 ==
true)) {
2753 Mat local_frame = cv::Mat(Size(frame.size().width, frame.size().height), CV_8UC1, buf, 1 * frame.size().width);
2754 Mat local_frame_1 = local_frame.clone();
2755 Mat local_frame_2 = local_frame.clone();
2756 int local_count = *mm_frmcount;
2757 vector <Point> bigone =
qhe_bigone(local_frame);
2758 if ((bigone[0].x < 0) && (bigone[0].y < 0)) {
2760 <<
"WARNING: largest frame returned error, beware T1 and T2 for frame: " 2764 tier_one(local_count, local_frame_1.clone(), bigone);
2765 tier_two(local_count, local_frame_2.clone(), bigone);
2771 while (*mm_killed ==
false) {
2772 while ((*mm_frameavail ==
false) || (*mm_tier1 ==
true) || (*mm_tier2 ==
true) || (*mm_tier3 ==
true)) {
2775 int local_count = *mm_frmcount;
2776 if (local_count == 0) {
2781 <<
"skipping early frame tier3 in frame: " 2789 Mat local_frame = cv::Mat(Size(frame.size().width, frame.size().height), CV_8UC1, buf, 1 * frame.size().width);
2790 Mat oldframe = cv::Mat(Size(frame.size().width, frame.size().height), CV_8UC1, buf2, 1 * frame.size().width);
2791 vector <Point> bigone =
qhe_bigone(local_frame);
2792 if ((bigone[0].x < 0) && (bigone[0].y < 0)) {
2794 <<
"WARNING: largest frame returned error, beware T3 and T4 for frame: " 2798 tier_three(local_count, local_frame.clone(), oldframe.clone(), bigone);
2799 tier_four(local_count, local_frame.clone(), oldframe.clone(), bigone);
2811 <<
"Exiting frame_extraction with errors"