Skip to content

Instantly share code, notes, and snippets.

@oeway
Last active November 3, 2021 15:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oeway/f59c1d1c49c94a831e5e21ba4c6111dd to your computer and use it in GitHub Desktop.
Save oeway/f59c1d1c49c94a831e5e21ba4c6111dd to your computer and use it in GitHub Desktop.
<docs lang="markdown">
[TODO: write documentation for this plugin.]
</docs>
<config lang="json">
{
"name": "PycroCam",
"type": "window",
"tags": [],
"ui": "",
"version": "0.1.2",
"api_version": "0.1.8",
"description": "A microscopy control plugin built on top of PycroManager",
"icon": "extension",
"inputs": null,
"outputs": null,
"env": "",
"requirements": [
"https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.22/vue.min.js",
"https://unpkg.com/buefy/dist/buefy.min.css",
"https://unpkg.com/buefy/dist/buefy.min.js",
"https://cdn.materialdesignicons.com/5.3.45/css/materialdesignicons.min.css",
"https://oeway.github.io/itk-vtk-viewer/itkVtkViewerCDN.js"
],
"dependencies": [],
"defaults": {"w": 20, "h": 10},
"runnable": true
}
</config>
<script lang="javascript">
api.registerCodec({
name: 'itkimage',
decoder: itkVtkViewer.utils.convertToItkImage
})
api.registerCodec({
name: 'ndarray',
decoder: itkVtkViewer.utils.ndarrayToItkImage
})
const app = new Vue({
el: '#app',
data: {
mmcore: null,
viewer: null,
liveRunning: false,
binning: 1,
exposure: 100,
cameraDevice: null,
},
methods: {
async init(mmcore){
this.mmcore = mmcore;
this.cameraDevice = await this.mmcore.getCameraDevice()
this.exposure = await this.mmcore.getExposure()
this.binning = await this.mmcore.getProperty(this.cameraDevice, 'Binning')
this.updateImage()
},
async createViewer(imageData, el) {
imageData = itkVtkViewer.utils.vtkITKHelper.convertItkToVtkImage(imageData)
// clear container
el.innerHTML = "";
const toolbar = document.createElement('div')
el.appendChild(toolbar)
const view = document.createElement('div')
el.appendChild(view)
const dims = imageData.getDimensions()
const is2D = dims.length === 2 || (dims.length === 3 && dims[2] === 1)
const viewer = itkVtkViewer.createViewer(view, {
image: imageData,
pointSets: null,
geometries: null,
use2D: is2D,
rotate: false,
uiContainer: toolbar
})
return viewer
},
async updateImage(){
if(!this.mmcore){
api.alert('No mmcore api provided.')
return
}
let img;
if(this.liveRunning){
img = await this.mmcore.getImage()
// if no image available, return
if(!img) return;
}
else{
img = await this.mmcore.snapImage()
}
if(!this.viewer){
const elm = document.getElementById('viewer')
this.viewer = await this.createViewer(img, elm)
}
else{
this.viewer.setImage(itkVtkViewer.utils.vtkITKHelper.convertItkToVtkImage(img))
}
if(this.liveRunning){
this.updateImage()
}
},
async toggleLive(){
this.liveRunning = !this.liveRunning
if(this.liveRunning){
this.mmcore.startContinuousSequenceAcquisition(0)
this.updateImage()
}
else{
this.mmcore.stopSequenceAcquisition()
}
},
async showDevicePropertyBrowser(){
const browser = await api.showDialog({src: "https://gist.github.com/oeway/d07f14fca4d9ab1febbde200d0369bf2", data:{'mmcore': this.mmcore}})
browser.on('property_changed', (item)=>{
if(item.device === this.cameraDevice && item.prop === 'Exposure'){
this.exposure = item.value
}
else if(item.device === this.cameraDevice && item.prop === 'Binning'){
this.binning = item.value
}
})
}
}
})
class ImJoyPlugin {
async setup() {
}
async run(ctx) {
await app.init(ctx.data.mmcore)
}
}
api.export(new ImJoyPlugin())
</script>
<window lang="html">
<div id="app">
<section>
<div class="buttons">
<b-button type="is-primary" @click="updateImage()" :loading="liveRunning">Snap</b-button>
<b-button :type="liveRunning?'is-danger': 'is-primary is-light'"
@click="toggleLive()">{{liveRunning?'Stop Live': 'Start Live'}}</b-button>
&nbsp;Exposure: <b-field>
<b-input placeholder="Exposure"
size="is-small"
@input="mmcore.setExposure(parseFloat(exposure))"
v-model="exposure"
type="number"
min="0"
max="10000">
</b-input>
</b-field>
&nbsp;Binning: <b-field>
<b-select placeholder="Binning"
size="is-small"
@input="mmcore.setProperty(cameraDevice, 'Binning', binning)"
v-model="binning">
<option :value="1">1</option>
<option :value="2">2</option>
<option :value="4">4</option>
<option :value="8">8</option>
<option :value="16">16</option>
</b-select>
</b-field>
&nbsp;&nbsp;<b-button size="is-small" @click="showDevicePropertyBrowser()">Device Properties</b-button>
</div>
</section>
<section id="viewer-section">
<div id="viewer" class="viewer-container">
</div>
</section>
</div>
</window>
<style lang="css">
#app{
margin-top: 2px;
}
#viewer-section{
display: table;
margin-top: 5px;
max-width: calc( 100vh - 32px );
}
.viewer-container{
display: table-cell;
position: relative;
}
.field {
margin-bottom: .2rem!important;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment