afshin-dini commited on
Commit
36ccd32
·
0 Parent(s):

Transfer project

Browse files
.bumpversion.cfg ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [bumpversion]
2
+ current_version = 0.3.0
3
+ commit = False
4
+ tag = False
5
+
6
+ [bumpversion:file:pyproject.toml]
7
+ search = version = "{current_version}"
8
+ replace = version = "{new_version}"
9
+
10
+ [bumpversion:file:src/deep_barcode_reader/__init__.py]
11
+ search = __version__ = "{current_version}"
12
+ replace = __version__ = "{new_version}"
13
+
14
+ [bumpversion:file:tests/test_deep_barcode_reader.py]
15
+ search = __version__ == "{current_version}"
16
+ replace = __version__ == "{new_version}"
.gitattributes ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ src/deep_barcode_reader/models/sr.caffemodel filter=lfs diff=lfs merge=lfs -text
2
+ src/deep_barcode_reader/models/sr.prototxt filter=lfs diff=lfs merge=lfs -text
3
+ tests/test_data/sample.jpg filter=lfs diff=lfs merge=lfs -text
.github/workflows/main.yml ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Sync to Hugging Face hub
2
+ on:
3
+ push:
4
+ branches:
5
+ - '**'
6
+
7
+ # to run this workflow manually from the Actions tab
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ sync-to-hub:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+ with:
16
+ fetch-depth: 0
17
+ lfs: true
18
+ - name: Add remote
19
+ env:
20
+ HF: ${{ secrets.HG }}
21
+ run: git remote add space https://industoai:$HF@huggingface.co/spaces/industoai/Deep-Barcode-Reader
22
+ - name: Push to hub
23
+ env:
24
+ HF: ${{ secrets.HG }}
25
+ run: git push --force https://industoai:$HF@huggingface.co/spaces/industoai/Deep-Barcode-Reader ${{ github.ref }}:main
.gitignore ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Pycharm files
2
+ .idea/
3
+
4
+ # poetry
5
+ poetry.lock
6
+
7
+ # Unit test files
8
+ .coverage
9
+ .coverage.*
10
+ .cache
11
+ .pytest_cache/
12
+ src/*/__pycache__/*
13
+
14
+ # mypy files
15
+ .mypy_cache/
16
+
17
+ # Probable environments files
18
+ .env
19
+ .venv
20
+ env/
21
+ venv/
.pre-commit-config.yaml ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # See https://pre-commit.com for more information
2
+ # See https://pre-commit.com/hooks.html for more hooks
3
+ default_language_version:
4
+ python: python3
5
+ repos:
6
+ - repo: https://github.com/pre-commit/pre-commit-hooks
7
+ rev: v4.5.0 # the release, git tag, or commit you want to use
8
+ hooks:
9
+ - id: check-toml
10
+ - id: check-yaml
11
+ - id: check-json
12
+ - id: end-of-file-fixer
13
+ - id: trailing-whitespace
14
+ - id: no-commit-to-branch
15
+ - id: check-executables-have-shebangs
16
+ - id: check-added-large-files
17
+ - id: check-case-conflict
18
+ - id: check-merge-conflict
19
+ - id: pretty-format-json
20
+ args:
21
+ - --autofix
22
+ - id: check-symlinks
23
+ - id: check-ast
24
+ - id: detect-private-key
25
+ - repo: https://github.com/psf/black
26
+ rev: 24.1.1
27
+ hooks:
28
+ - id: black
29
+ language: python
30
+ - repo: https://github.com/pre-commit/mirrors-mypy
31
+ rev: v1.8.0
32
+ hooks:
33
+ - id: mypy
34
+ language: system
35
+ args: [--strict, --ignore-missing-imports]
36
+ - repo: https://github.com/pycqa/pylint
37
+ rev: v3.0.3
38
+ hooks:
39
+ - id: pylint
40
+ language: system
41
+ - repo: https://github.com/Lucas-C/pre-commit-hooks
42
+ rev: v1.5.4
43
+ hooks:
44
+ - id: forbid-crlf
45
+ - id: remove-crlf
46
+ - id: forbid-tabs
47
+ - id: remove-tabs
48
+ - repo: https://github.com/PyCQA/bandit
49
+ rev: 1.7.7
50
+ hooks:
51
+ - id: bandit
52
+ args: ["--skip=B101"]
53
+ - repo: https://github.com/Lucas-C/pre-commit-hooks-markup
54
+ rev: v1.0.1
55
+ hooks:
56
+ - id: rst-linter
57
+ - repo: https://github.com/Yelp/detect-secrets
58
+ rev: v1.4.0
59
+ hooks:
60
+ - id: detect-secrets
61
+ language: python
62
+ exclude: "poetry.lock"
63
+ # args: ['--baseline', '.secrets.baseline']
64
+ - repo: https://github.com/shellcheck-py/shellcheck-py
65
+ rev: v0.9.0.6
66
+ hooks:
67
+ - id: shellcheck
68
+ args: ["--external-sources"]
69
+ - repo: https://github.com/python-poetry/poetry
70
+ rev: '1.7.1'
71
+ hooks:
72
+ - id: poetry-check
73
+ - id: poetry-lock
74
+ args: ["--no-update"]
Dockerfile ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## syntax=docker/dockerfile:1.1.7-experimental
2
+
3
+ ################
4
+ # Base builder #
5
+ ################
6
+ FROM python:3.10-bookworm as base_build
7
+
8
+ ENV \
9
+ # locale environment variables
10
+ LC_ALL=C.UTF-8 \
11
+ # python environemnt variables
12
+ PYTHONFAULTHANDLER=1 \
13
+ PYTHONUNBUFFERED=1 \
14
+ PYTHONHASHSEED=random \
15
+ # pip environmental variables
16
+ PIP_NO_CACHE_DIR=off \
17
+ PIP_DISABLE_PIP_VERSION_CHECK=on \
18
+ PIP_DEFAULT_TIMEOUT=100 \
19
+ # poetry version
20
+ POETRY_VERSION=1.5.0
21
+
22
+ # Install requirements
23
+ RUN apt-get update && apt-get install -y \
24
+ curl \
25
+ git \
26
+ bash \
27
+ build-essential \
28
+ libffi-dev \
29
+ libssl-dev \
30
+ tini \
31
+ openssh-client \
32
+ cargo \
33
+ musl-dev \
34
+ libzbar0 \
35
+ && apt-get autoremove -y \
36
+ && rm -rf /var/lib/apt/lists/* \
37
+ # github ssh key setting
38
+ && mkdir -p -m 0700 ~/.ssh && ssh-keyscan github.com | sort > ~/.ssh/known_hosts \
39
+ # Installing poetry and set the PATH
40
+ && curl -sSL https://install.python-poetry.org | python3 - \
41
+ && echo 'export PATH="/root/.local/bin:$PATH"' >>/root/.profile \
42
+ && export PATH="/root/.local/bin:$PATH" \
43
+ && true
44
+ SHELL ["/bin/bash", "-lc"]
45
+
46
+ # Copy poetry lock and pyproject config files to the container
47
+ WORKDIR /pysetup
48
+ COPY ./poetry.lock ./pyproject.toml /pysetup/
49
+ # Install pip/wheel/virtualenv and build the wheels based on the poetry lock
50
+ RUN --mount=type=ssh pip3 install wheel virtualenv poetry-plugin-export \
51
+ && poetry export -f requirements.txt --without-hashes -o /tmp/requirements.txt \
52
+ && pip3 wheel --wheel-dir=/tmp/wheelhouse --trusted-host 172.17.0.1 --find-links=http://172.17.0.1:3141/debian/ -r /tmp/requirements.txt \
53
+ && virtualenv /.venv && source /.venv/bin/activate && echo 'source /.venv/bin/activate' >>/root/.profile \
54
+ && pip3 install --no-deps --trusted-host 172.17.0.1 --find-links=http://172.17.0.1:3141/debian/ --find-links=/tmp/wheelhouse/ /tmp/wheelhouse/*.whl \
55
+ && true
56
+
57
+
58
+ ###########################
59
+ # Production base builder #
60
+ ###########################
61
+ FROM base_build as production_build
62
+ # Copy entrypoint script to the container and src files to the app directory
63
+ COPY ./docker/entrypoint.sh /docker-entrypoint.sh
64
+ COPY . /app/
65
+ WORKDIR /app
66
+ # Build the wheel packages with poetry and add them to the wheelhouse
67
+ RUN --mount=type=ssh source /.venv/bin/activate \
68
+ && poetry build -f wheel --no-interaction --no-ansi \
69
+ && cp dist/*.whl /tmp/wheelhouse \
70
+ && chmod a+x /docker-entrypoint.sh \
71
+ && true
72
+
73
+
74
+
75
+ ########################
76
+ # Production Container #
77
+ ########################
78
+ FROM python:3.10-bookworm as production
79
+ COPY --from=production_build /tmp/wheelhouse /tmp/wheelhouse
80
+ COPY --from=production_build /docker-entrypoint.sh /docker-entrypoint.sh
81
+ WORKDIR /app
82
+ # Install system level deps for running the package and install the wheels we built in the previous step.
83
+ RUN --mount=type=ssh apt-get update && apt-get install -y \
84
+ bash \
85
+ libffi8 \
86
+ libgl1 \
87
+ tini \
88
+ libzbar0 \
89
+ && apt-get autoremove -y \
90
+ && rm -rf /var/lib/apt/lists/* \
91
+ && chmod a+x /docker-entrypoint.sh \
92
+ && WHEELFILE=`echo /tmp/wheelhouse/deep_barcode_reader-*.whl` \
93
+ && pip3 install --trusted-host 172.17.0.1 --find-links=http://172.17.0.1:3141/debian/ --find-links=/tmp/wheelhouse/ "$WHEELFILE"[all] \
94
+ && rm -rf /tmp/wheelhouse/ \
95
+ && true
96
+ ENTRYPOINT ["/usr/bin/tini", "--", "/docker-entrypoint.sh"]
97
+
98
+
99
+
100
+ ############################
101
+ # Development base builder #
102
+ ############################
103
+ FROM base_build as development_build
104
+ # Copy src to app directory
105
+ COPY . /app
106
+ WORKDIR /app
107
+ # Install dependencies from poetry lock
108
+ RUN --mount=type=ssh source /.venv/bin/activate \
109
+ && apt-get update && apt-get install -y libgl1 libzbar0 \
110
+ && export PIP_FIND_LINKS=http://172.17.0.1:3141/debian/ \
111
+ && export PIP_TRUSTED_HOST=172.17.0.1 \
112
+ && pip3 install nvidia-cublas-cu12 nvidia-cusparse-cu12 triton nvidia-nccl-cu12 nvidia-cudnn-cu12 nvidia-cufft-cu12 nvidia-cusolver-cu12 \
113
+ && poetry install --no-interaction --no-ansi \
114
+ && true
115
+
116
+
117
+
118
+ ###################
119
+ # Tests Container #
120
+ ###################
121
+ FROM development_build as test
122
+ RUN --mount=type=ssh source /.venv/bin/activate \
123
+ && chmod a+x docker/*.sh \
124
+ && docker/pre_commit_init.sh \
125
+ && true
126
+ ENTRYPOINT ["/usr/bin/tini", "--", "docker/entrypoint-test.sh"]
127
+
128
+
129
+ #########################
130
+ # Development Container #
131
+ #########################
132
+ FROM development_build as development
133
+ RUN apt-get update && apt-get install -y zsh libzbar0 \
134
+ && sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" \
135
+ && echo "if [ \"\$NO_WHEELHOUSE\" = \"1\" ]" >>/root/.profile \
136
+ && echo "then" >>/root/.profile \
137
+ && echo " echo \"Wheelhouse disabled\"" >>/root/.profile \
138
+ && echo "else">>/root/.profile \
139
+ && echo " export PIP_TRUSTED_HOST=172.17.0.1" >>/root/.profile \
140
+ && echo " export PIP_FIND_LINKS=http://172.17.0.1:3141/debian/" >>/root/.profile \
141
+ && echo "fi" >>/root/.profile \
142
+ && echo "source /root/.profile" >>/root/.zshrc \
143
+ && pip3 install git-up \
144
+ && true
145
+ ENTRYPOINT ["/bin/zsh", "-l"]
README.md ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Deep Barcode Reader
3
+ emoji: 🔳
4
+ colorFrom: gray
5
+ colorTo: red
6
+ sdk: streamlit
7
+ sdk_version: 1.42.2
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+ # Deep-Barcode-Reader
12
+ This repository is used for reading different types of barcodes and QR codes from images.
13
+ The code is written in Python and uses OpenCV, Pyzbar, and other libraries for reading barcodes and QR codes.
14
+
15
+
16
+ ## How to Use
17
+ The library offers several functions for reading barcodes and QR codes from images.
18
+ General options can be selected before applying the reader method. These options are:
19
+ - `--data_path` is the path to the image file.
20
+ - `--result_path` is the path to the output file.
21
+ - `--verbose` is the verbosity level of the code.
22
+ - `--method` is the method for reading the barcode or QR code.
23
+ - `--model_size` is the size of the deep learning model.
24
+
25
+ The available methods are as:
26
+ - [Opencv Barcode Reader](#opencv-barcode-reader)
27
+ - [Zbar Barcode Reader](#zbar-barcode-reader)
28
+ - [QR Reader](#qr-reader)
29
+
30
+ ### Opencv Barcode Reader
31
+ This method can only detect barcodes but NOT QR codes. It can detect and decode EAN-8, EAN-13, UPC-A and UPC-E
32
+ barcode types. You can use the method by running the following command:
33
+ ```shell
34
+ deep_barcode_reader -vv -d tests/test_data/sample.jpg -m opencv
35
+ ```
36
+ This method can only detect specific types of barcodes. However, it is faster than the other methods.
37
+
38
+ ### Zbar Barcode Reader
39
+ This method can detect and decode both barcodes and QR codes.
40
+ It is very powerful to detect and decode different types of barcodes and QR codes.
41
+ You can use the method by running the following command:
42
+ ```shell
43
+ deep_barcode_reader -vv -d tests/test_data/sample.jpg -m zbar
44
+ ```
45
+
46
+ ### QR Reader
47
+ This method can only detect and decode QR codes.
48
+ Depending on the model size as `n` as nano, `s` as small, `m` as medium, or `l` as large,
49
+ the detection and decoding process time and accuracy can be changed.
50
+ ```shell
51
+ deep_barcode_reader -vv -d tests/test_data/sample.jpg -m zbar --model_size l
52
+ ```
53
+
54
+
55
+ ## How to Develop
56
+ Do the following only once after creating your project:
57
+ - Init the git repo with `git init`.
58
+ - Add files with `git add .`.
59
+ - Then `git commit -m 'initialize the project'`.
60
+ - Add remote url with `git remote add origin REPO_URL`.
61
+ - Then `git branch -M master`.
62
+ - `git push origin main`.
63
+ Then create a branch with `git checkout -b BRANCH_NAME` for further developments.
64
+ - Install poetry if you do not have it in your system from [here](https://python-poetry.org/docs/#installing-with-pipx).
65
+ - Create a virtual env preferably with virtualenv wrapper and `mkvirtualenv -p $(which python3.10) ENVNAME`.
66
+ - Then `git add poetry.lock`.
67
+ - Then `pre-commit install`.
68
+ - For applying changes use `pre-commit run --all-files`.
69
+
70
+
71
+ ## Docker Container
72
+ To run the docker with ssh, do the following first and then based on your need select ,test, development, or production containers:
73
+ ```shell
74
+ export DOCKER_BUILDKIT=1
75
+ export DOCKER_SSHAGENT="-v $SSH_AUTH_SOCK:$SSH_AUTH_SOCK -e SSH_AUTH_SOCK"
76
+ ```
77
+ ### Test Container
78
+ This container is used for testing purposes while it runs the test
79
+ ```shell
80
+ docker build --progress plain --ssh default --target test -t barcode_docker:test .
81
+ docker run -it --rm -v "$(pwd):/app" $(echo $DOCKER_SSHAGENT) barcode_docker:test
82
+ ```
83
+
84
+ ### Development Container
85
+ This container can be used for development purposes:
86
+ ```shell
87
+ docker build --progress plain --ssh default --target development -t barcode_docker:development .
88
+ docker run -it --rm -v "$(pwd):/app" -v /tmp:/tmp $(echo $DOCKER_SSHAGENT) barcode_docker:development
89
+ ```
90
+
91
+ ### Production Container
92
+ This container can be used for production purposes:
93
+ ```shell
94
+ docker build --progress plain --ssh default --target production -t barcode_docker:production .
95
+ docker run -it --rm -v "$(pwd):/app" -v /tmp:/tmp $(echo $DOCKER_SSHAGENT) barcode_docker:production deep_barcode_reader -vv -d tests/test_data/sample.jpg -m zbar --model_size l
96
+ ```
97
+
98
+ ## Hugging Face Deployment
99
+ The repository is also deployed in [hugging face](https://huggingface.co/spaces/afshin-dini/Deep-Barcode-Reader) in which one can upload images, select the appropriate method and its parameters and detect and decode the barcodes or QR codes.
100
+ It is good to mention that you can also run the application locally by running the following command:
101
+ ```shell
102
+ streamlit run app.py
103
+ ```
104
+ and then open the browser and go to the address `http://localhost:8501`.
app.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """This is a demo for running the barcode QR code reader usng streamlit library"""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Any, Optional
5
+ import asyncio
6
+
7
+ import streamlit as st
8
+ from PIL import Image
9
+ import numpy as np
10
+ import pandas as pd
11
+
12
+ from src.deep_barcode_reader.barcode import Wrapper
13
+
14
+
15
+ @dataclass
16
+ class DemoBarcodeReader:
17
+ """This is a demo class for barcode/qr code reader using different methods"""
18
+
19
+ image: Optional[Any] = field(init=False, default=None)
20
+ model_option: str = field(init=False, default="opencv")
21
+ model_size: str = field(init=False, default="n")
22
+
23
+ def upload_image(self) -> None:
24
+ """Upload an image from the streamlit page"""
25
+ uploaded_file = st.file_uploader(
26
+ "Choose an image...", type=["jpg", "png", "jpeg"]
27
+ )
28
+ if uploaded_file is not None:
29
+ self.image = Image.open(uploaded_file)
30
+ else:
31
+ self.image = Image.open("tests/test_data/sample.jpg")
32
+
33
+ st.image(
34
+ self.image, caption="Original/Uploaded Image", use_container_width=True
35
+ )
36
+
37
+ def select_model(self) -> None:
38
+ """Select a model for barcode/qr code reader"""
39
+ self.model_option = st.selectbox(
40
+ "Choose a reader/decoder model", ["zbar", "opencv", "qrreader"]
41
+ )
42
+ if self.model_option == "qrreader":
43
+ ml_size = st.selectbox(
44
+ "Choose a model size for QRReader method",
45
+ ["nano", "small", "medium", "large"],
46
+ )
47
+ self.model_size = (
48
+ "n"
49
+ if ml_size == "nano"
50
+ else "s" if ml_size == "small" else "m" if ml_size == "medium" else "l"
51
+ )
52
+
53
+ def process_image(self) -> None:
54
+ """Process the image for barcode/qr code reader"""
55
+ if st.button("Read/Decode Barcode/QR Code"):
56
+ reader = Wrapper(model_size=self.model_size, method=self.model_option)
57
+ detections, result_img = asyncio.run(
58
+ reader.method_selection(image=np.array(self.image), result_path="")
59
+ )
60
+ st.markdown("<h3>Detected Results</h3>", unsafe_allow_html=True)
61
+ st.image(result_img, caption="Decoded Result", use_container_width=True)
62
+ results = pd.DataFrame(
63
+ {
64
+ "Barcode/QR Types": detections.decoded_types,
65
+ "Data": detections.decoded_data,
66
+ "Boundary Box": [str(bbx) for bbx in detections.bbox_data],
67
+ }
68
+ )
69
+ st.markdown('<div class="center-container">', unsafe_allow_html=True)
70
+ st.markdown(
71
+ "<h3>Detailed Information of Detections</h3>", unsafe_allow_html=True
72
+ )
73
+ st.table(results)
74
+ st.markdown("</div>", unsafe_allow_html=True)
75
+
76
+ def design_page(self) -> None:
77
+ """Design the streamlit page for barcode/qr code reader"""
78
+ st.title("Image Barcode/QR Code Reader and Detector")
79
+ self.upload_image()
80
+ self.select_model()
81
+ self.process_image()
82
+
83
+
84
+ demo = DemoBarcodeReader()
85
+ demo.design_page()
docker/entrypoint-test.sh ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -l
2
+ set -e
3
+ if [ "$#" -eq 0 ]; then
4
+ # Kill cache, pytest complains about it if running local and docker tests in mapped volume
5
+ find tests -type d -name '__pycache__' -print0 | xargs -0 rm -rf {}
6
+ # Make sure the service itself is installed
7
+ poetry install
8
+ # Make sure pre-commit checks were not missed and run tests
9
+ git config --global --add safe.directory /app
10
+ poetry run pre-commit install
11
+ pre-commit run --all-files
12
+ pytest -v --junitxml=pytest.xml tests/
13
+ else
14
+ exec "$@"
15
+ fi
docker/entrypoint.sh ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -l
2
+ set -e
3
+ if [ "$#" -eq 0 ]; then
4
+ exec deep_barcode_reader --help
5
+ else
6
+ exec "$@"
7
+ fi
docker/pre_commit_init.sh ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash -l
2
+ if [ ! -d .git ]
3
+ then
4
+ git init
5
+ git checkout -b precommit_init
6
+ git add .
7
+ fi
8
+ set -e
9
+ poetry run pre-commit install
10
+ SKIP="poetry-lock" poetry run pre-commit run --all-files
packages.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ libzbar0
pyproject.toml ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [tool.poetry]
2
+ name = "deep_barcode_reader"
3
+ version = "0.3.0"
4
+ description = "It can read different types of barcodes"
5
+ authors = ["Afshin Dini <Afshin Dini>"]
6
+ readme = "README.md"
7
+ packages = [{include = "deep_barcode_reader", from = "src"}]
8
+
9
+ [tool.poetry.scripts]
10
+ deep_barcode_reader = "deep_barcode_reader.main:deep_barcode_reader_cli"
11
+
12
+ [tool.pylint.format]
13
+ max-line-length=150 # This defines the maximum number of characters on a single line in pylint
14
+
15
+ [tool.pylint.design]
16
+ max-attributes=10
17
+ max-positional-arguments=6
18
+ max-args=6
19
+
20
+ [tool.pylint.messages_control]
21
+ disable=["fixme"]
22
+
23
+ [tool.pylint.similarities]
24
+ min-similarity-lines = 8 # Minimum lines number of a similarity.
25
+ ignore-imports = true # Ignore imports when computing similarities.
26
+
27
+ [tool.pytest.ini_options]
28
+ junit_family="xunit2"
29
+ addopts="--cov=deep_barcode_reader --cov-fail-under=65 --cov-branch"
30
+ asyncio_mode="strict"
31
+
32
+
33
+ [tool.coverage.run]
34
+ omit = ["tests/*"]
35
+ branch = true
36
+
37
+ [[tool.poetry.source]]
38
+ name = "pytorch"
39
+ url = "https://download.pytorch.org/whl/cu118"
40
+ priority = "explicit"
41
+
42
+
43
+ [tool.poetry.dependencies]
44
+ python = "^3.10"
45
+ click = "^8.1.7"
46
+ ultralytics = "8.2.18"
47
+ qreader = "3.12"
48
+ pyzbar = "^0.1.9"
49
+ opencv-python = "^4.9.0.80"
50
+ torch = [
51
+ { version = "^2.1.2", source = "pytorch", platform = "!=darwin"},
52
+ { version = "^2.1.2", source = "pypi", platform = "darwin"},
53
+ ]
54
+ torchvision = [
55
+ { version = "^0.16.0", source = "pytorch", platform = "!=darwin"},
56
+ { version = "^0.16.0", source = "pypi", platform = "darwin"},
57
+ ]
58
+ numpy = "1.26.4"
59
+ streamlit = "^1.42.2"
60
+
61
+
62
+ [tool.poetry.group.dev.dependencies]
63
+ pytest = "^8.3.3"
64
+ coverage = "^7.6"
65
+ pytest-cov = "^6.0"
66
+ pylint = "^3.3.1"
67
+ black = "^24.10.0"
68
+ mypy = "^1.13.0"
69
+ bump2version = "^1.0.1"
70
+ bandit = "^1.7.10"
71
+ pre-commit = "^4.0.1"
72
+ detect-secrets = "^1.5"
73
+
74
+ [build-system]
75
+ requires = ["poetry-core>=1.5.0"]
76
+ build-backend = "poetry.core.masonry.api"
requirements.txt ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --extra-index-url https://download.pytorch.org/whl/cu118
2
+
3
+ altair==5.5.0 ; python_version >= "3.10" and python_version < "4.0"
4
+ attrs==25.1.0 ; python_version >= "3.10" and python_version < "4.0"
5
+ blinker==1.9.0 ; python_version >= "3.10" and python_version < "4.0"
6
+ cachetools==5.5.2 ; python_version >= "3.10" and python_version < "4.0"
7
+ certifi==2025.1.31 ; python_version >= "3.10" and python_version < "4.0"
8
+ charset-normalizer==3.4.1 ; python_version >= "3.10" and python_version < "4.0"
9
+ click==8.1.8 ; python_version >= "3.10" and python_version < "4.0"
10
+ colorama==0.4.6 ; python_version >= "3.10" and python_version < "4.0" and platform_system == "Windows"
11
+ contourpy==1.3.1 ; python_version >= "3.10" and python_version < "4.0"
12
+ cycler==0.12.1 ; python_version >= "3.10" and python_version < "4.0"
13
+ filelock==3.17.0 ; python_version >= "3.10" and python_version < "4.0"
14
+ fonttools==4.56.0 ; python_version >= "3.10" and python_version < "4.0"
15
+ fsspec==2025.2.0 ; python_version >= "3.10" and python_version < "4.0"
16
+ gitdb==4.0.12 ; python_version >= "3.10" and python_version < "4.0"
17
+ gitpython==3.1.44 ; python_version >= "3.10" and python_version < "4.0"
18
+ idna==3.10 ; python_version >= "3.10" and python_version < "4.0"
19
+ jinja2==3.1.5 ; python_version >= "3.10" and python_version < "4.0"
20
+ jsonschema-specifications==2024.10.1 ; python_version >= "3.10" and python_version < "4.0"
21
+ jsonschema==4.23.0 ; python_version >= "3.10" and python_version < "4.0"
22
+ kiwisolver==1.4.8 ; python_version >= "3.10" and python_version < "4.0"
23
+ markdown-it-py==3.0.0 ; python_version >= "3.10" and python_version < "4.0"
24
+ markupsafe==3.0.2 ; python_version >= "3.10" and python_version < "4.0"
25
+ matplotlib==3.10.0 ; python_version >= "3.10" and python_version < "4.0"
26
+ mdurl==0.1.2 ; python_version >= "3.10" and python_version < "4.0"
27
+ mpmath==1.3.0 ; python_version >= "3.10" and python_version < "4.0"
28
+ narwhals==1.27.1 ; python_version >= "3.10" and python_version < "4.0"
29
+ networkx==3.4.2 ; python_version >= "3.10" and python_version < "4.0"
30
+ numpy==1.26.4 ; python_version >= "3.10" and python_version < "4.0"
31
+ opencv-python==4.11.0.86 ; python_version >= "3.10" and python_version < "4.0"
32
+ packaging==24.2 ; python_version >= "3.10" and python_version < "4.0"
33
+ pandas==2.2.3 ; python_version >= "3.10" and python_version < "4.0"
34
+ pillow==11.1.0 ; python_version >= "3.10" and python_version < "4.0"
35
+ protobuf==5.29.3 ; python_version >= "3.10" and python_version < "4.0"
36
+ psutil==7.0.0 ; python_version >= "3.10" and python_version < "4.0"
37
+ py-cpuinfo==9.0.0 ; python_version >= "3.10" and python_version < "4.0"
38
+ pyarrow==19.0.1 ; python_version >= "3.10" and python_version < "4.0"
39
+ pydeck==0.9.1 ; python_version >= "3.10" and python_version < "4.0"
40
+ pygments==2.19.1 ; python_version >= "3.10" and python_version < "4.0"
41
+ pyparsing==3.2.1 ; python_version >= "3.10" and python_version < "4.0"
42
+ python-dateutil==2.9.0.post0 ; python_version >= "3.10" and python_version < "4.0"
43
+ pytz==2025.1 ; python_version >= "3.10" and python_version < "4.0"
44
+ pyyaml==6.0.2 ; python_version >= "3.10" and python_version < "4.0"
45
+ pyzbar==0.1.9 ; python_version >= "3.10" and python_version < "4.0"
46
+ qrdet==2.5 ; python_version >= "3.10" and python_version < "4.0"
47
+ qreader==3.12 ; python_version >= "3.10" and python_version < "4.0"
48
+ quadrilateral-fitter==1.12 ; python_version >= "3.10" and python_version < "4.0"
49
+ referencing==0.36.2 ; python_version >= "3.10" and python_version < "4.0"
50
+ requests==2.32.3 ; python_version >= "3.10" and python_version < "4.0"
51
+ rich==13.9.4 ; python_version >= "3.10" and python_version < "4.0"
52
+ rpds-py==0.23.1 ; python_version >= "3.10" and python_version < "4.0"
53
+ scipy==1.15.2 ; python_version >= "3.10" and python_version < "4.0"
54
+ seaborn==0.13.2 ; python_version >= "3.10" and python_version < "4.0"
55
+ shapely==2.0.7 ; python_version >= "3.10" and python_version < "4.0"
56
+ six==1.17.0 ; python_version >= "3.10" and python_version < "4.0"
57
+ smmap==5.0.2 ; python_version >= "3.10" and python_version < "4.0"
58
+ streamlit==1.42.2 ; python_version >= "3.10" and python_version < "4.0"
59
+ sympy==1.13.3 ; python_version >= "3.10" and python_version < "4.0"
60
+ tenacity==9.0.0 ; python_version >= "3.10" and python_version < "4.0"
61
+ thop==0.1.1.post2209072238 ; python_version >= "3.10" and python_version < "4.0"
62
+ toml==0.10.2 ; python_version >= "3.10" and python_version < "4.0"
63
+ torch==2.1.2+cu118 ; python_version >= "3.10" and python_version < "4.0"
64
+ torchvision==0.16.2+cu118 ; python_version >= "3.10" and python_version < "4.0"
65
+ tornado==6.4.2 ; python_version >= "3.10" and python_version < "4.0"
66
+ tqdm==4.67.1 ; python_version >= "3.10" and python_version < "4.0"
67
+ triton==2.1.0 ; platform_system == "Linux" and platform_machine == "x86_64" and python_version >= "3.10" and python_version < "4.0"
68
+ typing-extensions==4.12.2 ; python_version >= "3.10" and python_version < "4.0"
69
+ tzdata==2025.1 ; python_version >= "3.10" and python_version < "4.0"
70
+ ultralytics==8.2.18 ; python_version >= "3.10" and python_version < "4.0"
71
+ urllib3==2.3.0 ; python_version >= "3.10" and python_version < "4.0"
72
+ watchdog==6.0.0 ; python_version >= "3.10" and python_version < "4.0" and platform_system != "Darwin"
src/deep_barcode_reader/__init__.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """ It can read different types of barcodes """
2
+
3
+ __version__ = "0.3.0"
4
+
5
+ from .barcode import Wrapper, QRreader, BarcodeOpencv, BarcodeQRZbar
6
+ from .base import ReaderResults
7
+
8
+ __all__ = [
9
+ "Wrapper",
10
+ "QRreader",
11
+ "BarcodeOpencv",
12
+ "BarcodeQRZbar",
13
+ "ReaderResults",
14
+ ]
src/deep_barcode_reader/barcode.py ADDED
@@ -0,0 +1,160 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Barcode detector and reader models"""
2
+
3
+ # pylint: disable=E1101
4
+ import logging
5
+ from typing import Any, Tuple
6
+ from dataclasses import dataclass, field
7
+ from pathlib import Path
8
+
9
+ import numpy as np
10
+ import cv2
11
+
12
+ from pyzbar.pyzbar import decode
13
+ from qreader import QReader
14
+
15
+ from .base import BarcodeBase, ReaderResults
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ @dataclass
21
+ class BarcodeOpencv(BarcodeBase):
22
+ """This a simple 1D barcode reader using OpenCV. It can be used with
23
+ EAN-8, EAN-13, UPC-A and UPC-E types of barcodes"""
24
+
25
+ proto_file: Path = field(
26
+ init=False, default=Path("./src/deep_barcode_reader/models/sr.prototxt")
27
+ )
28
+ model_file: Path = field(
29
+ init=False, default=Path("./src/deep_barcode_reader/models/sr.caffemodel")
30
+ )
31
+
32
+ def __post_init__(self) -> None:
33
+ """Post initialization of the barcode reader class"""
34
+ if not self.model_file.exists():
35
+ logger.error(
36
+ "The model file does not exist for the BarcodeOpencv model. Please check the path."
37
+ )
38
+ if not self.proto_file.exists():
39
+ logger.error(
40
+ "The proto file does not exist for the BarcodeOpencv model. Please check the path."
41
+ )
42
+
43
+ async def detect_decode(self, image: Any) -> ReaderResults:
44
+ """Detect and decode barcode method from an image"""
45
+ result = ReaderResults(image=image)
46
+ barcode_reader = cv2.barcode.BarcodeDetector(
47
+ str(self.proto_file), str(self.model_file)
48
+ )
49
+ retval, decoded_info, barcode_types, boundary_boxs = (
50
+ barcode_reader.detectAndDecodeWithType(image)
51
+ )
52
+ if retval:
53
+ for idx, barc_txt in enumerate(decoded_info):
54
+ if barc_txt:
55
+ result.decoded_data.append(barc_txt)
56
+ result.bbox_data.append(
57
+ np.array(boundary_boxs[idx], dtype=np.int32)
58
+ )
59
+ result.decoded_types.append(barcode_types[idx])
60
+ if result.decoded_data:
61
+ logger.info(
62
+ "The barcode/qr code is detected and decoded successfully with BarcodeOpencv method."
63
+ )
64
+ else:
65
+ logger.warning(
66
+ "The barcode/qr code is not detected or decoded with BarcodeOpencv method."
67
+ )
68
+
69
+ return result
70
+
71
+
72
+ @dataclass
73
+ class BarcodeQRZbar(BarcodeBase):
74
+ """This is a QR code and barcode reader using Zbar library"""
75
+
76
+ async def detect_decode(self, image: Any) -> ReaderResults:
77
+ """Detect and decode barcode/qr method from an image"""
78
+ result = ReaderResults(image=image)
79
+ decoder = decode(image)
80
+ decoded_data = []
81
+ decoded_types = []
82
+ bbox_data = []
83
+ if decoder:
84
+ for decoded in decoder:
85
+ if decoded.data.decode("utf-8"):
86
+ decoded_data.append(decoded.data.decode("utf-8"))
87
+ decoded_types.append(decoded.type)
88
+ bbox_data.append(np.array(decoded.polygon, np.int64))
89
+ result.decoded_data = decoded_data
90
+ result.decoded_types = decoded_types
91
+ result.bbox_data = bbox_data
92
+ if result.decoded_data:
93
+ logger.info(
94
+ "The barcode/qr code is detected and decoded successfully with BarcodeQRZbar method."
95
+ )
96
+ else:
97
+ logger.warning(
98
+ "The barcode/qr code is not detected or decoded with BarcodeQRZbar method."
99
+ )
100
+ return result
101
+
102
+
103
+ @dataclass
104
+ class QRreader(BarcodeBase):
105
+ """This is a QR code reader using Qreader library"""
106
+
107
+ model_size: str = field(default="l")
108
+
109
+ async def detect_decode(self, image: Any) -> ReaderResults:
110
+ """Detect and decode barcode/qr method from an image"""
111
+ result = ReaderResults(image=image)
112
+ qr_reader = QReader(model_size=self.model_size)
113
+ detections = qr_reader.detect(image=image)
114
+ decoded_data = []
115
+ decoded_types = []
116
+ bbox_data = []
117
+ if detections:
118
+ for detection in detections:
119
+ decoded_text = qr_reader.decode(image, detection)
120
+ if decoded_text:
121
+ decoded_data.append(decoded_text)
122
+ decoded_types.append("QR")
123
+ bbox_data.append(np.array(detection["polygon_xy"], np.int64))
124
+ if decoded_data:
125
+ result.decoded_data = decoded_data
126
+ result.decoded_types = decoded_types
127
+ result.bbox_data = bbox_data
128
+ logger.info(
129
+ "The barcode/qr code is detected and decoded successfully with QRreader method."
130
+ )
131
+ else:
132
+ logger.warning(
133
+ "The barcode/qr code is not detected or decoded with QRreader method."
134
+ )
135
+ else:
136
+ logger.warning("The barcode/qr code is not detected with QRreader method.")
137
+
138
+ return result
139
+
140
+
141
+ @dataclass
142
+ class Wrapper:
143
+ """Wrapper class for barcode readers"""
144
+
145
+ method: str = field(default="opencv")
146
+ model_size: str = field(default="l")
147
+
148
+ async def method_selection(self, image: Any, result_path: str) -> Tuple[Any, Any]:
149
+ """Wrap the method selection for barcode reader"""
150
+ if self.method == "opencv":
151
+ barcode: Any = BarcodeOpencv()
152
+ elif self.method == "zbar":
153
+ barcode = BarcodeQRZbar()
154
+ elif self.method == "qrreader":
155
+ barcode = QRreader(model_size=self.model_size)
156
+ else:
157
+ barcode = BarcodeOpencv()
158
+ detections = await barcode.detect_decode(image)
159
+ result_image = await detections.visualize_results_async(result_path)
160
+ return detections, result_image
src/deep_barcode_reader/base.py ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """This is the base class for implementing barcode reader and decoder models"""
2
+
3
+ # pylint: disable=E1101
4
+ import logging
5
+ from typing import Any, List, Optional
6
+ from pathlib import Path
7
+ from abc import ABC, abstractmethod
8
+ from dataclasses import dataclass, field
9
+
10
+ import cv2
11
+
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ @dataclass
17
+ class BarcodeBase(ABC):
18
+ """This is the base class for implementing different methods of barcode/qr code reading and decoding"""
19
+
20
+ @abstractmethod
21
+ async def detect_decode(self, image: Any) -> Any:
22
+ """Detect and decode barcode/qr method from an image"""
23
+ raise NotImplementedError()
24
+
25
+
26
+ @dataclass
27
+ class ReaderResults:
28
+ """Dataclass for saving/visualizing barcode/qr code reader results"""
29
+
30
+ image: Any
31
+ decoded_data: List[str] = field(default_factory=list)
32
+ decoded_types: List[str] = field(default_factory=list)
33
+ bbox_data: List[Any] = field(default_factory=list)
34
+
35
+ def save_image(self, img: Any, file_name: str = "") -> None:
36
+ """Save the image to the output path for debugging"""
37
+ if file_name != "":
38
+ Path(file_name).parent.mkdir(parents=True, exist_ok=True)
39
+ cv2.imwrite(file_name, img)
40
+ logger.info("Image is saved to %s", file_name)
41
+
42
+ async def visualize_results_async(self, file_name: str) -> Optional[Any]:
43
+ """Visualize the results of the barcode/qr code reader"""
44
+ if self.image is None:
45
+ logger.error(
46
+ "The image is not provided as the image is not loaded properly or does not exist."
47
+ )
48
+ return None
49
+ img_bounding_box = self.image.copy()
50
+ if self.decoded_data is not None and self.bbox_data is not None:
51
+ for data, bbox in zip(self.decoded_data, self.bbox_data):
52
+ cv2.polylines(
53
+ img_bounding_box,
54
+ [bbox],
55
+ isClosed=True,
56
+ color=(0, 0, 255),
57
+ thickness=1,
58
+ )
59
+ cv2.putText(
60
+ img_bounding_box,
61
+ str(data),
62
+ (int(bbox[0][0]) - 10, int(bbox[0][1]) - 10),
63
+ cv2.FONT_HERSHEY_SIMPLEX,
64
+ 0.5,
65
+ (0, 0, 255),
66
+ 1,
67
+ )
68
+
69
+ self.save_image(img_bounding_box, file_name)
70
+ return img_bounding_box
src/deep_barcode_reader/logging.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Logger initialization"""
2
+
3
+ import logging
4
+ import logging.config
5
+ from typing import Any
6
+
7
+
8
+ def config_logger(loglevel: int) -> Any:
9
+ """Initialize a custom logger"""
10
+ default_logging_config = {
11
+ "version": 1,
12
+ "disable_existing_loggers": False,
13
+ "formatters": {
14
+ "standard": {
15
+ "format": "%(asctime)s - [%(levelname)s] [%(name)s.%(funcName)s:%(lineno)d (%(process)d)] | %(message)s",
16
+ "datefmt": "%Y-%m-%d %H:%M:%S",
17
+ },
18
+ },
19
+ "handlers": {
20
+ "console": {
21
+ "class": "logging.StreamHandler",
22
+ "formatter": "standard",
23
+ },
24
+ },
25
+ "root": {
26
+ "handlers": ["console"],
27
+ "level": loglevel,
28
+ },
29
+ }
30
+ logging.config.dictConfig(default_logging_config)
src/deep_barcode_reader/main.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Run the main code for Deep-Barcode-Reader"""
2
+
3
+ # pylint: disable=E1101
4
+ from pathlib import Path
5
+ import logging
6
+ import asyncio
7
+ import click
8
+ import cv2
9
+
10
+
11
+ from deep_barcode_reader import __version__
12
+ from deep_barcode_reader.logging import config_logger
13
+ from deep_barcode_reader.barcode import Wrapper
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @click.command()
19
+ @click.version_option(version=__version__)
20
+ @click.option(
21
+ "-v",
22
+ "--verbose",
23
+ count=True,
24
+ help="Shorthand for info/debug/warning/error loglevel (-v/-vv/-vvv/-vvvv)",
25
+ )
26
+ @click.option(
27
+ "-s",
28
+ "--result_path",
29
+ type=str,
30
+ default="output/test.png",
31
+ help="Path to save the result file.",
32
+ )
33
+ @click.option(
34
+ "-d",
35
+ "--data_path",
36
+ required=True,
37
+ type=click.Path(exists=True),
38
+ help="Path to data file.",
39
+ )
40
+ @click.option(
41
+ "-m",
42
+ "--method",
43
+ type=click.Choice(["opencv", "zbar", "qrreader"], case_sensitive=False),
44
+ default="opencv",
45
+ help="Path to data file.",
46
+ )
47
+ @click.option(
48
+ "--model_size",
49
+ type=click.Choice(["n", "s", "m", "l"], case_sensitive=False),
50
+ default="m",
51
+ help="Model size for the barcode reader.",
52
+ )
53
+ def deep_barcode_reader_cli(
54
+ verbose: int, result_path: str, data_path: Path, method: str, model_size: str
55
+ ) -> None:
56
+ """It can read different types of barcodes"""
57
+ if verbose == 1:
58
+ log_level = 10
59
+ elif verbose == 2:
60
+ log_level = 20
61
+ elif verbose == 3:
62
+ log_level = 30
63
+ else:
64
+ log_level = 40
65
+ config_logger(log_level)
66
+
67
+ reader = Wrapper(model_size=model_size, method=method)
68
+ _ = asyncio.get_event_loop().run_until_complete(
69
+ reader.method_selection(
70
+ image=cv2.imread(str(data_path)), result_path=result_path
71
+ )
72
+ )
src/deep_barcode_reader/models/sr.caffemodel ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e5d36889d8e6ef2f1c1f515f807cec03979320ac81792cd8fb927c31fd658ae3
3
+ size 23929
src/deep_barcode_reader/models/sr.prototxt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8ae41acba97e8b4a8e741ee350481e49b8e01d787193f470a4c95ee1c02d5b61
3
+ size 5984
tests/__init__.py ADDED
File without changes
tests/test_data/sample.jpg ADDED

Git LFS Details

  • SHA256: 486ef6c78000464774e6c181cbbc8e0a80e3ec9025095aa7fed97eb29bb81870
  • Pointer size: 131 Bytes
  • Size of remote file: 116 kB
tests/test_deep_barcode_reader.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ """Package level tests"""
2
+
3
+ from deep_barcode_reader import __version__
4
+
5
+
6
+ def test_version() -> None:
7
+ """Unit test for checking the version of the code"""
8
+ assert __version__ == "0.3.0"