2019-11-23 11:55:20 -05:00
|
|
|
package com.chameleonvision.vision;
|
2019-11-10 11:47:56 -05:00
|
|
|
|
2019-11-23 11:55:20 -05:00
|
|
|
import com.chameleonvision.config.ConfigManager;
|
|
|
|
|
import com.chameleonvision.util.LoopingRunnable;
|
|
|
|
|
import com.chameleonvision.vision.camera.CameraProcess;
|
|
|
|
|
import com.chameleonvision.vision.camera.CameraStreamer;
|
|
|
|
|
import com.chameleonvision.vision.pipeline.*;
|
2019-11-22 14:20:23 -08:00
|
|
|
import com.chameleonvision.web.ServerHandler;
|
|
|
|
|
import com.google.gson.Gson;
|
|
|
|
|
import com.google.gson.GsonBuilder;
|
2019-11-16 11:10:55 -08:00
|
|
|
import edu.wpi.cscore.VideoMode;
|
2019-11-23 20:13:01 -08:00
|
|
|
import edu.wpi.first.networktables.*;
|
2019-11-23 08:22:20 -08:00
|
|
|
import edu.wpi.first.wpiutil.CircularBuffer;
|
2019-11-15 16:01:50 -05:00
|
|
|
import org.opencv.core.Mat;
|
2019-11-10 11:47:56 -05:00
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
2019-11-22 14:20:23 -08:00
|
|
|
import java.util.HashMap;
|
2019-11-10 11:47:56 -05:00
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
public class VisionProcess {
|
|
|
|
|
|
|
|
|
|
private final CameraProcess cameraProcess;
|
|
|
|
|
private final List<CVPipeline> pipelines = new ArrayList<>();
|
2019-11-16 10:17:33 -08:00
|
|
|
private final CameraFrameRunnable cameraRunnable;
|
2019-11-16 14:30:44 -05:00
|
|
|
private final CameraStreamerRunnable streamRunnable;
|
2019-11-16 10:17:33 -08:00
|
|
|
private final VisionProcessRunnable visionRunnable;
|
2019-11-23 04:05:37 -05:00
|
|
|
public final CameraStreamer cameraStreamer;
|
|
|
|
|
|
2019-11-10 11:47:56 -05:00
|
|
|
private CVPipeline currentPipeline;
|
2019-11-22 14:20:23 -08:00
|
|
|
private int currentPipelineIndex = 0;
|
2019-11-10 11:47:56 -05:00
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
private final CVPipelineSettings driverModeSettings = new CVPipelineSettings();
|
|
|
|
|
private CVPipeline driverModePipeline = new DriverVisionPipeline(driverModeSettings);
|
2019-11-10 11:47:56 -05:00
|
|
|
|
2019-11-21 21:49:25 -08:00
|
|
|
// shitty stuff
|
2019-11-21 21:51:06 -08:00
|
|
|
private volatile Mat lastCameraFrame = new Mat();
|
2019-11-21 22:04:17 -08:00
|
|
|
private volatile boolean hasUnprocessedFrame = true;
|
2019-11-21 21:49:25 -08:00
|
|
|
private volatile CVPipelineResult lastPipelineResult;
|
|
|
|
|
|
2019-11-22 14:20:23 -08:00
|
|
|
// network table stuff
|
2019-11-23 20:13:01 -08:00
|
|
|
private NetworkTable defaultTable;
|
2019-11-23 04:05:37 -05:00
|
|
|
private NetworkTableEntry ntPipelineEntry;
|
|
|
|
|
private NetworkTableEntry ntDriverModeEntry;
|
2019-11-22 14:20:23 -08:00
|
|
|
private int ntDriveModeListenerID;
|
|
|
|
|
private int ntPipelineListenerID;
|
|
|
|
|
private NetworkTableEntry ntYawEntry;
|
|
|
|
|
private NetworkTableEntry ntPitchEntry;
|
|
|
|
|
private NetworkTableEntry ntAuxListEntry;
|
2019-11-23 04:05:37 -05:00
|
|
|
private NetworkTableEntry ntAreaEntry;
|
2019-11-22 14:20:23 -08:00
|
|
|
private NetworkTableEntry ntTimeStampEntry;
|
|
|
|
|
private NetworkTableEntry ntValidEntry;
|
2019-11-23 04:05:37 -05:00
|
|
|
private Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
2019-11-22 14:20:23 -08:00
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
VisionProcess(CameraProcess cameraProcess, String name) {
|
2019-11-10 11:47:56 -05:00
|
|
|
this.cameraProcess = cameraProcess;
|
|
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
pipelines.add(new CVPipeline2d("New Pipeline"));
|
2019-11-23 20:02:21 -05:00
|
|
|
setPipeline(0, false);
|
2019-11-15 16:01:50 -05:00
|
|
|
|
2019-11-16 10:17:33 -08:00
|
|
|
// Thread to grab frames from the camera
|
2019-11-23 04:05:37 -05:00
|
|
|
// TODO: (HIGH) fix video modes!!!
|
2019-11-23 09:11:38 -08:00
|
|
|
this.cameraRunnable = new CameraFrameRunnable(cameraProcess.getProperties().videoModes.get(0).fps);
|
2019-11-16 10:17:33 -08:00
|
|
|
|
2019-11-21 21:49:25 -08:00
|
|
|
lastPipelineResult = new DriverVisionPipeline.DriverPipelineResult(
|
|
|
|
|
null, cameraRunnable.getFrame(new Mat()), 0
|
|
|
|
|
);
|
|
|
|
|
|
2019-11-16 10:17:33 -08:00
|
|
|
// Thread to put frames on the dashboard
|
2019-11-16 11:10:55 -08:00
|
|
|
this.cameraStreamer = new CameraStreamer(cameraProcess, name);
|
2019-11-21 22:08:10 -08:00
|
|
|
this.streamRunnable = new CameraStreamerRunnable(30, cameraStreamer);
|
2019-11-16 10:17:33 -08:00
|
|
|
|
|
|
|
|
// Thread to process vision data
|
|
|
|
|
this.visionRunnable = new VisionProcessRunnable();
|
2019-11-23 20:13:01 -08:00
|
|
|
|
|
|
|
|
// network table
|
|
|
|
|
defaultTable = NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + cameraProcess.getProperties().name);
|
2019-11-21 05:32:19 -05:00
|
|
|
}
|
2019-11-16 10:17:33 -08:00
|
|
|
|
2019-11-21 05:32:19 -05:00
|
|
|
public void start() {
|
2019-11-23 20:13:01 -08:00
|
|
|
System.out.println("Starting NetworkTables");
|
|
|
|
|
initNT(defaultTable);
|
|
|
|
|
|
2019-11-21 05:32:19 -05:00
|
|
|
System.out.println("Starting camera thread.");
|
|
|
|
|
new Thread(cameraRunnable).start();
|
|
|
|
|
while (cameraRunnable.cameraFrame == null) {
|
|
|
|
|
try {
|
2019-11-21 22:04:17 -08:00
|
|
|
if (lastCameraFrame.cols() > 0) break;
|
2019-11-21 05:32:19 -05:00
|
|
|
} catch (Exception e) {
|
|
|
|
|
// e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
System.out.println("Starting vision thread.");
|
|
|
|
|
new Thread(visionRunnable).start();
|
|
|
|
|
System.out.println("Starting stream thread.");
|
|
|
|
|
new Thread(streamRunnable).start();
|
2019-11-10 11:47:56 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-22 14:20:23 -08:00
|
|
|
/**
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void initNT(NetworkTable newTable) {
|
|
|
|
|
ntPipelineEntry = newTable.getEntry("pipeline");
|
|
|
|
|
ntDriverModeEntry = newTable.getEntry("driver_mode");
|
|
|
|
|
ntPitchEntry = newTable.getEntry("pitch");
|
|
|
|
|
ntYawEntry = newTable.getEntry("yaw");
|
2019-11-23 04:05:37 -05:00
|
|
|
ntAreaEntry = newTable.getEntry("area");
|
2019-11-22 14:20:23 -08:00
|
|
|
ntTimeStampEntry = newTable.getEntry("timestamp");
|
|
|
|
|
ntValidEntry = newTable.getEntry("is_valid");
|
|
|
|
|
ntDriveModeListenerID = ntDriverModeEntry.addListener(this::setDriverMode, EntryListenerFlags.kUpdate);
|
|
|
|
|
ntPipelineListenerID = ntPipelineEntry.addListener(this::setPipeline, EntryListenerFlags.kUpdate);
|
|
|
|
|
ntDriverModeEntry.setBoolean(false);
|
|
|
|
|
ntPipelineEntry.setNumber(0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
private void setDriverMode(EntryNotification driverModeEntryNotification) {
|
|
|
|
|
setDriverMode(driverModeEntryNotification.value.getBoolean());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setDriverMode(boolean driverMode) {
|
|
|
|
|
if (driverMode) {
|
|
|
|
|
setPipelineInternal(driverModePipeline);
|
|
|
|
|
} else {
|
2019-11-23 20:02:21 -05:00
|
|
|
setPipeline(currentPipelineIndex, true);
|
2019-11-23 04:05:37 -05:00
|
|
|
}
|
2019-11-22 14:20:23 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Method called by the nt entry listener to update the next pipeline.
|
|
|
|
|
* @param notification the notification
|
|
|
|
|
*/
|
|
|
|
|
private void setPipeline(EntryNotification notification) {
|
|
|
|
|
var wantedPipelineIndex = (int) notification.value.getDouble();
|
|
|
|
|
|
|
|
|
|
if (wantedPipelineIndex >= pipelines.size()) {
|
|
|
|
|
ntPipelineEntry.setNumber(currentPipelineIndex);
|
|
|
|
|
} else {
|
|
|
|
|
currentPipelineIndex = wantedPipelineIndex;
|
2019-11-23 20:02:21 -05:00
|
|
|
setPipeline(wantedPipelineIndex, true);
|
2019-11-22 14:20:23 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-23 20:02:21 -05:00
|
|
|
public void setPipeline(int pipelineIndex, boolean updateUI) {
|
2019-11-10 11:47:56 -05:00
|
|
|
CVPipeline newPipeline = pipelines.get(pipelineIndex);
|
|
|
|
|
if (newPipeline != null) {
|
2019-11-22 14:20:23 -08:00
|
|
|
setPipelineInternal(newPipeline);
|
2019-11-23 04:05:37 -05:00
|
|
|
currentPipelineIndex = pipelineIndex;
|
|
|
|
|
|
|
|
|
|
// update the configManager
|
|
|
|
|
if(ConfigManager.settings.currentCamera.equals(cameraProcess.getProperties().name)) {
|
|
|
|
|
ConfigManager.settings.currentPipeline = pipelineIndex;
|
2019-11-23 20:02:21 -05:00
|
|
|
|
|
|
|
|
if (updateUI) {
|
|
|
|
|
HashMap<String, Object> pipeChange = new HashMap<>();
|
|
|
|
|
pipeChange.put("currentPipeline", pipelineIndex);
|
|
|
|
|
ServerHandler.broadcastMessage(pipeChange);
|
|
|
|
|
ServerHandler.sendFullSettings();
|
|
|
|
|
}
|
2019-11-23 04:05:37 -05:00
|
|
|
}
|
2019-11-22 14:20:23 -08:00
|
|
|
}
|
2019-11-10 11:47:56 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-22 14:20:23 -08:00
|
|
|
private void setPipelineInternal(CVPipeline pipeline) {
|
2019-11-10 11:47:56 -05:00
|
|
|
currentPipeline = pipeline;
|
|
|
|
|
currentPipeline.initPipeline(cameraProcess);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-22 14:20:23 -08:00
|
|
|
private void updateUI(CVPipelineResult data) {
|
|
|
|
|
if(cameraProcess.getProperties().name.equals(ConfigManager.settings.currentCamera)) {
|
|
|
|
|
HashMap<String, Object> WebSend = new HashMap<>();
|
|
|
|
|
HashMap<String, Object> point = new HashMap<>();
|
|
|
|
|
HashMap<String, Object> calculated = new HashMap<>();
|
|
|
|
|
List<Double> center = new ArrayList<>();
|
|
|
|
|
if (data.hasTarget) {
|
|
|
|
|
if(data instanceof CVPipeline2d.CVPipeline2dResult) {
|
|
|
|
|
CVPipeline2d.CVPipeline2dResult result = (CVPipeline2d.CVPipeline2dResult) data;
|
2019-11-23 04:05:37 -05:00
|
|
|
CVPipeline2d.Target2d bestTarget = result.targets.get(0);
|
2019-11-22 14:20:23 -08:00
|
|
|
center.add(bestTarget.rawPoint.center.x);
|
|
|
|
|
center.add(bestTarget.rawPoint.center.y);
|
|
|
|
|
calculated.put("pitch", bestTarget.pitch);
|
|
|
|
|
calculated.put("yaw", bestTarget.yaw);
|
2019-11-23 04:05:37 -05:00
|
|
|
} else if (data instanceof CVPipeline3d.CVPipeline3dResult) {
|
|
|
|
|
// TODO: (2.1) 3d stuff in UI
|
2019-11-22 14:20:23 -08:00
|
|
|
} else {
|
|
|
|
|
center.add(0.0);
|
|
|
|
|
center.add(0.0);
|
|
|
|
|
calculated.put("pitch", 0);
|
|
|
|
|
calculated.put("yaw", 0);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
center.add(0.0);
|
|
|
|
|
center.add(0.0);
|
|
|
|
|
calculated.put("pitch", 0);
|
|
|
|
|
calculated.put("yaw", 0);
|
|
|
|
|
}
|
|
|
|
|
point.put("fps", visionRunnable.fps);
|
|
|
|
|
point.put("calculated", calculated);
|
|
|
|
|
point.put("rawPoint", center);
|
|
|
|
|
WebSend.put("point", point);
|
|
|
|
|
ServerHandler.broadcastMessage(WebSend);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void updateNetworkTableData(CVPipelineResult data) {
|
|
|
|
|
ntValidEntry.setBoolean(data.hasTarget);
|
|
|
|
|
if(data.hasTarget && !(data instanceof DriverVisionPipeline.DriverPipelineResult)) {
|
|
|
|
|
if(data instanceof CVPipeline2d.CVPipeline2dResult) {
|
|
|
|
|
ntTimeStampEntry.setDouble(data.processTime);
|
|
|
|
|
|
|
|
|
|
//noinspection unchecked
|
2019-11-23 04:05:37 -05:00
|
|
|
List<CVPipeline2d.Target2d> targets = (List<CVPipeline2d.Target2d>) data.targets;
|
2019-11-22 14:20:23 -08:00
|
|
|
ntPitchEntry.setDouble(targets.get(0).pitch);
|
|
|
|
|
ntYawEntry.setDouble(targets.get(0).yaw);
|
2019-11-23 04:05:37 -05:00
|
|
|
ntAreaEntry.setDouble(targets.get(0).area);
|
2019-11-22 14:20:23 -08:00
|
|
|
ntAuxListEntry.setString(gson.toJson(targets));
|
|
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
} else if (data instanceof CVPipeline3d.CVPipeline3dResult) {
|
|
|
|
|
// TODO: (2.1) 3d stuff...
|
2019-11-22 14:20:23 -08:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
ntPitchEntry.setDouble(0.0);
|
|
|
|
|
ntYawEntry.setDouble(0.0);
|
2019-11-23 04:05:37 -05:00
|
|
|
ntAreaEntry.setDouble(0.0);
|
2019-11-22 14:20:23 -08:00
|
|
|
ntTimeStampEntry.setDouble(0.0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 11:10:55 -08:00
|
|
|
public void setVideoMode(VideoMode newMode) {
|
|
|
|
|
cameraProcess.setVideoMode(newMode);
|
2019-11-23 09:09:31 -08:00
|
|
|
cameraRunnable.updateCameraFPS(newMode.fps);
|
2019-11-16 11:10:55 -08:00
|
|
|
cameraStreamer.setNewVideoMode(newMode);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
public List<CVPipeline> getPipelines() {
|
|
|
|
|
return pipelines;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-10 11:47:56 -05:00
|
|
|
public CVPipeline getCurrentPipeline() {
|
|
|
|
|
return currentPipeline;
|
|
|
|
|
}
|
2019-11-15 16:01:50 -05:00
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
public int getCurrentPipelineIndex() {
|
|
|
|
|
return currentPipelineIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void addPipeline() {
|
|
|
|
|
// TODO: (2.1) add to UI option between 2d and 3d pipeline
|
|
|
|
|
pipelines.add(new CVPipeline2d());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void addPipeline(CVPipeline pipeline) {
|
|
|
|
|
pipelines.add(pipeline);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CameraProcess getCamera() {
|
|
|
|
|
return cameraProcess;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean getDriverMode() {
|
|
|
|
|
return (currentPipeline == driverModePipeline);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CVPipelineSettings getDriverModeSettings() {
|
|
|
|
|
return driverModePipeline.settings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CVPipeline getPipelineByIndex(int pipelineIndex) {
|
|
|
|
|
return pipelines.get(pipelineIndex);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 10:17:33 -08:00
|
|
|
/**
|
|
|
|
|
* CameraFrameRunnable grabs images from the cameraProcess
|
|
|
|
|
* at a specified loopTime
|
|
|
|
|
*/
|
|
|
|
|
protected class CameraFrameRunnable extends LoopingRunnable {
|
2019-11-21 05:32:19 -05:00
|
|
|
private Mat cameraFrame;
|
2019-11-15 16:01:50 -05:00
|
|
|
private long timestampMicros;
|
|
|
|
|
|
|
|
|
|
private final Object frameLock = new Object();
|
|
|
|
|
|
2019-11-16 10:17:33 -08:00
|
|
|
/**
|
|
|
|
|
* CameraFrameRunnable grabs images from the cameraProcess
|
2019-11-16 14:30:44 -05:00
|
|
|
* at a specified framerate
|
|
|
|
|
* @param cameraFPS FPS of camera
|
2019-11-16 10:17:33 -08:00
|
|
|
*/
|
2019-11-16 14:30:44 -05:00
|
|
|
CameraFrameRunnable(int cameraFPS) {
|
|
|
|
|
// add 2 FPS to allow for a bit of overhead
|
2019-11-23 04:05:37 -05:00
|
|
|
// TODO: (low) test the effect of this
|
2019-11-16 14:30:44 -05:00
|
|
|
super(1000L/(cameraFPS + 2));
|
2019-11-16 10:17:33 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-23 09:09:31 -08:00
|
|
|
void updateCameraFPS(int newFPS) {
|
|
|
|
|
super.loopTimeMs = 1000L / (newFPS + 2);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-15 16:01:50 -05:00
|
|
|
@Override
|
2019-11-16 10:17:33 -08:00
|
|
|
public void process() {
|
2019-11-23 19:28:11 -08:00
|
|
|
// System.out.println("running camera grabber process");
|
2019-11-16 10:17:33 -08:00
|
|
|
|
2019-11-21 22:04:17 -08:00
|
|
|
// Grab camera frames
|
|
|
|
|
var camData = cameraProcess.getFrame();
|
|
|
|
|
if (camData.getLeft().cols() > 0) {
|
2019-11-21 05:32:19 -05:00
|
|
|
// System.out.println("grabbing frame");
|
|
|
|
|
// synchronized (frameLock) {
|
2019-11-21 21:49:25 -08:00
|
|
|
// cameraFrame = camData.getLeft();
|
2019-11-21 05:32:19 -05:00
|
|
|
// }
|
2019-11-21 22:04:17 -08:00
|
|
|
timestampMicros = camData.getRight();
|
|
|
|
|
camData.getLeft().copyTo(lastCameraFrame);
|
|
|
|
|
hasUnprocessedFrame = true;
|
|
|
|
|
|
2019-11-22 14:20:23 -08:00
|
|
|
}
|
2019-11-15 16:01:50 -05:00
|
|
|
}
|
|
|
|
|
|
2019-11-16 10:17:33 -08:00
|
|
|
public Mat getFrame(Mat dst) {
|
2019-11-21 05:32:19 -05:00
|
|
|
if (cameraFrame != null) {
|
|
|
|
|
dst = cameraFrame;
|
|
|
|
|
} else {
|
|
|
|
|
System.out.println("no frame");
|
2019-11-16 10:17:33 -08:00
|
|
|
}
|
2019-11-21 05:32:19 -05:00
|
|
|
return dst;
|
2019-11-15 16:01:50 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 10:17:33 -08:00
|
|
|
/**
|
|
|
|
|
* VisionProcessRunnable will process images as quickly as possible
|
|
|
|
|
*/
|
|
|
|
|
private class VisionProcessRunnable implements Runnable {
|
2019-11-15 16:01:50 -05:00
|
|
|
|
2019-11-23 08:23:49 -08:00
|
|
|
volatile Double fps = 0.0;
|
2019-11-23 08:22:20 -08:00
|
|
|
private CircularBuffer fpsAveragingBuffer = new CircularBuffer(7);
|
2019-11-23 08:23:49 -08:00
|
|
|
@SuppressWarnings("FieldCanBeLocal")
|
2019-11-15 16:01:50 -05:00
|
|
|
private CVPipelineResult result;
|
2019-11-16 10:17:33 -08:00
|
|
|
private Mat streamBuffer = new Mat();
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
2019-11-23 08:22:20 -08:00
|
|
|
var lastUpdateTimeNanos = System.nanoTime();
|
2019-11-16 10:17:33 -08:00
|
|
|
while(!Thread.interrupted()) {
|
2019-11-23 19:28:11 -08:00
|
|
|
// System.out.println("running vision process");
|
2019-11-21 22:04:17 -08:00
|
|
|
|
|
|
|
|
while(!hasUnprocessedFrame) {
|
|
|
|
|
try {
|
|
|
|
|
Thread.sleep(3);
|
|
|
|
|
} catch (InterruptedException e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-21 21:51:06 -08:00
|
|
|
lastCameraFrame.copyTo(streamBuffer); // = //cameraRunnable.getFrame(streamBuffer);
|
2019-11-21 22:04:17 -08:00
|
|
|
hasUnprocessedFrame = false;
|
|
|
|
|
|
2019-11-21 05:32:19 -05:00
|
|
|
if (streamBuffer.cols() > 0 && streamBuffer.rows() > 0) {
|
|
|
|
|
result = currentPipeline.runPipeline(streamBuffer);
|
2019-11-21 21:49:25 -08:00
|
|
|
lastPipelineResult = result;
|
2019-11-22 14:20:23 -08:00
|
|
|
|
2019-11-23 20:13:01 -08:00
|
|
|
var yes = lastPipelineResult==null;
|
|
|
|
|
|
2019-11-22 14:20:23 -08:00
|
|
|
updateNetworkTableData(lastPipelineResult);
|
|
|
|
|
updateUI(lastPipelineResult);
|
|
|
|
|
|
2019-11-21 05:32:19 -05:00
|
|
|
} else {
|
|
|
|
|
// System.err.println("Bad streambuffer mat");
|
|
|
|
|
}
|
2019-11-23 08:22:20 -08:00
|
|
|
|
|
|
|
|
var deltaTimeNanos = lastUpdateTimeNanos - System.nanoTime();
|
|
|
|
|
fpsAveragingBuffer.addFirst(1.0 / (deltaTimeNanos * 1E-09));
|
|
|
|
|
lastUpdateTimeNanos = System.nanoTime();
|
|
|
|
|
fps = getAverageFPS();
|
|
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
// TODO: (HIGH) do something with the result
|
2019-11-16 10:17:33 -08:00
|
|
|
}
|
|
|
|
|
}
|
2019-11-23 08:22:20 -08:00
|
|
|
|
|
|
|
|
public double getAverageFPS() {
|
|
|
|
|
var temp = 0.0;
|
|
|
|
|
for(int i = 0; i < 7; i++) {
|
|
|
|
|
temp += fpsAveragingBuffer.get(i);
|
|
|
|
|
}
|
|
|
|
|
temp /= 7.0;
|
|
|
|
|
return temp;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 10:17:33 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-16 14:30:44 -05:00
|
|
|
private class CameraStreamerRunnable extends LoopingRunnable {
|
2019-11-16 10:17:33 -08:00
|
|
|
|
2019-11-23 04:05:37 -05:00
|
|
|
public final CameraStreamer streamer;
|
2019-11-16 10:17:33 -08:00
|
|
|
private Mat streamBuffer = new Mat();
|
|
|
|
|
|
2019-11-21 22:08:10 -08:00
|
|
|
private CameraStreamerRunnable(int cameraFPS, CameraStreamer streamer) {
|
|
|
|
|
// add 2 FPS to allow for a bit of overhead
|
2019-11-23 04:05:37 -05:00
|
|
|
// TODO: (low) test the effect of this
|
2019-11-21 22:08:10 -08:00
|
|
|
super(1000L/(cameraFPS + 2));
|
2019-11-16 10:17:33 -08:00
|
|
|
this.streamer = streamer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2019-11-16 14:30:44 -05:00
|
|
|
protected void process() {
|
2019-11-23 19:28:11 -08:00
|
|
|
// System.out.println("running camera streamer");
|
2019-11-22 07:52:19 -08:00
|
|
|
Mat latestMat = lastPipelineResult.outputMat; //visionRunnable.result;
|
|
|
|
|
if (latestMat != null && latestMat.cols() > 0) {
|
|
|
|
|
latestMat.copyTo(streamBuffer);
|
2019-11-21 21:49:25 -08:00
|
|
|
streamer.runStream(streamBuffer);
|
2019-11-21 05:32:19 -05:00
|
|
|
// if (toStreamMat != null && toStreamMat.cols() > 0) {
|
|
|
|
|
// } else {
|
|
|
|
|
// System.out.println("fuuuuck");
|
|
|
|
|
// }
|
|
|
|
|
}
|
2019-11-16 10:17:33 -08:00
|
|
|
}
|
|
|
|
|
}
|
2019-11-10 11:47:56 -05:00
|
|
|
}
|