Skip to content

Canvas annotation app #407

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 25 commits into from
Mar 19, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
fefe378
iniital app commit (wip)
Feb 10, 2020
e86af3b
add tesseract-ocr into req, test use canvas util img for pyterract im…
ycaokris Feb 10, 2020
788473f
Merge pull request #408 from plotly/oss-canvas-kris
sstripps1 Feb 10, 2020
b671d64
Add basic layout structure
ycaokris Feb 11, 2020
2333d9d
Merge branch 'oss-canvas-text' into oss-canvas-kris
ycaokris Feb 11, 2020
83e0edd
Minor tweaks
ycaokris Feb 11, 2020
44a6bc6
set fixed canvas to 200
ycaokris Feb 11, 2020
734effb
Merge pull request #409 from plotly/oss-canvas-kris
sstripps1 Feb 11, 2020
95b3e73
Add extra IAM segment for testing out model
ycaokris Feb 11, 2020
bc94b58
adding iam trained model to app
Feb 11, 2020
84b3fc5
updating requirements and adding procfile
Feb 11, 2020
326a521
cleaning up app divs
Feb 12, 2020
d46a341
Add reset button, style change, change linewidth for canvas, widen ca…
ycaokris Feb 12, 2020
1fbd4cf
Add exception handling for out of bounding box
ycaokris Feb 12, 2020
97c5afe
removing iam model, minor styling tweaks, linting app.py
Feb 12, 2020
1cc5bbc
fixing bounding box error message
Feb 12, 2020
950c663
removing IAM model dependencies from app requirements
Feb 12, 2020
eeee18c
Replace clear feature from dcc link to canvas clear rc, styling edit
ycaokris Feb 13, 2020
4012f16
Use rc to handle out of bounding box issue
ycaokris Feb 14, 2020
8e57ceb
Clean up
ycaokris Feb 14, 2020
9fdb73a
Add readme
ycaokris Feb 14, 2020
fbe4f1e
Merge pull request #411 from plotly/oss-canvas-text-clear-btn
ycaokris Feb 14, 2020
bcfe527
rename this app
ycaokris Feb 14, 2020
62b1ccc
Merge branch 'master' into oss-canvas-text
Mar 19, 2020
becee44
Linting Code
AirballClaytonCalvin Mar 19, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions apps/dash-canvas-ocr/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Created by .ignore support plugin (hsz.mobi)
### Python template
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# celery beat schedule file
celerybeat-schedule

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

1 change: 1 addition & 0 deletions apps/dash-canvas-ocr/Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: gunicorn app:server
40 changes: 40 additions & 0 deletions apps/dash-canvas-ocr/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Dash Canvas OCR

## How to Use this app

Write inside Canvas with your mouse toggling, or tablet stylus, and click **Sign** to translate your handwritten digits via optical character recognition.
The result of text recognition output will be reflected on the page.


### Running the app locally
We suggest you to create a separate virtual environment running Python 3 for this app, and install all of the required dependencies there. Run in Terminal/Command Prompt:

```
git clone https://github.com/plotly/dash-sample-apps
cd dash-sample-apps/apps/dash-canvas-ocr
python3 -m virtualenv venv
```
In UNIX system:

```
source venv/bin/activate
```
In Windows:

```
venv\Scripts\activate
```
This app requires installation of `tesseract` on your local device, check [this guide](https://linuxhint.com/install-tesseract-ocr-linux/) to install it according to your operating system.
To install all of the required packages to your virtual environment, simply run:

```
pip install -r requirements.txt
```

and all of the required `pip` packages, will be installed, and the app will be able to run.

```
pythonb app.py
```

![screenshot](screenshot.png)
120 changes: 120 additions & 0 deletions apps/dash-canvas-ocr/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
from PIL import Image
import base64
from io import BytesIO

import dash
import numpy as np
import dash_html_components as html
import dash_core_components as dcc
from dash_canvas import DashCanvas
from dash_canvas.utils import array_to_data_url, parse_jsonstring
from dash.dependencies import Input, Output, State
from dash.exceptions import PreventUpdate

import pytesseract

app = dash.Dash(__name__)
server = app.server

canvas_width = 800
canvas_height = 200

app.layout = html.Div(
[
# Banner
html.Div(
[
html.Img(src=app.get_asset_url("ocr-logo.png"), className="app__logo"),
html.H4("Dash OCR", className="header__text"),
],
className="app__header",
),
# Canvas
html.Div(
[
html.Div(
[
html.P(
"Write inside the canvas with your stylus and press Sign",
className="section_title",
),
html.Div(
DashCanvas(
id="canvas",
lineWidth=8,
width=canvas_width,
height=canvas_height,
hide_buttons=[
"zoom",
"pan",
"line",
"pencil",
"rectangle",
"select",
],
add_only=False,
lineColor="black",
goButtonTitle="Sign",
),
className="canvas-outer",
style={"margin-top": "1em"},
),
],
className="v-card-content",
),
html.Div(
html.Button(id="clear", children="clear"),
className="v-card-content-markdown-outer",
),
html.Div(
[
html.B("Text Recognition Output", className="section_title"),
dcc.Loading(dcc.Markdown(id="text-output", children="")),
],
className="v-card-content",
style={"margin-top": "1em"},
),
],
className="app__content",
),
]
)


@app.callback(Output("canvas", "json_objects"), [Input("clear", "n_clicks")])
def clear_canvas(n):
if n is None:
return dash.no_update
strings = ['{"objects":[ ]}', '{"objects":[]}']
return strings[n % 2]


@app.callback(
Output("text-output", "children"), [Input("canvas", "json_data")],
)
def update_data(string):
if string:

try:
mask = parse_jsonstring(string, shape=(canvas_height, canvas_width))
except:
return "Out of Bounding Box, click clear button and try again"
# np.savetxt('data.csv', mask) use this to save the canvas annotations as a numpy array
# Invert True and False
mask = (~mask.astype(bool)).astype(int)

image_string = array_to_data_url((255 * mask).astype(np.uint8))

# this is from canvas.utils.image_string_to_PILImage(image_string)
img = Image.open(BytesIO(base64.b64decode(image_string[22:])))

text = "{}".format(
pytesseract.image_to_string(img, lang="eng", config="--psm 6")
)
return text
else:
raise PreventUpdate


if __name__ == "__main__":
app.run_server(debug=True)
2 changes: 2 additions & 0 deletions apps/dash-canvas-ocr/apt-packages
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
tesseract-ocr
libtesseract-dev
Loading