Files
PhotonVision/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java

222 lines
8.9 KiB
Java
Raw Normal View History

package com.chameleonvision.vision.process;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.vision.Orientation;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.web.ServerHandler;
2019-09-25 10:32:22 -07:00
import edu.wpi.cscore.VideoException;
import edu.wpi.first.networktables.*;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class VisionProcess implements Runnable {
2019-09-15 19:07:58 -04:00
2019-10-20 10:13:07 +03:00
private final String cameraName;
public final CameraProcess cameraProcess;
2019-10-20 10:13:07 +03:00
// NetworkTables
public NetworkTableEntry ntPipelineEntry;
public NetworkTableEntry ntDriverModeEntry;
private int ntDriveModeListenerID;
private int ntPipelineListenerID;
2019-10-20 10:13:07 +03:00
private NetworkTableEntry ntYawEntry;
private NetworkTableEntry ntPitchEntry;
private NetworkTableEntry ntDistanceEntry;
private NetworkTableEntry ntTimeStampEntry;
private NetworkTableEntry ntValidEntry;
// chameleon specific
private Pipeline currentPipeline;
private CVProcess cvProcess;
// pipeline process items
private List<MatOfPoint> foundContours = new ArrayList<>();
private List<MatOfPoint> filteredContours = new ArrayList<>();
private List<MatOfPoint> deSpeckledContours = new ArrayList<>();
2019-10-20 10:13:07 +03:00
private List<RotatedRect> groupedContours = new ArrayList<>();
private Mat cameraInputMat = new Mat();
private Mat hsvThreshMat = new Mat();
private Mat streamOutputMat = new Mat();
private long timeStamp = 0;
2019-09-22 02:49:30 -04:00
public VisionProcess(CameraProcess cameraProcess) {
2019-09-22 02:49:30 -04:00
// USBCamera settings
cvProcess = new CVProcess(cameraProcess.getCamVals());
this.cameraProcess = cameraProcess; // new USBCameraProcess(cameraProcess);
2019-09-22 02:49:30 -04:00
this.cameraName = cameraProcess.getCamName();
initNT(NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + cameraProcess.getNickname()));
2019-10-20 10:13:07 +03:00
}
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
private void driverModeListener(EntryNotification entryNotification) {
cameraProcess.setDriverMode(entryNotification.value.getBoolean());
2019-10-20 10:13:07 +03:00
}
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
private void pipelineListener(EntryNotification entryNotification) {
var ntPipelineIndex = (int) entryNotification.value.getDouble();
if (ntPipelineIndex >= cameraProcess.getPipelines().size()) {
ntPipelineEntry.setNumber(cameraProcess.getCurrentPipelineIndex());
} else {
var pipeline = cameraProcess.getCurrentPipeline();
cameraProcess.setCurrentPipelineIndex(ntPipelineIndex);
2019-10-20 10:13:07 +03:00
try {
cameraProcess.setExposure(pipeline.exposure);
2019-10-20 10:13:07 +03:00
} catch (VideoException e) {
System.err.println(e.toString());
}
cameraProcess.setBrightness(pipeline.brightness);
if (SettingsManager.generalSettings.currentCamera.equals(cameraName)) {
SettingsManager.generalSettings.currentPipeline = ntPipelineIndex;
2019-10-20 10:13:07 +03:00
HashMap<String, Object> pipeChange = new HashMap<>();
pipeChange.put("currentPipeline", ntPipelineIndex);
ServerHandler.broadcastMessage(pipeChange);
ServerHandler.sendFullSettings();
2019-10-20 10:13:07 +03:00
}
}
}
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
private void updateNetworkTables(PipelineResult pipelineResult) {
if (pipelineResult.IsValid) {
ntValidEntry.setBoolean(true);
ntYawEntry.setNumber(pipelineResult.Yaw);
ntPitchEntry.setNumber(pipelineResult.Pitch);
ntDistanceEntry.setNumber(pipelineResult.Area);
ntTimeStampEntry.setNumber(timeStamp);
NetworkTableInstance.getDefault().flush();
} else {
ntYawEntry.setNumber(0.0);
ntPitchEntry.setNumber(0.0);
ntDistanceEntry.setNumber(0.0);
ntTimeStampEntry.setNumber(timeStamp);
ntValidEntry.setBoolean(false);
}
}
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
private PipelineResult runVisionProcess(Mat inputImage, Mat outputImage) {
2019-11-02 12:46:36 -07:00
return cvProcess.runPipeline(
2019-11-02 12:38:42 -07:00
currentPipeline,
inputImage,
outputImage,
cameraProcess.getCamVals(),
currentPipeline.orientation.equals(Orientation.Inverted),
cameraProcess.getDriverMode()
);
2019-10-20 10:13:07 +03:00
}
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
@Override
public void run() {
// processing time tracking
long startTime;
long fpsLastTime = 0;
double processTimeMs;
double fps = 0;
double uiFps = 0;
int maxFps = cameraProcess.getVideoMode().fps;
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
new Thread(cameraProcess).start();
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
long lastFrameEndNanosec = 0;
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
while (!Thread.interrupted()) {
startTime = System.nanoTime();
if ((startTime - lastFrameEndNanosec) * 1e-6 >= 1000.0 / (maxFps + 3)) { // 3 additional fps to allow for overhead
2019-10-20 10:13:07 +03:00
foundContours.clear();
filteredContours.clear();
groupedContours.clear();
deSpeckledContours.clear();
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
// update FPS for ui only every 0.5 seconds
if ((startTime - fpsLastTime) * 1e-6 >= 500) {
if (fps >= maxFps) {
uiFps = maxFps;
} else {
uiFps = fps;
}
fpsLastTime = System.nanoTime();
}
2019-09-22 02:49:30 -04:00
currentPipeline = cameraProcess.getCurrentPipeline();
2019-10-20 10:13:07 +03:00
// start fps counter right before grabbing input frame
timeStamp = cameraProcess.getLatestFrame(cameraInputMat);
if (cameraInputMat.cols() == 0 && cameraInputMat.rows() == 0) {
continue;
}
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
// get vision data
var pipelineResult = runVisionProcess(cameraInputMat, streamOutputMat);
updateNetworkTables(pipelineResult);
if (cameraName.equals(SettingsManager.generalSettings.currentCamera)) {
2019-10-20 10:13:07 +03:00
HashMap<String, Object> WebSend = new HashMap<>();
HashMap<String, Object> point = new HashMap<>();
HashMap<String, Object> calculated = new HashMap<>();
List<Double> center = new ArrayList<>();
if (pipelineResult.IsValid) {
center.add(pipelineResult.RawPoint.center.x);
center.add(pipelineResult.RawPoint.center.y);
calculated.put("pitch", pipelineResult.Pitch);
calculated.put("yaw", pipelineResult.Yaw);
} else {
center.add(0.0);
center.add(0.0);
calculated.put("pitch", 0);
calculated.put("yaw", 0);
}
point.put("fps", uiFps);
point.put("calculated", calculated);
point.put("rawPoint", center);
WebSend.put("point", point);
2019-11-01 18:02:48 +02:00
ServerHandler.broadcastMessage(WebSend);
2019-10-20 10:13:07 +03:00
}
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
cameraProcess.updateFrame(streamOutputMat);
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
cameraInputMat.release();
hsvThreshMat.release();
2019-09-22 02:49:30 -04:00
2019-10-20 10:13:07 +03:00
// calculate FPS
lastFrameEndNanosec = System.nanoTime();
processTimeMs = (lastFrameEndNanosec - startTime) * 1e-6;
fps = 1000 / processTimeMs;
//please dont enable if you are not debugging
// System.out.printf("%s - Process time: %-5.2fms, FPS: %-5.2f, FoundContours: %d, FilteredContours: %d, GroupedContours: %d\n", cameraName, processTimeMs, fps, FoundContours.size(), FilteredContours.size(), GroupedContours.size());
}
}
}
/**
* Removes the old value change listeners
* calls {@link #initNT}
*
* @param newTable passed to {@link #initNT}
*/
public void resetNT(NetworkTable newTable) {
ntDriverModeEntry.removeListener(ntDriveModeListenerID);
ntPipelineEntry.removeListener(ntPipelineListenerID);
initNT(newTable);
}
/**
* Rebases the writing location for the vision process - pipeline output
*
* @param newTable the new writing location
*/
private void initNT(NetworkTable newTable) {
ntPipelineEntry = newTable.getEntry("pipeline");
ntDriverModeEntry = newTable.getEntry("driver_mode");
ntPitchEntry = newTable.getEntry("pitch");
ntYawEntry = newTable.getEntry("yaw");
ntDistanceEntry = newTable.getEntry("distance");
ntTimeStampEntry = newTable.getEntry("timestamp");
ntValidEntry = newTable.getEntry("is_valid");
ntDriveModeListenerID = ntDriverModeEntry.addListener(this::driverModeListener, EntryListenerFlags.kUpdate);
ntPipelineListenerID = ntPipelineEntry.addListener(this::pipelineListener, EntryListenerFlags.kUpdate);
ntDriverModeEntry.setBoolean(false);
ntPipelineEntry.setNumber(cameraProcess.getCurrentPipelineIndex());
2019-10-20 10:13:07 +03:00
}
}