Add photo detection framework (#8)
Closes #5. Reviewed-on: Georgi_Lab/ALVINN_f7#8
This commit is contained in:
@@ -1,22 +1,21 @@
|
||||
<template>
|
||||
<f7-page name="about">
|
||||
<f7-navbar title="About" back-link="Back"></f7-navbar>
|
||||
<f7-block-title>About My App</f7-block-title>
|
||||
<f7-block-title>About A.L.V.I.N.N.</f7-block-title>
|
||||
<f7-block>
|
||||
<p>
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Magni molestiae laudantium
|
||||
dignissimos est nobis delectus nemo ea alias voluptatum architecto, amet similique, saepe
|
||||
iste consectetur in repellat ut minus quibusdam!
|
||||
ALVINN is an object detection neural network specializing in the identification of anatomical structures from imagery of dissected, embalmed specimens in anatomy teaching labratories.
|
||||
ALVINN is intended as a learning aid only; it is not a tool for medical diagnosis, intervention, or treatment.
|
||||
</p>
|
||||
<p>
|
||||
Molestias et distinctio porro nesciunt ratione similique, magni doloribus, rerum nobis,
|
||||
aliquam quae reiciendis quasi modi. Nam a recusandae, fugiat in ea voluptates fuga eius,
|
||||
velit corrupti reprehenderit dignissimos consequatur!
|
||||
All of the images in ALVINN's models have been collected by students and faculty of Midwestern University's anatomy classes.
|
||||
</p>
|
||||
<p>
|
||||
Blanditiis, cumque quo adipisci. Molestiae, dolores dolorum quos doloremque ipsa ullam
|
||||
eligendi commodi deserunt doloribus inventore magni? Ea mollitia veniam nostrum nihil, iusto
|
||||
doloribus a at! Ea molestiae ullam delectus!
|
||||
ALVINN is conceived and created by Justin Georgi.
|
||||
Other contributions from:
|
||||
<ul>
|
||||
<li>Alexandra Davis</li>
|
||||
</ul>
|
||||
</p>
|
||||
</f7-block>
|
||||
</f7-page>
|
||||
|
||||
138
src/pages/detect.vue
Normal file
138
src/pages/detect.vue
Normal file
@@ -0,0 +1,138 @@
|
||||
<template>
|
||||
<f7-page name="detect">
|
||||
<!-- Top Navbar -->
|
||||
<f7-navbar :sliding="false" back-link="Back">
|
||||
<f7-nav-title sliding>{{ regions[activeRegion] }}</f7-nav-title>
|
||||
</f7-navbar>
|
||||
<f7-block style="display: flex; justify-content: flex-start; flex-direction: column; align-items: center; height: calc(100% - var(--f7-navbar-height) - var(--f7-safe-area-top));">
|
||||
<div class="image-box" style="display: flex; flex-direction: column; align-items: center; flex: 1 1 0%;" >
|
||||
<img :src="imageView" ref="image_src" style="min-width: 0; min-height: 0; flex: 1 1 0"/>
|
||||
<div ref="structure_box" style="border: solid 3px yellow; position: absolute; display: none;" />
|
||||
</div>
|
||||
<f7-segmented class="image-menu" raised style="margin: 5px; width: 50%; max-width: 400px; min-width: 192px; flex: 0 0 auto;">
|
||||
<f7-button popover-open="#region-popover">
|
||||
<img :src="imageRegion" style="height: 100%;" />
|
||||
</f7-button>
|
||||
<f7-button @click="setData" :class="(imageLoaded) ? '' : 'disabled'">
|
||||
<img src="../assets/icons/visibility.svg" style="height: 100%;" />
|
||||
</f7-button>
|
||||
<f7-button @click="selectImage">
|
||||
<img src="../assets/icons/image.svg" style="height: 100%;" />
|
||||
</f7-button>
|
||||
<f7-button @click="setData">
|
||||
<img src="../assets/icons/videocam.svg" style="height: 100%;" />
|
||||
</f7-button>
|
||||
</f7-segmented>
|
||||
<input type="file" ref="image_chooser" @change="getImage()" accept="image/png, image/jpg, image/jpeg" style="display: none;"/>
|
||||
<div v-if="resultData && resultData.detections" class="chip-results" style="flex: 0 0 auto;">
|
||||
<f7-chip v-for="(result, idx) in resultData.detections" :class="(idx == selectedChip) ? 'selected-chip' : ''" :text="result.label" media=" " :tooltip="result.confidence.toFixed(1)" :media-bg-color="chipColor(result.confidence)" deleteable @click="selectChip(idx)" @delete="deleteChip(idx)" />
|
||||
</div>
|
||||
</f7-block>
|
||||
</f7-page>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.chip-results {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 5px;
|
||||
--f7-chip-border-radius: 16px;
|
||||
--f7-chip-media-size: 32px;
|
||||
--f7-chip-font-weight: normal;
|
||||
}
|
||||
|
||||
.chip-results .chip {
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.selected-chip {
|
||||
font-weight: 500;
|
||||
box-shadow: 4px 4px 1px var(--f7-theme-color);
|
||||
transform: translate(-2px, -2px);
|
||||
}
|
||||
|
||||
.image-menu .button {
|
||||
aspect-ratio: 1;
|
||||
height: auto;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { f7 } from 'framework7-vue'
|
||||
import fakeData from './testData.js'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
f7route: Object,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
regions: ['Thorax','Abdomen/Pelvis','Limbs','Head and Neck'],
|
||||
resultData: {},
|
||||
selectedChip: -1,
|
||||
activeRegion: 4,
|
||||
imageRegion: '',
|
||||
imageLoaded: false,
|
||||
imageView: '../assets/icons/image.svg',
|
||||
}
|
||||
},
|
||||
created () {
|
||||
switch (this.f7route.params.region) {
|
||||
case 'thorax':
|
||||
this.activeRegion = 0
|
||||
this.imageRegion = '../assets/regions/thorax.svg'
|
||||
break;
|
||||
case 'abdomen':
|
||||
this.activeRegion = 1
|
||||
this.imageRegion = '../assets/regions/abdpel.svg'
|
||||
break;
|
||||
case 'limbs':
|
||||
this.activeRegion = 2
|
||||
this.imageRegion = '../assets/regions/limb.svg'
|
||||
break;
|
||||
case 'head':
|
||||
this.activeRegion = 3
|
||||
this.imageRegion = '../assets/regions/headneck.svg'
|
||||
break;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
chipColor (confVal) {
|
||||
if (confVal >= 90) return 'green'
|
||||
if (confVal >= 70) return 'lime'
|
||||
return 'yellow';
|
||||
},
|
||||
setData () {
|
||||
this.resultData = fakeData.testData
|
||||
},
|
||||
selectImage () {
|
||||
this.$refs.image_chooser.click()
|
||||
//TODO This really needs to be a promise and resolve system
|
||||
this.imageLoaded = true;
|
||||
var box = this.$refs.structure_box
|
||||
},
|
||||
selectChip ( iChip ) {
|
||||
this.selectedChip = iChip
|
||||
var box = this.$refs.structure_box
|
||||
var img = this.$refs.image_src
|
||||
var imgWidth = img.offsetWidth
|
||||
var imgHeight = img.offsetHeight
|
||||
box.style.display = "block"
|
||||
box.style.left = `calc( 50% - ${imgWidth/2}px + ${this.resultData.detections[iChip].left * imgWidth}px)`
|
||||
box.style.top = `${this.resultData.detections[iChip].top * imgHeight}px`
|
||||
box.style.width = `${(this.resultData.detections[iChip].right - this.resultData.detections[iChip].left) * imgWidth}px`
|
||||
box.style.height = `${(this.resultData.detections[iChip].bottom - this.resultData.detections[iChip].top) * imgHeight}px`
|
||||
},
|
||||
deleteChip ( iChip ) {
|
||||
f7.dialog.confirm(`${this.resultData.detections[iChip].label} is identified with ${this.resultData.detections[iChip].confidence.toFixed(1)}% confidence. Are you sure you want to delete it?`, () => {
|
||||
this.resultData.detections.splice(iChip, 1)
|
||||
});
|
||||
},
|
||||
getImage () {
|
||||
var example = this.$refs.image_chooser.files[0];
|
||||
this.imageView = URL.createObjectURL(example);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -7,54 +7,25 @@
|
||||
</f7-nav-left>
|
||||
<f7-nav-title sliding>A.L.V.I.N.N.</f7-nav-title>
|
||||
</f7-navbar>
|
||||
<!-- Toolbar-->
|
||||
<f7-toolbar bottom>
|
||||
<f7-link>Left Link</f7-link>
|
||||
<f7-link>Right Link</f7-link>
|
||||
</f7-toolbar>
|
||||
<!-- Page content-->
|
||||
<div style="display: flex; flex-direction: column; justify-content: center; align-items: center; width: 100%;">
|
||||
<h2>Anatomy Lab Visual Identification Neural Network</h2>
|
||||
<h4>Veterinary Anatomy Edition</h4>
|
||||
<p>Select a region to begin</p>
|
||||
<f7-segmented raised style="flex-wrap: wrap;">
|
||||
<f7-button style="height: auto; width: auto;">
|
||||
<f7-button style="height: auto; width: auto;" href="/detect/thorax/">
|
||||
<img src="../assets/regions/thorax.svg" />
|
||||
</f7-button>
|
||||
<f7-button style="height: auto; width: auto;">
|
||||
<f7-button style="height: auto; width: auto;" href="/detect/abdomen/">
|
||||
<img src="../assets/regions/abdpel.svg" />
|
||||
</f7-button>
|
||||
<f7-button style="height: auto; width: auto;">
|
||||
<f7-button style="height: auto; width: auto;" href="/detect/limbs/">
|
||||
<img src="../assets/regions/limb.svg" />
|
||||
</f7-button>
|
||||
<f7-button style="height: auto; width: auto;">
|
||||
<f7-button style="height: auto; width: auto;" href="/detect/head/">
|
||||
<img src="../assets/regions/headneck.svg" />
|
||||
</f7-button>
|
||||
</f7-segmented>
|
||||
</div>
|
||||
<f7-block-title>Navigation</f7-block-title>
|
||||
<f7-list strong inset dividersIos>
|
||||
<f7-list-item link="/about/" title="About"></f7-list-item>
|
||||
</f7-list>
|
||||
|
||||
<f7-block-title>Modals</f7-block-title>
|
||||
<f7-block class="grid grid-cols-2 grid-gap">
|
||||
<f7-button fill popup-open="#my-popup">Popup</f7-button>
|
||||
</f7-block>
|
||||
|
||||
<f7-list strong inset dividersIos>
|
||||
<f7-list-item
|
||||
title="Dynamic (Component) Route"
|
||||
link="/dynamic-route/blog/45/post/125/?foo=bar#about"
|
||||
></f7-list-item>
|
||||
<f7-list-item
|
||||
title="Default Route (404)"
|
||||
link="/load-something-that-doesnt-exist/"
|
||||
></f7-list-item>
|
||||
<f7-list-item
|
||||
title="Request Data & Load"
|
||||
link="/request-and-load/user/123456/"
|
||||
></f7-list-item>
|
||||
</f7-list>
|
||||
</f7-page>
|
||||
</template>
|
||||
@@ -1,25 +0,0 @@
|
||||
<template>
|
||||
<f7-page>
|
||||
<f7-navbar :title="`${user.firstName} ${user.lastName}`" back-link="Back"></f7-navbar>
|
||||
<f7-block strong inset>
|
||||
{{ user.about }}
|
||||
</f7-block>
|
||||
<f7-list strong inset dividers-ios>
|
||||
<f7-list-item
|
||||
v-for="(link, index) in user.links"
|
||||
:key="index"
|
||||
:link="link.url"
|
||||
:title="link.title"
|
||||
external
|
||||
target="_blank"
|
||||
></f7-list-item>
|
||||
</f7-list>
|
||||
</f7-page>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
user: Object,
|
||||
},
|
||||
};
|
||||
</script>
|
||||
55
src/pages/testData.js
Normal file
55
src/pages/testData.js
Normal file
@@ -0,0 +1,55 @@
|
||||
export default {
|
||||
testData: {
|
||||
"id": "manual",
|
||||
"detections": [
|
||||
{
|
||||
"top": 0.5543267130851746,
|
||||
"left": 0.514180064201355,
|
||||
"bottom": 0.7492024302482605,
|
||||
"right": 0.5877177715301514,
|
||||
"label": "Lung, Right",
|
||||
"confidence": 91.04458093643188
|
||||
},
|
||||
{
|
||||
"top": 0.24095627665519714,
|
||||
"left": 0.5838792324066162,
|
||||
"bottom": 0.9880742430686951,
|
||||
"right": 0.8479938507080078,
|
||||
"label": "Diaphragm",
|
||||
"confidence": 88.7181043624878
|
||||
},
|
||||
{
|
||||
"top": 0.3355500102043152,
|
||||
"left": 0.3559962809085846,
|
||||
"bottom": 0.4628722071647644,
|
||||
"right": 0.6606560349464417,
|
||||
"label": "Aorta",
|
||||
"confidence": 85.63258051872253
|
||||
},
|
||||
{
|
||||
"top": 0.46723803877830505,
|
||||
"left": 0.28829023241996765,
|
||||
"bottom": 0.8604505658149719,
|
||||
"right": 0.5213174819946289,
|
||||
"label": "Heart",
|
||||
"confidence": 85.21404266357422
|
||||
},
|
||||
{
|
||||
"top": 0.428698867559433,
|
||||
"left": 0.1482502520084381,
|
||||
"bottom": 0.5519284009933472,
|
||||
"right": 0.5934896469116211,
|
||||
"label": "Phrenic nerve",
|
||||
"confidence": 81.82616829872131
|
||||
},
|
||||
{
|
||||
"top": 0.4919853210449219,
|
||||
"left": 0.4810255169868469,
|
||||
"bottom": 0.5394672155380249,
|
||||
"right": 0.5925238728523254,
|
||||
"label": "Vena Cava, Caudal",
|
||||
"confidence": 75.55835843086243
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user