I have a Django project designed to receive JSON requests from LabView. These requests contain an image encoded as a Base64 string. The Django server processes these requests, using the Halcon library to analyze the image data and return a JSON response containing the analysis results.
I also built a Docker image for Django + Halcon: https://hub.docker.com/r/fluber/halcon201143
Use Docker-Compose to help Django Development: https://blog.winerva.com/2024/02/29/use-docker-compose-to-help-django-development/

Halcon main function list:
- himage_from_numpy_array
- rgb1_to_gray
- threshold
- create_shape_model_xld
- set_shape_model_metric
- find_shape_model
- vector_angle_to_rigid
- affine_trans_image
- reduce_domain
# tree .
.
|-- db.sqlite3
|-- image_processing
| |-- __init__.py
| |-- __pycache__
| | |-- __init__.cpython-38.pyc
| | |-- admin.cpython-38.pyc
| | |-- aoi.cpython-38.pyc
| | |-- apps.cpython-38.pyc
| | |-- models.cpython-38.pyc
| | |-- urls.cpython-38.pyc
| | `-- views.cpython-38.pyc
| |-- admin.py
| |-- aoi.py
| |-- aoi.py.bk.1
| |-- apps.py
| |-- migrations
| | |-- __init__.py
| | `-- __pycache__
| | `-- __init__.cpython-38.pyc
| |-- models.py
| |-- tests.py
| |-- urls.py
| `-- views.py
|-- install-linux.sh
|-- labview_aoi
| |-- __init__.py
| |-- __pycache__
| | |-- __init__.cpython-38.pyc
| | |-- json_config.cpython-38.pyc
| | |-- settings.cpython-38.pyc
| | |-- urls.cpython-38.pyc
| | `-- wsgi.cpython-38.pyc
| |-- asgi.py
| |-- config.json
| |-- json_config.py
| |-- settings.py
| |-- urls.py
| `-- wsgi.py
|-- manage.py
|-- output
| |-- Inspections
| | `-- 20250417085025071569
| | |-- gray.png
| | |-- image.png
| | |-- ng_reply.json
| | |-- outer_surface.png
| | |-- pull_ring.png
| | |-- rectangle.png
| | `-- words.png
| `-- Models
| `-- AB39218
| |-- AB39218-model.hobj
| |-- AB39218-model.png
| |-- AB39218-outer-surface.hobj
| |-- AB39218-rect.png
| |-- AB39218-rectangle1.hobj
| |-- AB39218-rectangle2.hobj
| |-- AB39218-rectangle3.hobj
| |-- AB39218-rectangle4.hobj
| |-- AB39218-surface.png
| |-- AB39218-white.png
| |-- AB39218-words.hobj
| |-- AB39218-words.png
| |-- AB39218.png
| `-- AB39218.shm
`-- requirements.txt
11 directories, 55 files
#
Here’s how to adapt the obfuscation process:
1. Install PyArmor
#pip install pyarmor
Collecting pyarmor
Downloading pyarmor-9.1.3-py3-none-any.whl (2.9 MB)
|████████████████████████████████| 2.9 MB 1.2 MB/s
Collecting pyarmor.cli.core~=7.6.5
Downloading pyarmor_cli_core-7.6.5-cp38-none-manylinux1_x86_64.whl (459 kB)
|████████████████████████████████| 459 kB 1.4 MB/s
Installing collected packages: pyarmor.cli.core, pyarmor
Successfully installed pyarmor-9.1.3 pyarmor.cli.core
2. Initialize and Configure the Project
Since pyarmor init
is no longer available, you’ll need to set up the project manually and use pyarmor cfg
.
Create a .pyarmor_config.txt
file in the root directory of your project (where manage.py
is located). Here’s a basic configuration you can start with:
[pyarmor]
project = .
[build]
entry = manage.py
[package]
name = labview_aoi
version = 1.0
Then, configure the project using:
# pyarmor cfg
INFO Python 3.8.10
INFO Pyarmor 9.1.3 (trial), 000000, non-profits
INFO Platform linux.x86_64
------------------------------------------------------------
Section: pyarmor
Current options
major = 9
minor = 1
patch = 3
cli.core = 7.6.5
mini.core = 1.0
ecc.core = 1.0
vmc.core = 1.0
timeout = 6
regurl = https://api.dashingsoft.com/pr...
buyurl = https://jondy.github.io/paypal...
docurl = https://pyarmor.readthedocs.io...
Global options
Local options
------------------------------------------------------------
Section: logging
Current options
Global options
Local options
------------------------------------------------------------
Section: finder
Current options
recursive = 0
excludes = */__pycache__
pyexts = .py .pyw
data_files = 0
findall = 0
Global options
Local options
------------------------------------------------------------
Section: builder
Current options
encoding = utf-8
enable_trace = 0
enable_themida = 0
import_prefix = 0
bootstrap_file = __file__
exclude_co_names = <lambda> <listcomp> <setcomp> ...
exclude_restrict_modules = __init__
outer_keyname = pyarmor.rkey
inline_plugin_marker = pyarmor
plugins = CodesignPlugin DarwinUniversal...
jit_iv_threshold = 100
rft_enables = builtin import function class ...
rft_auto_exclude = 1
rft_auto_export = 1
rft_dev_mode = 0
rft_simple_import = 0
group_device_flag = 22
propagate_package_options = 0
optimize = -1
type_comments = false
trace_rft = 0
enable_jit = 0
enable_bcc = 0
enable_rft = 0
assert_call = 0
assert_import = 0
mix_str = 0
mix_coname = 0
mix_localnames = 1
mix_argnames = 0
obf_module = 1
obf_code = 1
wrap_mode = 1
restrict_module = 1
import_check_license = 0
clear_module_co = 1
clear_frame_locals = 0
rft_mix_import_name = 0
strip_package_name = 1
private_module_same_as_restrict = 0
Global options
Local options
------------------------------------------------------------
Section: runtime
Current options
universal = 0
package_name_format = pyarmor_runtime_{suffix}
simple_extension_name = 1
patch_extension = 1
obf_key_mode = 0
outer = 0
on_error = 0
nts = local
nts_timeout = 3
timer = 0
messages = messages.cfg:utf-8
Global options
Local options
------------------------------------------------------------
Section: pack
Current options
strip = 0
no_matched_pyc = error
Global options
Local options
------------------------------------------------------------
Section: bcc
Current options
unsupported_functions = exec eval super locals __asser...
unsupported_nodes = AsyncFunctionDef AsyncFor Asyn...
call_function_ex = 0
trace_lineno = 0
keep_nest_name = 0
ignore_lambda = 0
enable_pure_function = 1
enable_comprehension = 1
Global options
Local options
------------------------------------------------------------
Section: mix.str
Current options
threshold = 8
Global options
Local options
------------------------------------------------------------
Section: assert.call
Current options
auto_mode = and
Global options
Local options
------------------------------------------------------------
Section: assert.import
Current options
auto_mode = and
Global options
Local options
3. Generate the Obfuscated Code
Use the pyarmor gen
command to generate the obfuscated code directly into the dist
directory. You can obfuscate all the Python files in your project with a single command, or you can target specific packages.
# pyarmor gen -O dist/image_processing image_processing/*.py
# pyarmor gen -O dist/labview_aoi labview_aoi/*.py
# pyarmor gen -O dist manage.py
This command should:
- Obfuscate all
.py
files in theimage_processing
andlabview_aoi
directories, as well asmanage.py
. - Place the obfuscated output in the
dist
directory.
4. Run the Application
After running the gen
command, you should be able to run your application from the dist
directory. The exact command will depend on your application type, but for a Django project, it would likely be:
# cd dist
# python3 manage.py runserver 8080
Watching for file changes with StatReloader
Performing system checks...
System check identified no issues (0 silenced).
You have 18 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions.
Run 'python manage.py migrate' to apply them.
April 17, 2025 - 09:23:18
Django version 4.2.20, using settings 'labview_aoi.settings'
Starting development server at http://127.0.0.1:8080/
Quit the server with CONTROL-C.
Key Takeaways
- pip install pyarmor
- create .pyarmor_config.txt
- pyarmor cfg
- pyarmor gen -O dist/image_processing image_processing/*.py
- pyarmor gen -O dist/labview_aoi labview_aoi/*.py
- pyarmor gen -O dist manage.py
- cd dist
- python3 manage.py runserver 8080
PyArmor Official Website: https://pyarmor.readthedocs.io/
Django Offical WebSet: https://www.djangoproject.com/
自動引用通知: Bottle cap optical inspection - Winerva Blog