finished color picker in the ui

This commit is contained in:
ori agranat
2019-12-03 00:28:36 +02:00
parent 92aed5696f
commit b4e4f7b57c
4 changed files with 186 additions and 268 deletions

View File

@@ -1,65 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_12">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" 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: 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: 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.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" />
<orderEntry type="library" name="Maven: com.google.code.gson:gson:2.8.5" level="project" />
<orderEntry type="library" name="Maven: org.msgpack:msgpack-core:0.8.18" level="project" />
<orderEntry type="library" name="Maven: org.msgpack:jackson-dataformat-msgpack:0.8.18" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.9" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.10.0.pr1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.10.0.pr1" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.10.0.pr1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-java:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:linuxaarch64bionic:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:linuxraspbian:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:linuxx86-64:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:osxx86-64:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cscore:cscore-jni:windowsx86-64:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.cameraserver:cameraserver-java:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-java:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:osxx86-64:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxraspbian:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:linuxx86-64:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.ntcore:ntcore-jni:windowsx86-64:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.wpiutil:wpiutil-java:2019.4.1-213-g56d782b" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-java:3.4.7-1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:linuxaarch64bionic:3.4.7-1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:linuxraspbian:3.4.7-1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:linuxx86-64:3.4.7-1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:osxx86-64:3.4.7-1" level="project" />
<orderEntry type="library" name="Maven: edu.wpi.first.thirdparty.frc2020.opencv:opencv-jni:windowsx86-64:3.4.7-1" level="project" />
</component>
</module>

View File

@@ -0,0 +1,113 @@
var canvas = undefined;
var image = undefined;
function initColorPicker() {
canvas = document.createElement('canvas');
image = document.getElementById('CameraStream');
canvas.width = image.width;
canvas.height = image.height;
}
function colorPickerClick(event, currentFunction, currentRange) {
let rect = image.getBoundingClientRect();
let x = Math.round(event.clientX - rect.left);
let y = Math.round(event.clientY - rect.top);
let context = canvas.getContext('2d');
context.drawImage(image, 0, 0, image.width, image.height);
let pixelData = context.getImageData(x, y, 1, 1).data;
if (currentFunction !== undefined) {
return currentFunction(pixelData, currentRange);
}
}
function eyeDrop(pixel) {
let hsv = RGBtoHSV(pixel);
let range = createRange([hsv]);
range = widenRange(range);
return range
}
function expand(pixel, currentRange) {
let hsv = RGBtoHSV(pixel);
let widenHSV = widenRange([[].concat(hsv), hsv]);
return createRange(currentRange.concat(widenHSV));
}
function shrink(pixel, currentRange) {
let hsv = RGBtoHSV(pixel);
let widenHSV = widenRange([[].concat(hsv), hsv]);
if (!shrinkRange(currentRange, widenHSV[0]))
shrinkRange(currentRange, widenHSV[1]);
return currentRange
}
function RGBtoHSV(numbers) {
let r = numbers[0],
g = numbers[1],
b = numbers[2];
r = r / 255;
g = g / 255;
b = b / 255;
let minRGB = Math.min(r, Math.min(g, b));
let maxRGB = Math.max(r, Math.max(g, b));
let d = (r === minRGB) ? g - b : ((b === minRGB) ? r - g : b - r);
let h = (r === minRGB) ? 3 : ((b === minRGB) ? 1 : 5);
let H = 30 * (h - d / (maxRGB - minRGB));
let S = 255 * (maxRGB - minRGB) / maxRGB;
let V = 255 * maxRGB;
if (isNaN(H))
H = 0;
if (isNaN(S))
S = 0;
if (isNaN(V))
V = 0;
return [Math.round(H), Math.round(S), Math.round(V)];
}
function createRange(HSVColors) {
let range = [[], []];
for (var i = 0; i < 3; i++) {
range[0][i] = HSVColors[0][i];
range[1][i] = HSVColors[0][i];
for (var j = HSVColors.length - 1; j >= 0; j--) {
range[0][i] = Math.min(HSVColors[j][i], range[0][i]);
range[1][i] = Math.max(HSVColors[j][i], range[1][i]);
}
}
return range;//[[Hmin,Smin,Vmin],[Hmax,Smax,Vmax]]
}
function widenRange(range) {
let expanded = [[], []];
for (let i = 0; i < 3; i++) {
//Expanding the range by 10
expanded[0][i] = Math.max(0, range[0][i] - 10);
expanded[1][i] = Math.min(255, range[1][i] + 10);
}
expanded[1][0] = Math.min(180, expanded[1][0]);//h is up to 180
return expanded;
}
function shrinkRange(range, color) {
let inside = true;
for (let i = 0; i < color.length && inside; i++) {
if (!(range[0][i] <= color[i] <= range[1][i]))
inside = false;
}
if (inside) {
for (let j = 0; j < color.length; j++) {
if (color[j] - range[0][j] < range[1][j] - color[j])
range[0][j] = Math.min(range[0][j] + 10, range[1][j]);//shrink from min side
else
range[1][j] = Math.max(range[1][j] - 10, range[0][j]);//shrink from max side
}
}
return inside;//returns if color is inside or not
}
export default {initColorPicker, colorPickerClick, eyeDrop, expand, shrink}

View File

@@ -85,7 +85,7 @@
<div style="padding-left:30px">
<keep-alive>
<!-- vision component -->
<component v-model="pipeline" :is="selectedComponent" @update="$emit('save')"/>
<component v-model="pipeline" :is="selectedComponent" ref="component" @update="$emit('save')"/>
</keep-alive>
</div>
</v-col>
@@ -100,7 +100,7 @@
</v-tabs>
<!-- camera image stream -->
<div class="videoClass">
<img id="CameraStream" v-if="cameraList.length > 0" :src="streamAddress" crossorigin="Anonymous"/>
<img id="CameraStream" v-if="cameraList.length > 0" :src="streamAddress" @click="onImageClick" crossorigin="Anonymous"/>
<span v-else>No Cameras Are connected</span>
<h5 id="Point">{{point}}</h5>
</div>
@@ -155,6 +155,9 @@
CVinput
},
methods: {
onImageClick(event){
this.$refs.component.onClick(event);
},
toCameraNameChange() {
this.newCameraName = this.cameraList[this.currentCameraIndex];
this.isCameraNameEdit = true;

View File

@@ -1,51 +1,52 @@
<template>
<div v-on:camera-loaded="init">
<div>
<CVrangeSlider v-model="value.hue" name="Hue" :min="0" :max="180" @input="handleData('hue')"/>
<CVrangeSlider v-model="value.saturation" name="Saturation" :min="0" :max="255" @input="handleData('saturation')"/>
<CVrangeSlider v-model="value.saturation" name="Saturation" :min="0" :max="255"
@input="handleData('saturation')"/>
<CVrangeSlider v-model="value.value" name="Value" :min="0" :max="255" @input="handleData('value')"/>
<v-divider color="darkgray "/>
<v-btn style="margin: 20px;" tile color="#4baf62" @click="setMode(1)">
<v-icon>colorize</v-icon>
Eye drop
</v-btn>
<v-btn style="margin: 20px;" tile color="#4baf62" @click="setMode(2)">
<v-icon>add</v-icon>
Expand Selection
</v-btn>
<v-btn style="margin: 20px;" tile color="#4baf62" @click="setMode(3)">
<v-divider color="darkgray " style="margin-top: 5px"/>
<v-btn style="margin: 20px;" tile color="#4baf62" @click="setFunction(1)" small>
<v-icon>colorize</v-icon>
Eye drop
</v-btn>
<v-btn style="margin: 20px;" tile color="#4baf62" @click="setFunction(2)" small>
<v-icon>add</v-icon>
Expand Selection
</v-btn>
<v-btn style="margin: 20px;" tile color="#4baf62" @click="setFunction(3)" small>
<v-icon>remove</v-icon>
Shrink Selection
</v-btn>
<!-- <CVswitch v-model="driverState.isDriver" name="Driver Mode" @input="sendDriverMode"/> -->
<v-divider color="darkgray "/>
<CVswitch v-model="value.erode" name="Erode" @input="handleData('erode')"/>
<CVswitch v-model="value.dilate" name="Dilate" @input="handleData('dilate')"/>
<canvas id="canvas" style="display:none;" />
</div>
</template>
<script>
import CVrangeSlider from '../../components/cv-range-slider'
import CVswitch from '../../components/cv-switch'
import CVrangeSlider from '../../components/cv-range-slider'
import CVswitch from '../../components/cv-switch'
export default {
name: 'Threshold',
props:['value'],
components:{
props: ['value'],
components: {
CVrangeSlider,
CVswitch
},
data() {
return {
mode:0,//0 none,1 eyedrop, 2 expand,3 shrink
currentFunction: undefined,
colorPicker: undefined,
currentBinaryState: 0
}
},
computed: {
computed: {
pipeline: {
get() {
return this.$store.state.pipeline;
}
},
},
driverState: {
get() {
return this.$store.state.driverMode;
@@ -53,197 +54,63 @@ import CVswitch from '../../components/cv-switch'
set(val) {
this.$store.commit("driverMode", val);
}
}
}
},
methods:{
init()
{
console.log("init");
let img = document.getElementById('CameraStream');
img.crossOrigin = 'Anonymous';
img.setAttribute('crossOrigin', '');
let x,y;
let ref = this;
img.addEventListener('click', function (evt) {
let rect = img.getBoundingClientRect();
x = Math.round(evt.clientX - rect.left);
y = Math.round(evt.clientY - rect.top);
let canvas = document.getElementById('canvas');
canvas.width = img.width;
canvas.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
let pixelData = canvas.getContext('2d').getImageData(x, y, 1, 1).data;//Creating a canvas to get the pixel color, i wish there was a better way to do it
switch (ref.mode)
{
case 1: ref.eyeDrop(pixelData);break;
case 2: ref.expand(pixelData);break;
case 3: ref.shrink(pixelData);break;
}
});
},
eyeDrop(pixel) {
console.log("eye droppping on "+pixel);
let hsv = this.RGBtoHSV(pixel);
let range = this.createRange([hsv]);
range = this.widenRange(range);
this.setRange(range);
this.setMode(0);
methods: {
onClick(event) {
let hsvArray = this.colorPicker.colorPickerClick(event, this.currentFunction,
[[this.value.hue[0], this.value.saturation[0], this.value.value[0]], [this.value.hue[1], this.value.saturation[1], this.value.value[1]]]);
this.currentFunction = undefined;
this.value.hue = [hsvArray[0][0], hsvArray[1][0]];
this.value.saturation = [hsvArray[0][1], hsvArray[1][1]];
this.value.value = [hsvArray[0][2], hsvArray[1][2]];
this.value.isBinary = this.currentBinaryState;
let msg = this.$msgPack.encode({
'hue': this.value.hue,
'saturation': this.value.saturation,
'value': this.value.value,
'isBinary': this.value.isBinary
});
this.$socket.send(msg);
this.$emit('update');
},
expand(pixel) {
console.log("expanding on "+pixel);
let hsv = this.RGBtoHSV(pixel);
let widenHSV = this.widenRange([[].concat(hsv),hsv]);
let range = this.createRange(this.getRange().concat(widenHSV));
this.setRange(range);
this.setMode(0);
},
shrink(pixel) {
let hsv = this.RGBtoHSV(pixel);
let widenHSV = this.widenRange([[].concat(hsv),hsv]);
let range = this.getRange();
if(!this.shrinkRange(range,widenHSV[0]))
this.shrinkRange(range,widenHSV[1]);
console.log(range);
this.setRange(range);
this.setMode(0);
},
//Sets driver mode on when m is not zero (aka while choosing a color)
setMode: function(m)
{
this.mode=m;
this.driverState.isDriver=(m!==0);
this.handleInput('driverMode', this.driverState);
this.$emit("update");
},
//----------------------------------------------
//Color utils
//numbers is an array of 3 rgb values, returns array for 3 hsv values
RGBtoHSV: function(numbers) {
let r = numbers[0],
g = numbers[1],
b = numbers[2];
r = r / 255;
g = g / 255;
b = b / 255;
let minRGB = Math.min(r, Math.min(g, b));
let maxRGB = Math.max(r, Math.max(g, b));
let d = (r == minRGB) ? g - b : ((b == minRGB) ? r - g : b - r);
let h = (r == minRGB) ? 3 : ((b == minRGB) ? 1 : 5);
let H = 30 * (h - d / (maxRGB - minRGB));
let S = 255 * (maxRGB - minRGB) / maxRGB;
let V = 255 * maxRGB;
if(isNaN(H))
H=0;
if(isNaN(S))
S=0;
if(isNaN(V))
V=0;
return [Math.round(H), Math.round(S), Math.round(V)];
},
rgbToHex: function(rgb) {
var hex = Number(rgb).toString(16);
if (hex.length < 2) {
hex = "0" + hex;
setFunction(index) {
this.currentBinaryState = this.value.isBinary;
if (this.currentBinaryState === true) {
this.value.isBinary = false;
this.handleData('isBinary')
}
return hex;
},
fullColorHex: function(color) {
var red = this.rgbToHex(color[0]);
var green = this.rgbToHex(color[1]);
var blue = this.rgbToHex(color[2]);
return red + green + blue;
},
//----------------------------------------------
//Range utils
createRange: function(HSVColors)
{
let range = [[],[]];
for (var i = 0; i < 3; i++) {
range[0][i]=HSVColors[0][i];
range[1][i]=HSVColors[0][i];
for (var j = HSVColors.length - 1; j >= 0; j--) {
range[0][i]=Math.min(HSVColors[j][i],range[0][i]);
range[1][i]=Math.max(HSVColors[j][i],range[1][i]);
}
switch (index) {
case 0:
this.currentFunction = undefined;
break;
case 1:
this.currentFunction = this.colorPicker.eyeDrop;
break;
case 2:
this.currentFunction = this.colorPicker.expand;
break;
case 3:
this.currentFunction = this.colorPicker.shrink;
break;
}
return range;//[[Hmin,Smin,Vmin],[Hmax,Smax,Vmax]]
},
//This function adds 10 extra units to each side of the sliders, not to be confued with the expand selection button
widenRange(range)
{
let expanded = [[],[]]
for (var i = 0; i < 3; i++) {
//Expanding the range by 10
expanded[0][i]=Math.max(0, range[0][i]-10);
expanded[1][i]=Math.min(255, range[1][i]+10);
}
expanded[1][0]=Math.min(180,expanded[1][0]);//h is up to 180
return expanded;
},
//If color in range then take the closer range value to color and set it to color plus or minus 10
//For example if hmax is 200 hmin is 100 and color's h is 120 range will become [130,200]
shrinkRange(range,color)
{
let inside = true;
for(let i =0;i<color.length&&inside;i++)
{
if(!(range[0][i]<=color[i]<=range[1][i]))
inside=false;
}
if(inside)
{
for(let j =0;j<color.length;j++){
if(color[j]-range[0][j]<range[1][j]-color[j])
range[0][j]=Math.min(range[0][j]+10,range[1][j])//shrink from min side
else
range[1][j]=Math.max(range[1][j]-10,range[0][j])//shrink from max side
}
}
console.log("range"+range);
return inside;//returns if color is inside or not
},
//applies the range to store
setRange(range)
{
this.value.hue = [range[0][0],range[1][0]];
this.handleData('hue');
this.value.saturation = [range[0][1],range[1][1]];
this.handleData('saturation');
this.value.value = [range[0][2],range[1][2]];
this.handleData('value');
},
//returns the current range in format [[Hmin,Smin,Vmin],[Hmax,Smax,Vmax]]
getRange(){
let a= this.value;
return [[a.hue[0],a.saturation[0],a.value[0]],[a.hue[1],a.saturation[1],a.value[1]]];
},
handleData(val){
this.handleInput(val,this.value[val]);
handleData(val) {
this.handleInput(val, this.value[val]);
this.$emit('update')
},
},
},
mounted: function()
{
let a = this.init;
window.onload = function() {
if(document.getElementById('CameraStream'))
a();//this.init();
mounted: function () {
const self = this;
this.colorPicker = require('../../plugins/ColorPicker').default;
window.addEventListener('load', function () {
self.colorPicker.initColorPicker();
})
}
}
}
</script>
<style lang="" scoped>
</style>