2019-09-28 21:42:04 +03:00
< template >
2020-06-26 04:39:14 -07:00
< div >
2020-07-31 13:50:50 -07:00
< v-row
no - gutters
class = "pa-3"
>
< v-col
cols = "12"
md = "7"
2020-06-26 04:39:14 -07:00
>
2020-08-14 12:39:21 -07:00
<!-- Camera card -- >
2020-07-31 13:50:50 -07:00
< v-card
class = "mb-3 pr-6 pb-3"
color = "primary"
dark
>
< v-card-title > Camera Settings < / v-card-title >
< div class = "ml-5" >
< CVselect
v - model = "currentCameraIndex"
name = "Camera"
: list = "$store.getters.cameraList"
2021-12-03 22:08:51 -06:00
: select - cols = "$vuetify.breakpoint.mdAndUp ? 10 : 7"
2022-01-16 08:25:37 -08:00
@ input = "handleInput('currentCamera',currentCameraIndex)"
2020-07-31 13:50:50 -07:00
/ >
< CVnumberinput
v - model = "cameraSettings.fov"
2020-12-23 00:42:39 -08:00
: tooltip = "cameraSettings.isFovConfigurable ? 'Field of view (in degrees) of the camera measured across the diagonal of the frame, in a video mode which covers the whole sensor area.' : 'This setting is managed by a vendor'"
2023-06-09 13:09:41 -04:00
name = "Maximum Diagonal FOV"
2020-08-14 12:39:21 -07:00
: disabled = "!cameraSettings.isFovConfigurable"
2021-12-03 22:08:51 -06:00
: label - cols = "$vuetify.breakpoint.mdAndUp ? undefined : 7"
2020-07-31 13:50:50 -07:00
/ >
< br >
< v-btn
style = "margin-top:10px"
small
color = "secondary"
@ click = "sendCameraSettings"
>
< v-icon left >
mdi - content - save
< / v-icon >
Save Camera Settings
< / v-btn >
< / div >
< / v-card >
2020-08-14 12:39:21 -07:00
<!-- Calibration card -- >
2020-07-31 13:50:50 -07:00
< v-card
class = "pr-6 pb-3"
color = "primary"
2020-06-26 04:39:14 -07:00
dark
2020-07-31 13:50:50 -07:00
>
< v-card-title > Camera Calibration < / v-card-title >
2020-08-14 12:39:21 -07:00
2020-07-31 13:50:50 -07:00
< div class = "ml-5" >
< v-row >
2020-08-14 12:39:21 -07:00
<!-- Calibration input -- >
< v-col
cols = "12"
md = "6"
>
2021-11-21 19:34:06 -06:00
< v-form
ref = "form"
v - model = "settingsValid"
>
< CVselect
v - model = "selectedFilteredResIndex"
name = "Resolution"
select - cols = "7"
: list = "stringResolutionList"
: disabled = "isCalibrating"
tooltip = "Resolution to calibrate at (you will have to calibrate every resolution you use 3D mode on)"
/ >
2023-01-14 20:23:14 -05:00
< CVselect
v - model = "streamingFrameDivisor"
name = "Decimation"
tooltip = "Resolution to which camera frames are downscaled for detection. Calibration still uses full-res"
: list = "calibrationDivisors"
select - cols = "7"
@ rollback = "e => rollback('streamingFrameDivisor', e)"
/ >
2021-11-21 19:34:06 -06:00
< CVselect
v - model = "boardType"
name = "Board Type"
select - cols = "7"
: list = "['Chessboard', 'Dot Grid']"
: disabled = "isCalibrating"
tooltip = "Calibration board pattern to use"
/ >
< CVnumberinput
v - model = "squareSizeIn"
name = "Pattern Spacing (in)"
tooltip = "Spacing between pattern features in inches"
: disabled = "isCalibrating"
: rules = "[v => (v > 0) || 'Size must be positive']"
2021-12-03 22:08:51 -06:00
: label - cols = "$vuetify.breakpoint.mdAndUp ? 5 : 7"
2021-11-21 19:34:06 -06:00
/ >
< CVnumberinput
v - model = "boardWidth"
2023-06-09 13:09:41 -04:00
name = "Board Width"
2021-11-21 19:34:06 -06:00
tooltip = "Width of the board in dots or chessboard squares"
: disabled = "isCalibrating"
: rules = "[v => (v >= 4) || 'Width must be at least 4']"
2021-12-03 22:08:51 -06:00
: label - cols = "$vuetify.breakpoint.mdAndUp ? 5 : 7"
2021-11-21 19:34:06 -06:00
/ >
< CVnumberinput
v - model = "boardHeight"
2023-06-09 13:09:41 -04:00
name = "Board Height"
2021-11-21 19:34:06 -06:00
tooltip = "Height of the board in dots or chessboard squares"
: disabled = "isCalibrating"
: rules = "[v => (v >= 4) || 'Height must be at least 4']"
2021-12-03 22:08:51 -06:00
: label - cols = "$vuetify.breakpoint.mdAndUp ? 5 : 7"
2021-11-21 19:34:06 -06:00
/ >
< / v-form >
2020-07-31 13:50:50 -07:00
< / v-col >
2020-08-14 12:39:21 -07:00
<!-- Calibrated table -- >
2020-07-31 13:50:50 -07:00
< v-col
2020-08-14 12:39:21 -07:00
cols = "12"
md = "6"
2020-07-31 13:50:50 -07:00
>
2020-08-14 12:39:21 -07:00
< v-row
align = "start"
class = "pb-4"
>
< v-simple-table
fixed - header
height = "100%"
dense
>
< thead style = "font-size: 1.25rem;" >
< tr >
< th class = "text-center" >
< tooltipped-label text = "Resolution" / >
< / th >
< th class = "text-center" >
< tooltipped-label
tooltip = "Average reprojection error of the calibration, in pixels"
text = "Mean Error"
/ >
< / th >
< th class = "text-center" >
< tooltipped-label
tooltip = "Standard deviation of the mean error, in pixels"
text = "Standard Deviation"
/ >
< / th >
2022-10-08 23:08:57 -04:00
< th class = "text-center" >
< tooltipped-label
tooltip = "Estimated Horizontal FOV, in degrees"
text = "Horizontal FOV"
/ >
< / th >
< th class = "text-center" >
< tooltipped-label
tooltip = "Estimated Vertical FOV, in degrees"
text = "Vertical FOV"
/ >
< / th >
< th class = "text-center" >
< tooltipped-label
tooltip = "Estimated Diagonal FOV, in degrees"
text = "Diagonal FOV"
/ >
< / th >
2020-08-14 12:39:21 -07:00
< / tr >
< / thead >
< tbody >
< tr
v - for = "(value, index) in filteredResolutionList"
: key = "index"
>
2020-11-21 18:14:27 -08:00
< td > { { value . width } } X { { value . height } } < / td >
2020-08-14 12:39:21 -07:00
< td >
{ { isCalibrated ( value ) ? value . mean . toFixed ( 2 ) + "px" : "—" } }
< / td >
< td > { { isCalibrated ( value ) ? value . standardDeviation . toFixed ( 2 ) + "px" : "—" } } < / td >
2022-10-08 23:08:57 -04:00
< td > { { isCalibrated ( value ) ? value . horizontalFOV . toFixed ( 2 ) + "°" : "—" } } < / td >
< td > { { isCalibrated ( value ) ? value . verticalFOV . toFixed ( 2 ) + "°" : "—" } } < / td >
< td > { { isCalibrated ( value ) ? value . diagonalFOV . toFixed ( 2 ) + "°" : "—" } } < / td >
2020-08-14 12:39:21 -07:00
< / tr >
< / tbody >
< / v-simple-table >
< / v-row >
< v-row justify = "center" >
< v-chip
v - show = "isCalibrating"
label
: color = "snapshotAmount < 25 ? 'grey' : 'secondary'"
>
Snapshots : { { snapshotAmount } } of at least { { minSnapshots } }
< / v-chip >
< / v-row >
< / v-col >
< / v-row >
< v-row v-if = "isCalibrating" >
< v-col
cols = "12"
class = "pt-0"
>
< CVslider
v - model = "$store.getters.currentPipelineSettings.cameraExposure"
2022-10-21 21:12:11 -05:00
: disabled = "$store.getters.currentPipelineSettings.cameraAutoExposure"
2020-08-14 12:39:21 -07:00
name = "Exposure"
: min = "0"
: max = "100"
slider - cols = "8"
2022-10-21 21:12:11 -05:00
step = "0.1"
tooltip = "Directly controls how much light is allowed to fall onto the sensor, which affects apparent brightness"
2020-08-14 12:39:21 -07:00
@ input = "e => handlePipelineUpdate('cameraExposure', e)"
/ >
< CVslider
2020-10-05 19:22:58 -07:00
v - model = "$store.getters.currentPipelineSettings.cameraBrightness"
2020-08-14 12:39:21 -07:00
name = "Brightness"
: min = "0"
: max = "100"
slider - cols = "8"
@ input = "e => handlePipelineUpdate('cameraBrightness', e)"
/ >
2022-10-21 21:12:11 -05:00
< CVswitch
v - model = "$store.getters.currentPipelineSettings.cameraAutoExposure"
class = "pt-2"
name = "Auto Exposure"
tooltip = "Enables or Disables camera automatic adjustment for current lighting conditions"
@ input = "e => handlePipelineUpdate('cameraAutoExposure', e)"
/ >
2022-12-28 11:21:41 -08:00
< CVslider
v - if = "cameraGain >= 0"
v - model = "cameraGain"
name = "Camera Gain"
min = "0"
max = "100"
tooltip = "Controls camera gain, similar to brightness"
: slider - cols = "largeBox"
@ input = "handlePipelineData('cameraGain')"
@ rollback = "e => rollback('cameraGain', e)"
/ >
2020-08-14 12:39:21 -07:00
< CVslider
2022-02-28 00:45:29 -05:00
v - if = "$store.getters.currentPipelineSettings.cameraRedGain !== -1"
v - model = "$store.getters.currentPipelineSettings.cameraRedGain"
name = "Red AWB Gain"
min = "0"
max = "100"
tooltip = "Controls red automatic white balance gain, which affects how the camera captures colors in different conditions"
: slider - cols = "8"
@ input = "e => handlePipelineData('cameraRedGain', e)"
/ >
< CVslider
v - if = "$store.getters.currentPipelineSettings.cameraBlueGain !== -1"
v - model = "$store.getters.currentPipelineSettings.cameraBlueGain"
name = "Blue AWB Gain"
min = "0"
max = "100"
tooltip = "Controls blue automatic white balance gain, which affects how the camera captures colors in different conditions"
: slider - cols = "8"
@ input = "e => handlePipelineData('cameraBlueGain', e)"
2020-07-31 13:50:50 -07:00
/ >
< / v-col >
< / v-row >
2020-08-14 12:39:21 -07:00
2020-07-31 13:50:50 -07:00
< v-row >
2020-08-14 12:39:21 -07:00
< v-col align -self = " center " >
2020-07-31 13:50:50 -07:00
< v-btn
small
color = "secondary"
2020-08-14 12:39:21 -07:00
style = "width: 100%;"
: disabled = "disallowCalibration"
2020-07-31 13:50:50 -07:00
@ click = "sendCalibrationMode"
>
2020-08-14 12:39:21 -07:00
{ { isCalibrating ? "Take Snapshot" : "Start Calibration" } }
2020-07-31 13:50:50 -07:00
< / v-btn >
< / v-col >
2020-08-14 12:39:21 -07:00
< v-col align -self = " center " >
2020-07-31 13:50:50 -07:00
< v-btn
small
2020-08-14 12:39:21 -07:00
: color = "hasEnough ? 'accent' : 'red'"
: class = "hasEnough ? 'black--text' : 'white---text'"
style = "width: 100%;"
2020-07-31 13:50:50 -07:00
: disabled = "checkCancellation"
@ click = "sendCalibrationFinish"
>
2020-11-21 18:14:27 -08:00
{ { hasEnough ? "Finish Calibration" : "Cancel Calibration" } }
2020-07-31 13:50:50 -07:00
< / v-btn >
< / v-col >
< v-col >
< v-btn
color = "accent"
small
outlined
2020-08-14 12:39:21 -07:00
style = "width: 100%;"
2021-11-21 19:34:06 -06:00
: disabled = "!settingsValid"
2020-07-31 13:50:50 -07:00
@ click = "downloadBoard"
>
< v-icon left >
mdi - download
< / v-icon >
2023-06-09 13:09:41 -04:00
Download Calibration Target
2020-07-31 13:50:50 -07:00
< / v-btn >
< / v-col >
2023-01-18 16:29:58 -05:00
< v-col >
< v-btn
color = "secondary"
small
style = "width: 100%;"
@ click = "$refs.importCalibrationFromCalibdb.click()"
>
< v-icon left >
mdi - upload
< / v-icon >
Import From CalibDB
< / v-btn >
< / v-col >
2020-07-31 13:50:50 -07:00
< / v-row >
< / div >
< / v-card >
< / v-col >
< v-col
class = "pl-md-3 pt-3 pt-md-0"
cols = "12"
md = "5"
>
2020-11-21 18:14:27 -08:00
< template >
< CVimage
2022-10-30 13:16:17 -05:00
: id = "cameras-cal"
2023-06-09 13:09:41 -04:00
: idx = "1"
2020-11-21 18:14:27 -08:00
: disconnected = "!$store.state.backendConnected"
scale = "100"
style = "border-radius: 5px;"
/ >
< v-dialog
v - model = "snack"
width = "500px"
2021-01-08 21:03:18 -05:00
: persistent = "true"
2020-11-21 18:14:27 -08:00
>
< v-card
color = "primary"
dark
>
< v-card-title > Camera Calibration < / v-card-title >
< div
class = "ml-3"
>
< v-col align = "center" >
2020-12-05 12:18:07 -08:00
< template v-if = "calibrationInProgress && !calibrationFailed" >
2020-11-21 18:14:27 -08:00
< v-progress-circular
indeterminate
: size = "70"
: width = "8"
color = "accent"
/ >
2023-02-26 21:39:46 -06:00
< v-card-text > Camera is being calibrated . This process may take several minutes ... < / v-card-text >
2020-11-21 18:14:27 -08:00
< / template >
< template v-else-if = "!calibrationFailed" >
< v-icon
color = "green"
size = "70"
>
mdi - check - bold
< / v-icon >
< v-card-text > Camera has been successfully calibrated at { { stringResolutionList [ selectedFilteredResIndex ] } } ! < / v-card-text >
< / template >
< template v-else >
< v-icon
color = "red"
size = "70"
>
mdi - close
< / v-icon >
< v-card-text > Camera calibration failed ! Make sure that the photos are taken such that the rainbow grid circles align with the corners of the chessboard , and try again . More information is available in the program logs . < / v-card-text >
< / template >
< / v-col >
< / div >
< v-card-actions >
< v-spacer / >
< v-btn
2020-12-05 12:18:07 -08:00
v - if = "!calibrationInProgress || calibrationFailed"
2020-11-21 18:14:27 -08:00
color = "white"
text
@ click = "closeDialog"
>
OK
< / v-btn >
< / v-card-actions >
< / v-card >
< / v-dialog >
< / template >
2020-07-31 13:50:50 -07:00
< / v-col >
< / v-row >
2023-01-18 16:29:58 -05:00
2023-06-09 13:09:41 -04:00
<!-- Special hidden upload input that gets 'clicked' when the user imports calibdb data -- >
2023-01-18 16:29:58 -05:00
< input
ref = "importCalibrationFromCalibdb"
type = "file"
accept = ".json"
style = "display: none;"
@ change = "readImportedCalibration"
2023-06-09 13:09:41 -04:00
>
2023-01-18 16:29:58 -05:00
2023-06-09 13:09:41 -04:00
< v-snackbar
v - model = "uploadSnack"
top
: color = "uploadSnackData.color"
timeout = "-1"
>
2023-01-18 16:29:58 -05:00
< span > { { uploadSnackData . text } } < / span >
< / v-snackbar >
2020-06-26 04:39:14 -07:00
< / div >
2019-09-28 21:42:04 +03:00
< / template >
< script >
2020-08-14 12:39:21 -07:00
import CVselect from '../components/common/cv-select' ;
import CVnumberinput from '../components/common/cv-number-input' ;
import CVslider from '../components/common/cv-slider' ;
2022-10-21 21:12:11 -05:00
import CVswitch from '../components/common/cv-switch' ;
2020-08-14 12:39:21 -07:00
import CVimage from "../components/common/cv-image" ;
import TooltippedLabel from "../components/common/cv-tooltipped-label" ;
2021-11-21 19:34:06 -06:00
import jsPDF from "jspdf" ;
import "../jsPDFFonts/Prompt-Regular-normal.js" ;
2019-10-29 23:58:06 +02:00
2020-08-14 12:39:21 -07:00
export default {
name : 'Cameras' ,
components : {
2020-11-21 18:14:27 -08:00
TooltippedLabel ,
2020-08-14 12:39:21 -07:00
CVselect ,
CVnumberinput ,
CVslider ,
2022-10-21 21:12:11 -05:00
CVswitch ,
2020-08-14 12:39:21 -07:00
CVimage
} ,
data ( ) {
return {
snack : false ,
2020-11-21 18:14:27 -08:00
calibrationInProgress : false ,
calibrationFailed : false ,
2021-01-05 17:30:55 -08:00
filteredVideomodeIndex : 0 ,
2021-11-21 19:34:06 -06:00
settingsValid : true ,
2023-01-14 20:23:14 -05:00
unfilteredStreamDivisors : [ 1 , 2 , 4 ] ,
2023-01-18 16:29:58 -05:00
uploadSnackData : {
color : "success" ,
text : "" ,
} ,
uploadSnack : false ,
2020-08-14 12:39:21 -07:00
}
} ,
computed : {
disallowCalibration ( ) {
2021-11-21 19:34:06 -06:00
return ! ( this . calibrationData . boardType === 0 || this . calibrationData . boardType === 1 ) || ! this . settingsValid ;
2019-09-28 21:42:04 +03:00
} ,
2020-08-14 12:39:21 -07:00
checkCancellation ( ) {
if ( this . isCalibrating ) {
return false
} else if ( this . disallowCalibration ) {
return true ;
} else {
return true
Add solvePNP, 3d tab on the UI, and some other misc bug fixes (#35)
* Rebase solvePNP on master
* added 3D tab minimap and csv reader
* More solvePNP
* Create draw pipe for pnp data
* SolvePNP piping work
* Move sorting into solvepnppipe
* Create calibration pipeline
* Update CalibrateSolvePNPPipeline.java
* add camera tilt angle
* Add calibration slider and snapshot button to 3D view
* Mirror updates in the socket handler
* add 3d calibration mode to the pipeline manager
* created calibration functions in ui and backend
* Start plumbing calibration
* Add snapshot and other handling to the RequestHandler
* added select resolution before starting calibration
* Rename solvePNPPipe to bounding box solve pnp pipe
* Update BoundingBoxSolvePNPPipe.java
* Add Mat serializer and CameraCalibrationConfig
* Begun calibration saving, fixed UI/Backend snapshot count mismatch
* Add (unplumbed) option to set checkerboard size
This will allow users to change the units their calibration is in
* Create chessboard.png
* Fix calibration NPE
* changed string serialization to a json send
* bug fixed cancellation button
* Fix spelling of snapshot in 3d.vue
* Plumb resolution change
* Set resolution during config, start on config serialization
* Update .gitignore
* Config fixes
* Start transition away from cvpipeline3d
* fix NPE on uncalibrated cameras
* clear list on fail
* Fix video mode index error
* ignore getters in camera calibration config
* Create json constructor for jsonmat
* get solvePNP mostly returning sane values
* Fix solvePNP bug and add unit test
* FIx calibration mat truncation
* added capture amount model upload and minimap data
* Standardize on meters in calibration and bounding box
* fix json out of bounds and handle null calibration more gracefully
* don't put text on calibrate image, go back to inches
* convert distance to meters
this means calibration will need to be in inches
* Actually save raw contor
* Update GroupContoursPipe.java
* Add all calibration return to camera capture
* hard code 2019 target
* bugfixed draw2d added fail calib popup, merge end and cancel
added the res index to the calib start
* Clarify error message and draw more fancy rectangles
* Cleanup memory in solvepnp
* re did minimap component
* fix npe if left/right is null
* remove references to 2d
* try-catch running the current pipeline
* Add method to find corners using the harris corner detector
* Possibly fix left/right missmatch
* Fix 3D Tab error
* FIx file permissions, mat serializer adjustments
* fixed mini map for field coordinates
* mini map changes fov
* Update SolvePNPPipe.java
* get rid of target corners
* some memory leak fixes
* fixed mini map location
* added position under minimap
* changed player fov look
* put all targets in the web send
* re did target send to ui added target tables, bugfix calibration
* fixed y position
* Add tilt angle to capture properties
* maybe fix y axis in minimap
* Add square size to onCalibrationEnding
* Possibly add square size to UI
* fix NPE with pitch
* Fix bug with sending multiple targets
* Only instantiate 3d stuff if we are in 3d mode
* Fix array list exceptions
* Fix bug in sort contors
list was truncated too early
* added download chess, tilt setting and ordinal tilt,
* added square size connection
* removed unused code
* Update pom version to 2.1-RELEASE
* Send camera calibrations to UI
* Stream pose list to a LIst
* Only stream necessary parts of the aux list entry
* Make broadcastMessage synchronized to prevent ConcurrentModificationExceptions
* added fps counter changed squaresize steps bug fixes in tables
* bugfix camera settings cam wont change
Authored-by: oriagranat9 <oriagranat9@gmail.com>
2019-12-31 04:53:20 -08:00
}
2019-10-12 18:09:05 +03:00
} ,
2020-08-14 12:39:21 -07:00
currentCameraIndex : {
get ( ) {
return this . $store . state . currentCameraIndex ;
2020-06-26 04:39:14 -07:00
} ,
2020-08-14 12:39:21 -07:00
set ( value ) {
this . $store . commit ( 'currentCameraIndex' , value ) ;
}
} ,
2022-12-28 11:21:41 -08:00
cameraGain : {
get ( ) {
return parseInt ( this . $store . getters . currentPipelineSettings . cameraGain )
} ,
set ( val ) {
this . $store . commit ( "mutatePipeline" , { "cameraGain" : parseInt ( val ) } ) ;
}
} ,
2023-01-14 20:23:14 -05:00
calibrationDivisors : {
get ( ) {
return this . unfilteredStreamDivisors . filter ( item => {
2023-06-09 13:09:41 -04:00
const res = this . stringResolutionList [ this . selectedFilteredResIndex ] . split ( " X " ) . map ( it => parseInt ( it ) ) ;
2023-01-14 20:23:14 -05:00
console . log ( res ) ;
console . log ( item ) ;
// Realistically, we need more than 320x240, but lower than this is
// basically unusable. For now, don't allow decimations that take us
// below that
const ret = ( ( res [ 0 ] / item ) >= 300 && ( res [ 1 ] / item ) >= 220 ) || ( item === 1 ) ;
console . log ( ret ) ;
return ret ;
} )
}
} ,
2020-08-14 12:39:21 -07:00
// Makes sure there's only one entry per resolution
filteredResolutionList : {
get ( ) {
let list = this . $store . getters . videoFormatList ;
let filtered = [ ] ;
list . forEach ( ( it , i ) => {
if ( ! filtered . some ( e => e . width === it . width && e . height === it . height ) ) {
it [ 'index' ] = i ;
const calib = this . getCalibrationCoeffs ( it ) ;
2020-11-21 18:14:27 -08:00
if ( calib != null ) {
2020-08-14 12:39:21 -07:00
it [ 'standardDeviation' ] = calib . standardDeviation ;
it [ 'mean' ] = calib . perViewErrors . reduce ( ( a , b ) => a + b ) / calib . perViewErrors . length ;
2022-10-08 23:08:57 -04:00
it [ 'horizontalFOV' ] = 2 * Math . atan2 ( it . width / 2 , calib . intrinsics [ 0 ] ) * ( 180 / Math . PI ) ;
it [ 'verticalFOV' ] = 2 * Math . atan2 ( it . height / 2 , calib . intrinsics [ 4 ] ) * ( 180 / Math . PI ) ;
it [ 'diagonalFOV' ] = 2 * Math . atan2 ( Math . sqrt ( it . width * * 2 + ( it . height / ( calib . intrinsics [ 4 ] / calib . intrinsics [ 0 ] ) ) * * 2 ) / 2 , calib . intrinsics [ 0 ] ) * ( 180 / Math . PI ) ;
2020-06-26 04:39:14 -07:00
}
2020-08-14 12:39:21 -07:00
filtered . push ( it ) ;
2020-06-26 04:39:14 -07:00
}
2020-08-14 12:39:21 -07:00
} ) ;
filtered . sort ( ( a , b ) => ( b . width + b . height ) - ( a . width + a . height ) ) ;
return filtered
}
} ,
stringResolutionList : {
get ( ) {
return this . filteredResolutionList . map ( res => ` ${ res [ 'width' ] } X ${ res [ 'height' ] } ` ) ;
}
} ,
cameraSettings : {
get ( ) {
return this . $store . getters . currentCameraSettings ;
2020-06-26 04:39:14 -07:00
} ,
2020-08-14 12:39:21 -07:00
set ( value ) {
this . $store . commit ( 'cameraSettings' , value ) ;
}
} ,
2023-01-14 20:23:14 -05:00
streamingFrameDivisor : {
get ( ) {
return this . $store . getters . currentPipelineSettings . streamingFrameDivisor ;
} ,
set ( val ) {
this . $store . commit ( "mutatePipeline" , { "streamingFrameDivisor" : val } ) ;
this . handlePipelineUpdate ( "streamingFrameDivisor" , val ) ;
}
} ,
2020-08-14 12:39:21 -07:00
boardType : {
get ( ) {
return this . calibrationData . boardType
2020-06-26 04:39:14 -07:00
} ,
2020-08-14 12:39:21 -07:00
set ( value ) {
this . $store . commit ( 'mutateCalibrationState' , { [ 'boardType' ] : value } ) ;
}
} ,
snapshotAmount : {
get ( ) {
return this . calibrationData . count
}
} ,
minSnapshots : {
get ( ) {
return this . calibrationData . minCount
}
} ,
hasEnough : {
get ( ) {
return this . calibrationData . hasEnough
}
} ,
boardWidth : {
get ( ) {
return this . calibrationData . patternWidth
2020-06-26 04:39:14 -07:00
} ,
2020-08-14 12:39:21 -07:00
set ( value ) {
this . $store . commit ( 'mutateCalibrationState' , { [ 'patternWidth' ] : value } )
}
} ,
boardHeight : {
get ( ) {
return this . calibrationData . patternHeight
2020-06-26 04:39:14 -07:00
} ,
2020-08-14 12:39:21 -07:00
set ( value ) {
this . $store . commit ( 'mutateCalibrationState' , { [ 'patternHeight' ] : value } )
2020-06-26 04:39:14 -07:00
}
} ,
2020-08-14 12:39:21 -07:00
squareSizeIn : {
get ( ) {
return this . calibrationData . squareSizeIn
2020-03-19 14:02:49 +02:00
} ,
2020-08-14 12:39:21 -07:00
set ( value ) {
this . $store . commit ( 'mutateCalibrationState' , { [ 'squareSizeIn' ] : value } )
}
} ,
calibrationData : {
get ( ) {
return this . $store . state . calibrationData
}
} ,
isCalibrating : {
get ( ) {
return this . $store . getters . currentPipelineIndex === - 2 ;
}
} ,
selectedFilteredResIndex : {
get ( ) {
return this . filteredVideomodeIndex
2020-01-25 23:11:02 +02:00
} ,
2020-08-14 12:39:21 -07:00
set ( i ) {
2020-09-04 18:18:44 -07:00
console . log ( ` Setting filtered index to ${ i } ` ) ;
this . filteredVideomodeIndex = i ;
2020-08-14 12:39:21 -07:00
this . $store . commit ( 'mutateCalibrationState' , { [ 'videoModeIndex' ] : this . filteredResolutionList [ i ] . index } ) ;
}
} ,
} ,
methods : {
2023-06-09 13:09:41 -04:00
readImportedCalibration ( event ) {
// let formData = new FormData();
// formData.append("zipData", event.target.files[0]);
const filename = event . target . files [ 0 ] . name ;
event . target . files [ 0 ] . text ( ) . then ( fileText => {
const data = {
"cameraIndex" : this . $store . getters . currentCameraIndex ,
"payload" : fileText ,
"filename" : filename ,
2023-01-18 16:29:58 -05:00
} ;
2023-06-09 13:09:41 -04:00
this . axios
. post ( "http://" + this . $address + "/api/calibration/import" , data , {
headers : { "Content-Type" : "text/plain" } ,
} )
. then ( ( ) => {
this . uploadSnackData = {
color : "success" ,
text :
"Calibration imported successfully!" ,
} ;
this . uploadSnack = true ;
} )
. catch ( ( err ) => {
if ( err . response ) {
this . uploadSnackData = {
color : "error" ,
text :
"Error while uploading calibration file! Could not process provided file." ,
} ;
} else if ( err . request ) {
this . uploadSnackData = {
color : "error" ,
text :
"Error while uploading calibration file! No respond to upload attempt." ,
} ;
} else {
this . uploadSnackData = {
color : "error" ,
text : "Error while uploading calibration file!" ,
} ;
}
this . uploadSnack = true ;
} ) ;
2023-01-18 16:29:58 -05:00
2023-06-09 13:09:41 -04:00
} )
2023-01-18 16:29:58 -05:00
} ,
2020-11-21 18:14:27 -08:00
closeDialog ( ) {
this . snack = false ;
this . calibrationInProgress = false ;
this . calibrationFailed = false ;
} ,
2020-08-14 12:39:21 -07:00
getCalibrationCoeffs ( resolution ) {
const calList = this . $store . getters . calibrationList ;
let ret = null ;
calList . forEach ( cal => {
2020-11-21 18:14:27 -08:00
if ( cal . width === resolution . width && cal . height === resolution . height ) {
2020-08-14 12:39:21 -07:00
ret = cal
}
2020-09-04 18:18:44 -07:00
} ) ;
2020-08-14 12:39:21 -07:00
return ret ;
} ,
downloadBoard ( ) {
2023-06-09 13:09:41 -04:00
const config = {
type : this . boardType === 0 ? "chessboard" : "dotgrid" ,
boardWidthIn : this . boardWidth ,
boardHeightIn : this . boardHeight ,
patternSpacingIn : this . squareSizeIn
}
const doc = new jsPDF ( { unit : "in" , format : "letter" } )
doc . setFont ( "Prompt-Regular" )
doc . setFontSize ( 12 )
const paperWidth = 8.5
const paperHeight = 11.0
// Draw the selected pattern to the document
switch ( config . type ) {
case "chessboard" :
// eslint-disable-next-line no-case-declarations
const chessboardStartX = ( paperWidth - config . boardWidthIn * config . patternSpacingIn ) / 2
// eslint-disable-next-line no-case-declarations
const chessboardStartY = ( paperHeight - config . boardWidthIn * config . patternSpacingIn ) / 2
for ( let squareY = 0 ; squareY < config . boardHeightIn ; squareY ++ ) {
for ( let squareX = 0 ; squareX < config . boardWidthIn ; squareX ++ ) {
const xPos = chessboardStartX + squareX * config . patternSpacingIn
const yPos = chessboardStartY + squareY * config . patternSpacingIn
// Only draw the odd squares to create the chessboard pattern
if ( ( xPos + yPos + 0.25 ) % 2 === 0 ) {
doc . rect ( xPos , yPos , config . patternSpacingIn , config . patternSpacingIn , "F" )
2021-11-21 19:34:06 -06:00
}
}
}
2023-06-09 13:09:41 -04:00
break
case "dotgrid" :
// eslint-disable-next-line no-case-declarations
const dotgridStartX = ( paperWidth - ( 2 * ( config . boardWidthIn - 1 ) + ( ( config . boardHeightIn - 1 ) % 2 ) ) * config . patternSpacingIn ) / 2.0
// eslint-disable-next-line no-case-declarations
const dotgridStartY = ( paperHeight - ( config . boardHeightIn - config . patternSpacingIn ) ) / 2
for ( let squareY = 0 ; squareY < config . boardHeightIn ; squareY ++ ) {
for ( let squareX = 0 ; squareX < config . boardWidthIn ; squareX ++ ) {
const xPos = dotgridStartX + ( 2 * squareX + ( squareY % 2 ) ) * config . patternSpacingIn
const yPos = dotgridStartY + squareY * config . patternSpacingIn
doc . circle ( xPos , yPos , config . patternSpacingIn / 4 , "F" )
2021-11-21 19:34:06 -06:00
}
}
2023-06-09 13:09:41 -04:00
break
}
2021-11-21 19:34:06 -06:00
2023-06-09 13:09:41 -04:00
// Draw ruler pattern
const lineStartX = 1.0
const lineEndX = paperWidth - lineStartX
const lineY = paperHeight - 1.0
2021-11-21 19:34:06 -06:00
2023-06-09 13:09:41 -04:00
doc . setLineWidth ( 0.01 )
doc . line ( lineStartX , lineY , lineEndX , lineY )
2021-11-21 19:34:06 -06:00
2023-06-09 13:09:41 -04:00
for ( let tickX = lineStartX ; tickX <= lineEndX ; tickX ++ ) {
doc . line ( tickX , lineY , tickX , lineY + 0.25 )
doc . text ( ` ${ tickX - 1 } ${ tickX - 1 === 0 ? " in" : "" } ` , tickX + 0.1 , lineY + 0.25 )
}
2021-11-21 19:34:06 -06:00
2023-06-09 13:09:41 -04:00
// Add branding
const logoImage = new Image ( ) ;
logoImage . src = require ( '@/assets/logos/logoMono.png' ) ;
doc . addImage ( logoImage , 'PNG' , 1.0 , 0.75 , 1.4 , 0.5 ) ;
2021-11-21 19:34:06 -06:00
2023-06-09 13:09:41 -04:00
doc . text ( ` ${ config . boardWidthIn } x ${ config . boardHeightIn } | ${ config . patternSpacingIn } in ` , paperWidth - 1 , 1.0 ,
{
maxWidth : ( paperWidth - 2.0 ) / 2 ,
align : "right" ,
}
)
doc . save ( ` calibrationTarget- ${ config . type } .pdf ` )
2020-08-14 12:39:21 -07:00
} ,
sendCameraSettings ( ) {
this . axios . post ( "http://" + this . $address + "/api/settings/camera" , {
"settings" : this . cameraSettings ,
"index" : this . $store . state . currentCameraIndex
2022-10-17 11:41:57 -05:00
} ) . then ( response => {
2020-08-14 12:39:21 -07:00
if ( response . status === 200 ) {
this . $store . state . saveBar = true ;
2019-11-09 21:26:02 +02:00
}
Add solvePNP, 3d tab on the UI, and some other misc bug fixes (#35)
* Rebase solvePNP on master
* added 3D tab minimap and csv reader
* More solvePNP
* Create draw pipe for pnp data
* SolvePNP piping work
* Move sorting into solvepnppipe
* Create calibration pipeline
* Update CalibrateSolvePNPPipeline.java
* add camera tilt angle
* Add calibration slider and snapshot button to 3D view
* Mirror updates in the socket handler
* add 3d calibration mode to the pipeline manager
* created calibration functions in ui and backend
* Start plumbing calibration
* Add snapshot and other handling to the RequestHandler
* added select resolution before starting calibration
* Rename solvePNPPipe to bounding box solve pnp pipe
* Update BoundingBoxSolvePNPPipe.java
* Add Mat serializer and CameraCalibrationConfig
* Begun calibration saving, fixed UI/Backend snapshot count mismatch
* Add (unplumbed) option to set checkerboard size
This will allow users to change the units their calibration is in
* Create chessboard.png
* Fix calibration NPE
* changed string serialization to a json send
* bug fixed cancellation button
* Fix spelling of snapshot in 3d.vue
* Plumb resolution change
* Set resolution during config, start on config serialization
* Update .gitignore
* Config fixes
* Start transition away from cvpipeline3d
* fix NPE on uncalibrated cameras
* clear list on fail
* Fix video mode index error
* ignore getters in camera calibration config
* Create json constructor for jsonmat
* get solvePNP mostly returning sane values
* Fix solvePNP bug and add unit test
* FIx calibration mat truncation
* added capture amount model upload and minimap data
* Standardize on meters in calibration and bounding box
* fix json out of bounds and handle null calibration more gracefully
* don't put text on calibrate image, go back to inches
* convert distance to meters
this means calibration will need to be in inches
* Actually save raw contor
* Update GroupContoursPipe.java
* Add all calibration return to camera capture
* hard code 2019 target
* bugfixed draw2d added fail calib popup, merge end and cancel
added the res index to the calib start
* Clarify error message and draw more fancy rectangles
* Cleanup memory in solvepnp
* re did minimap component
* fix npe if left/right is null
* remove references to 2d
* try-catch running the current pipeline
* Add method to find corners using the harris corner detector
* Possibly fix left/right missmatch
* Fix 3D Tab error
* FIx file permissions, mat serializer adjustments
* fixed mini map for field coordinates
* mini map changes fov
* Update SolvePNPPipe.java
* get rid of target corners
* some memory leak fixes
* fixed mini map location
* added position under minimap
* changed player fov look
* put all targets in the web send
* re did target send to ui added target tables, bugfix calibration
* fixed y position
* Add tilt angle to capture properties
* maybe fix y axis in minimap
* Add square size to onCalibrationEnding
* Possibly add square size to UI
* fix NPE with pitch
* Fix bug with sending multiple targets
* Only instantiate 3d stuff if we are in 3d mode
* Fix array list exceptions
* Fix bug in sort contors
list was truncated too early
* added download chess, tilt setting and ordinal tilt,
* added square size connection
* removed unused code
* Update pom version to 2.1-RELEASE
* Send camera calibrations to UI
* Stream pose list to a LIst
* Only stream necessary parts of the aux list entry
* Make broadcastMessage synchronized to prevent ConcurrentModificationExceptions
* added fps counter changed squaresize steps bug fixes in tables
* bugfix camera settings cam wont change
Authored-by: oriagranat9 <oriagranat9@gmail.com>
2019-12-31 04:53:20 -08:00
}
2020-08-14 12:39:21 -07:00
)
} ,
isCalibrated ( resolution ) {
return this . $store . getters . currentCameraSettings . calibrations
2020-09-04 18:18:44 -07:00
. some ( e => e . width === resolution . width && e . height === resolution . height ) ;
2020-08-14 12:39:21 -07:00
} ,
sendCalibrationMode ( ) {
let data = {
[ 'cameraIndex' ] : this . $store . state . currentCameraIndex
} ;
2023-06-09 13:09:41 -04:00
if ( this . isCalibrating ) {
2020-08-14 12:39:21 -07:00
data [ 'takeCalibrationSnapshot' ] = true
} else {
2022-10-29 05:57:32 -05:00
// This store prevents an edge case of a user not selecting a different resolution, which causes the set logic to not be called
this . $store . commit ( 'mutateCalibrationState' , { [ 'videoModeIndex' ] : this . filteredResolutionList [ this . selectedFilteredResIndex ] . index } ) ;
2020-09-04 18:18:44 -07:00
const calData = this . calibrationData ;
calData . isCalibrating = true ;
data [ 'startPnpCalibration' ] = calData ;
console . log ( "starting calibration with index " + calData . videoModeIndex ) ;
2020-08-14 12:39:21 -07:00
}
2022-10-29 05:57:32 -05:00
this . $store . commit ( 'currentPipelineIndex' , - 2 ) ;
2023-01-06 17:25:11 -08:00
this . $store . state . websocket . ws . send ( this . $msgPack . encode ( data ) ) ;
2020-08-14 12:39:21 -07:00
} ,
sendCalibrationFinish ( ) {
2020-09-04 18:18:44 -07:00
console . log ( "finishing calibration for index " + this . $store . getters . currentCameraIndex ) ;
2020-08-14 12:39:21 -07:00
this . snack = true ;
2020-11-21 18:14:27 -08:00
this . calibrationInProgress = true ;
2020-08-14 12:39:21 -07:00
2023-06-09 13:09:41 -04:00
this . axios . post ( "http://" + this . $address + "/api/settings/endCalibration" , { idx : this . $store . getters . currentCameraIndex } )
2020-08-14 12:39:21 -07:00
. then ( ( response ) => {
2020-11-21 18:14:27 -08:00
if ( response . status === 200 ) {
this . calibrationInProgress = false ;
} else {
this . calibrationFailed = true ;
}
Add solvePNP, 3d tab on the UI, and some other misc bug fixes (#35)
* Rebase solvePNP on master
* added 3D tab minimap and csv reader
* More solvePNP
* Create draw pipe for pnp data
* SolvePNP piping work
* Move sorting into solvepnppipe
* Create calibration pipeline
* Update CalibrateSolvePNPPipeline.java
* add camera tilt angle
* Add calibration slider and snapshot button to 3D view
* Mirror updates in the socket handler
* add 3d calibration mode to the pipeline manager
* created calibration functions in ui and backend
* Start plumbing calibration
* Add snapshot and other handling to the RequestHandler
* added select resolution before starting calibration
* Rename solvePNPPipe to bounding box solve pnp pipe
* Update BoundingBoxSolvePNPPipe.java
* Add Mat serializer and CameraCalibrationConfig
* Begun calibration saving, fixed UI/Backend snapshot count mismatch
* Add (unplumbed) option to set checkerboard size
This will allow users to change the units their calibration is in
* Create chessboard.png
* Fix calibration NPE
* changed string serialization to a json send
* bug fixed cancellation button
* Fix spelling of snapshot in 3d.vue
* Plumb resolution change
* Set resolution during config, start on config serialization
* Update .gitignore
* Config fixes
* Start transition away from cvpipeline3d
* fix NPE on uncalibrated cameras
* clear list on fail
* Fix video mode index error
* ignore getters in camera calibration config
* Create json constructor for jsonmat
* get solvePNP mostly returning sane values
* Fix solvePNP bug and add unit test
* FIx calibration mat truncation
* added capture amount model upload and minimap data
* Standardize on meters in calibration and bounding box
* fix json out of bounds and handle null calibration more gracefully
* don't put text on calibrate image, go back to inches
* convert distance to meters
this means calibration will need to be in inches
* Actually save raw contor
* Update GroupContoursPipe.java
* Add all calibration return to camera capture
* hard code 2019 target
* bugfixed draw2d added fail calib popup, merge end and cancel
added the res index to the calib start
* Clarify error message and draw more fancy rectangles
* Cleanup memory in solvepnp
* re did minimap component
* fix npe if left/right is null
* remove references to 2d
* try-catch running the current pipeline
* Add method to find corners using the harris corner detector
* Possibly fix left/right missmatch
* Fix 3D Tab error
* FIx file permissions, mat serializer adjustments
* fixed mini map for field coordinates
* mini map changes fov
* Update SolvePNPPipe.java
* get rid of target corners
* some memory leak fixes
* fixed mini map location
* added position under minimap
* changed player fov look
* put all targets in the web send
* re did target send to ui added target tables, bugfix calibration
* fixed y position
* Add tilt angle to capture properties
* maybe fix y axis in minimap
* Add square size to onCalibrationEnding
* Possibly add square size to UI
* fix NPE with pitch
* Fix bug with sending multiple targets
* Only instantiate 3d stuff if we are in 3d mode
* Fix array list exceptions
* Fix bug in sort contors
list was truncated too early
* added download chess, tilt setting and ordinal tilt,
* added square size connection
* removed unused code
* Update pom version to 2.1-RELEASE
* Send camera calibrations to UI
* Stream pose list to a LIst
* Only stream necessary parts of the aux list entry
* Make broadcastMessage synchronized to prevent ConcurrentModificationExceptions
* added fps counter changed squaresize steps bug fixes in tables
* bugfix camera settings cam wont change
Authored-by: oriagranat9 <oriagranat9@gmail.com>
2019-12-31 04:53:20 -08:00
}
2020-11-21 18:14:27 -08:00
) . catch ( ( ) => {
this . calibrationFailed = true ;
2020-08-14 12:39:21 -07:00
} ) ;
2019-09-28 21:42:04 +03:00
}
}
2020-08-14 12:39:21 -07:00
}
2019-09-28 21:42:04 +03:00
< / script >
2023-06-09 13:09:41 -04:00
< style >
: : - webkit - scrollbar {
height : 0.55 em ;
}
< / style >
2020-08-14 12:39:21 -07:00
< style scoped >
2020-11-21 18:14:27 -08:00
. v - data - table {
text - align : center ;
background - color : transparent ! important ;
width : 100 % ;
height : 100 % ;
overflow - y : auto ;
}
2020-08-14 12:39:21 -07:00
2020-11-21 18:14:27 -08:00
. v - data - table th {
background - color : # 006492 ! important ;
}
. v - data - table th , td {
font - size : 1 rem ! important ;
}
2021-11-21 17:22:56 -08:00
< / style >