Separate out camera and merge detection mixins
Signed-off-by: Justin Georgi <justin.georgi@gmail.com>
This commit is contained in:
45
src/pages/camera-mixin.js
Normal file
45
src/pages/camera-mixin.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
async openCamera() {
|
||||||
|
var cameraLoaded = false
|
||||||
|
const devicesList = await navigator.mediaDevices.enumerateDevices()
|
||||||
|
this.videoDeviceAvailable = devicesList.some( d => d.kind == "videoinput")
|
||||||
|
if (this.videoDeviceAvailable) {
|
||||||
|
navigator.mediaDevices.getUserMedia({video: true})
|
||||||
|
var vidConstraint = {
|
||||||
|
video: {
|
||||||
|
width: {
|
||||||
|
ideal: 1920
|
||||||
|
},
|
||||||
|
height: {
|
||||||
|
ideal: 1080
|
||||||
|
},
|
||||||
|
facingMode: 'environment'
|
||||||
|
},
|
||||||
|
audio: false
|
||||||
|
}
|
||||||
|
const stream = await navigator.mediaDevices.getUserMedia(vidConstraint);
|
||||||
|
cameraLoaded = true
|
||||||
|
this.cameraStream = stream
|
||||||
|
}
|
||||||
|
return cameraLoaded
|
||||||
|
},
|
||||||
|
closeCamera () {
|
||||||
|
this.cameraStream.getTracks().forEach( t => t.stop())
|
||||||
|
this.videoAvailable = false
|
||||||
|
},
|
||||||
|
captureVidFrame() {
|
||||||
|
const vidViewer = this.$refs.vid_viewer
|
||||||
|
vidViewer.pause()
|
||||||
|
let tempCVS = document.createElement('canvas')
|
||||||
|
tempCVS.height = vidViewer.videoHeight || parseInt(vidViewer.style.height)
|
||||||
|
tempCVS.width = vidViewer.videoWidth || parseInt(vidViewer.style.width)
|
||||||
|
const tempCtx = tempCVS.getContext('2d')
|
||||||
|
tempCtx.drawImage(vidViewer, 0, 0)
|
||||||
|
this.getImage(tempCVS.toDataURL())
|
||||||
|
},
|
||||||
|
async videoStream() {
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -109,13 +109,13 @@
|
|||||||
import SvgIcon from '../components/svg-icon.vue'
|
import SvgIcon from '../components/svg-icon.vue'
|
||||||
|
|
||||||
import submitMixin from './submit-mixin'
|
import submitMixin from './submit-mixin'
|
||||||
import localDetectMixin from './local-detect'
|
import detectionMixin from './detection-mixin'
|
||||||
import remoteDetectMixin from './remote-detect'
|
import cameraMixin from './camera-mixin'
|
||||||
|
|
||||||
import thoraxClasses from '../models/thorax/classes.json'
|
import thoraxClasses from '../models/thorax/classes.json'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
mixins: [submitMixin, localDetectMixin, remoteDetectMixin],
|
mixins: [submitMixin, detectionMixin, cameraMixin],
|
||||||
props: {
|
props: {
|
||||||
f7route: Object,
|
f7route: Object,
|
||||||
},
|
},
|
||||||
@@ -160,9 +160,9 @@
|
|||||||
this.detectorName = 'thorax'
|
this.detectorName = 'thorax'
|
||||||
this.classesList = thoraxClasses
|
this.classesList = thoraxClasses
|
||||||
/* VITE setting */
|
/* VITE setting */
|
||||||
//this.modelLocation = '../models/thorax/model.json'
|
this.modelLocation = '../models/thorax/model.json'
|
||||||
/* PWA Build setting */
|
/* PWA Build setting */
|
||||||
this.modelLocation = './models/thorax/model.json'
|
//this.modelLocation = './models/thorax/model.json'
|
||||||
this.modelLocationCordova = 'https://localhost/models/thorax/model.json'
|
this.modelLocationCordova = 'https://localhost/models/thorax/model.json'
|
||||||
break;
|
break;
|
||||||
case 'abdomen':
|
case 'abdomen':
|
||||||
@@ -260,29 +260,10 @@
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (mode == "camera") {
|
if (mode == "camera") {
|
||||||
const devicesList = await navigator.mediaDevices.enumerateDevices()
|
this.videoAvailable = await this.openCamera()
|
||||||
this.videoDeviceAvailable = devicesList.some( d => d.kind == "videoinput")
|
if (this.videoAvailable) { return }
|
||||||
if (this.videoDeviceAvailable) {
|
|
||||||
navigator.mediaDevices.getUserMedia({video: true})
|
|
||||||
var vidConstraint = {
|
|
||||||
video: {
|
|
||||||
width: {
|
|
||||||
ideal: 1920
|
|
||||||
},
|
|
||||||
height: {
|
|
||||||
ideal: 1080
|
|
||||||
},
|
|
||||||
facingMode: 'environment'
|
|
||||||
},
|
|
||||||
audio: false
|
|
||||||
}
|
}
|
||||||
const stream = await navigator.mediaDevices.getUserMedia(vidConstraint);
|
this.$refs.image_chooser.click()
|
||||||
this.videoAvailable = true
|
|
||||||
this.cameraStream = stream
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var loadResult = this.$refs.image_chooser.click()
|
|
||||||
},
|
},
|
||||||
onFail (message) {
|
onFail (message) {
|
||||||
alert(`Camera fail: ${message}`)
|
alert(`Camera fail: ${message}`)
|
||||||
@@ -331,8 +312,7 @@
|
|||||||
getImage (searchImage) {
|
getImage (searchImage) {
|
||||||
let loadImage = new Promise(resolve => {
|
let loadImage = new Promise(resolve => {
|
||||||
if (this.videoAvailable) {
|
if (this.videoAvailable) {
|
||||||
this.cameraStream.getTracks().forEach( t => t.stop())
|
this.closeCamera()
|
||||||
this.videoAvailable = false
|
|
||||||
this.detecting = true
|
this.detecting = true
|
||||||
resolve(searchImage)
|
resolve(searchImage)
|
||||||
} else if (this.isCordova && this.imageLoadMode == "camera") {
|
} else if (this.isCordova && this.imageLoadMode == "camera") {
|
||||||
@@ -370,19 +350,6 @@
|
|||||||
f7.dialog.alert(`Error loading image: ${e.message}`)
|
f7.dialog.alert(`Error loading image: ${e.message}`)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async videoStream() {
|
|
||||||
//TODO
|
|
||||||
},
|
|
||||||
captureVidFrame() {
|
|
||||||
const vidViewer = this.$refs.vid_viewer
|
|
||||||
vidViewer.pause()
|
|
||||||
let tempCVS = document.createElement('canvas')
|
|
||||||
tempCVS.height = vidViewer.videoHeight || parseInt(vidViewer.style.height)
|
|
||||||
tempCVS.width = vidViewer.videoWidth || parseInt(vidViewer.style.width)
|
|
||||||
const tempCtx = tempCVS.getContext('2d')
|
|
||||||
tempCtx.drawImage(vidViewer, 0, 0)
|
|
||||||
this.getImage(tempCVS.toDataURL())
|
|
||||||
},
|
|
||||||
async submitData () {
|
async submitData () {
|
||||||
var uploadData = this.showResults
|
var uploadData = this.showResults
|
||||||
.filter( d => { return d.aboveThreshold && d.isSearched && !d.isDeleted })
|
.filter( d => { return d.aboveThreshold && d.isSearched && !d.isDeleted })
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import * as tf from '@tensorflow/tfjs'
|
import * as tf from '@tensorflow/tfjs'
|
||||||
|
import { f7 } from 'framework7-vue'
|
||||||
|
|
||||||
var model = null
|
var model = null
|
||||||
|
|
||||||
@@ -77,6 +78,70 @@ export default {
|
|||||||
console.timeEnd('post-process')
|
console.timeEnd('post-process')
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
},
|
||||||
|
getRemoteLabels() {
|
||||||
|
var self = this
|
||||||
|
var modelURL = `http://${this.serverSettings.address}:${this.serverSettings.port}/detectors`
|
||||||
|
var xhr = new XMLHttpRequest()
|
||||||
|
xhr.open("GET", modelURL)
|
||||||
|
xhr.setRequestHeader('Content-Type', 'application/json')
|
||||||
|
xhr.timeout = 10000
|
||||||
|
xhr.ontimeout = this.remoteTimeout
|
||||||
|
xhr.onload = function () {
|
||||||
|
if (this.status !== 200) {
|
||||||
|
console.log(xhr.response)
|
||||||
|
const errorResponse = JSON.parse(xhr.response)
|
||||||
|
f7.dialog.alert(`ALVINN has encountered an error: ${errorResponse.error}`)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
var detectors = JSON.parse(xhr.response).detectors
|
||||||
|
var findLabel = detectors
|
||||||
|
.find( d => { return d.name == self.detectorName } )?.labels
|
||||||
|
.filter( l => { return l != "" } ).sort()
|
||||||
|
.map( l => { return {'name': l, 'detect': true} } )
|
||||||
|
self.detectorLabels = findLabel || []
|
||||||
|
}
|
||||||
|
xhr.onerror = function (e) {
|
||||||
|
f7.dialog.alert('ALVINN has encountered an unknown server error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send()
|
||||||
|
},
|
||||||
|
remoteDetect() {
|
||||||
|
var self = this
|
||||||
|
var modelURL = `http://${this.serverSettings.address}:${this.serverSettings.port}/detect`
|
||||||
|
var xhr = new XMLHttpRequest()
|
||||||
|
xhr.open("POST", modelURL)
|
||||||
|
xhr.timeout = 10000
|
||||||
|
xhr.ontimeout = this.remoteTimeout
|
||||||
|
xhr.setRequestHeader('Content-Type', 'application/json')
|
||||||
|
xhr.onload = function () {
|
||||||
|
self.detecting = false
|
||||||
|
if (this.status !== 200) {
|
||||||
|
console.log(xhr.response)
|
||||||
|
const errorResponse = JSON.parse(xhr.response)
|
||||||
|
f7.dialog.alert(`ALVINN has encountered an error: ${errorResponse.error}`)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.resultData = JSON.parse(xhr.response)
|
||||||
|
self.uploadDirty = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var doodsData = {
|
||||||
|
"detector_name": this.detectorName,
|
||||||
|
"detect": {
|
||||||
|
"*": 1
|
||||||
|
},
|
||||||
|
"data": this.imageView.src.split(',')[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
xhr.send(JSON.stringify(doodsData))
|
||||||
|
},
|
||||||
|
remoteTimeout () {
|
||||||
|
this.detecting = false
|
||||||
|
f7.dialog.alert('No connection to remote ALVINN instance. Please check app settings.')
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,63 +0,0 @@
|
|||||||
export default {
|
|
||||||
methods: {
|
|
||||||
getRemoteLabels() {
|
|
||||||
var self = this
|
|
||||||
var modelURL = `http://${this.serverSettings.address}:${this.serverSettings.port}/detectors`
|
|
||||||
var xhr = new XMLHttpRequest()
|
|
||||||
xhr.open("GET", modelURL)
|
|
||||||
xhr.setRequestHeader('Content-Type', 'application/json')
|
|
||||||
xhr.timeout = 10000
|
|
||||||
xhr.ontimeout = this.remoteTimeout
|
|
||||||
xhr.onload = function () {
|
|
||||||
if (this.status !== 200) {
|
|
||||||
console.log(xhr.response)
|
|
||||||
const errorResponse = JSON.parse(xhr.response)
|
|
||||||
f7.dialog.alert(`ALVINN has encountered an error: ${errorResponse.error}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var detectors = JSON.parse(xhr.response).detectors
|
|
||||||
var findLabel = detectors
|
|
||||||
.find( d => { return d.name == self.detectorName } )?.labels
|
|
||||||
.filter( l => { return l != "" } ).sort()
|
|
||||||
.map( l => { return {'name': l, 'detect': true} } )
|
|
||||||
self.detectorLabels = findLabel || []
|
|
||||||
}
|
|
||||||
|
|
||||||
xhr.send()
|
|
||||||
},
|
|
||||||
remoteDetect() {
|
|
||||||
var self = this
|
|
||||||
var modelURL = `http://${this.serverSettings.address}:${this.serverSettings.port}/detect`
|
|
||||||
var xhr = new XMLHttpRequest()
|
|
||||||
xhr.open("POST", modelURL)
|
|
||||||
xhr.timeout = 10000
|
|
||||||
xhr.ontimeout = this.remoteTimeout
|
|
||||||
xhr.setRequestHeader('Content-Type', 'application/json')
|
|
||||||
xhr.onload = function () {
|
|
||||||
self.detecting = false
|
|
||||||
if (this.status !== 200) {
|
|
||||||
console.log(xhr.response)
|
|
||||||
const errorResponse = JSON.parse(xhr.response)
|
|
||||||
f7.dialog.alert(`ALVINN has encountered an error: ${errorResponse.error}`)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self.resultData = JSON.parse(xhr.response)
|
|
||||||
self.uploadDirty = true
|
|
||||||
}
|
|
||||||
|
|
||||||
var doodsData = {
|
|
||||||
"detector_name": this.detectorName,
|
|
||||||
"detect": {
|
|
||||||
"*": 1
|
|
||||||
},
|
|
||||||
"data": this.imageView.src.split(',')[1]
|
|
||||||
}
|
|
||||||
|
|
||||||
xhr.send(JSON.stringify(doodsData))
|
|
||||||
},
|
|
||||||
remoteTimeout () {
|
|
||||||
this.detecting = false
|
|
||||||
f7.dialog.alert('No connection to remote ALVINN instance. Please check app settings.')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user