2019-11-10 11:47:56 -05:00
|
|
|
package com.chameleonvision.classabstraction;
|
|
|
|
|
|
|
|
|
|
import com.chameleonvision.classabstraction.camera.CameraProcess;
|
2019-11-16 10:17:33 -08:00
|
|
|
import com.chameleonvision.classabstraction.camera.CameraStreamer;
|
2019-11-10 11:47:56 -05:00
|
|
|
import com.chameleonvision.classabstraction.pipeline.CVPipeline;
|
2019-11-15 16:01:50 -05:00
|
|
|
import com.chameleonvision.classabstraction.pipeline.CVPipelineResult;
|
2019-11-10 11:47:56 -05:00
|
|
|
import com.chameleonvision.classabstraction.pipeline.CVPipelineSettings;
|
|
|
|
|
import com.chameleonvision.classabstraction.pipeline.DriverVisionPipeline;
|
2019-11-16 14:30:44 -05:00
|
|
|
import com.chameleonvision.classabstraction.util.LoopingRunnable;
|
2019-11-16 11:10:55 -08:00
|
|
|
import edu.wpi.cscore.VideoMode;
|
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;
|
|
|
|
|
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-16 11:10:55 -08:00
|
|
|
private final CameraStreamer cameraStreamer;
|
2019-11-10 11:47:56 -05:00
|
|
|
private CVPipeline currentPipeline;
|
|
|
|
|
|
|
|
|
|
private final CVPipelineSettings driverVisionSettings = new CVPipelineSettings();
|
|
|
|
|
|
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-19 21:29:15 -08:00
|
|
|
public VisionProcess(CameraProcess cameraProcess, String name) {
|
2019-11-10 11:47:56 -05:00
|
|
|
this.cameraProcess = cameraProcess;
|
|
|
|
|
|
|
|
|
|
pipelines.add(new DriverVisionPipeline(() -> driverVisionSettings));
|
|
|
|
|
setPipeline(pipelines.get(0));
|
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-16 14:30:44 -05:00
|
|
|
// TODO: fix video modes!!!
|
|
|
|
|
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-16 15:00:03 -05:00
|
|
|
this.streamRunnable = new CameraStreamerRunnable(1000L/32, cameraStreamer);
|
2019-11-16 10:17:33 -08:00
|
|
|
|
|
|
|
|
// Thread to process vision data
|
|
|
|
|
this.visionRunnable = new VisionProcessRunnable();
|
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() {
|
|
|
|
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPipeline(int pipelineIndex) {
|
|
|
|
|
CVPipeline newPipeline = pipelines.get(pipelineIndex);
|
|
|
|
|
if (newPipeline != null) {
|
|
|
|
|
setPipeline(newPipeline);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void setPipeline(CVPipeline pipeline) {
|
|
|
|
|
currentPipeline = pipeline;
|
|
|
|
|
currentPipeline.initPipeline(cameraProcess);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 11:10:55 -08:00
|
|
|
public void setVideoMode(VideoMode newMode) {
|
|
|
|
|
cameraProcess.setVideoMode(newMode);
|
|
|
|
|
cameraStreamer.setNewVideoMode(newMode);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-10 11:47:56 -05:00
|
|
|
public CVPipeline getCurrentPipeline() {
|
|
|
|
|
return currentPipeline;
|
|
|
|
|
}
|
2019-11-15 16:01:50 -05:00
|
|
|
|
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
|
|
|
|
|
// TODO: test the affect of this
|
|
|
|
|
super(1000L/(cameraFPS + 2));
|
2019-11-16 10:17:33 -08:00
|
|
|
}
|
|
|
|
|
|
2019-11-15 16:01:50 -05:00
|
|
|
@Override
|
2019-11-16 10:17:33 -08:00
|
|
|
public void process() {
|
2019-11-21 22:04:17 -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-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
|
|
|
|
|
|
|
|
private CVPipelineResult result;
|
2019-11-16 10:17:33 -08:00
|
|
|
private Mat streamBuffer = new Mat();
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void run() {
|
|
|
|
|
while(!Thread.interrupted()) {
|
2019-11-21 22:04:17 -08:00
|
|
|
System.out.println("running vision process");
|
|
|
|
|
|
|
|
|
|
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-21 05:32:19 -05:00
|
|
|
} else {
|
|
|
|
|
// System.err.println("Bad streambuffer mat");
|
|
|
|
|
}
|
2019-11-16 10:17:33 -08:00
|
|
|
// TODO do something with the result
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 14:30:44 -05:00
|
|
|
private class CameraStreamerRunnable extends LoopingRunnable {
|
2019-11-16 10:17:33 -08:00
|
|
|
|
|
|
|
|
private final CameraStreamer streamer;
|
|
|
|
|
private Mat streamBuffer = new Mat();
|
|
|
|
|
|
2019-11-16 14:30:44 -05:00
|
|
|
private CameraStreamerRunnable(Long loopTimeMs, CameraStreamer streamer) {
|
2019-11-16 10:17:33 -08:00
|
|
|
super(loopTimeMs);
|
|
|
|
|
this.streamer = streamer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
2019-11-16 14:30:44 -05:00
|
|
|
protected void process() {
|
2019-11-21 22:04:17 -08:00
|
|
|
System.out.println("running camera streamer");
|
2019-11-21 21:49:25 -08:00
|
|
|
CVPipelineResult latestResult = lastPipelineResult; //visionRunnable.result;
|
2019-11-21 05:32:19 -05:00
|
|
|
if (latestResult != null) {
|
|
|
|
|
Mat toStreamMat = visionRunnable.result.outputMat;
|
2019-11-21 21:49:25 -08:00
|
|
|
toStreamMat.copyTo(streamBuffer);
|
|
|
|
|
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
|
|
|
}
|