-
Notifications
You must be signed in to change notification settings - Fork 385
Add feature/conveyor application barcode #758
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
Open
TamseSaso
wants to merge
9
commits into
main
Choose a base branch
from
feat/conveyor-application-barcode
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a8c8f98
Add feature/conveyor application barcode
TamseSaso abbec47
Made requested changes
TamseSaso 73a5623
fixed typo in README.md
TamseSaso a4df694
added changes in README and requirements
TamseSaso 774b7d3
pushed changes to resolve pre-commit issues
TamseSaso 6ee7b3c
Reset .pre-commit-config.yaml to match origin/main
TamseSaso 0bb0e14
pushed changes to resolve pre-commit issues
TamseSaso bd6a56a
merge main
klemen1999 af465a9
renamed to 'barcode-detection-conveyor-belt'
klemen1999 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
111 changes: 111 additions & 0 deletions
111
neural-networks/object-detection/barcode-detection-conveyor-belt/README.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,111 @@ | ||
| # Barcode Detection on Conveyor Belt | ||
|
|
||
| This example demonstrates how to detect and decode barcodes in real-time using computer vision. The application is designed for conveyor belt applications where barcodes need to be detected and decoded from video streams. It uses a [barcode detection model](https://models.luxonis.com/luxonis/barcode-detection/75edea0f-79c9-4091-a48c-f81424b3ccab) for detecting barcode regions and combines multiple decoding strategies (pyzbar and zxing-cpp) to ensure robust barcode recognition across various formats and conditions. | ||
|
|
||
| The system processes high-resolution camera input, intelligently crops detected barcode regions, and applies multiple fallback decoding strategies including rotation and color inversion to maximize recognition success rates. | ||
|
|
||
| ## ⚠️ Important Notice | ||
|
|
||
| **This application will work poorly on fixed focus devices.** The barcode detection and decoding algorithms require clear, focused images to function effectively. Fixed focus cameras may struggle to capture sharp barcode images at varying distances, leading to: | ||
|
|
||
| - Reduced detection accuracy | ||
| - Failed barcode decoding attempts | ||
| - Inconsistent performance | ||
|
|
||
| For optimal results, use devices with autofocus capabilities or ensure barcodes are positioned at the camera's fixed focal distance. | ||
|
|
||
| ## Recommended Devices | ||
|
|
||
| We recommend using **OAK4-CS** for this example. Its **global-shutter** color sensor is best for fast-moving conveyor belts, reducing motion blur and rolling-shutter artifacts that can cause missed or incorrect decodes. | ||
|
|
||
| The application will also run on **OAK4-S** and **OAK4-D** devices. For rolling-shutter or fixed-focus variants, keep barcodes near the best-focus distance and ensure good lighting to maximize decoding reliability. See the notice above regarding fixed-focus cameras. | ||
|
|
||
| ## Demo | ||
|
|
||
|  | ||
|
|
||
| > **Note:** The stream may appear purplish because the OAK4-CS lacks an IR-cut filter. | ||
|
|
||
| ## Usage | ||
|
|
||
| Running this example requires a **Luxonis device** connected to your computer. Refer to the [documentation](https://docs.luxonis.com/software-v3/) to setup your device if you haven't done it already. | ||
|
|
||
| You can run the example fully on device ([`STANDALONE` mode](#standalone-mode-rvc4-only)) or using your computer as host ([`PERIPHERAL` mode](#peripheral-mode)). | ||
|
|
||
| Here is a list of all available parameters: | ||
|
|
||
| ``` | ||
| -d DEVICE, --device DEVICE | ||
| Optional name, DeviceID or IP of the camera to connect to. (default: None) | ||
| -fps FPS_LIMIT, --fps_limit FPS_LIMIT | ||
| FPS limit for the model runtime. (default: 10 for RVC2, 30 for RVC4) | ||
| --media_path MEDIA_PATH | ||
| Optional path to video file for processing instead of live camera feed. (default: None) | ||
| ``` | ||
|
|
||
| ## Peripheral Mode | ||
|
|
||
| ### Installation | ||
|
|
||
| Install libraries: | ||
|
|
||
| **Ubuntu:** | ||
|
|
||
| ```bash | ||
| sudo apt-get update && apt-get install -y libzbar0 libzbar-dev | ||
| ``` | ||
|
|
||
| **macOS:** | ||
|
|
||
| ```bash | ||
| brew install zbar | ||
| ``` | ||
|
|
||
| You need to first prepare a **Python 3.10** environment with the following packages installed: | ||
|
|
||
| - [DepthAI](https://pypi.org/project/depthai/), | ||
| - [DepthAI Nodes](https://pypi.org/project/depthai-nodes/). | ||
|
|
||
| You can simply install them by running: | ||
|
|
||
| ```bash | ||
| pip install -r requirements.txt | ||
| ``` | ||
|
|
||
| Running in peripheral mode requires a host computer and there will be communication between device and host which could affect the overall speed of the app. Below are some examples of how to run the example. | ||
|
|
||
| ### Examples | ||
|
|
||
| Start the demo: | ||
|
|
||
| ```bash | ||
| python3 main.py | ||
| ``` | ||
|
|
||
| This will run the example with default arguments. | ||
|
|
||
| ```bash | ||
| python3 main.py --device 192.168.1.100 --fps_limit 15 | ||
| ``` | ||
|
|
||
| This will connect to a specific device and set the FPS limit to 15. | ||
|
|
||
| ```bash | ||
| python3 main.py --media_path test_video.mp4 | ||
| ``` | ||
|
|
||
| This will process a video file instead of live camera feed. | ||
|
|
||
| ## Standalone Mode (RVC4 only) | ||
|
|
||
| Running the example in the standalone mode, app runs entirely on the device. | ||
| To run the example in this mode, first install the `oakctl` tool using the installation instructions [here](https://docs.luxonis.com/software-v3/oak-apps/oakctl). | ||
|
|
||
| The app can then be run with: | ||
|
|
||
| ```bash | ||
| oakctl connect <DEVICE_IP> | ||
| oakctl app run . | ||
| ``` | ||
|
|
||
| This will run the example with default argument values. If you want to change these values you need to edit the `oakapp.toml` file (refer [here](https://docs.luxonis.com/software-v3/oak-apps/configuration/) for more information about this configuration file). |
2 changes: 2 additions & 0 deletions
2
...ject-detection/barcode-detection-conveyor-belt/depthai_models/barcode-detection.RVC2.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| model: luxonis/barcode-detection:768x576 | ||
| platform: RVC2 |
2 changes: 2 additions & 0 deletions
2
...ject-detection/barcode-detection-conveyor-belt/depthai_models/barcode-detection.RVC4.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| model: luxonis/barcode-detection:768x576 | ||
| platform: RVC4 |
95 changes: 95 additions & 0 deletions
95
neural-networks/object-detection/barcode-detection-conveyor-belt/main.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| from pathlib import Path | ||
| import depthai as dai | ||
| from depthai_nodes.node import ParsingNeuralNetwork | ||
|
|
||
| from utils.arguments import initialize_argparser | ||
| from utils.simple_barcode_overlay import SimpleBarcodeOverlay | ||
| from utils.barcode_decoder import BarcodeDecoder | ||
| from utils.host_crop_config_creator import CropConfigsCreator | ||
|
|
||
| _, args = initialize_argparser() | ||
|
|
||
| visualizer = dai.RemoteConnection(httpPort=8082) | ||
| device = dai.Device(dai.DeviceInfo(args.device)) if args.device else dai.Device() | ||
| platform = device.getPlatform().name | ||
| print(f"Platform: {platform}") | ||
|
|
||
| frame_type = ( | ||
| dai.ImgFrame.Type.BGR888i if platform == "RVC4" else dai.ImgFrame.Type.BGR888p | ||
| ) | ||
|
|
||
| if not args.fps_limit: | ||
| args.fps_limit = 10 if platform == "RVC2" else 30 | ||
| print( | ||
| f"\nFPS limit set to {args.fps_limit} for {platform} platform. If you want to set a custom FPS limit, use the --fps_limit flag.\n" | ||
| ) | ||
|
|
||
| with dai.Pipeline(device) as pipeline: | ||
| print("Creating pipeline...") | ||
|
|
||
| model_description = dai.NNModelDescription.fromYamlFile( | ||
| f"barcode-detection.{platform}.yaml" | ||
| ) | ||
| nn_archive = dai.NNArchive( | ||
| dai.getModelFromZoo( | ||
| model_description, | ||
| ) | ||
| ) | ||
|
|
||
| if args.media_path: | ||
| replay = pipeline.create(dai.node.ReplayVideo) | ||
| replay.setReplayVideoFile(Path(args.media_path)) | ||
| replay.setOutFrameType(frame_type) | ||
| replay.setLoop(True) | ||
| if args.fps_limit: | ||
| replay.setFps(args.fps_limit) | ||
| else: | ||
| cam = pipeline.create(dai.node.Camera).build() | ||
|
|
||
| cam_out = cam.requestOutput((2592, 1944), frame_type, fps=args.fps_limit) | ||
| input_node = replay.out if args.media_path else cam_out | ||
|
|
||
| resize_node = pipeline.create(dai.node.ImageManip) | ||
| resize_node.setMaxOutputFrameSize( | ||
| nn_archive.getInputWidth() * nn_archive.getInputHeight() * 3 | ||
| ) | ||
| resize_node.initialConfig.setOutputSize( | ||
| nn_archive.getInputWidth(), | ||
| nn_archive.getInputHeight(), | ||
| mode=dai.ImageManipConfig.ResizeMode.STRETCH, | ||
| ) | ||
| resize_node.initialConfig.setFrameType(frame_type) | ||
| input_node.link(resize_node.inputImage) | ||
|
|
||
| detection_nn: ParsingNeuralNetwork = pipeline.create(ParsingNeuralNetwork).build( | ||
| resize_node.out, nn_archive | ||
| ) | ||
|
|
||
| crop_code = pipeline.create(CropConfigsCreator).build( | ||
| detection_nn.out, | ||
| source_size=(2592, 1944), | ||
| target_size=(640, 480), | ||
| resize_mode=dai.ImageManipConfig.ResizeMode.LETTERBOX, | ||
| ) | ||
|
|
||
| crop_manip = pipeline.create(dai.node.ImageManip) | ||
| crop_manip.inputConfig.setReusePreviousMessage(False) | ||
| crop_manip.setMaxOutputFrameSize(640 * 480 * 5) | ||
| input_node.link(crop_manip.inputImage) | ||
| crop_code.config_output.link(crop_manip.inputConfig) | ||
|
|
||
| decoder = pipeline.create(BarcodeDecoder) | ||
| crop_manip.out.link(decoder.input) | ||
|
|
||
| barcode_overlay = pipeline.create(SimpleBarcodeOverlay).build( | ||
| decoder.output, resize_node.out, detection_nn.out | ||
| ) | ||
|
|
||
| visualizer.addTopic("Barcode Overlay", barcode_overlay.output) | ||
|
|
||
| pipeline.run() | ||
|
|
||
| while True: | ||
| key = visualizer.waitKey(1) | ||
| if key == ord("q"): | ||
| break | ||
Binary file added
BIN
+6.02 MB
...etworks/object-detection/barcode-detection-conveyor-belt/media/barcode_demo.gif
TamseSaso marked this conversation as resolved.
Show resolved
Hide resolved
|
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions
17
neural-networks/object-detection/barcode-detection-conveyor-belt/oakapp.toml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| identifier = "com.example.object-detection.conveyor-application-barcodes" | ||
| app_version = "1.0.0" | ||
|
|
||
| prepare_container = [ | ||
| { type = "RUN", command = "apt-get update" }, | ||
| { type = "RUN", command = "apt-get install -y python3 python3-pip libzbar0 libzbar-dev" }, | ||
| { type = "COPY", source = "requirements.txt", target = "requirements.txt" }, | ||
| { type = "RUN", command = "pip3 install -r /app/requirements.txt --break-system-packages"}, | ||
| ] | ||
|
|
||
| prepare_build_container = [] | ||
|
|
||
| build_steps = [] | ||
|
|
||
| depthai_models = { yaml_path = "./depthai_models" } | ||
|
|
||
| entrypoint = ["bash", "-c", "python3 -u /app/main.py"] |
6 changes: 6 additions & 0 deletions
6
neural-networks/object-detection/barcode-detection-conveyor-belt/requirements.txt
TamseSaso marked this conversation as resolved.
Show resolved
Hide resolved
TamseSaso marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| depthai>=3.0.0 | ||
| depthai-nodes==0.3.4 | ||
| numpy>=1.22 | ||
| opencv-python-headless~=4.10.0 | ||
| pyzbar==0.1.9 | ||
| Pillow==12.0.0 |
77 changes: 77 additions & 0 deletions
77
neural-networks/object-detection/barcode-detection-conveyor-belt/utils/annotation_node.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| from typing import List | ||
| import depthai as dai | ||
|
|
||
| from depthai_nodes import ImgDetectionsExtended, SECONDARY_COLOR | ||
| from depthai_nodes.utils import AnnotationHelper | ||
|
|
||
|
|
||
| class AnnotationNode(dai.node.ThreadedHostNode): | ||
| def __init__(self) -> None: | ||
| super().__init__() | ||
|
|
||
| self.input = self.createInput() | ||
| self.input.setPossibleDatatypes([(dai.DatatypeEnum.Buffer, True)]) | ||
|
|
||
| self.out = self.createOutput() | ||
| self.out.setPossibleDatatypes([(dai.DatatypeEnum.Buffer, True)]) | ||
|
|
||
| def build( | ||
| self, | ||
| gather_data_msg: dai.Node.Output, | ||
| ) -> "AnnotationNode": | ||
| gather_data_msg.link(self.input) | ||
| return self | ||
|
|
||
| def run(self) -> None: | ||
| while self.isRunning(): | ||
| gather_data_msg: dai.Buffer = self.input.get() | ||
|
|
||
| img_detections_extended_msg: ImgDetectionsExtended = ( | ||
| gather_data_msg.reference_data | ||
| ) | ||
|
|
||
| msg_group_list: List[dai.MessageGroup] = gather_data_msg.gathered | ||
|
|
||
| annotations = AnnotationHelper() | ||
|
|
||
| for img_detection_extended_msg, msg_group in zip( | ||
| img_detections_extended_msg.detections, msg_group_list | ||
| ): | ||
| xmin, ymin, xmax, ymax = ( | ||
| img_detection_extended_msg.rotated_rect.getOuterRect() | ||
| ) | ||
|
|
||
| try: | ||
| xmin = float(xmin) | ||
| ymin = float(ymin) | ||
| xmax = float(xmax) | ||
| ymax = float(ymax) | ||
| except Exception: | ||
| pass | ||
|
|
||
| xmin = max(0.0, min(1.0, xmin)) | ||
| ymin = max(0.0, min(1.0, ymin)) | ||
| xmax = max(0.0, min(1.0, xmax)) | ||
| ymax = max(0.0, min(1.0, ymax)) | ||
|
|
||
| annotations.draw_rectangle((xmin, ymin), (xmax, ymax)) | ||
|
|
||
| barcode_text = "" | ||
| if "0" in msg_group: | ||
| buf_msg: dai.Buffer = msg_group["0"] | ||
| barcode_text = buf_msg.getData().decode("utf-8", errors="ignore") | ||
|
|
||
| if barcode_text: | ||
| annotations.draw_text( | ||
| text=barcode_text, | ||
| position=(xmin + 0.01, ymin + 0.03), | ||
| size=20, | ||
| color=SECONDARY_COLOR, | ||
| ) | ||
|
|
||
| annotations_msg = annotations.build( | ||
| timestamp=img_detections_extended_msg.getTimestamp(), | ||
| sequence_num=img_detections_extended_msg.getSequenceNum(), | ||
| ) | ||
|
|
||
| self.out.send(annotations_msg) |
38 changes: 38 additions & 0 deletions
38
neural-networks/object-detection/barcode-detection-conveyor-belt/utils/arguments.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| import argparse | ||
|
|
||
|
|
||
| def initialize_argparser(): | ||
| """Initialize the argument parser for the script.""" | ||
| parser = argparse.ArgumentParser( | ||
| formatter_class=argparse.ArgumentDefaultsHelpFormatter | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "-d", | ||
| "--device", | ||
| help="Optional name, DeviceID or IP of the camera to connect to.", | ||
| required=False, | ||
| default=None, | ||
| type=str, | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "-fps", | ||
| "--fps_limit", | ||
| help="FPS limit for the model runtime.", | ||
| required=False, | ||
| default=None, | ||
| type=int, | ||
| ) | ||
|
|
||
| parser.add_argument( | ||
| "-media", | ||
| "--media_path", | ||
| help="Path to the media file you aim to run the model on. If not set, the model will run on the camera input.", | ||
| required=False, | ||
| default=None, | ||
| type=str, | ||
| ) | ||
| args = parser.parse_args() | ||
|
|
||
| return parser, args |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.