### features
- added auto install and update
- added calibration status and accuracy message
- added 2020 loading station pnp model

### bugs
- fixed solve pnp model upload 
- fixed solve pnp draw
This commit is contained in:
Matt
2020-01-28 10:44:52 -08:00
committed by oriagranat9
parent a0b89168b4
commit 515faa182f
28 changed files with 368 additions and 161 deletions

View File

@@ -54,20 +54,10 @@ workflows:
version: 2
release:
jobs:
- build_ui:
filters:
branches:
only:
- master
- dev
- build_ui
- build_jar:
requires:
- build_ui
filters:
branches:
only:
- master
- dev
- deploy:
requires:
- build_jar

View File

@@ -5,6 +5,12 @@
[9.819867, -17],
[19.625,0]
],
"2020 Loading Station": [
[-3.54,5.5],
[-3.54,-5.5],
[3.54,-5.5],
[3.54,5.5]
],
"2019 Dual Target": [
[-7.75, 3],
[-7.75, -3],

View File

@@ -17,10 +17,14 @@
<mini-map class="miniMapClass" :targets="targets" :horizontal-f-o-v="horizontalFOV"/>
</v-col>
<v-col>
<v-select v-model="selectedModel" :items="FRCtargets" item-text="name" item-value="data" dark color="#4baf62" item-color="green"/>
<v-select v-model="selectedModel" :items="FRCtargets" item-text="name" item-value="data" dark
color="#4baf62" item-color="green"/>
<v-btn small v-if="selectedModel !== null" @click="uploadPremade">Upload Premade</v-btn>
</v-col>
</v-row>
<v-snackbar v-model="snack" top :color="snackbar.color">
<span>{{snackbar.text}}</span>
</v-snackbar>
</div>
</template>
@@ -41,7 +45,12 @@
return {
is3D: false,
selectedModel: null,
FRCtargets: null
FRCtargets: null,
snackbar: {
color: "success",
text: ""
},
snack: false
}
},
methods: {
@@ -57,13 +66,50 @@
});
},
onParse(result) {
this.uploadModel(result.data);
if (result.data.length > 0) {
let data = [];
for (let item of result.data) {
let tmp = [];
tmp.push(Number(item[0]));
tmp.push(Number(item[1]));
if (isNaN(tmp[0]) || isNaN(tmp[1])) {
this.snackbar = {
color: "error",
text: "Error: cvs did parse correctly"
};
this.snack = true;
return;
}
data.push(tmp);
}
this.uploadModel(data);
} else {
this.snackbar = {
color: "error",
text: "Error: cvs did not contain any data"
};
this.snack = true;
}
},
uploadPremade() {
this.uploadModel(this.selectedModel);
},
uploadModel(model) {
this.axios.post("http://" + this.$address + "/api/vision/pnpModel", model);
this.axios.post("http://" + this.$address + "/api/vision/pnpModel", model).then((response) => {
this.snackbar = {
color: "success",
text: "File uploaded successfully"
};
this.snack = true;
}).catch((error) => {
this.snackbar = {
color: "error",
text: "An error occurred"
};
this.snack = true;
})
}
},
computed: {

View File

@@ -11,7 +11,7 @@
<component :is="selectedComponent" @update="$emit('save')"/>
</div>
</v-col>
<v-col class="colsClass" v-show="selectedTab === 1 || selectedTab === 2">
<v-col class="colsClass" v-show="selectedTab === 1">
<div class="videoClass">
<img :src="streamAddress" alt="Camera Stream">
</div>
@@ -34,18 +34,13 @@
data() {
return {
selectedTab: 0,
tabList:[General, Cameras]
}
},
computed: {
selectedComponent: {
get() {
switch (this.selectedTab) {
case 0:
return "General";
case 1:
return "Cameras";
}
return "";
return this.tabList[this.selectedTab];
}
},
streamAddress: {

View File

@@ -48,9 +48,21 @@
<span>Snapshot Amount: {{snapshotAmount}}</span>
</v-col>
</v-row>
<div v-if="isCalibrating">
<v-checkbox v-model="isAdvanced" label="Advanced Menu" dark/>
<div v-if="isAdvanced">
<CVslider name="Exposure" v-model="pipeline.exposure" :min="0" :max="100"
@input="handleData('exposure')"/>
<CVslider name="Brightness" v-model="pipeline.brightness" :min="0" :max="100"
@input="handleData('brightness')"/>
<CVslider name="Gain" v-if="pipeline.gain !== -1" v-model="pipeline.gain" :min="0" :max="100"
@input="handleData('gain')"/>
<CVselect name="FPS" v-model="pipeline.videoModeIndex" :list="stringFpsList" @input="changeFps"/>
</div>
</div>
</div>
<v-snackbar v-model="snack">
<span>Calibration Failed</span>
<v-snackbar v-model="snack" top :color="snackbar.color">
<span>{{snackbar.text}}</span>
</v-snackbar>
</div>
</template>
@@ -58,12 +70,14 @@
<script>
import CVselect from '../../components/cv-select'
import CVnumberinput from '../../components/cv-number-input'
import CVslider from '../../components/cv-slider'
export default {
name: 'CameraSettings',
components: {
CVselect,
CVnumberinput
CVnumberinput,
CVslider
},
data() {
return {
@@ -77,13 +91,24 @@
text: "Cancel Calibration",
color: "red"
},
snackbar: {
color: "success",
text: ""
},
squareSize: 1.0,
snapshotAmount: 0,
hasEnough: false,
snack: false
snack: false,
isAdvanced: false
}
},
methods: {
handleData(val) {
this.handleInput(val, this.pipeline[val]);
},
changeFps() {
this.handleInput('videoModeIndex', this.filteredFpsList[this.pipeline['videoModeIndex']]['actualIndex']);
},
sendCameraSettings() {
const self = this;
this.axios.post("http://" + this.$address + "/api/settings/camera", this.cameraSettings).then(
@@ -129,9 +154,13 @@
let connection_string = "/api/settings/endCalibration";
let data = {};
data['squareSize'] = this.squareSize;
self.axios.post("http://" + this.$address + connection_string, data).then(
function (response) {
if (response.status === 500) {
self.axios.post("http://" + this.$address + connection_string, data).then((response) => {
if (response.status === 200) {
self.snackbar = {
color: "success",
text: "calibration successful. \n" +
"accuracy: " + response.data['accuracy'].toFixed(5)
};
self.snack = true;
}
self.isCalibrating = false;
@@ -141,7 +170,19 @@
self.cancellationModeButton.text = "Cancel Calibration";
self.cancellationModeButton.color = "red";
}
);
).catch(() => {
self.snackbar = {
color: "error",
text: "calibration failed"
};
self.snack = true;
self.isCalibrating = false;
self.hasEnough = false;
self.snapshotAmount = 0;
self.calibrationModeButton.text = "Start Calibration";
self.cancellationModeButton.text = "Cancel Calibration";
self.cancellationModeButton.color = "red";
});
}
},
computed: {
@@ -186,6 +227,27 @@
return tmp_list;
}
},
filteredFpsList() {
let selectedRes = this.$store.state.resolutionList[this.resolutionIndex];
let tmpList = [];
for (let i in this.$store.state.resolutionList) {
let res = JSON.parse(JSON.stringify(this.$store.state.resolutionList[i]));
if (!tmpList.some(e => e['fps'] === res['fps'])) {
if (res.width === selectedRes.width && res.height === selectedRes.height) {
res['actualIndex'] = parseInt(i);
tmpList.push(res);
}
}
}
return tmpList;
},
stringFpsList() {
let tmp = [];
for (let i of this.filteredFpsList) {
tmp.push(i['fps']);
}
return tmp;
},
stringResolutionList: {
get() {
let tmp = [];
@@ -203,7 +265,9 @@
this.$store.commit('cameraSettings', value);
}
},
pipeline() {
return this.$store.state.pipeline
}
}
}
</script>

View File

@@ -1,5 +1,9 @@
<template>
<div>
<div style="margin-top: 15px">
<span>General Settings:</span>
<v-divider color="white"></v-divider>
</div>
<CVnumberinput v-model="settings.teamNumber" name="Team Number"/>
<CVradio v-model="settings.connectionType" :list="['DHCP','Static']"/>
<v-divider color="white"/>
@@ -9,6 +13,30 @@
<v-divider color="white"/>
<CVinput name="Hostname" v-model="settings.hostname"/>
<v-btn style="margin-top:10px" small color="#4baf62" @click="sendGeneralSettings">Save General Settings</v-btn>
<div style="margin-top: 20px">
<span>Install or Update:</span>
<v-divider color="white"></v-divider>
</div>
<div v-if="!isLoading">
<v-row dense align="center">
<v-col :cols="3">
<span>Choose a newer version: </span>
</v-col>
<v-col :cols="6">
<v-file-input accept=".jar" dark v-model="file"></v-file-input>
</v-col>
</v-row>
<v-btn small @click="installOrUpdate">{{fileUploadText}}</v-btn>
</div>
<div v-else style="text-align: center; margin-top: 20px">
<v-progress-circular color="white" :indeterminate="true" size="32"
width="4"></v-progress-circular>
<br>
<span>Please wait this may take a while</span>
</div>
<v-snackbar v-model="snack" top :color="snackbar.color">
<span>{{snackbar.text}}</span>
</v-snackbar>
</div>
</template>
@@ -25,26 +53,64 @@
CVinput
},
data() {
return {}
return {
file: undefined,
snackbar: {
color: "success",
text: ""
},
snack: false,
isLoading: false
}
},
methods: {
sendGeneralSettings() {
const self = this;
this.axios.post("http://" + this.$address + "/api/settings/general", this.settings).then(
function (response) {
if (response.status === 200){
if (response.status === 200) {
self.$store.state.saveBar = true;
}
}
)
},
installOrUpdate() {
let formData = new FormData();
formData.append('file', this.file);
if (this.file !== undefined) {
this.isLoading = true;
}
this.axios.post("http://" + this.$address + "/api/install", formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then(() => {
this.snackbar = {
color: "success",
text: "Installation successful"
};
this.isLoading = false;
this.snack = true;
}).catch(error => {
this.snackbar = {
color: "error",
text: error.response.data
};
this.isLoading = false;
this.snack = true;
})
}
},
computed: {
isDisabled() {
if (this.settings.connectionType === 0) {
return true;
fileUploadText() {
if (this.file !== undefined) {
return "Install and update"
} else {
return "Install current version"
}
return false;
},
isDisabled() {
return this.settings.connectionType === 0;
},
settings: {
get() {

View File

@@ -7,33 +7,32 @@
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/testimages" type="java-resource" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: io.javalin:javalin:3.4.1" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.31" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.3.31" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.31" level="project" />
<orderEntry type="library" name="Maven: io.javalin:javalin:3.7.0" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.61" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib:1.3.61" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-common:1.3.61" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains:annotations:13.0" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.26" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-server:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.61" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.28" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-server:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: javax.servlet:javax.servlet-api:3.1.0" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-webapp:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-servlet:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-security:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-server:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-servlet:9.4.19.v20190610" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-http:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-util:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-io:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-webapp:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-xml:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-servlet:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-security:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-server:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-common:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-api:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-client:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty:jetty-client:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.eclipse.jetty.websocket:websocket-servlet:9.4.25.v20191220" level="project" />
<orderEntry type="library" name="Maven: org.json:json:20190722" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-nop:1.7.26" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-math3:3.6.1" level="project" />

View File

@@ -6,7 +6,7 @@
<groupId>org.chameleon-vision.main</groupId>
<artifactId>chameleon-vision</artifactId>
<version>2.2-RELEASE</version>
<version>2.3-RELEASE</version>
<build>
<plugins>
<!--setup for java jdk 12-->
@@ -63,7 +63,7 @@
<dependency>
<groupId>io.javalin</groupId>
<artifactId>javalin</artifactId>
<version>3.4.1</version>
<version>RELEASE</version>
</dependency>
<!--org.json from saving and loading data-->

View File

@@ -4,11 +4,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class JsonMat {

View File

@@ -4,10 +4,6 @@ import com.chameleonvision.Debug;
import com.chameleonvision.util.ShellExec;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
public class ScriptEvent {
private static final ShellExec executor = new ShellExec(true, true);

View File

@@ -4,10 +4,28 @@ import edu.wpi.cscore.VideoMode;
import org.opencv.core.Scalar;
import java.awt.*;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
public class Helpers {
private static final String kServicePath = "/etc/systemd/system/chameleonVision.service";
private static final String kServiceString = "[Unit]\n" +
"Description=chameleon vision\n" +
"\n" +
"[Service]\n" +
"ExecStart=/usr/bin/java -jar %s \n" +
"StandardOutput=file:/var/log/something.out.txt\n" +
"StandardError=file:/var/log/something.err.txt\n" +
"Type=simple\n" +
"WorkingDirectory=/usr/local/bin\n" +
"\n" +
"[Install]\n" +
"WantedBy=multi-user.target\n" +
"\n";
private Helpers() {
}
@@ -17,9 +35,19 @@ public class Helpers {
public static HashMap VideoModeToHashMap(VideoMode videoMode) {
return new HashMap<String, Object>() {{
put("width", videoMode.width);
put("height", videoMode.height);
put("fps", videoMode.fps);
put("pixelFormat", videoMode.pixelFormat.toString());}};
put("width", videoMode.width);
put("height", videoMode.height);
put("fps", videoMode.fps);
put("pixelFormat", videoMode.pixelFormat.toString());
}};
}
public static void setService(Path filePath) throws IOException, InterruptedException {
String newService = String.format(kServiceString, filePath.toString());
Writer writer = new FileWriter(kServicePath, false);
writer.write(newService);
writer.close();
Process p = Runtime.getRuntime().exec("systemctl enable chameleonVision.service");
p.waitFor();
}
}

View File

@@ -1,7 +1,5 @@
package com.chameleonvision.util;
import com.chameleonvision.config.serializers.StandardCVPipelineSettingsDeserializer;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipelineSettings;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
import com.fasterxml.jackson.databind.json.JsonMapper;

View File

@@ -1,8 +1,5 @@
package com.chameleonvision.util;
import java.lang.Math;
import edu.wpi.first.wpiutil.math.Num;
import org.apache.commons.math3.util.FastMath;
public class MathHandler {

View File

@@ -4,17 +4,18 @@ import com.chameleonvision.Debug;
import com.chameleonvision.config.CameraCalibrationConfig;
import com.chameleonvision.config.CameraConfig;
import com.chameleonvision.config.ConfigManager;
import com.chameleonvision.config.FullCameraConfiguration;
import com.chameleonvision.networktables.NetworkTablesManager;
import com.chameleonvision.scripting.ScriptEventType;
import com.chameleonvision.scripting.ScriptManager;
import com.chameleonvision.config.FullCameraConfiguration;
import com.chameleonvision.util.LoopingRunnable;
import com.chameleonvision.util.MathHandler;
import com.chameleonvision.vision.camera.CameraStreamer;
import com.chameleonvision.vision.camera.USBCameraCapture;
import com.chameleonvision.vision.pipeline.*;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import com.chameleonvision.vision.pipeline.CVPipelineResult;
import com.chameleonvision.vision.pipeline.CVPipelineSettings;
import com.chameleonvision.vision.pipeline.PipelineManager;
import com.chameleonvision.vision.pipeline.impl.DriverVisionPipeline;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipelineSettings;
import com.chameleonvision.web.SocketHandler;
import com.fasterxml.jackson.core.JsonProcessingException;
@@ -25,11 +26,10 @@ import edu.wpi.first.wpilibj.geometry.Pose2d;
import edu.wpi.first.wpiutil.CircularBuffer;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.Mat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.stream.Collectors;

View File

@@ -5,7 +5,10 @@ import com.chameleonvision.config.CameraConfig;
import com.chameleonvision.config.ConfigManager;
import com.chameleonvision.vision.VisionManager;
import com.chameleonvision.vision.VisionProcess;
import com.chameleonvision.vision.pipeline.impl.*;
import com.chameleonvision.vision.pipeline.impl.Calibrate3dPipeline;
import com.chameleonvision.vision.pipeline.impl.DriverVisionPipeline;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipelineSettings;
import com.chameleonvision.web.SocketHandler;
import edu.wpi.cscore.VideoMode;
import edu.wpi.first.networktables.NetworkTableEntry;

View File

@@ -38,6 +38,7 @@ public class Calibrate3dPipeline extends CVPipeline<DriverVisionPipeline.DriverP
private TermCriteria criteria = new TermCriteria(3, 30, 0.001); //(Imgproc.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
private int captureCount = 0;
private double calibrationAccuracy = 0;
private boolean wantsSnapshot = false;
private double squareSizeInches;
@@ -129,7 +130,7 @@ public class Calibrate3dPipeline extends CVPipeline<DriverVisionPipeline.DriverP
List<Mat> tvecs = new ArrayList<>();
try {
Calib3d.calibrateCamera(objpoints, imgpoints, imageSize, cameraMatrix, distortionCoeffs, rvecs, tvecs);
calibrationAccuracy = Calib3d.calibrateCamera(objpoints, imgpoints, imageSize, cameraMatrix, distortionCoeffs, rvecs, tvecs);
} catch(Exception e) {
System.err.println("Camera calibration failed!");
initPipeline(cameraCapture);
@@ -162,4 +163,8 @@ public class Calibrate3dPipeline extends CVPipeline<DriverVisionPipeline.DriverP
public int getSnapshotCount() {
return captureCount + 1;
}
public double getCalibrationAccuracy(){
return calibrationAccuracy;
}
}

View File

@@ -10,7 +10,6 @@ import com.chameleonvision.vision.pipeline.pipes.Draw2dCrosshairPipe;
import com.chameleonvision.vision.pipeline.pipes.RotateFlipPipe;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.Mat;
import org.opencv.core.RotatedRect;
import java.util.List;

View File

@@ -9,13 +9,13 @@ import com.chameleonvision.vision.pipeline.CVPipelineResult;
import com.chameleonvision.vision.pipeline.pipes.*;
import edu.wpi.first.wpilibj.geometry.Pose2d;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.core.*;
import java.awt.*;
import java.util.List;
import static com.chameleonvision.vision.pipeline.impl.StandardCVPipeline.*;
import static com.chameleonvision.vision.pipeline.impl.StandardCVPipeline.StandardCVPipelineResult;
@SuppressWarnings("WeakerAccess")
public class StandardCVPipeline extends CVPipeline<StandardCVPipelineResult, StandardCVPipelineSettings> {
@@ -135,10 +135,11 @@ public class StandardCVPipeline extends CVPipeline<StandardCVPipelineResult, Sta
if (solvePNPPipe == null)
solvePNPPipe = new SolvePNPPipe(settings, cameraCapture.getCurrentCalibrationData(), cameraCapture.getProperties().getTilt());
if (drawSolvePNPPipe == null)
drawSolvePNPPipe = new DrawSolvePNPPipe(cameraCapture.getCurrentCalibrationData());
drawSolvePNPPipe = new DrawSolvePNPPipe(settings, cameraCapture.getCurrentCalibrationData());
solvePNPPipe.setConfig(settings, cameraCapture.getCurrentCalibrationData(), cameraCapture.getProperties().getTilt());
drawSolvePNPPipe.setConfig(cameraCapture.getCurrentCalibrationData());
drawSolvePNPPipe.setConfig(settings);
}

View File

@@ -1,16 +1,17 @@
package com.chameleonvision.vision.pipeline.pipes;
import com.chameleonvision.vision.camera.CaptureStaticProperties;
import com.chameleonvision.vision.enums.CalibrationMode;
import com.chameleonvision.vision.enums.TargetOrientation;
import com.chameleonvision.vision.enums.TargetRegion;
import com.chameleonvision.vision.pipeline.Pipe;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import com.chameleonvision.vision.enums.CalibrationMode;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.math3.util.FastMath;
import org.opencv.core.Point;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
public class Collect2dTargetsPipe implements Pipe<Pair<List<StandardCVPipeline.TrackedTarget>, CaptureStaticProperties>, List<StandardCVPipeline.TrackedTarget>> {

View File

@@ -1,7 +1,7 @@
package com.chameleonvision.vision.pipeline.pipes;
import com.chameleonvision.vision.camera.CaptureStaticProperties;
import com.chameleonvision.util.Helpers;
import com.chameleonvision.vision.camera.CaptureStaticProperties;
import com.chameleonvision.vision.pipeline.Pipe;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import org.apache.commons.lang3.tuple.Pair;

View File

@@ -4,6 +4,7 @@ import com.chameleonvision.config.CameraCalibrationConfig;
import com.chameleonvision.util.Helpers;
import com.chameleonvision.vision.pipeline.Pipe;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipelineSettings;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.calib3d.Calib3d;
import org.opencv.core.*;
@@ -11,59 +12,44 @@ import org.opencv.core.Point;
import org.opencv.imgproc.Imgproc;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class DrawSolvePNPPipe implements Pipe<Pair<Mat, List<StandardCVPipeline.TrackedTarget>>, Mat> {
private MatOfPoint3f boxCornerMat = new MatOfPoint3f();
private MatOfPoint tempMatOfPoints = new MatOfPoint();
public Scalar green = Helpers.colorToScalar(Color.GREEN);
public Scalar blue = Helpers.colorToScalar(Color.BLUE);
public Scalar red = Helpers.colorToScalar(Color.RED);
public Scalar orange = Helpers.colorToScalar(Color.orange);
public DrawSolvePNPPipe(CameraCalibrationConfig settings) {
public DrawSolvePNPPipe(StandardCVPipelineSettings standardCVPipelineSettings, CameraCalibrationConfig settings) {
setConfig(settings);
// setObjectBox(14.5, 6, 2);
set2020Box();
setBox(standardCVPipelineSettings.targetCornerMat);
}
public void setObjectBox(double targetWidth, double targetHeight, double targetDepth) {
// implementation from 5190 Green Hope Falcons
private void setBox(MatOfPoint3f mat) {
boxCornerMat.release();
boxCornerMat = new MatOfPoint3f(
new Point3(-targetWidth/2d, -targetHeight/2d, 0),
new Point3(-targetWidth/2d, targetHeight/2d, 0),
new Point3(targetWidth/2d, targetHeight/2d, 0),
new Point3(targetWidth/2d, -targetHeight/2d, 0),
new Point3(-targetWidth/2d, -targetHeight/2d, -targetDepth),
new Point3(-targetWidth/2d, targetHeight/2d, -targetDepth),
new Point3(targetWidth/2d, targetHeight/2d, -targetDepth),
new Point3(targetWidth/2d, -targetHeight/2d, -targetDepth)
);
var list = mat.toList();
var auxList = list.stream().map(it -> new Point3(it.x, it.y, it.z - 6)).collect(Collectors.toList());
var finalList = new ArrayList<>(list);
finalList.addAll(auxList);
boxCornerMat.fromList(finalList);
}
public void set2020Box() {
boxCornerMat.release();
boxCornerMat = new MatOfPoint3f(
new Point3(-19.625, 0, 0),
new Point3(-9.819867, -17, 0),
new Point3(9.819867, -17, 0),
new Point3(19.625, 0, 0),
new Point3(-19.625, 0, -6),
new Point3(-9.819867, -17, -6),
new Point3(9.819867, -17, -6),
new Point3(19.625, 0, -6)
);
public void setConfig(StandardCVPipelineSettings settings) {
setBox(settings.targetCornerMat);
}
private Mat cameraMatrix = new Mat();
private MatOfDouble distortionCoefficients = new MatOfDouble();
public void setConfig(CameraCalibrationConfig config) {
if(config == null) {
if (config == null) {
System.err.println("got passed a null config! Returning...");
return;
}
@@ -82,17 +68,17 @@ public class DrawSolvePNPPipe implements Pipe<Pair<Mat, List<StandardCVPipeline.
long processStartNanos = System.nanoTime();
var image = targets.getLeft();
for(var it : targets.getRight()) {
for (var it : targets.getRight()) {
try {
Calib3d.projectPoints(boxCornerMat, it.rVector, it.tVector, this.cameraMatrix, this.distortionCoefficients, imagePoints, new Mat() , 0);
Calib3d.projectPoints(boxCornerMat, it.rVector, it.tVector, this.cameraMatrix, this.distortionCoefficients, imagePoints, new Mat(), 0);
} catch (Exception e) {
e.printStackTrace();
}
var pts = imagePoints.toList();
// draw left and right targets if possible
if(it.leftRightDualTargetPair != null) {
if (it.leftRightDualTargetPair != null) {
var left = it.leftRightDualTargetPair.getLeft();
var right = it.leftRightDualTargetPair.getRight();
Imgproc.rectangle(image, left.tl(), left.br(), new Scalar(200, 200, 0), 4);
@@ -101,7 +87,7 @@ public class DrawSolvePNPPipe implements Pipe<Pair<Mat, List<StandardCVPipeline.
// draw poly dp
var list = it.approxPoly.toList();
for(int i = 0; i < list.size(); i++) {
for (int i = 0; i < list.size(); i++) {
var next = (i == list.size() - 1) ? list.get(0) : list.get(i + 1);
Imgproc.line(image, list.get(i), next, red, 2);
}
@@ -110,7 +96,7 @@ public class DrawSolvePNPPipe implements Pipe<Pair<Mat, List<StandardCVPipeline.
Imgproc.circle(image, it.minAreaRect.center, 5, red);
// draw corners
for(int i = 0; i < it.imageCornerPoints.rows(); i++) {
for (int i = 0; i < it.imageCornerPoints.rows(); i++) {
var point = new Point(it.imageCornerPoints.get(i, 0));
Imgproc.circle(image, point, 4, green, 5);
}

View File

@@ -1,7 +1,7 @@
package com.chameleonvision.vision.pipeline.pipes;
import com.chameleonvision.vision.camera.CaptureStaticProperties;
import com.chameleonvision.util.MathHandler;
import com.chameleonvision.vision.camera.CaptureStaticProperties;
import com.chameleonvision.vision.pipeline.Pipe;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.MatOfPoint;

View File

@@ -7,7 +7,6 @@ import com.chameleonvision.vision.pipeline.Pipe;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.imgproc.Imgproc;
import org.opencv.imgproc.Moments;

View File

@@ -6,7 +6,6 @@ import com.chameleonvision.vision.pipeline.Pipe;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.commons.math3.util.FastMath;
import org.opencv.core.*;
import java.util.ArrayList;
import java.util.Comparator;

View File

@@ -2,9 +2,7 @@ package com.chameleonvision.vision.pipeline.pipes;
import com.chameleonvision.vision.pipeline.Pipe;
import org.apache.commons.lang3.tuple.Pair;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.imgproc.Imgproc;
import java.util.ArrayList;

View File

@@ -1,29 +1,31 @@
package com.chameleonvision.web;
import com.chameleonvision.Exceptions.DuplicatedKeyException;
import com.chameleonvision.Main;
import com.chameleonvision.config.ConfigManager;
import com.chameleonvision.network.NetworkIPMode;
import com.chameleonvision.networktables.NetworkTablesManager;
import com.chameleonvision.util.Helpers;
import com.chameleonvision.util.Platform;
import com.chameleonvision.util.ProgramDirectoryUtilities;
import com.chameleonvision.vision.VisionManager;
import com.chameleonvision.vision.VisionProcess;
import com.chameleonvision.vision.camera.USBCameraCapture;
import com.chameleonvision.vision.pipeline.CVPipelineSettings;
import com.chameleonvision.vision.pipeline.PipelineManager;
import com.chameleonvision.vision.pipeline.impl.Calibrate3dPipeline;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipelineSettings;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import edu.wpi.cscore.VideoMode;
import edu.wpi.first.wpilibj.geometry.Rotation2d;
import io.javalin.http.Context;
import io.javalin.http.Handler;
import org.apache.commons.math3.ml.neuralnet.Network;
import org.opencv.core.Point;
import io.javalin.http.UploadedFile;
import org.opencv.core.Point3;
import java.io.IOException;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -174,33 +176,67 @@ public class RequestHandler {
System.out.println("Finishing Cal");
if (pipeManager.calib3dPipe.hasEnoughSnapshots()) {
if (pipeManager.calib3dPipe.tryCalibration()) {
HashMap<String, Double> tmp = new HashMap<String, Double>();
tmp.put("accuracy", pipeManager.calib3dPipe.getCalibrationAccuracy());
ctx.json(tmp);
ctx.status(200);
} else {
System.err.println("CALFAIL");
ctx.status(500);
}
} else {
ctx.status(201);
}
pipeManager.setCalibrationMode(false);
ctx.status(200);
}
public static void onPnpModel(Context ctx) throws JsonProcessingException {
//noinspection unchecked
List<List<Number>> points = kObjectMapper.readValue(ctx.body(), List.class);
// each entry should be an xy pair
var pointsList = new ArrayList<Point3>();
for (List<Number> point : points) {
double x, y;
x = point.get(0).doubleValue();
y = point.get(1).doubleValue();
var pointToAdd = new Point3(x, y, 0.0);
pointsList.add(pointToAdd);
try {
// each entry should be an xy pair
var pointsList = new ArrayList<Point3>();
for (List<Number> point : points) {
double x, y;
x = point.get(0).doubleValue();
y = point.get(1).doubleValue();
var pointToAdd = new Point3(x, y, 0.0);
pointsList.add(pointToAdd);
}
System.out.println(pointsList.toString());
if (VisionManager.getCurrentUIVisionProcess().pipelineManager.getCurrentPipeline().settings instanceof StandardCVPipelineSettings) {
var settings = (StandardCVPipelineSettings) VisionManager.getCurrentUIVisionProcess().pipelineManager.getCurrentPipeline().settings;
settings.targetCornerMat.fromList(pointsList);
}
} catch (Exception e) {
ctx.status(500);
}
System.out.println(pointsList.toString());
if (VisionManager.getCurrentUIVisionProcess().pipelineManager.getCurrentPipeline().settings instanceof StandardCVPipelineSettings) {
var settings = (StandardCVPipelineSettings) VisionManager.getCurrentUIVisionProcess().pipelineManager.getCurrentPipeline().settings;
settings.targetCornerMat.fromList(pointsList);
}
public static void onInstallOrUpdate(Context ctx) {
Platform p = Platform.getCurrentPlatform();
try {
if (p == Platform.LINUX_RASPBIAN || p == Platform.LINUX_64) {
UploadedFile file = ctx.uploadedFile("file");
Path filePath;
if (file != null) {
filePath = Paths.get(ProgramDirectoryUtilities.getProgramDirectory(), file.getFilename());
File target = new File(filePath.toString());
OutputStream stream = new FileOutputStream(target);
file.getContent().transferTo(stream);
stream.close();
} else {
filePath = Paths.get(new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI()).getPath()); // quirk to get the current file directory
}
Helpers.setService(filePath);
ctx.status(200);
} else {
ctx.result("Only Linux Platforms Support this feature");
ctx.status(500);
}
} catch (Exception e) {
ctx.result(e.toString());
ctx.status(500);
}
}
}

View File

@@ -35,6 +35,7 @@ public class Server {
app.post("/api/settings/snapshot", RequestHandler::onSnapshot);
app.post("/api/settings/endCalibration", RequestHandler::onCalibrationEnding);
app.post("/api/vision/pnpModel", RequestHandler::onPnpModel);
app.post("/api/install", RequestHandler::onInstallOrUpdate);
app.start(port);
}
}

View File

@@ -11,7 +11,6 @@ import com.chameleonvision.vision.enums.ImageRotationMode;
import com.chameleonvision.vision.enums.StreamDivisor;
import com.chameleonvision.vision.pipeline.CVPipeline;
import com.chameleonvision.vision.pipeline.impl.StandardCVPipeline;
import com.chameleonvision.vision.pipeline.CVPipelineSettings;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -26,7 +25,6 @@ import org.msgpack.jackson.dataformat.MessagePackFactory;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;
@@ -53,8 +51,8 @@ public class SocketHandler {
@SuppressWarnings("unchecked")
void onBinaryMessage(WsBinaryMessageContext context) throws Exception {
Map<String, Object> deserialized = objectMapper.readValue(ArrayUtils.toPrimitive(context.data()), new TypeReference<>() {
});
Map<String, Object> deserialized = objectMapper.readValue((byte[]) ArrayUtils.toPrimitive(context.data()),
new TypeReference<>(){});
for (Map.Entry<String, Object> entry : deserialized.entrySet()) {
try {
VisionProcess currentProcess = VisionManager.getCurrentUIVisionProcess();
@@ -266,11 +264,11 @@ public class SocketHandler {
tmp.put("streamDivisor", currentVisionProcess.cameraStreamer.getDivisor().ordinal());
tmp.put("resolution", currentVisionProcess.getCamera().getProperties().getCurrentVideoModeIndex());
tmp.put("tilt", currentVisionProcess.getCamera().getProperties().getTilt().getDegrees());
List<CameraCalibrationConfig.UICameraCalibrationConfig> calibrations = currentCamera.getAllCalibrationData().stream()
.map(CameraCalibrationConfig.UICameraCalibrationConfig::new).collect(Collectors.toList());
tmp.put("calibration", calibrations);
return tmp;
}