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"
2020-07-31 13:50:50 -07:00
: class = "['pb-3 ', 'pr-lg-3']"
lg = "8"
2020-07-13 19:34:31 -07:00
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-07-31 13:50:50 -07:00
style = "display: flex; flex-direction: column"
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"
2020-07-31 13:50:50 -07:00
style = "height: 15%; min-height: 50px;"
2020-07-13 19:34:31 -07:00
>
2020-08-14 12:39:21 -07:00
Cameras
2020-07-31 13:50:50 -07:00
< v-switch
v - model = "driverMode"
label = "Driver Mode"
style = "margin-left: auto;"
color = "accent"
/ >
2020-07-13 19:34:31 -07:00
< / v-card-title >
< v-row
align = "center"
>
< 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-07-31 13:50:50 -07:00
class = "pb-0 pt-0"
style = "height: 100%;"
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
2020-07-31 13:50:50 -07:00
: id = "idx === 0 ? 'normal-stream' : ''"
2020-07-13 19:34:31 -07:00
: address = "$store.getters.streamAddress[idx]"
2020-07-31 13:50:50 -07:00
: disconnected = "!$store.state.backendConnected"
2020-07-13 19:34:31 -07:00
scale = "100"
2020-07-31 13:50:50 -07:00
: max - height = "$store.getters.isDriverMode ? '40vh' : '300px'"
: max - height - md = "$store.getters.isDriverMode ? '50vh' : '320px'"
: max - height - xl = "$store.getters.isDriverMode ? '60vh' : '450px'"
2020-07-13 19:34:31 -07:00
: alt = "'Stream' + idx"
2020-07-31 13:50:50 -07:00
: color - picking = "$store.state.colorPicking && idx == 0"
2020-07-13 19:34:31 -07:00
@ click = "onImageClick"
/ >
< / 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"
2020-07-31 13:50:50 -07:00
lg = "4"
2020-07-13 19:34:31 -07:00
align - self = "stretch"
>
< v-card
color = "primary"
>
< camera-and-pipeline-select / >
< / v-card >
< v-card
2020-07-31 13:50:50 -07:00
: disabled = "$store.getters.isDriverMode || $store.state.colorPicking"
2020-07-13 19:34:31 -07:00
class = "mt-3"
color = "primary"
>
< v-row
align = "center"
class = "pl-3 pr-3"
>
2020-09-04 18:18:44 -07:00
<!-- -- >
2020-07-13 19:34:31 -07:00
< v-col lg = "12" >
< p style = "color: white;" >
Processing mode :
< / p >
< v-btn-toggle
v - model = "processingMode"
mandatory
dark
class = "fill"
>
2020-07-31 13:50:50 -07:00
< v-btn
color = "secondary"
>
2020-07-13 19:34:31 -07:00
< v-icon > mdi - crop - square < / v-icon >
< span > 2 D < / span >
< / v-btn >
2020-07-31 13:50:50 -07:00
< v-btn
color = "secondary"
2020-09-04 18:18:44 -07:00
@ click = "on3DClick"
2020-07-31 13:50:50 -07:00
>
< v-icon > mdi - cube - outline < / v-icon >
< span > 3 D < / span >
< / v-btn >
2020-07-13 19:34:31 -07:00
< / 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
2020-08-14 12:39:21 -07:00
v - for = "(tab, i) in tabs.filter(it => it.name !== '3D' || $store.getters.currentPipelineSettings.solvePNPEnabled)"
2020-07-13 19:34:31 -07:00
: key = "i"
>
{ { tab . name } }
< / v-tab >
< / v-tabs >
< div class = "pl-4 pr-4 pt-2" >
< keep-alive >
< component
: is = "(tabs[selectedTabs[idx]] || tabs[0]).component"
2020-07-31 13:50:50 -07:00
: ref = "(tabs[selectedTabs[idx]] || tabs[0]).name"
2020-07-13 19:34:31 -07:00
v - model = "$store.getters.pipeline"
@ update = "$emit('save')"
/ >
< / keep-alive >
< / div >
< / v-card >
< / v-col >
< / v-row >
< / v-container >
2020-09-04 18:18:44 -07:00
<!-- snack bar and modal -- >
2020-06-26 04:39:14 -07:00
< 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 >
2020-09-04 18:18:44 -07:00
< v-dialog
v - model = "dialog"
width = "500"
>
< v-card
color = "primary"
dark
>
< v-card-title >
Current resolution not calibrated
< / v-card-title >
< v-card-text >
Because the current resolution { { this . $store . getters . videoFormatList [ this . $store . getters . currentPipelineSettings . cameraVideoModeIndex ] . width } }
x { { this . $store . getters . videoFormatList [ this . $store . getters . currentPipelineSettings . cameraVideoModeIndex ] . height } }
is not yet calibrated , 3 D mode cannot be enabled . Please
< a
href = "/#/cameras"
class = "white--text"
@ click = "$emit('switch-to-cameras')"
> visit the Cameras tab < / a > to calibrate this resolution . For now , SolvePNP will do nothing .
< / v-card-text >
< v-divider / >
< v-card-actions >
< v-spacer / >
< v-btn
color = "white"
text
@ click = "closeUncalibratedDialog"
>
OK
< / v-btn >
< / v-card-actions >
< / v-card >
< / v-dialog >
2020-06-26 04:39:14 -07:00
< / 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-31 13:50:50 -07:00
selectedTabsData : [ 0 , 0 , 0 , 0 ] ,
2020-05-25 22:46:44 +03:00
snackbar : false ,
2020-07-31 13:50:50 -07:00
counterData : 0 ,
2020-09-04 18:18:44 -07:00
dialog : false ,
processingModeOverride : false
2020-05-25 22:46:44 +03:00
}
} ,
computed : {
2020-07-31 13:50:50 -07:00
selectedTabs : {
get ( ) {
return this . $store . getters . isDriverMode ? [ 0 ] : this . selectedTabsData ;
} ,
set ( value ) {
this . selectedTabsData = value ;
}
} ,
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 = [ ] ;
2020-07-31 13:50:50 -07:00
if ( this . $vuetify . breakpoint . smAndDown || this . $store . getters . isDriverMode || ( this . $vuetify . breakpoint . mdAndDown && ! this . $store . state . compactMode ) ) {
2020-07-13 19:34:31 -07:00
// One big tab group with all the tabs
ret [ 0 ] = Object . values ( tabs ) ;
2020-07-31 13:50:50 -07:00
} else if ( this . $vuetify . breakpoint . mdAndDown || ! this . $store . state . compactMode ) {
2020-07-13 19:34:31 -07:00
// 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 ( ) {
2020-09-04 18:18:44 -07:00
return ( this . $store . getters . currentPipelineSettings . solvePNPEnabled || this . processingModeOverride ) ? 1 : 0 ;
2020-05-25 22:46:44 +03:00
} ,
set ( value ) {
2020-09-04 18:18:44 -07:00
if ( this . $store . getters . isCalibrated ) {
this . $store . getters . currentPipelineSettings . solvePNPEnabled = value === 1 ;
this . handlePipelineUpdate ( "solvePNPEnabled" , value === 1 ) ;
}
2020-07-31 13:50:50 -07:00
}
} ,
driverMode : {
get ( ) {
return this . $store . getters . isDriverMode ;
} ,
set ( value ) {
this . $store . getters . currentCameraSettings . currentPipelineIndex = value ? - 1 : 0 ;
this . handleInputWithIndex ( 'currentPipeline' , value ? - 1 : 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-31 13:50:50 -07:00
if ( this . $store . state . colorPicking ) {
ret = [ 0 ] ; // We want the input stream only while color picking
} else if ( ! this . $store . getters . isDriverMode ) {
2020-07-13 19:34:31 -07:00
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
}
} ,
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 : {
2020-09-04 18:18:44 -07:00
isCalibrated ( ) {
const resolution = this . $store . getters . videoFormatList [ this . $store . getters . currentPipelineSettings . cameraVideoModeIndex ] ;
return this . $store . getters . currentCameraSettings . calibrations
. some ( e => e . width === resolution . width && e . height === resolution . height )
} ,
2020-06-26 04:39:14 -07:00
onImageClick ( event ) {
2020-07-31 13:50:50 -07:00
// Only run on the input stream
if ( event . target . alt !== "Stream0" ) return ;
// Get a reference to the threshold tab (if it is shown) and call its "onClick" method
let ref = this . $refs [ "Threshold" ] ;
if ( ref && ref [ 0 ] )
ref [ 0 ] . onClick ( event )
2020-06-26 04:39:14 -07:00
} ,
2020-09-04 18:18:44 -07:00
on3DClick ( ) {
if ( ! this . $store . getters . isCalibrated ) {
this . dialog = true ;
this . processingModeOverride = true ;
}
} ,
closeUncalibratedDialog ( ) {
this . dialog = false ;
this . processingModeOverride = false ;
// this.$store.getters.currentPipelineSettings.solvePNPEnabled = false;
this . handlePipelineUpdate ( "solvePNPEnabled" , false ) ;
}
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
th {
width : 80 px ;
text - align : center ;
}
< / style >