@@ -90,6 +90,14 @@ struct VideoROI {
9090 float y;
9191 float width;
9292 float height;
93+
94+ void fromRect (cv::Rect rect, float scaleX, float scaleY)
95+ {
96+ x = rect.x / scaleX;
97+ y = rect.y / scaleY;
98+ width = rect.width / scaleX;
99+ height = rect.height / scaleY;
100+ }
93101};
94102
95103std::ostream& operator <<(std::ostream& os, const VideoROI& obj) {
@@ -276,6 +284,7 @@ int classify_digit(const cv::Ptr<cv::ml::SVM>& svm, const cv::Mat& region)
276284 resized.copyTo (centeredMat (cv::Rect (x_offset, y_offset, width, height)));
277285 }
278286 catch (const std::exception& e) {
287+ std::cout << " Trying to resize with rect " << cv::Rect (x_offset, y_offset, width, height) << std::endl;
279288 std::cerr << " Error in digit classification: " << e.what () << std::endl;
280289 return -1 ;
281290 }
@@ -315,7 +324,7 @@ int8_t classify_score(const cv::Ptr<cv::ml::SVM>& svm, cv::Mat& region, OverlayC
315324 }
316325 else if (overlay.id == 3 )
317326 {
318- cv::threshold (gray, thresholded, 130 , 255 , cv::THRESH_BINARY_INV);
327+ cv::threshold (gray, thresholded, 135 , 255 , cv::THRESH_BINARY_INV);
319328 }
320329
321330 cv::Mat left_mat = thresholded (cv::Rect (0 , 0 , thresholded.cols / 2 , thresholded.rows ));
@@ -401,184 +410,6 @@ cv::Ptr<cv::ml::SVM> preload_digit_model(const std::string& svm_path)
401410 return svm;
402411}
403412
404- VideoAnalysis* process (const char * video_path, OverlayConfig overlay)
405- {
406- VideoAnalysis* analysis = new VideoAnalysis ();
407-
408- cv::Ptr<cv::ml::SVM> svm = preload_digit_model (" ./foreign/svm_model.xml" );
409-
410- int SKIP_RATE = 20 ;
411- int SCORE_CHECK_DELAY = 450 ;
412-
413- cv::VideoCapture cap (video_path, cv::CAP_FFMPEG);
414- cap.set (cv::CAP_PROP_HW_ACCELERATION, cv::VIDEO_ACCELERATION_ANY);
415- if (!cap.isOpened ()) return 0 ;
416-
417- double fps = cap.get (cv::CAP_PROP_FPS);
418- int width = cap.get (cv::CAP_PROP_FRAME_WIDTH);
419- int height = cap.get (cv::CAP_PROP_FRAME_HEIGHT);
420- int frame_count = cap.get (cv::CAP_PROP_FRAME_COUNT);
421-
422- std::cout << " Selected overlay: " << overlay << std::endl;
423-
424- std::cout << " FPS: " << fps << " \n "
425- << " Width: " << width << " \n "
426- << " Height: " << height << " \n "
427- << " Total Frames: " << frame_count << std::endl;
428-
429- cv::Rect redRoi = roiFromVideoInfo (width, height, overlay.red );
430- cv::Rect greenRoi = roiFromVideoInfo (width, height, overlay.green );
431- cv::Rect redScoreRoi = roiFromVideoInfo (width, height, overlay.red_score );
432- cv::Rect greenScoreRoi = roiFromVideoInfo (width, height, overlay.green_score );
433- cv::Mat frame;
434- cv::Ptr<cv::Tracker> tracker = cv::TrackerMIL::create ();
435-
436- cap >> frame;
437-
438- while (redRoi.width == 0 || redRoi.height == 0 )
439- {
440- // cv::rectangle(frame, redRoi, cv::Scalar(0, 255, 0), 2);
441- imshow (" tracker" , frame);
442- redRoi = selectROI (" tracker" , frame);
443- std::cout << " Red ROI: " << redRoi << std::endl;
444- }
445- while (greenRoi.width == 0 || greenRoi.height == 0 )
446- {
447- greenRoi = selectROI (" tracker" , frame);
448- std::cout << " Green ROI: " << greenRoi << std::endl;
449- }
450- while (redScoreRoi.width == 0 || redScoreRoi.height == 0 )
451- {
452- redScoreRoi = selectROI (" tracker" , frame);
453- std::cout << " Red score ROI: " << redScoreRoi << std::endl;
454- }
455- while (greenScoreRoi.width == 0 || greenScoreRoi.height == 0 )
456- {
457- greenScoreRoi = selectROI (" tracker" , frame);
458- std::cout << " Green score ROI: " << greenScoreRoi << std::endl;
459- }
460-
461- bool redOn = false ;
462- bool greenOn = false ;
463-
464- int doubleTimeout = 0 ;
465- int frames_to_skip = SKIP_RATE;
466- bool should_check_score = false ; // Should we check the score?
467- uint32_t delay_check_frame = -1 ; // Another frame far in the future just in case there was video on 14-14
468-
469- uint8_t last_red = -1 ;
470- uint8_t last_green = -1 ;
471-
472- for (int i = 1 ; i < frame_count; i++) {
473- int seconds = i / 30 ;
474- cap >> frame;
475- if (should_check_score || i == delay_check_frame)
476- {
477- if (i == delay_check_frame) std::cout << " Delay check at " << delay_check_frame << std::endl;
478- cv::Mat redScoreMask = frame (redScoreRoi);
479- cv::Mat greenScoreMask = frame (greenScoreRoi);
480-
481- uint8_t redScore = classify_score (svm, redScoreMask, overlay);
482- uint8_t greenScore = classify_score (svm, greenScoreMask, overlay);
483- std::cout << " [ANALYSIS] Score at frame " << i << " : " << static_cast <int >(redScore) << " -" << static_cast <int >(greenScore) << std::endl;
484- // If the score is the same as before, the last touch must have been simul or annuled, so we overwrite
485- // if (redScore == last_red && greenScore == last_green)
486- // {
487- // analysis->touch_count -= 1;
488- // // If i is the delay check frame, it's not the actual time when it happened
489- // if (should_check_score)
490- // {
491- // analysis->touches[analysis->touch_count].frame = i;
492- // }
493- // }
494- // else
495- // {
496- analysis->touches [analysis->touch_count ].frame = i;
497- // }
498- // Update last score accordingly
499- if (analysis->touch_count > 0 )
500- {
501- analysis->touches [analysis->touch_count - 1 ].score1 = redScore;
502- analysis->touches [analysis->touch_count - 1 ].score2 = greenScore;
503- }
504- analysis->touch_count ++;
505- last_red = redScore;
506- last_green = greenScore;
507- should_check_score = false ;
508- }
509- if (frames_to_skip > 0 )
510- {
511- frames_to_skip--;
512- continue ;
513- }
514- cv::Mat hsvFrame;
515- cv::cvtColor (frame, hsvFrame, cv::COLOR_RGB2HSV);
516- cv::Mat redMat = hsvFrame (redRoi);
517- cv::Mat greenMat = hsvFrame (greenRoi);
518-
519- cv::Mat redMask;
520- cv::inRange (redMat, cv::Scalar (120 , 100 , 160 ), cv::Scalar (140 , 255 , 255 ), redMask);
521- int redThreshold = redRoi.area () / 3 ;
522- int redPixels = cv::countNonZero (redMask);
523-
524- if (i > 2900 && i < 3000 ) std::cout << " Red " << redPixels << " , threshold: " << redThreshold << std::endl;
525-
526- if (redPixels >= redThreshold && !redOn)
527- {
528- std::cout << " Red light at " << i << std::endl;
529- should_check_score = true ;
530- // delay_check_frame = MIN(i + SCORE_CHECK_DELAY, frame_count - 3);
531- redOn = true ;
532- }
533- if (redPixels < redThreshold / 3 && redOn)
534- {
535- redOn = false ;
536- doubleTimeout = i + 50 ;
537- }
538-
539- cv::Mat greenMask;
540- cv::inRange (greenMat, cv::Scalar (50 , 100 , 160 ), cv::Scalar (70 , 255 , 255 ), greenMask);
541- int greenThreshold = redRoi.area () / 2 ;
542- int greenPixels = cv::countNonZero (greenMask);
543- // std::cout << "Green pixels: " << greenPixels << std::endl;
544- if (greenPixels > greenThreshold && !greenOn)
545- {
546- // std::cout << "Green light at " << i << std::endl;
547- should_check_score = true ;
548- // delay_check_frame = MIN(i + SCORE_CHECK_DELAY, frame_count - 3);
549- greenOn = true ;
550- }
551- if (greenPixels < greenThreshold / 2 && greenOn)
552- {
553- greenOn = false ;
554- doubleTimeout = i + 50 ;
555- }
556-
557- if (!redOn && !greenOn)
558- {
559- frames_to_skip = SKIP_RATE;
560- }
561- }
562-
563- if (analysis->touch_count > 0 ) analysis->touch_count --;
564-
565- return analysis;
566- }
567-
568- VideoAnalysis* find_video_touches (const char * video_path, uint8_t overlay_id)
569- {
570- try
571- {
572- auto result = process (video_path, OVERLAYS[overlay_id]);
573- return result;
574- }
575- catch (const std::exception& e)
576- {
577- std::cerr << " Caught exception: " << e.what () << std::endl;
578- }
579- return 0 ;
580- }
581-
582413void js_memcpy (void * dest, void * source, size_t size) {
583414 memcpy (dest, source, size);
584415}
@@ -851,6 +682,55 @@ extern "C" StreamAnalysis* cut_stream(const std::string& tesseract_path, const s
851682 int frame_count = cap.get (cv::CAP_PROP_FRAME_COUNT);
852683 OverlayConfig overlay = OVERLAYS[overlay_id];
853684
685+ cv::Mat frame;
686+
687+ if (overlay_id == 3 )
688+ {
689+ cap.read (frame);
690+ cap.set (cv::CAP_PROP_POS_FRAMES, 0 );
691+ while (true ) {
692+ cv::Mat drawingFrame = frame.clone ();
693+
694+ cv::Rect overlayRect = cv::selectROI (" Select the overlay region" , drawingFrame);
695+ int x = overlayRect.x ;
696+ int y = 0 ;
697+ int width = drawingFrame.cols - overlayRect.x - 1 ;
698+ int height = overlayRect.y + overlayRect.height ;
699+
700+ cv::Rect redNameRect (overlayRect.x , height * 0.02 , width / 2 , height * 0.2 );
701+ cv::Rect greenNameRect (overlayRect.x + width / 2 , height * 0.02 , width / 2 , height * 0.2 );
702+ cv::rectangle (drawingFrame, redNameRect, cv::Scalar (0 , 0 , 255 ), 2 );
703+ cv::rectangle (drawingFrame, greenNameRect, cv::Scalar (0 , 255 , 0 ), 2 );
704+
705+ cv::Rect timeRect (overlayRect.x + width * 0.4 , height * 0.33 , width * 0.2 , height * 0.2 );
706+ cv::rectangle (drawingFrame, timeRect, cv::Scalar (255 , 0 , 0 ), 2 );
707+
708+ cv::Rect redScoreRect (overlayRect.x + width * 0.275 , height * 0.78 , width * 0.1 , height * 0.18 );
709+ cv::Rect greenScoreRect (overlayRect.x + width * 0.635 , height * 0.78 , width * 0.1 , height * 0.18 );
710+ cv::rectangle (drawingFrame, redScoreRect, cv::Scalar (0 , 0 , 255 ), 2 );
711+ cv::rectangle (drawingFrame, greenScoreRect, cv::Scalar (0 , 255 , 0 ), 2 );
712+ imshow (" Press BACKSPACE if the overlay does not line up, otherwise press ENTER" , drawingFrame);
713+ int key = cv::waitKey (5000 );
714+ std::cout << " Got key: " << key << std::endl;
715+ if (key == 127 || key == 8 ) // Backspace
716+ {
717+ cv::destroyWindow (" Select the overlay region" );
718+ cv::destroyWindow (" Press BACKSPACE if the overlay does not line up, otherwise press ENTER" );
719+ continue ;
720+ }
721+
722+ overlay.red_name .fromRect (redNameRect, frame.cols , frame.rows );
723+ overlay.green_name .fromRect (greenNameRect, frame.cols , frame.rows );
724+ overlay.time .fromRect (timeRect, frame.cols , frame.rows );
725+ overlay.red_score .fromRect (redScoreRect, frame.cols , frame.rows );
726+ overlay.green_score .fromRect (greenScoreRect, frame.cols , frame.rows );
727+
728+ cv::destroyWindow (" Select the overlay region" );
729+ cv::destroyWindow (" Press BACKSPACE if the overlay does not line up, otherwise press ENTER" );
730+ break ;
731+ }
732+ }
733+
854734 analysis->fps = fps;
855735 analysis->frame_count = frame_count;
856736
@@ -871,8 +751,6 @@ extern "C" StreamAnalysis* cut_stream(const std::string& tesseract_path, const s
871751 cv::Rect timeRoi = roiFromVideoInfo (width, height, overlay.time );
872752 cv::Rect tableauRoi = roiFromVideoInfo (width, height, overlay.tableau );
873753
874- cv::Mat frame;
875-
876754 int skip_rate = SKIP_SECONDS * fps;
877755 int min_bout_length = MIN_BOUT_SECONDS * fps;
878756
@@ -901,7 +779,7 @@ extern "C" StreamAnalysis* cut_stream(const std::string& tesseract_path, const s
901779 }
902780 bool score_nonzero = redScore > 0 || greenScore > 0 ;
903781
904- // std::cout << "Score at frame " << i << " (" << i / fps << "s, " << i * 100 / frame_count << "%): " << (int)redScore << "-" << (int)greenScore << std::endl;
782+ std::cout << " Score at frame " << i << " (" << i / fps << " s, " << i * 100 / frame_count << " %): " << (int )redScore << " -" << (int )greenScore << std::endl;
905783
906784 if (!bout_running && score_nonzero)
907785 {
@@ -916,6 +794,12 @@ extern "C" StreamAnalysis* cut_stream(const std::string& tesseract_path, const s
916794 cap.set (cv::CAP_PROP_POS_FRAMES, i - rewind_amount * skip_rate);
917795 cap.read (local_frame);
918796
797+ cv::Mat redScoreMask = frame (redScoreRoi);
798+ cv::Mat greenScoreMask = frame (greenScoreRoi);
799+ int8_t redScore = classify_score (svm, redScoreMask, overlay);
800+ int8_t greenScore = classify_score (svm, greenScoreMask, overlay);
801+ if (redScore > 0 || greenScore > 0 ) continue ;
802+
919803 cv::Mat timeMat = local_frame (timeRoi);
920804 cv::cvtColor (timeMat, timeMat, cv::COLOR_BGR2GRAY);
921805 tess.SetImage (timeMat.data , timeMat.cols , timeMat.rows , 1 , timeMat.step ); // Feed binary image to Tesseract
@@ -1004,14 +888,30 @@ extern "C" StreamAnalysis* cut_stream(const std::string& tesseract_path, const s
1004888 }
1005889 if (bout_running && !score_nonzero)
1006890 {
891+ // cv::Mat local_frame;
892+ // cap.set(cv::CAP_PROP_POS_FRAMES, i + skip_rate);
893+ // cap.read(local_frame);
894+
895+ // cv::Mat redScoreMask = local_frame(redScoreRoi);
896+ // cv::Mat greenScoreMask = local_frame(greenScoreRoi);
897+ // int8_t redScore = classify_score(svm, redScoreMask, overlay);
898+ // int8_t greenScore = classify_score(svm, greenScoreMask, overlay);
899+ // if (redScore > 0 || greenScore > 0)
900+ // {
901+ // std::cout << "Score hit 0 at frame " << i << ", but score restored immediately after" << std::endl;
902+ // }
903+ // else
904+ // {
1007905 std::cout << " Bout ended at frame " << i << " (" << i / fps << " s, " << i * 100 / frame_count << " %)!" << std::endl;
1008906 bout_running = false ;
1009907 if (i - analysis->bouts [analysis->bout_count ].start_frame > min_bout_length)
1010908 {
1011909 analysis->bouts [analysis->bout_count ].end_frame = i;
1012910 analysis->bout_count += 1 ;
1013911 }
912+ // }
1014913 }
914+ // cap.set(cv::CAP_PROP_POS_FRAMES, i);
1015915
1016916 frames_to_skip = skip_rate;
1017917 }
0 commit comments