2020-05-25 22:46:44 +03:00
< template >
2020-06-26 04:39:14 -07:00
< div >
2020-07-13 19:34:31 -07:00
< v-container
class = "pa-3"
fluid
>
< v-row
no - gutters
align = "center"
justify = "center"
2020-06-26 04:39:14 -07:00
>
2020-07-13 19:34:31 -07:00
< v-col
cols = "12"
: class = "['pb-3 ', $store.getters.isDriverMode ? '' : 'pr-lg-3']"
: lg = "$store.getters.isDriverMode ? 12 : 8"
align - self = "stretch"
2020-06-26 04:39:14 -07:00
>
2020-07-13 19:34:31 -07:00
< v-card
color = "primary"
height = "100%"
2020-06-26 04:39:14 -07:00
dark
>
2020-07-13 19:34:31 -07:00
< v-card-title
class = "pb-0 mb-0 pl-4 pt-1"
style = "height: 10%;"
>
Cameras
< / v-card-title >
< v-row
align = "center"
style = "height: 90%;"
>
< v-col
v - for = "idx in (selectedOutputs instanceof Array ? selectedOutputs : [selectedOutputs])"
: key = "idx"
cols = "12"
: md = "selectedOutputs.length === 1 ? 12 : Math.floor(12 / selectedOutputs.length)"
2020-06-26 04:39:14 -07:00
>
2020-07-13 19:34:31 -07:00
< div style = "position: relative; width: 100%; height: 100%;" >
< cvImage
: address = "$store.getters.streamAddress[idx]"
scale = "100"
max - height = "300px"
max - height - md = "320px"
max - height - xl = "450px"
: alt = "'Stream' + idx"
@ click = "onImageClick"
/ >
< span style = "position: absolute; top: 2%; left: 2%; font-size: 28px; -webkit-text-stroke: 1px black;" > { { parseFloat ( fps ) . toFixed ( 2 ) } } < / span >
< / div >
< / v-col >
2020-06-26 04:39:14 -07:00
< / v-row >
2020-07-13 19:34:31 -07:00
< / v-card >
< / v-col >
< v-col
cols = "12"
class = "pb-3"
: lg = "$store.getters.isDriverMode ? 12 : 4"
align - self = "stretch"
>
< v-card
color = "primary"
>
< camera-and-pipeline-select / >
< / v-card >
< v-card
v - if = "!$store.getters.isDriverMode"
class = "mt-3"
color = "primary"
>
< v-row
align = "center"
class = "pl-3 pr-3"
>
< v-col lg = "12" >
< p style = "color: white;" >
Processing mode :
< / p >
< v-btn-toggle
v - model = "processingMode"
mandatory
dark
class = "fill"
>
< v-btn color = "secondary" >
< v-icon > mdi - cube - outline < / v-icon >
< span > 3 D < / span >
< / v-btn >
< v-btn color = "secondary" >
< v-icon > mdi - crop - square < / v-icon >
< span > 2 D < / span >
< / v-btn >
< / v-btn-toggle >
< / v-col >
< v-col lg = "12" >
< p style = "color: white;" >
Stream display :
< / p >
< v-btn-toggle
v - model = "selectedOutputs"
: multiple = "$vuetify.breakpoint.mdAndUp"
mandatory
dark
class = "fill"
>
< v-btn
color = "secondary"
class = "fill"
>
< v-icon > mdi - palette < / v-icon >
< span > Normal < / span >
< / v-btn >
< v-btn
color = "secondary"
class = "fill"
>
< v-icon > mdi - compare < / v-icon >
< span > Threshold < / span >
< / v-btn >
< / v-btn-toggle >
< / v-col >
< / v-row >
< / v-card >
< / v-col >
< / v-row >
< v-row no -gutters >
< v-col
v - for = "(tabs, idx) in tabGroups"
: key = "idx"
: cols = "Math.floor(12 / tabGroups.length)"
: class = "idx != tabGroups.length - 1 ? 'pr-3' : ''"
align - self = "stretch"
>
< v-card
color = "primary"
height = "100%"
class = "pr-4 pl-4"
>
< v-tabs
v - if = "!$store.getters.isDriverMode"
v - model = "selectedTabs[idx]"
grow
background - color = "primary"
dark
height = "48"
slider - color = "accent"
>
< v-tab
v - for = "(tab, i) in tabs.filter(it => it.name !== '3D' || is3D)"
: key = "i"
>
{ { tab . name } }
< / v-tab >
< / v-tabs >
< div class = "pl-4 pr-4 pt-2" >
< keep-alive >
<!-- vision component -- >
< component
: is = "(tabs[selectedTabs[idx]] || tabs[0]).component"
ref = "component"
v - model = "$store.getters.pipeline"
: is3d = "is3D"
@ update = "$emit('save')"
/ >
< / keep-alive >
< / div >
< / v-card >
< / v-col >
< / v-row >
< / v-container >
2020-06-26 04:39:14 -07:00
<!-- snack bar -- >
< v-snackbar
v - model = "snackbar"
: timeout = "3000"
top
color = "error"
>
< span style = "color:#000" > Can not remove the only pipeline ! < / span >
< v-btn
color = "black"
text
@ click = "snackbar = false"
>
Close
< / v-btn >
< / v-snackbar >
< / div >
2020-05-25 22:46:44 +03:00
< / template >
< script >
import CameraAndPipelineSelect from "../components/pipeline/CameraAndPipelineSelect" ;
2020-07-13 19:34:31 -07:00
import cvImage from '../components/common/cv-image' ;
import InputTab from './PipelineViews/InputTab' ;
import ThresholdTab from './PipelineViews/ThresholdTab' ;
import ContoursTab from './PipelineViews/ContoursTab' ;
import OutputTab from './PipelineViews/OutputTab' ;
import TargetsTab from "./PipelineViews/TargetsTab" ;
import PnPTab from './PipelineViews/PnPTab' ;
2020-05-25 22:46:44 +03:00
export default {
name : 'CameraTab' ,
components : {
CameraAndPipelineSelect ,
cvImage ,
InputTab ,
ThresholdTab ,
ContoursTab ,
OutputTab ,
2020-07-13 19:34:31 -07:00
TargetsTab ,
PnPTab ,
2020-05-25 22:46:44 +03:00
} ,
data ( ) {
return {
2020-07-13 19:34:31 -07:00
selectedTabs : [ 0 , 0 , 0 , 0 ] ,
2020-05-25 22:46:44 +03:00
snackbar : false ,
2020-07-13 19:34:31 -07:00
is3D : false ,
2020-05-25 22:46:44 +03:00
}
} ,
computed : {
2020-07-13 19:34:31 -07:00
tabGroups : {
2020-05-25 22:46:44 +03:00
get ( ) {
2020-07-13 19:34:31 -07:00
let tabs = {
input : {
name : "Input" ,
component : "InputTab" ,
} ,
threshold : {
name : "Threshold" ,
component : "ThresholdTab" ,
} ,
contours : {
name : "Contours" ,
component : "ContoursTab" ,
} ,
output : {
name : "Output" ,
component : "OutputTab" ,
} ,
targets : {
name : "Target Info" ,
component : "TargetsTab" ,
} ,
pnp : {
name : "3D" ,
component : "PnPTab" ,
}
} ;
// 2D array of tab names and component names; each sub-array is a separate tab group
let ret = [ ] ;
if ( this . $vuetify . breakpoint . smAndDown || ! this . $store . state . compactMode || this . $store . getters . isDriverMode ) {
// One big tab group with all the tabs
ret [ 0 ] = Object . values ( tabs ) ;
} else if ( this . $vuetify . breakpoint . mdAndDown ) {
// Two tab groups, one with "input, threshold, contours, output" and the other with "target info, 3D"
ret [ 0 ] = [ tabs . input , tabs . threshold , tabs . contours , tabs . output ] ;
ret [ 1 ] = [ tabs . targets , tabs . pnp ] ;
} else if ( this . $vuetify . breakpoint . lgAndDown ) {
// Three tab groups, one with "input", one with "threshold, contours, output", and the other with "target info, 3D"
ret [ 0 ] = [ tabs . input ] ;
ret [ 1 ] = [ tabs . threshold , tabs . contours , tabs . output ] ;
ret [ 2 ] = [ tabs . targets , tabs . pnp ] ;
} else if ( this . $vuetify . breakpoint . xl ) {
// Three tab groups, one with "input", one with "threshold, contours", and the other with "output, target info, 3D"
ret [ 0 ] = [ tabs . input ] ;
ret [ 1 ] = [ tabs . threshold ] ;
ret [ 2 ] = [ tabs . contours , tabs . output ]
ret [ 3 ] = [ tabs . targets , tabs . pnp ] ;
}
return ret ;
}
} ,
processingMode : {
get ( ) {
return this . is3D ? 0 : 1 ;
2020-05-25 22:46:44 +03:00
} ,
set ( value ) {
2020-07-13 19:34:31 -07:00
this . is3D = value === 0 ;
2020-05-25 22:46:44 +03:00
}
} ,
2020-07-13 19:34:31 -07:00
selectedOutputs : {
// All this logic exists to deal with the reality that the output select buttons sometimes need an array and sometimes need a number (depending on whether or not they're exclusive)
2020-05-25 22:46:44 +03:00
get ( ) {
2020-07-13 19:34:31 -07:00
// We switch the selector to single-select only on sm-and-down size devices, so we have to return a Number instead of an Array in that state
2020-07-16 16:37:29 -07:00
let ret ;
2020-07-13 19:34:31 -07:00
if ( ! this . $store . getters . isDriverMode ) {
ret = this . $store . state . selectedOutputs || [ 0 ] ;
2020-07-16 16:37:29 -07:00
} else {
ret = [ 1 ] ; // We want the output stream in driver mode
2020-07-13 19:34:31 -07:00
}
if ( this . $vuetify . breakpoint . mdAndUp ) {
return ret ;
} else {
return ret [ 0 ] || 0 ;
}
} ,
set ( value ) {
let valToCommit = [ 0 ] ;
if ( value instanceof Array ) {
// Value is already an array, we don't need to do anything
value . sort ( ) ; // Sort for visual consistency
valToCommit = value ;
} else if ( value ) {
// Value is assumed to be a number, so we wrap it into an array
valToCommit = [ value ] ;
}
this . $store . commit ( "selectedOutputs" , valToCommit ) ;
// TODO: Currently the backend just sends both streams regardless of the selected outputs value, so we don't need to send anything
// this.handlePipelineUpdate('selectedOutputs', valToCommit);
2020-05-25 22:46:44 +03:00
}
} ,
fps : {
get ( ) {
Bootup sprint (#18)
* Did some stuff
* Fix gradle, start implementing mjpeg frame consumer
* Did some stuff
* bade changes
* rename camera config to USBCameraConfiguration, add name
* unrename cameraconfiguration
* Add pub/sub framework
* Add setResolution to mjpeg frame consumer
* add NTDataConsumer
* Add some totally broken hsv hacks
* Start refactoring UI data
* Update index.js
* Commit and push, he says
* Fix up some errors
* Fix input tab
* Fix fps
* Update index.js
* Add pipeline field setting, update PipelineManager, fix nullpointers and USBCameraSettables
* Change v-model to point to data()
* update hsv to use mutations
* Work on saving, fix hsv
* Rename shouldErode/shouldDilate to erode and dilate
* Hook all the tabs up to the Store
* Change handleData to handlePipelineData
* camera quirk redo, add ICCSub to SocketHandler
* Fix some property names
* Fixed tons of naming in UI, fix backend for multi-val PSCs, fix PSC enums
* change pipeline type to an int in store
* Fix mutation naming
* Attempt threshold fix
* Update SocketHandler.java
* Add truthy data sending
* Start adding logging support
* [UI] Add delay to slider input boxes (#1)
* [UI] [Backend] potentially fix camera settings, various logging tweaks
* Don't release raw input mat
* add setVideoModeIndex to vision settables
* Implement pipeline index in socket handler, add framework for renaming/changing pipes
* (ish) get pipeline change working
* Create index.html
* Cleanups, fix pipeline index bug, fix stream res for MJPG, add dashboard stream (unused)
* Refactor UI to use mutatePipeline, send pipeline results
* Update NetworkConfig.java
* Change double to number
* Run spotless
* Fix reversal of large/small comparators
* Fix left/right
* Fix pitch/yaw calculation bug, fix area bug
* Use Vue.set instead of assignment
This fixes {{ }}
* Update App.vue
* run spotless
* Actually add pipelines and reassign indecies
* Delete old pipeline configs
Fixes duplication on renaming pipeline
* Start working on deleting pipes
* Fix camera nickname change
* run spotless
* Fix some test stuff
* Update VisionModuleManagerTest.java
* vision source manager test is still broken
* Fix VisionSourceManager test
* Apply spotless 2 electric boogaloo
Co-authored-by: Banks Troutman <btrout.dhrs@gmail.com>
Co-authored-by: Declan Freeman-Gleason <declanfreemangleason@gmail.com>
Co-authored-by: Aaryan Agrawal <54345060+13Ducks@users.noreply.github.com>
2020-07-07 01:01:58 -07:00
return this . $store . getters . currentCameraFPS ;
2020-05-25 22:46:44 +03:00
}
2020-07-12 10:37:04 -07:00
} ,
latency : {
get ( ) {
return this . $store . getters . currentPipelineResults . latency ;
}
2020-05-25 22:46:44 +03:00
}
2020-06-26 04:39:14 -07:00
} ,
methods : {
onImageClick ( event ) {
if ( this . selectedTab === 1 ) {
this . $refs . component . onClick ( event ) ;
}
} ,
2020-05-25 22:46:44 +03:00
}
}
< / script >
< style scoped >
2020-07-13 19:34:31 -07:00
. v - btn - toggle . fill {
width : 100 % ;
height : 100 % ;
}
. v - btn - toggle . fill > . v - btn {
width : 50 % ;
height : 100 % ;
}
2020-05-25 22:46:44 +03:00
. colsClass {
padding : 0 ! important ;
}
. videoClass {
text - align : center ;
}
th {
width : 80 px ;
text - align : center ;
}
< / style >