Created initial general documentation
This commit is contained in:
parent
dd7a3ff2e5
commit
ea10cf1ce9
16 changed files with 607 additions and 73 deletions
19
doc/Makefile
Normal file
19
doc/Makefile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
35
doc/make.bat
Normal file
35
doc/make.bat
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=source
|
||||
set BUILDDIR=build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
3
doc/requirements.txt
Normal file
3
doc/requirements.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
Sphinx
|
||||
sphinxcontrib-httpdomain
|
||||
sphinx_rtd_theme
|
||||
24
doc/source/api.rst
Normal file
24
doc/source/api.rst
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
REST API
|
||||
======================================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
API Documentation
|
||||
=================
|
||||
|
||||
Summary
|
||||
-------
|
||||
.. qrefflask:: openflexure_microscope.api.v1:app
|
||||
:undoc-endpoints: index
|
||||
:undoc-static:
|
||||
:endpoints:
|
||||
|
||||
Details
|
||||
-----------
|
||||
.. autoflask:: openflexure_microscope.api.v1:app
|
||||
:undoc-endpoints: index
|
||||
:undoc-static:
|
||||
:endpoints:
|
||||
:order: path
|
||||
5
doc/source/basecamera.rst
Normal file
5
doc/source/basecamera.rst
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Base Streaming Camera
|
||||
=======================================================
|
||||
|
||||
.. automodule:: openflexure_microscope.camera.base
|
||||
:members:
|
||||
10
doc/source/camera.rst
Normal file
10
doc/source/camera.rst
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
Camera Functionality
|
||||
=======================================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
picamera.rst
|
||||
basecamera.rst
|
||||
capture.rst
|
||||
5
doc/source/capture.rst
Normal file
5
doc/source/capture.rst
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Stream Object
|
||||
=======================================================
|
||||
|
||||
.. automodule:: openflexure_microscope.camera.capture
|
||||
:members:
|
||||
202
doc/source/conf.py
Normal file
202
doc/source/conf.py
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file does only contain a selection of the most common options. For a
|
||||
# full list see the documentation:
|
||||
# http://www.sphinx-doc.org/en/master/config
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'OpenFlexure Microscope Software'
|
||||
copyright = '2018, Bath Open Instrumentation Group'
|
||||
author = 'Bath Open Instrumentation Group'
|
||||
|
||||
# The short X.Y version
|
||||
version = ''
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = ''
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'sphinx.ext.autodoc',
|
||||
'sphinx.ext.napoleon',
|
||||
'sphinx.ext.intersphinx',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.viewcode',
|
||||
'sphinx.ext.githubpages',
|
||||
'sphinx.ext.ifconfig',
|
||||
'sphinxcontrib.httpdomain',
|
||||
'sphinxcontrib.autohttp.flask',
|
||||
'sphinxcontrib.autohttp.flaskqref',
|
||||
]
|
||||
|
||||
# Override ordering
|
||||
autodoc_member_order = 'bysource'
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = None
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
#
|
||||
# The default sidebars (for documents that don't match any pattern) are
|
||||
# defined by theme itself. Builtin themes are using these templates by
|
||||
# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
|
||||
# 'searchbox.html']``.
|
||||
#
|
||||
# html_sidebars = {}
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ---------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'OpenFlexureMicroscopeSoftwaredoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ------------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'OpenFlexureMicroscopeSoftware.tex', 'OpenFlexure Microscope Software Documentation',
|
||||
'Bath Open Instrumentation Group', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ------------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'openflexuremicroscopesoftware', 'OpenFlexure Microscope Software Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output ----------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'OpenFlexureMicroscopeSoftware', 'OpenFlexure Microscope Software Documentation',
|
||||
author, 'OpenFlexureMicroscopeSoftware', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Epub output -------------------------------------------------
|
||||
|
||||
# Bibliographic Dublin Core info.
|
||||
epub_title = project
|
||||
|
||||
# The unique identifier of the text. This can be a ISBN number
|
||||
# or the project homepage.
|
||||
#
|
||||
# epub_identifier = ''
|
||||
|
||||
# A unique identification for the text.
|
||||
#
|
||||
# epub_uid = ''
|
||||
|
||||
# A list of files that should not be packed into the epub file.
|
||||
epub_exclude_files = ['search.html']
|
||||
|
||||
|
||||
# -- Extension configuration -------------------------------------------------
|
||||
|
||||
# -- Options for intersphinx extension ---------------------------------------
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {
|
||||
'openflexure_stage': ('https://openflexure-stage.readthedocs.io/en/latest/', None),
|
||||
'picamera': ('https://picamera.readthedocs.io/en/release-1.13/', None)
|
||||
}
|
||||
|
||||
# -- Options for todo extension ----------------------------------------------
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = True
|
||||
18
doc/source/index.rst
Normal file
18
doc/source/index.rst
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
Welcome to OpenFlexure Microscope Software's documentation!
|
||||
===========================================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
microscope.rst
|
||||
camera.rst
|
||||
api.rst
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
9
doc/source/microscope.rst
Normal file
9
doc/source/microscope.rst
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
Microscope class
|
||||
=======================================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
.. automodule:: openflexure_microscope.microscope
|
||||
:members:
|
||||
5
doc/source/picamera.rst
Normal file
5
doc/source/picamera.rst
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Raspberry Pi Streaming Camera
|
||||
=======================================================
|
||||
|
||||
.. automodule:: openflexure_microscope.camera.pi
|
||||
:members:
|
||||
|
|
@ -81,7 +81,13 @@ class StreamAPI(MicroscopeView):
|
|||
|
||||
def get(self):
|
||||
"""
|
||||
Video streaming route. Put this in the src attribute of an img tag.
|
||||
Real-time MJPEG stream from the microscope camera
|
||||
|
||||
.. :quickref: State; Camera stream
|
||||
|
||||
:>header Accept: image/jpeg
|
||||
:>header Content-Type: image/jpeg
|
||||
:status 200: stream active
|
||||
"""
|
||||
# Restart stream worker thread
|
||||
self.microscope.camera.start_worker()
|
||||
|
|
@ -99,7 +105,39 @@ class StateAPI(MicroscopeView):
|
|||
|
||||
def get(self):
|
||||
"""
|
||||
Return JSONified microscope state.
|
||||
JSON representation of the microscope object.
|
||||
|
||||
.. :quickref: State; Microscope state
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /state/ HTTP/1.1
|
||||
Accept: application/json
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"preview_active": false,
|
||||
"record_active": false,
|
||||
"stream_active": true
|
||||
}
|
||||
|
||||
:>header Accept: application/json
|
||||
:>header Content-Type: application/json
|
||||
:status 200: state available
|
||||
"""
|
||||
return jsonify(self.microscope.state)
|
||||
|
||||
|
|
@ -115,17 +153,42 @@ class PositionAPI(MicroscopeView):
|
|||
def get(self):
|
||||
"""
|
||||
Return current x, y and z positions of the stage.
|
||||
|
||||
|
||||
.. :quickref: Position; Get current position
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /position/ HTTP/1.1
|
||||
Accept: application/json
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
}
|
||||
|
||||
:>json int x: x steps
|
||||
:>json int y: y steps
|
||||
:>json int z: z steps
|
||||
"""
|
||||
return jsonify(self.microscope.state['position'])
|
||||
|
||||
def post(self):
|
||||
"""
|
||||
Set x, y and z positions of the stage.
|
||||
|
||||
|
||||
.. :quickref: Position; Update current position
|
||||
|
||||
|
||||
:reqheader Accept: application/json
|
||||
:<json boolean absolute: (true) move to absolute position, (false) move by relative amount
|
||||
:<json boolean force: allow moving by more than programmed limit
|
||||
|
|
@ -183,8 +246,25 @@ class CaptureListAPI(MicroscopeView):
|
|||
def get(self):
|
||||
"""
|
||||
Get list of image captures.
|
||||
|
||||
|
||||
.. :quickref: Capture collection; Get collection of captures
|
||||
|
||||
:>header Accept: application/json
|
||||
:query include_unavailable: return json representations of captures that have been completely deleted
|
||||
|
||||
:>jsonarr boolean available: availability of capture data
|
||||
:>jsonarr string filename: filename of capture
|
||||
:>jsonarr string id: unique id of the capture object
|
||||
:>jsonarr boolean keep_on_disk: keep the capture file on microscope after closing
|
||||
:>jsonarr boolean locked: file locked for modifications (mostly used for video recording)
|
||||
:>jsonarr string path: path on pi storage to the capture file, if available
|
||||
:>jsonarr boolean stream: capture stored in-memory as a BytesIO stream
|
||||
:>jsonarr json uri: - **download** *(string)*: api uri to the capture file download
|
||||
- **metadata** *(string)*: api uri to the capture json representation
|
||||
|
||||
:>header Content-Type: application/json
|
||||
:status 200: capture found
|
||||
:status 404: no capture found with that id
|
||||
"""
|
||||
include_unavailable = get_bool(request.args.get('include_unavailable'))
|
||||
|
||||
|
|
@ -197,8 +277,8 @@ class CaptureListAPI(MicroscopeView):
|
|||
|
||||
def delete(self):
|
||||
"""
|
||||
Delete all captures.
|
||||
|
||||
Delete all captures (not yet implemented)
|
||||
|
||||
.. :quickref: Capture collection; Delete all captures
|
||||
"""
|
||||
return jsonify({"error": "not yet implemented"})
|
||||
|
|
@ -206,16 +286,47 @@ class CaptureListAPI(MicroscopeView):
|
|||
def post(self):
|
||||
"""
|
||||
Create a new image capture.
|
||||
|
||||
|
||||
.. :quickref: Capture collection; New capture
|
||||
|
||||
:reqheader Accept: application/json
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
POST /position/ HTTP/1.1
|
||||
Accept: application/json
|
||||
|
||||
{
|
||||
"filename": "myfirstcapture",
|
||||
"keep_on_disk": true,
|
||||
"use_video_port": true,
|
||||
"size": {
|
||||
"x": 640,
|
||||
"y": 480
|
||||
}
|
||||
}
|
||||
|
||||
:>header Accept: application/json
|
||||
|
||||
:<json string filename: filename of stored capture
|
||||
:<json boolean keep_on_disk: keep the capture file on microscope after closing
|
||||
:<json boolean use_video_port: capture still image from the video port (lower resolution)
|
||||
|
||||
:<json boolean use_video_port: capture still image from the video port
|
||||
:<json json size: - **x** *(int)*: x-axis resize
|
||||
- **y** *(int)*: y-axis resize
|
||||
|
||||
:>json boolean available: availability of capture data
|
||||
:>json string filename: filename of capture
|
||||
:>json string id: unique id of the capture object
|
||||
:>json boolean keep_on_disk: keep the capture file on microscope after closing
|
||||
:>json boolean locked: file locked for modifications (mostly used for video recording)
|
||||
:>json string path: path on pi storage to the capture file, if available
|
||||
:>json boolean stream: capture stored in-memory as a BytesIO stream
|
||||
:>json json uri: - **download** *(string)*: api uri to the capture file download
|
||||
- **metadata** *(string)*: api uri to the capture json representation
|
||||
|
||||
:<header Content-Type: application/json
|
||||
:status 200: capture created
|
||||
:status 422: invalid parameters
|
||||
"""
|
||||
state = parse_payload(request)
|
||||
|
||||
|
|
@ -263,8 +374,48 @@ class CaptureAPI(MicroscopeView):
|
|||
def get(self, capture_id):
|
||||
"""
|
||||
Get JSON representation of a capture
|
||||
|
||||
|
||||
.. :quickref: Capture; Get capture
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /capture/d0b2067abbb946f19351e075c5e7cd5b/ HTTP/1.1
|
||||
Accept: application/json
|
||||
|
||||
**Example response**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Vary: Accept
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"available": true,
|
||||
"filename": "2018-11-16_10-21-53.jpeg",
|
||||
"id": "d0b2067abbb946f19351e075c5e7cd5b",
|
||||
"keep_on_disk": false,
|
||||
"locked": false,
|
||||
"path": "capture/2018-11-16_10-21-53.jpeg",
|
||||
"stream": false,
|
||||
"uri": {
|
||||
"download": "/api/v1/capture/d0b2067abbb946f19351e075c5e7cd5b/download",
|
||||
"metadata": "/api/v1/capture/d0b2067abbb946f19351e075c5e7cd5b/"
|
||||
}
|
||||
}
|
||||
|
||||
:>json boolean available: availability of capture data
|
||||
:>json string filename: filename of capture
|
||||
:>json string id: unique id of the capture object
|
||||
:>json boolean keep_on_disk: keep the capture file on microscope after closing
|
||||
:>json boolean locked: file locked for modifications (mostly used for video recording)
|
||||
:>json string path: path on pi storage to the capture file, if available
|
||||
:>json boolean stream: capture stored in-memory as a BytesIO stream
|
||||
:>json json uri: - **download** *(string)*: api uri to the capture file download
|
||||
- **metadata** *(string)*: api uri to the capture json representation
|
||||
|
||||
"""
|
||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
||||
|
||||
|
|
@ -290,7 +441,7 @@ class CaptureAPI(MicroscopeView):
|
|||
|
||||
def delete(self, capture_id):
|
||||
"""
|
||||
Delete a capture
|
||||
Delete a capture (not yet implemented)
|
||||
|
||||
.. :quickref: Capture; Delete capture
|
||||
"""
|
||||
|
|
@ -298,7 +449,7 @@ class CaptureAPI(MicroscopeView):
|
|||
|
||||
def put(self, capture_id):
|
||||
"""
|
||||
Modify the metadata of a capture
|
||||
Modify the metadata of a capture (not yet implemented)
|
||||
|
||||
.. :quickref: Capture; Update capture metadata
|
||||
"""
|
||||
|
|
@ -315,6 +466,20 @@ class CaptureDownloadAPI(MicroscopeView):
|
|||
Return image data for a capture.
|
||||
|
||||
.. :quickref: Capture; Download capture file
|
||||
|
||||
**Example request**:
|
||||
|
||||
.. sourcecode:: http
|
||||
|
||||
GET /capture/d0b2067abbb946f19351e075c5e7cd5b/download?thumbnail=true HTTP/1.1
|
||||
Accept: image/jpeg
|
||||
|
||||
:>header Accept: image/jpeg
|
||||
:query thumbnail: return an image thumbnail e.g. ?thumbnail=true
|
||||
|
||||
:>header Content-Type: image/jpeg
|
||||
:status 200: capture data found
|
||||
:status 404: no capture found with that id
|
||||
"""
|
||||
print(capture_id)
|
||||
capture_obj = self.microscope.camera.image_from_id(capture_id)
|
||||
|
|
|
|||
|
|
@ -34,13 +34,12 @@ def entry_by_id(id: str, object_list: list):
|
|||
|
||||
|
||||
class CameraEvent(object):
|
||||
def __init__(self):
|
||||
"""
|
||||
Create a frame-signaller object for StreamingCamera.
|
||||
"""
|
||||
A frame-signaller object used by any instances or subclasses of BaseCamera.
|
||||
|
||||
An event-like class that signals all active clients
|
||||
when a new frame is available.
|
||||
"""
|
||||
An event-like class that signals all active clients when a new frame is available.
|
||||
"""
|
||||
def __init__(self):
|
||||
self.events = {}
|
||||
|
||||
def wait(self, timeout: int=5):
|
||||
|
|
@ -79,21 +78,23 @@ class CameraEvent(object):
|
|||
|
||||
|
||||
class BaseCamera(object):
|
||||
"""
|
||||
Base implementation of StreamingCamera.
|
||||
"""
|
||||
def __init__(self):
|
||||
"""Base implementation of StreamingCamera."""
|
||||
self.thread = None # Background thread that reads frames from camera
|
||||
self.camera = None # Camera object, for direct access to camera
|
||||
self.thread = None #: Background thread reading frames from camera
|
||||
self.camera = None #: Camera object
|
||||
|
||||
self.frame = None # Current frame is stored here by background thread
|
||||
self.last_access = 0 # Time of last client access to the camera
|
||||
self.frame = None #: bytes: Current frame is stored here by background thread
|
||||
self.last_access = 0 #: time: Time of last client access to the camera
|
||||
self.event = CameraEvent()
|
||||
|
||||
self.state = {} # Create dict for capture state
|
||||
self.settings = {} # Create dict to store settings
|
||||
self.state = {} #: dict: Dictionary for capture state
|
||||
self.settings = {} #: dict: Dictionary of camera settings
|
||||
|
||||
# Capture data
|
||||
self.images = []
|
||||
self.videos = []
|
||||
self.images = [] #: list: List of image capture objects
|
||||
self.videos = [] #: list: List of video recording objects
|
||||
|
||||
def __enter__(self):
|
||||
"""Create camera on context enter."""
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ thumbnail_size = (60, 60)
|
|||
|
||||
|
||||
class StreamObject(object):
|
||||
"""
|
||||
StreamObject used to store and process capture data, and metadata.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
write_to_file: bool=None,
|
||||
|
|
|
|||
|
|
@ -55,12 +55,12 @@ DEFAULT_CONFIG = os.path.join(HERE, 'config_picamera.yaml')
|
|||
|
||||
|
||||
class StreamingCamera(BaseCamera):
|
||||
"""Raspberry Pi camera implementation of StreamingCamera."""
|
||||
def __init__(self):
|
||||
"""Raspberry Pi camera implementation of StreamingCamera."""
|
||||
# Run BaseCamera init
|
||||
BaseCamera.__init__(self)
|
||||
# Attach to Pi camera
|
||||
self.camera = picamera.PiCamera()
|
||||
self.camera = picamera.PiCamera() #: :py:class:`picamera.PiCamera`: Picamera object
|
||||
|
||||
# Camera settings
|
||||
self.settings.update({
|
||||
|
|
@ -93,13 +93,21 @@ class StreamingCamera(BaseCamera):
|
|||
|
||||
# HANDLE SETTINGS
|
||||
|
||||
# TODO: Handle exceptions
|
||||
# TODO: Have this take a dictionary (not a config file)
|
||||
# TODO: Web API entry point to send settings as JSON to this method
|
||||
# TODO: Separate method to store current settings back to YAML file
|
||||
# TODO: API entry point to get settings to JSON
|
||||
def update_settings(self, config_path: str=None) -> None:
|
||||
"""Open config_picamera.yaml file and write to camera."""
|
||||
"""
|
||||
Open config_picamera.yaml file and write to camera.
|
||||
|
||||
Todo:
|
||||
TODO: Handle exceptions
|
||||
|
||||
TODO: Have this take a dictionary (not a config file)
|
||||
|
||||
TODO: Web API entry point to send settings as JSON to this method
|
||||
|
||||
TODO: Separate method to store current settings back to YAML file
|
||||
|
||||
TODO: API entry point to get settings to JSON
|
||||
"""
|
||||
global DEFAULT_CONFIG
|
||||
|
||||
paused_stream = False
|
||||
|
|
@ -164,7 +172,12 @@ class StreamingCamera(BaseCamera):
|
|||
"Cannot update camera settings while recording is active.")
|
||||
|
||||
def change_zoom(self, zoom_value: int=1) -> None:
|
||||
"""Change the camera zoom, handling recentering and scaling."""
|
||||
"""Change the camera zoom, handling recentering and scaling.
|
||||
|
||||
Todo:
|
||||
TODO: Needs to be re-implemented
|
||||
|
||||
"""
|
||||
zoom_value = float(zoom_value)
|
||||
if zoom_value < 1:
|
||||
zoom_value = 1
|
||||
|
|
@ -204,17 +217,20 @@ class StreamingCamera(BaseCamera):
|
|||
folder: str='record',
|
||||
fmt: str='h264',
|
||||
quality: int=15):
|
||||
"""Start a new video recording, writing to a target object.
|
||||
"""Start recording.
|
||||
|
||||
Start a new video recording, writing to a target object.
|
||||
|
||||
Args:
|
||||
target (str/BytesIO): Target object to write bytes to.
|
||||
write_to_file (bool/NoneType): Should the StreamObject write to a file?
|
||||
filename (str): Name of the stored file. Defaults to timestamp.
|
||||
folder (str): Relative directory to store data file in.
|
||||
fmt (str): Format of the capture.
|
||||
|
||||
Returns:
|
||||
target_object (str/BytesIO): Target object.
|
||||
|
||||
target (str/BytesIO): Target object to write bytes to.
|
||||
(default StreamObject)
|
||||
write_to_file (bool/NoneType): Should the StreamObject write to a file?
|
||||
(default True for video capture)
|
||||
filename (str): Name of the stored file.
|
||||
(defaults to timestamp)
|
||||
folder (str): Relative directory to store data file in.
|
||||
fmt (str): Format of the capture.
|
||||
(default 'h264')
|
||||
"""
|
||||
# Start recording method only if a current recording is not running
|
||||
if not self.state['record_active']:
|
||||
|
|
@ -274,9 +290,9 @@ class StreamingCamera(BaseCamera):
|
|||
"""
|
||||
Pause capture on a splitter port.
|
||||
|
||||
splitter_port (int): Splitter port to stop recording on
|
||||
resolution ((int, int)): Resolution to set the camera to,
|
||||
after stopping recording.
|
||||
Args:
|
||||
splitter_port (int): Splitter port to stop recording on
|
||||
resolution ((int, int)): Resolution to set the camera to, after stopping recording.
|
||||
"""
|
||||
logging.debug("Pausing stream")
|
||||
# If no resolution is specified, default to image_resolution
|
||||
|
|
@ -296,9 +312,9 @@ class StreamingCamera(BaseCamera):
|
|||
"""
|
||||
Resume capture on a splitter port.
|
||||
|
||||
splitter_port (int): Splitter port to start recording on
|
||||
resolution ((int, int)): Resolution to set the camera to,
|
||||
before starting recording.
|
||||
Args:
|
||||
splitter_port (int): Splitter port to start recording on
|
||||
resolution ((int, int)): Resolution to set the camera to, before starting recording.
|
||||
"""
|
||||
logging.debug("Unpausing stream")
|
||||
if not resolution:
|
||||
|
|
@ -330,17 +346,14 @@ class StreamingCamera(BaseCamera):
|
|||
Defaults to JPEG format.
|
||||
Target object can be overridden for development purposes.
|
||||
|
||||
target (str/BytesIO): Target object to write data bytes to.
|
||||
write_to_file (bool): Should the StreamObject write to a file,
|
||||
instead of BytesIO stream?
|
||||
use_video_port (bool): Capture from the video port used for streaming.
|
||||
(lower resolution, faster)
|
||||
filename (str): Name of the stored file.
|
||||
(defaults to timestamp)
|
||||
folder (str): Relative directory to store data file in.
|
||||
fmt (str): Format of the capture.
|
||||
(default 'h264')
|
||||
resize ((int, int)): Resize the captured image.
|
||||
Args:
|
||||
target (str/BytesIO): Target object to write data bytes to.
|
||||
write_to_file (bool): Should the StreamObject write to a file, instead of BytesIO stream?
|
||||
use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster.
|
||||
filename (str): Name of the stored file. Defaults to timestamp.
|
||||
folder (str): Relative directory to store data file in.
|
||||
fmt (str): Format of the capture.
|
||||
resize ((int, int)): Resize the captured image.
|
||||
"""
|
||||
# If no target is specified, store to StreamingCamera
|
||||
if not target:
|
||||
|
|
@ -391,9 +404,9 @@ class StreamingCamera(BaseCamera):
|
|||
resize: Tuple[int, int]=None) -> np.ndarray:
|
||||
"""Capture an uncompressed still YUV image to a Numpy array.
|
||||
|
||||
use_video_port (bool): Capture from the video port used for streaming.
|
||||
(lower resolution, faster)
|
||||
resize ((int, int)): Resize the captured image.
|
||||
Args:
|
||||
use_video_port (bool): Capture from the video port used for streaming. Lower resolution, faster.
|
||||
resize ((int, int)): Resize the captured image.
|
||||
"""
|
||||
if use_video_port:
|
||||
resolution = self.settings['video_resolution']
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Defines a microscope object, binding a camera and stage with basic functionality.
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from openflexure_stage import OpenFlexureStage
|
||||
|
|
@ -6,12 +10,20 @@ from .camera.pi import StreamingCamera
|
|||
|
||||
|
||||
class Microscope(object):
|
||||
"""
|
||||
A basic microscope object.
|
||||
|
||||
The camera and stage should already be initialised, and passed as arguments.
|
||||
|
||||
Args:
|
||||
camera (:py:class:`openflexure_microscope.camera.pi.StreamingCamera`): camera object
|
||||
microscope (:py:class:`openflexure_stage.stage.OpenFlexureStage`): stage object
|
||||
"""
|
||||
def __init__(self, camera: StreamingCamera, stage: OpenFlexureStage):
|
||||
"""Create the microscope object. The camera and stage should already be initialised."""
|
||||
print("Assigning camera")
|
||||
self.camera = camera
|
||||
self.camera = camera #: :py:class:`openflexure_microscope.camera.pi.StreamingCamera`: Picamera object
|
||||
print("Assigning stage")
|
||||
self.stage = stage
|
||||
self.stage = stage #: :py:class:`openflexure_stage.stage.OpenFlexureStage`: OpenFlexure stage object
|
||||
self.stage.backlash = np.zeros(3, dtype=np.int)
|
||||
|
||||
def __enter__(self):
|
||||
|
|
@ -30,6 +42,11 @@ class Microscope(object):
|
|||
# Create unified state
|
||||
@property
|
||||
def state(self):
|
||||
"""Dictionary of the basic microscope state.
|
||||
|
||||
Return:
|
||||
dict: Dictionary containing position data, and :py:attr:`openflexure_microscope.camera.base.BaseCamera.state`
|
||||
"""
|
||||
state = {}
|
||||
|
||||
# Add stage position
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue