Rename Camera and CamProcess to USBCamera and USBCameraProcess

Further changes:
- Add CameraProcess interface
- Change VisionProcess to pass the interface as parameter
This commit is contained in:
Matt
2019-11-02 10:10:02 -07:00
parent 570a042e35
commit 24313ba45b
12 changed files with 290 additions and 201 deletions

View File

@@ -145,7 +145,7 @@ public class Main {
if (ntClientModeServer != null) {
NetworkTableInstance.getDefault().startClient(ntClientModeServer);
} else {
NetworkTableInstance.getDefault().startClientTeam(SettingsManager.GeneralSettings.teamNumber);
NetworkTableInstance.getDefault().startClientTeam(SettingsManager.generalSettings.teamNumber);
}
}

View File

@@ -43,7 +43,7 @@ public class NetworkManager {
e.printStackTrace();
}
var teamBytes = NetworkManager.GetTeamNumberIPBytes(SettingsManager.GeneralSettings.teamNumber);
var teamBytes = NetworkManager.GetTeamNumberIPBytes(SettingsManager.generalSettings.teamNumber);
if (interfaces.size() > 0) {
for (var inetface : interfaces) {
@@ -85,7 +85,7 @@ public class NetworkManager {
return true;
}
var genSettings = SettingsManager.GeneralSettings;
var genSettings = SettingsManager.generalSettings;
boolean isStatic = genSettings.connectionType.equals(NetworkIPMode.STATIC);
if (isStatic) {

View File

@@ -14,36 +14,36 @@ import java.nio.file.Paths;
public class SettingsManager {
public static final Path SettingsPath = Paths.get(System.getProperty("user.dir"), "settings");
public static com.chameleonvision.settings.GeneralSettings GeneralSettings;
public static GeneralSettings generalSettings;
private SettingsManager() {}
public static void initialize() {
initGeneralSettings();
var allCameras = CameraManager.getAllCamerasByName();
if (!allCameras.containsKey(GeneralSettings.currentCamera) && allCameras.size() > 0) {
if (!allCameras.containsKey(generalSettings.currentCamera) && allCameras.size() > 0) {
var cam = allCameras.entrySet().stream().findFirst().get().getValue();
GeneralSettings.currentCamera = cam.name;
GeneralSettings.currentPipeline = cam.getCurrentPipelineIndex();
generalSettings.currentCamera = cam.name;
generalSettings.currentPipeline = cam.getCurrentPipelineIndex();
}
}
private static void initGeneralSettings() {
FileHelper.CheckPath(SettingsPath);
try {
GeneralSettings = new Gson().fromJson(new FileReader(Paths.get(SettingsPath.toString(), "settings.json").toString()), com.chameleonvision.settings.GeneralSettings.class);
generalSettings = new Gson().fromJson(new FileReader(Paths.get(SettingsPath.toString(), "settings.json").toString()), com.chameleonvision.settings.GeneralSettings.class);
} catch (FileNotFoundException e) {
GeneralSettings = new GeneralSettings();
generalSettings = new GeneralSettings();
}
}
public static void updateCameraSetting(String cameraName, int pipelineNumber) {
GeneralSettings.currentCamera = cameraName;
GeneralSettings.currentPipeline = pipelineNumber;
generalSettings.currentCamera = cameraName;
generalSettings.currentPipeline = pipelineNumber;
}
public static void updatePipelineSetting(int pipelineNumber) {
GeneralSettings.currentPipeline = pipelineNumber;
generalSettings.currentPipeline = pipelineNumber;
}
public static void saveSettings() {
@@ -55,7 +55,7 @@ public class SettingsManager {
try {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
FileWriter writer = new FileWriter(Paths.get(SettingsPath.toString(), "settings.json").toString());
gson.toJson(GeneralSettings, writer);
gson.toJson(generalSettings, writer);
writer.flush();
writer.close();
} catch (IOException e) {

View File

@@ -4,19 +4,16 @@ import com.chameleonvision.vision.Pipeline;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.type.MapType;
import com.fasterxml.jackson.databind.type.ArrayType;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.google.gson.*;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class CameraDeserializer implements JsonDeserializer<Camera> {
public class CameraDeserializer implements JsonDeserializer<USBCamera> {
@Override
public Camera deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
public USBCamera deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context) throws JsonParseException {
try {
var jsonObj = jsonElement.getAsJsonObject();
var camFOV = jsonObj.get("FOV").getAsDouble();
@@ -32,8 +29,8 @@ public class CameraDeserializer implements JsonDeserializer<Camera> {
// always null-check new features
boolean isDriver = isDriverObj != null && isDriverObj.getAsBoolean();
int driverExposure = driverExposureObj == null ? Camera.DEFAULT_EXPOSURE : driverExposureObj.getAsInt();
int driverBrightness = driverBrightnessObj == null ? Camera.DEFAULT_BRIGHTNESS : driverBrightnessObj.getAsInt();
int driverExposure = driverExposureObj == null ? USBCamera.DEFAULT_EXPOSURE : driverExposureObj.getAsInt();
int driverBrightness = driverBrightnessObj == null ? USBCamera.DEFAULT_BRIGHTNESS : driverBrightnessObj.getAsInt();
StreamDivisor divisor = divisorObj == null ? StreamDivisor.none : StreamDivisor.values()[divisorObj.getAsInt()];
var pipelines = jsonObj.get("pipelines");
@@ -47,7 +44,7 @@ public class CameraDeserializer implements JsonDeserializer<Camera> {
e.printStackTrace();
}
var newCamera = actualPipelines != null ? new Camera(camName, camFOV, actualPipelines, videoModeIndex, divisor, isDriver) : new Camera(camName, camFOV, videoModeIndex, divisor, isDriver);
var newCamera = actualPipelines != null ? new USBCamera(camName, camFOV, actualPipelines, videoModeIndex, divisor, isDriver) : new USBCamera(camName, camFOV, videoModeIndex, divisor, isDriver);
newCamera.setNickname(camNickname != null ? camNickname : "");
newCamera.setDriverExposure(driverExposure);
newCamera.setDriverBrightness(driverBrightness);

View File

@@ -1,9 +1,9 @@
package com.chameleonvision.vision.camera;
import com.chameleonvision.settings.GeneralSettings;
import com.chameleonvision.util.FileHelper;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.vision.process.USBCameraProcess;
import com.chameleonvision.vision.process.VisionProcess;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -21,10 +21,10 @@ public class CameraManager {
private static final Path CamConfigPath = Paths.get(SettingsManager.SettingsPath.toString(), "cameras");
private static LinkedHashMap<String, Camera> AllCamerasByName = new LinkedHashMap<>();
public static HashMap<String, VisionProcess> AllVisionProcessesByName = new HashMap<>();
private static LinkedHashMap<String, USBCamera> allCamerasByName = new LinkedHashMap<>();
public static HashMap<String, VisionProcess> allVisionProcessesByName = new HashMap<>();
static HashMap<String, UsbCameraInfo> AllUsbCameraInfosByName = new HashMap<>() {{
static HashMap<String, UsbCameraInfo> allUsbCameraInfosByName = new HashMap<>() {{
var suffix = 0;
for (var info : UsbCamera.enumerateUsbCameras()) {
var cap = new VideoCapture(info.dev);
@@ -40,31 +40,31 @@ public class CameraManager {
}
}};
public static HashMap<String, Camera> getAllCamerasByName() {
return AllCamerasByName;
public static HashMap<String, USBCamera> getAllCamerasByName() {
return allCamerasByName;
}
public static List<String> getAllCameraByNickname(){
var cameras = getAllCamerasByName();
return cameras.values().stream().map(Camera::getNickname).collect(Collectors.toList());
return cameras.values().stream().map(USBCamera::getNickname).collect(Collectors.toList());
}
public static boolean initializeCameras() {
if (AllUsbCameraInfosByName.size() == 0) return false;
if (allUsbCameraInfosByName.size() == 0) return false;
FileHelper.CheckPath(CamConfigPath);
AllUsbCameraInfosByName.forEach((key, value) -> {
allUsbCameraInfosByName.forEach((key, value) -> {
var camPath = Paths.get(CamConfigPath.toString(), String.format("%s.json", key));
File camJsonFile = new File(camPath.toString());
if (camJsonFile.exists() && camJsonFile.length() != 0) {
try {
Gson gson = new GsonBuilder().registerTypeAdapter(Camera.class, new CameraDeserializer()).create();
Gson gson = new GsonBuilder().registerTypeAdapter(USBCamera.class, new CameraDeserializer()).create();
var camJsonFileReader = new FileReader(camPath.toString());
var gsonRead = gson.fromJson(camJsonFileReader, Camera.class);
AllCamerasByName.put(key, gsonRead);
var gsonRead = gson.fromJson(camJsonFileReader, USBCamera.class);
allCamerasByName.put(key, gsonRead);
} catch (FileNotFoundException ex) {
ex.printStackTrace();
}
} else {
if (!addCamera(new Camera(key), key)) {
if (!addCamera(new USBCamera(key), key)) {
System.err.println("Failed to add camera! Already exists!");
}
}
@@ -73,39 +73,39 @@ public class CameraManager {
}
public static void initializeThreads(){
AllCamerasByName.forEach((key, value) -> {
VisionProcess visionProcess = new VisionProcess(value);
AllVisionProcessesByName.put(key, visionProcess);
allCamerasByName.forEach((name, camera) -> {
VisionProcess visionProcess = new VisionProcess(new USBCameraProcess(camera));
allVisionProcessesByName.put(name, visionProcess);
new Thread(visionProcess).start();
});
}
private static boolean addCamera(Camera camera, String cameraName) {
if (AllCamerasByName.containsKey(cameraName)) return false;
camera.addPipeline();
AllCamerasByName.put(cameraName, camera);
private static boolean addCamera(USBCamera USBCamera, String cameraName) {
if (allCamerasByName.containsKey(cameraName)) return false;
USBCamera.addPipeline();
allCamerasByName.put(cameraName, USBCamera);
return true;
}
private static Camera getCamera(String cameraName) {
return AllCamerasByName.get(cameraName);
private static USBCamera getCamera(String cameraName) {
return allCamerasByName.get(cameraName);
}
public static Camera getCameraByIndex(int index) {
return AllCamerasByName.get( (AllCamerasByName.keySet().toArray())[ index ] );
public static USBCamera getCameraByIndex(int index) {
return allCamerasByName.get( (allCamerasByName.keySet().toArray())[ index ] );
}
public static Camera getCurrentCamera() throws CameraException {
if (AllCamerasByName.size() == 0) throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA);
var curCam = AllCamerasByName.get(SettingsManager.GeneralSettings.currentCamera);
public static USBCamera getCurrentCamera() throws CameraException {
if (allCamerasByName.size() == 0) throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA);
var curCam = allCamerasByName.get(SettingsManager.generalSettings.currentCamera);
if (curCam == null) throw new CameraException(CameraException.CameraExceptionType.BAD_CAMERA);
return curCam;
}
public static Integer getCurrentCameraIndex() throws CameraException {
if (AllCamerasByName.size() == 0) throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA);
List<String> arr = new ArrayList<>(AllCamerasByName.keySet());
for (var i = 0; i < AllCamerasByName.size(); i++){
if (SettingsManager.GeneralSettings.currentCamera.equals(arr.get(i))){
if (allCamerasByName.size() == 0) throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA);
List<String> arr = new ArrayList<>(allCamerasByName.keySet());
for (var i = 0; i < allCamerasByName.size(); i++){
if (SettingsManager.generalSettings.currentCamera.equals(arr.get(i))){
return i;
}
}
@@ -113,13 +113,13 @@ public class CameraManager {
}
public static void setCurrentCamera(String cameraName) throws CameraException {
if (!AllCamerasByName.containsKey(cameraName))
if (!allCamerasByName.containsKey(cameraName))
throw new CameraException(CameraException.CameraExceptionType.BAD_CAMERA);
SettingsManager.GeneralSettings.currentCamera = cameraName;
SettingsManager.generalSettings.currentCamera = cameraName;
SettingsManager.updateCameraSetting(cameraName, getCurrentCamera().getCurrentPipelineIndex());
}
public static void setCurrentCamera(int cameraIndex) throws CameraException {
List<String> s = new ArrayList<String>(AllCamerasByName.keySet());
List<String> s = new ArrayList<String>(allCamerasByName.keySet());
setCurrentCamera(s.get(cameraIndex));
}
@@ -136,20 +136,20 @@ public class CameraManager {
}
public static VisionProcess getVisionProcessByCameraName(String cameraName) {
return AllVisionProcessesByName.get(cameraName);
return allVisionProcessesByName.get(cameraName);
}
public static VisionProcess getCurrentVisionProcess() throws CameraException {
if (!SettingsManager.GeneralSettings.currentCamera.equals("")){
return AllVisionProcessesByName.get(SettingsManager.GeneralSettings.currentCamera);
if (!SettingsManager.generalSettings.currentCamera.equals("")){
return allVisionProcessesByName.get(SettingsManager.generalSettings.currentCamera);
}
throw new CameraException(CameraException.CameraExceptionType.NO_CAMERA);
}
public static void saveCameras() {
for (var entry : AllCamerasByName.entrySet()) {
for (var entry : allCamerasByName.entrySet()) {
try {
Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(Camera.class, new CameraSerializer()).create();
Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(USBCamera.class, new CameraSerializer()).create();
FileWriter writer = new FileWriter(Paths.get(CamConfigPath.toString(), String.format("%s.json", entry.getKey())).toString());
gson.toJson(entry.getValue(), writer);
writer.flush();

View File

@@ -3,22 +3,22 @@ import com.google.gson.*;
import java.lang.reflect.Type;
public class CameraSerializer implements JsonSerializer<Camera> {
public class CameraSerializer implements JsonSerializer<USBCamera> {
@Override
public JsonElement serialize(Camera camera, Type type, JsonSerializationContext context) {
public JsonElement serialize(USBCamera USBCamera, Type type, JsonSerializationContext context) {
JsonObject obj = new JsonObject();
obj.addProperty("FOV", camera.getFOV());
obj.addProperty("path", camera.path);
obj.addProperty("name", camera.name);
obj.addProperty("nickname", camera.getNickname());
obj.addProperty("streamDivisor", camera.getStreamDivisor().ordinal());
var pipelines = context.serialize(camera.getPipelines());
obj.addProperty("FOV", USBCamera.getFOV());
obj.addProperty("path", USBCamera.path);
obj.addProperty("name", USBCamera.name);
obj.addProperty("nickname", USBCamera.getNickname());
obj.addProperty("streamDivisor", USBCamera.getStreamDivisor().ordinal());
var pipelines = context.serialize(USBCamera.getPipelines());
obj.add("pipelines", pipelines);
obj.addProperty("resolution", camera.getVideoModeIndex());
obj.add("camVideoMode", context.serialize(camera.getVideoMode()));
obj.add("isDriver",context.serialize(camera.getDriverMode()));
obj.add("driverExposure",context.serialize(camera.getDriverExposure()));
obj.add("driverBrightness",context.serialize(camera.getDriverBrightness()));
obj.addProperty("resolution", USBCamera.getVideoModeIndex());
obj.add("camVideoMode", context.serialize(USBCamera.getVideoMode()));
obj.add("isDriver",context.serialize(USBCamera.getDriverMode()));
obj.add("driverExposure",context.serialize(USBCamera.getDriverExposure()));
obj.add("driverBrightness",context.serialize(USBCamera.getDriverBrightness()));
return obj;
}
}

View File

@@ -21,8 +21,8 @@ public class CameraValues {
public final double HorizontalFocalLength;
public final double VerticalFocalLength;
public CameraValues(Camera camera) {
this(camera.getVideoMode().width, camera.getVideoMode().height, camera.getFOV());
public CameraValues(USBCamera USBCamera) {
this(USBCamera.getVideoMode().width, USBCamera.getVideoMode().height, USBCamera.getFOV());
}
public CameraValues(int imageWidth, int imageHeight, double fov) {

View File

@@ -13,7 +13,7 @@ import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Camera {
public class USBCamera {
private static final double DEFAULT_FOV = 60.8;
private static final StreamDivisor DEFAULT_STREAMDIVISOR = StreamDivisor.none;
@@ -49,31 +49,31 @@ public class Camera {
private int driverBrightness;
private boolean isDriver;
public Camera(String cameraName) {
public USBCamera(String cameraName) {
this(cameraName, DEFAULT_FOV);
}
public Camera(String cameraName, double fov) {
this(cameraName, CameraManager.AllUsbCameraInfosByName.get(cameraName), fov);
public USBCamera(String cameraName, double fov) {
this(cameraName, CameraManager.allUsbCameraInfosByName.get(cameraName), fov);
}
public Camera(String cameraName, UsbCameraInfo usbCameraInfo, double fov) {
public USBCamera(String cameraName, UsbCameraInfo usbCameraInfo, double fov) {
this(cameraName, usbCameraInfo, fov, DEFAULT_STREAMDIVISOR);
}
public Camera(String cameraName, UsbCameraInfo usbCamInfo, double fov, StreamDivisor divisor) {
public USBCamera(String cameraName, UsbCameraInfo usbCamInfo, double fov, StreamDivisor divisor) {
this(cameraName, usbCamInfo, fov, new ArrayList<>(), 0, divisor, false);
}
public Camera(String cameraName, double fov, List<Pipeline> pipelines, int videoModeIndex, StreamDivisor divisor, boolean isDriver) {
this(cameraName, CameraManager.AllUsbCameraInfosByName.get(cameraName), fov, pipelines, videoModeIndex, divisor, isDriver);
public USBCamera(String cameraName, double fov, List<Pipeline> pipelines, int videoModeIndex, StreamDivisor divisor, boolean isDriver) {
this(cameraName, CameraManager.allUsbCameraInfosByName.get(cameraName), fov, pipelines, videoModeIndex, divisor, isDriver);
}
public Camera(String cameraName, double fov, int videoModeIndex, StreamDivisor divisor, boolean isDriver) {
public USBCamera(String cameraName, double fov, int videoModeIndex, StreamDivisor divisor, boolean isDriver) {
this(cameraName, fov, new ArrayList<>(), videoModeIndex, divisor, isDriver);
}
public Camera(String cameraName, UsbCameraInfo usbCamInfo, double fov, List<Pipeline> pipelines, int videoModeIndex, StreamDivisor divisor, boolean isDriver) {
public USBCamera(String cameraName, UsbCameraInfo usbCamInfo, double fov, List<Pipeline> pipelines, int videoModeIndex, StreamDivisor divisor, boolean isDriver) {
FOV = fov;
name = cameraName;
@@ -99,13 +99,13 @@ public class Camera {
}
}
var initTimeMs = (System.nanoTime() - initTimeout) / 1e6;
System.out.printf("Camera initialized in %.2fms\n", initTimeMs);
System.out.printf("USBCamera initialized in %.2fms\n", initTimeMs);
}
var trueVideoModes = UsbCam.enumerateVideoModes();
availableVideoModes = Arrays.stream(trueVideoModes).filter(v ->
v.fps >= MINIMUM_FPS && v.width >= MINIMUM_WIDTH && v.height >= MINIMUM_HEIGHT && ALLOWED_PIXEL_FORMATS.contains(v.pixelFormat)).toArray(VideoMode[]::new);
if (availableVideoModes.length == 0) {
System.err.println("Camera not supported!");
System.err.println("USBCamera not supported!");
throw new RuntimeException(new CameraException(CameraException.CameraExceptionType.BAD_CAMERA));
}
if (videoModeIndex <= availableVideoModes.length - 1) {
@@ -283,7 +283,7 @@ public class Camera {
try {
UsbCam.setExposureManual(exposure);
} catch (VideoException e) {
System.err.println("Camera Does not support exposure change");
System.err.println("USBCamera Does not support exposure change");
}
}
@@ -311,9 +311,9 @@ public class Camera {
//Deletes old camera nt table
NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + this.nickname).getInstance().deleteAllEntries();
nickname = newNickname;
if (CameraManager.AllVisionProcessesByName.containsKey(this.name)) {
if (CameraManager.allVisionProcessesByName.containsKey(this.name)) {
NetworkTable newNT = NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + this.nickname);
CameraManager.AllVisionProcessesByName.get(this.name).resetNT(newNT);
CameraManager.allVisionProcessesByName.get(this.name).resetNT(newNT);
}
}

View File

@@ -1,77 +1,31 @@
package com.chameleonvision.vision.process;
import com.chameleonvision.vision.camera.Camera;
import com.chameleonvision.vision.camera.StreamDivisor;
import org.opencv.core.CvType;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.vision.camera.CamVideoMode;
import com.chameleonvision.vision.camera.CameraValues;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
public class CameraProcess implements Runnable {
import java.util.List;
private final Camera camera;
private final int maxFPS;
private final Object inputFrameLock = new Object();
private final Object outputFrameLock = new Object();
private Mat inputFrame;
private Mat outputFrame;
private long timestamp;
private StreamDivisor divisor;
public interface CameraProcess extends Runnable {
CameraProcess(Camera camera) {
this.camera = camera;
maxFPS = camera.getVideoMode().fps;
updateFrameSize();
}
long getLatestFrame(Mat outputFrame);
public void updateFrameSize() {
var camVals = camera.getCamVals();
divisor = camera.getStreamDivisor();
var newWidth = camVals.ImageWidth / divisor.value;
var newHeight = camVals.ImageHeight / divisor.value;
synchronized (inputFrameLock) {
inputFrame = new Mat(newWidth, newHeight, CvType.CV_8UC3);
}
synchronized (outputFrameLock) {
outputFrame = new Mat(newWidth, newHeight, CvType.CV_8UC3);
}
}
void updateFrame(Mat inputFrame);
void updateFrame(Mat inputFrame) {
synchronized (inputFrameLock) {
inputFrame.copyTo(this.inputFrame);
}
}
void updateFrameSize();
long getLatestFrame(Mat outputFrame) {
synchronized (outputFrameLock) {
this.outputFrame.copyTo(outputFrame);
return timestamp;
}
}
String getCamName();
CameraValues getCamVals();
boolean getDriverMode();
void setDriverMode(boolean isDriverMode);
List<Pipeline> getPipelines();
Pipeline getCurrentPipeline();
int getCurrentPipelineIndex();
void setExposure(int exposure);
void setBrightness(int brightness);
CamVideoMode getVideoMode();
String getNickname();
void setCurrentPipelineIndex(int ntPipelineIndex);
@Override
public void run() {
while (!Thread.interrupted()) {
synchronized (outputFrameLock) {
timestamp = camera.grabFrame(outputFrame);
}
synchronized (inputFrameLock) {
if (divisor.value != 1) {
var camVals = camera.getCamVals();
var newWidth = camVals.ImageWidth / divisor.value;
var newHeight = camVals.ImageHeight / divisor.value;
Size newSize = new Size(newWidth, newHeight);
Imgproc.resize(inputFrame, inputFrame, newSize);
}
camera.putFrame(inputFrame);
}
var msToWait = (long) 1000 / maxFPS;
try {
Thread.sleep(msToWait);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

View File

@@ -0,0 +1,144 @@
package com.chameleonvision.vision.process;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.vision.camera.CamVideoMode;
import com.chameleonvision.vision.camera.CameraValues;
import com.chameleonvision.vision.camera.USBCamera;
import com.chameleonvision.vision.camera.StreamDivisor;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Size;
import org.opencv.imgproc.Imgproc;
import java.util.List;
public class USBCameraProcess implements CameraProcess {
private final USBCamera usbCamera;
private final int maxFPS;
private final Object inputFrameLock = new Object();
private final Object outputFrameLock = new Object();
private Mat inputFrame;
private Mat outputFrame;
private long timestamp;
private StreamDivisor divisor;
public USBCameraProcess(USBCamera usbCamera) {
this.usbCamera = usbCamera;
maxFPS = usbCamera.getVideoMode().fps;
updateFrameSize();
}
public void updateFrameSize() {
var camVals = usbCamera.getCamVals();
divisor = usbCamera.getStreamDivisor();
var newWidth = camVals.ImageWidth / divisor.value;
var newHeight = camVals.ImageHeight / divisor.value;
synchronized (inputFrameLock) {
inputFrame = new Mat(newWidth, newHeight, CvType.CV_8UC3);
}
synchronized (outputFrameLock) {
outputFrame = new Mat(newWidth, newHeight, CvType.CV_8UC3);
}
}
public void updateFrame(Mat inputFrame) {
synchronized (inputFrameLock) {
inputFrame.copyTo(this.inputFrame);
}
}
public long getLatestFrame(Mat outputFrame) {
synchronized (outputFrameLock) {
this.outputFrame.copyTo(outputFrame);
return timestamp;
}
}
@Override
public void run() {
while (!Thread.interrupted()) {
synchronized (outputFrameLock) {
timestamp = usbCamera.grabFrame(outputFrame);
}
synchronized (inputFrameLock) {
if (divisor.value != 1) {
var camVals = usbCamera.getCamVals();
var newWidth = camVals.ImageWidth / divisor.value;
var newHeight = camVals.ImageHeight / divisor.value;
Size newSize = new Size(newWidth, newHeight);
Imgproc.resize(inputFrame, inputFrame, newSize);
}
usbCamera.putFrame(inputFrame);
}
var msToWait = (long) 1000 / maxFPS;
try {
Thread.sleep(msToWait);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
// USBCamera stuff
@Override
public String getCamName() {
return usbCamera.name;
}
@Override
public CameraValues getCamVals() {
return usbCamera.getCamVals();
}
@Override
public boolean getDriverMode() {
return usbCamera.getDriverMode();
}
@Override
public void setDriverMode(boolean isDriverMode) {
usbCamera.setDriverMode(isDriverMode);
}
@Override
public List<Pipeline> getPipelines() {
return usbCamera.getPipelines();
}
@Override
public Pipeline getCurrentPipeline() {
return usbCamera.getCurrentPipeline();
}
@Override
public int getCurrentPipelineIndex() {
return usbCamera.getCurrentPipelineIndex();
}
@Override
public void setExposure(int exposure) {
usbCamera.setExposure(exposure);
}
@Override
public void setBrightness(int brightness) {
usbCamera.setBrightness(brightness);
}
@Override
public CamVideoMode getVideoMode() {
return usbCamera.getVideoMode();
}
@Override
public String getNickname() {
return usbCamera.getNickname();
}
@Override
public void setCurrentPipelineIndex(int wantedIndex) {
usbCamera.setCurrentPipelineIndex(wantedIndex);
}
}

View File

@@ -1,10 +1,8 @@
package com.chameleonvision.vision.process;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.vision.CalibrationMode;
import com.chameleonvision.vision.Orientation;
import com.chameleonvision.vision.Pipeline;
import com.chameleonvision.vision.camera.Camera;
import com.chameleonvision.web.ServerHandler;
import edu.wpi.cscore.VideoException;
import edu.wpi.first.networktables.*;
@@ -17,7 +15,6 @@ import java.util.List;
public class VisionProcess implements Runnable {
private final Camera camera;
private final String cameraName;
public final CameraProcess cameraProcess;
// NetworkTables
@@ -45,36 +42,36 @@ public class VisionProcess implements Runnable {
private Scalar BoxRectColor = new Scalar(0, 0, 233);
private long timeStamp = 0;
public VisionProcess(Camera processCam) {
camera = processCam;
this.cameraName = camera.name;
public VisionProcess(CameraProcess cameraProcess) {
initNT(NetworkTableInstance.getDefault().getTable("/chameleon-vision/"+processCam.getNickname()));
// USBCamera settings
cvProcess = new CVProcess(cameraProcess.getCamVals());
this.cameraProcess = cameraProcess; // new USBCameraProcess(cameraProcess);
// camera settings
cvProcess = new CVProcess(camera.getCamVals());
cameraProcess = new CameraProcess(camera);
this.cameraName = cameraProcess.getCamName();
initNT(NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + cameraProcess.getNickname()));
}
private void driverModeListener(EntryNotification entryNotification) {
camera.setDriverMode(entryNotification.value.getBoolean());
cameraProcess.setDriverMode(entryNotification.value.getBoolean());
}
private void pipelineListener(EntryNotification entryNotification) {
var ntPipelineIndex = (int) entryNotification.value.getDouble();
if (ntPipelineIndex >= camera.getPipelines().size()) {
ntPipelineEntry.setNumber(camera.getCurrentPipelineIndex());
if (ntPipelineIndex >= cameraProcess.getPipelines().size()) {
ntPipelineEntry.setNumber(cameraProcess.getCurrentPipelineIndex());
} else {
var pipeline = camera.getCurrentPipeline();
camera.setCurrentPipelineIndex(ntPipelineIndex);
var pipeline = cameraProcess.getCurrentPipeline();
cameraProcess.setCurrentPipelineIndex(ntPipelineIndex);
try {
camera.setExposure(pipeline.exposure);
cameraProcess.setExposure(pipeline.exposure);
} catch (VideoException e) {
System.err.println(e.toString());
}
camera.setBrightness(pipeline.brightness);
if (SettingsManager.GeneralSettings.currentCamera.equals(cameraName)) {
SettingsManager.GeneralSettings.currentPipeline = ntPipelineIndex;
cameraProcess.setBrightness(pipeline.brightness);
if (SettingsManager.generalSettings.currentCamera.equals(cameraName)) {
SettingsManager.generalSettings.currentPipeline = ntPipelineIndex;
HashMap<String, Object> pipeChange = new HashMap<>();
pipeChange.put("currentPipeline", ntPipelineIndex);
ServerHandler.broadcastMessage(pipeChange);
@@ -123,7 +120,7 @@ public class VisionProcess implements Runnable {
if (currentPipeline.orientation.equals(Orientation.Inverted)) {
Core.flip(inputImage, inputImage, -1);
}
if (camera.getDriverMode()) {
if (cameraProcess.getDriverMode()) {
inputImage.copyTo(outputImage);
return pipelineResult;
}
@@ -150,9 +147,9 @@ public class VisionProcess implements Runnable {
pipelineResult.IsValid = true;
switch (currentPipeline.calibrationMode) {
case None:
///use the center of the camera to find the pitch and yaw difference
pipelineResult.CalibratedX = camera.getCamVals().CenterX;
pipelineResult.CalibratedY = camera.getCamVals().CenterY;
///use the center of the USBCamera to find the pitch and yaw difference
pipelineResult.CalibratedX = cameraProcess.getCamVals().CenterX;
pipelineResult.CalibratedY = cameraProcess.getCamVals().CenterY;
break;
case Single:
// use the static point as a calibration method instead of the center
@@ -165,7 +162,7 @@ public class VisionProcess implements Runnable {
pipelineResult.CalibratedY = (finalRect.center.x * currentPipeline.m) + currentPipeline.b;
break;
}
// var camVals = camera.getCamVals();
// var camVals = cameraProcess.getCamVals();
// if (currentPipeline.isCalibrated) {
// pipelineResult.CalibratedX = (finalRect.center.y - currentPipeline.b) / currentPipeline.m;
// pipelineResult.CalibratedY = (finalRect.center.x * currentPipeline.m) + currentPipeline.b;
@@ -173,8 +170,8 @@ public class VisionProcess implements Runnable {
// pipelineResult.CalibratedX = camVals.CenterX;
// pipelineResult.CalibratedY = camVals.CenterY;
// }
pipelineResult.Pitch = camera.getCamVals().CalculatePitch(finalRect.center.y, pipelineResult.CalibratedY);
pipelineResult.Yaw = camera.getCamVals().CalculateYaw(finalRect.center.x, pipelineResult.CalibratedX);
pipelineResult.Pitch = cameraProcess.getCamVals().CalculatePitch(finalRect.center.y, pipelineResult.CalibratedY);
pipelineResult.Yaw = cameraProcess.getCamVals().CalculateYaw(finalRect.center.x, pipelineResult.CalibratedX);
pipelineResult.Area = finalRect.size.area();
drawContour(outputImage, finalRect);
}
@@ -193,7 +190,7 @@ public class VisionProcess implements Runnable {
double processTimeMs;
double fps = 0;
double uiFps = 0;
int maxFps = camera.getVideoMode().fps;
int maxFps = cameraProcess.getVideoMode().fps;
new Thread(cameraProcess).start();
@@ -201,10 +198,11 @@ public class VisionProcess implements Runnable {
while (!Thread.interrupted()) {
startTime = System.nanoTime();
if ((startTime - lastFrameEndNanosec) * 1e-6 >= 1000.0 / maxFps + 3) { // 3 additional fps to allow for overhead
if ((startTime - lastFrameEndNanosec) * 1e-6 >= 1000.0 / (maxFps + 3)) { // 3 additional fps to allow for overhead
foundContours.clear();
filteredContours.clear();
groupedContours.clear();
deSpeckledContours.clear();
// update FPS for ui only every 0.5 seconds
if ((startTime - fpsLastTime) * 1e-6 >= 500) {
@@ -216,7 +214,7 @@ public class VisionProcess implements Runnable {
fpsLastTime = System.nanoTime();
}
currentPipeline = camera.getCurrentPipeline();
currentPipeline = cameraProcess.getCurrentPipeline();
// start fps counter right before grabbing input frame
timeStamp = cameraProcess.getLatestFrame(cameraInputMat);
if (cameraInputMat.cols() == 0 && cameraInputMat.rows() == 0) {
@@ -226,7 +224,7 @@ public class VisionProcess implements Runnable {
// get vision data
var pipelineResult = runVisionProcess(cameraInputMat, streamOutputMat);
updateNetworkTables(pipelineResult);
if (cameraName.equals(SettingsManager.GeneralSettings.currentCamera)) {
if (cameraName.equals(SettingsManager.generalSettings.currentCamera)) {
HashMap<String, Object> WebSend = new HashMap<>();
HashMap<String, Object> point = new HashMap<>();
HashMap<String, Object> calculated = new HashMap<>();
@@ -293,6 +291,6 @@ public class VisionProcess implements Runnable {
ntDriveModeListenerID = ntDriverModeEntry.addListener(this::driverModeListener, EntryListenerFlags.kUpdate);
ntPipelineListenerID = ntPipelineEntry.addListener(this::pipelineListener, EntryListenerFlags.kUpdate);
ntDriverModeEntry.setBoolean(false);
ntPipelineEntry.setNumber(camera.getCurrentPipelineIndex());
ntPipelineEntry.setNumber(cameraProcess.getCurrentPipelineIndex());
}
}

View File

@@ -1,23 +1,19 @@
package com.chameleonvision.web;
import com.chameleonvision.settings.GeneralSettings;
import com.chameleonvision.vision.*;
import com.chameleonvision.vision.camera.Camera;
import com.chameleonvision.vision.camera.USBCamera;
import com.chameleonvision.vision.camera.CameraException;
import com.chameleonvision.settings.SettingsManager;
import com.chameleonvision.vision.camera.CameraManager;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.wpi.cscore.VideoException;
import io.javalin.websocket.*;
import org.apache.commons.lang3.ArrayUtils;
import org.msgpack.jackson.dataformat.MessagePackFactory;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.nio.ByteBuffer;
import java.util.*;
@@ -49,7 +45,7 @@ public class ServerHandler {
switch (entry.getKey()) {
case "generalSettings": {
for (HashMap.Entry<String, Object> e : ((HashMap<String, Object>) entry.getValue()).entrySet()) {
setField(SettingsManager.GeneralSettings, e.getKey(), e.getValue());
setField(SettingsManager.generalSettings, e.getKey(), e.getValue());
}
SettingsManager.saveSettings();
sendFullSettings();
@@ -182,8 +178,8 @@ public class ServerHandler {
private void setField(Object obj, String fieldName, Object value) {
try {
if (obj instanceof Camera) {
var cam = (Camera)obj;
if (obj instanceof USBCamera) {
var cam = (USBCamera)obj;
if (fieldName.equals("driverBrightness")) {
cam.setDriverBrightness((Integer)value);
} else if (fieldName.equals("driverExposure")) {
@@ -234,12 +230,12 @@ public class ServerHandler {
private static HashMap<String, Object> getOrdinalSettings() {
HashMap<String, Object> tmp = new HashMap<>();
tmp.put("teamNumber", SettingsManager.GeneralSettings.teamNumber);
tmp.put("connectionType", SettingsManager.GeneralSettings.connectionType.ordinal());
tmp.put("ip", SettingsManager.GeneralSettings.ip);
tmp.put("gateway", SettingsManager.GeneralSettings.gateway);
tmp.put("netmask", SettingsManager.GeneralSettings.netmask);
tmp.put("hostname", SettingsManager.GeneralSettings.hostname);
tmp.put("teamNumber", SettingsManager.generalSettings.teamNumber);
tmp.put("connectionType", SettingsManager.generalSettings.connectionType.ordinal());
tmp.put("ip", SettingsManager.generalSettings.ip);
tmp.put("gateway", SettingsManager.generalSettings.gateway);
tmp.put("netmask", SettingsManager.generalSettings.netmask);
tmp.put("hostname", SettingsManager.generalSettings.hostname);
return tmp;
}