package com.shootoff.camera; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Optional; import javafx.geometry.Bounds; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.rules.ErrorCollector; import org.slf4j.LoggerFactory; import com.shootoff.camera.shot.DisplayShot; import com.shootoff.config.Configuration; import com.shootoff.gui.MockCanvasManager; import com.shootoff.plugins.TrainingExerciseBase; import ch.qos.logback.classic.Logger; import static org.hamcrest.core.IsEqual.equalTo; @Ignore public class ShotDetectionTestor implements VideoFinishedListener { private static int ALLOWED_COORD_VARIANCE = 3; @BeforeClass public static void setUpBaseClass() { System.setProperty("shootoff.home", System.getProperty("user.dir")); Configuration.disableErrorReporting(); TrainingExerciseBase.silence(true); nu.pattern.OpenCV.loadShared(); // Disable all loggers because our output has gotten verbose // enough that Travis-CI kills us. Comment out the lines below // and ensure tests don't call Configuration.setDebugMode(false) // to get debug output for specific tests. Logger rootLogger = (Logger) LoggerFactory.getLogger(org.slf4j.Logger.ROOT_LOGGER_NAME); rootLogger.detachAndStopAllAppenders(); } public void checkShots(ErrorCollector collector, final List<DisplayShot> actualShots, List<Shot> requiredShots, List<Shot> optionalShots, boolean isColorWarning) { List<Shot> mutableActualShots = new ArrayList<Shot>(actualShots); for (Shot shot : requiredShots) { Optional<Shot> potentialShotMatch = findPotentialShotMatch(mutableActualShots, shot); collector.checkThat(String.format("Shot (%.2f, %.2f, %s) not found", shot.getX(), shot.getY(), shot.getColor().toString()), potentialShotMatch.isPresent(), equalTo(true)); if (potentialShotMatch.isPresent()) { if (isColorWarning && !potentialShotMatch.get().getColor().equals(shot.getColor())) { System.err.println(String.format("Shot (%.2f, %.2f, %s) detected with wrong color", shot.getX(), shot.getY(), shot.getColor().toString())); } else { collector.checkThat( String.format("Shot (%.2f, %.2f, %s) has wrong color", shot.getX(), shot.getY(), shot.getColor().toString()), potentialShotMatch.get().getColor(), equalTo(shot.getColor())); } mutableActualShots.remove(potentialShotMatch.get()); } } for (Shot shot : optionalShots) { Optional<Shot> potentialShotMatch = findPotentialShotMatch(mutableActualShots, shot); if (potentialShotMatch.isPresent()) { if (isColorWarning && !potentialShotMatch.get().getColor().equals(shot.getColor())) { System.err.println(String.format("Optional shot (%.2f, %.2f, %s) detected with wrong color", shot.getX(), shot.getY(), shot.getColor().toString())); } else { collector.checkThat( String.format("Optional shot (%.2f, %.2f, %s) has wrong color", shot.getX(), shot.getY(), shot.getColor().toString()), potentialShotMatch.get().getColor(), equalTo(shot.getColor())); } mutableActualShots.remove(potentialShotMatch.get()); } else { System.err.println(String.format("Optional shot (%.2f, %.2f, %s) not found", shot.getX(), shot.getY(), shot.getColor().toString())); } } // If you are getting this failure you're either detecting noise that // wasn't detected before // or you found a shot that was previously missed and not accounted for, // thus you should // add it to the required shot list for the respective test. StringBuilder reason = new StringBuilder(); if (mutableActualShots.size() == 1) { reason.append(String.format("There was %d shot that was detected that isn't account for: ", mutableActualShots.size())); } else if (mutableActualShots.size() > 1) { reason.append(String.format("There are %d shots that were detected that aren't account for: ", mutableActualShots.size())); } if (!mutableActualShots.isEmpty()) { Iterator<Shot> it = mutableActualShots.iterator(); while (it.hasNext()) { Shot s = it.next(); reason.append(String.format("(%.2f, %.2f, %s)", s.getX(), s.getY(), s.getColor().toString())); if (it.hasNext()) reason.append(", "); } } collector.checkThat(reason.toString(), mutableActualShots.isEmpty(), equalTo(true)); } public Optional<Shot> findPotentialShotMatch(List<Shot> actualShots, Shot testedShot) { for (Shot shot : actualShots) { if (Math.abs(shot.getX() - testedShot.getX()) <= ALLOWED_COORD_VARIANCE && Math.abs(shot.getY() - testedShot.getY()) <= ALLOWED_COORD_VARIANCE) { return Optional.of(shot); } } return Optional.empty(); } Object processingLock = new Object(); protected List<DisplayShot> findShots(String videoPath, Optional<Bounds> projectionBounds, MockCanvasManager mockManager, Configuration config, boolean[][] sectorStatuses) { File videoFile = new File(ShotDetectionTestor.class.getResource(videoPath).getFile()); MockCameraManager cameraManager = new MockCameraManager(new MockCamera(videoFile), mockManager, sectorStatuses, projectionBounds, this); cameraManager.start(); try { synchronized (processingLock) { processingLock.wait(); } } catch (InterruptedException e) { e.printStackTrace(); } return mockManager.getShots(); } @Override public void videoFinished() { synchronized (processingLock) { processingLock.notifyAll(); } } }