mirror of
https://github.com/LdDl/go-darknet.git
synced 2025-09-26 19:51:27 +08:00
Compare commits
64 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
f5e648f099 | ||
![]() |
63dd49eee7 | ||
![]() |
ae97f8ced4 | ||
![]() |
549fd8d315 | ||
![]() |
0880b53f27 | ||
![]() |
1969bdad71 | ||
![]() |
36d89f7409 | ||
![]() |
51c7e39572 | ||
![]() |
7e34b459e6 | ||
![]() |
a18a9cf3e0 | ||
![]() |
3d4b8507dc | ||
![]() |
7edf795470 | ||
![]() |
020dc47d85 | ||
![]() |
f813086971 | ||
![]() |
7b59b7be33 | ||
![]() |
774662381f | ||
![]() |
d8cd9728c2 | ||
![]() |
8213e6e9ac | ||
![]() |
1b4b71fa8e | ||
![]() |
7ed6d2e7c9 | ||
![]() |
4c748e7ba4 | ||
![]() |
b27d031c92 | ||
![]() |
fb66efa419 | ||
![]() |
25fd9865dd | ||
![]() |
687c472ea9 | ||
![]() |
b8f4ad6d57 | ||
![]() |
40df8cce91 | ||
![]() |
13a0697585 | ||
![]() |
29e4d0d8bb | ||
![]() |
165e59aaf3 | ||
![]() |
81223ac67d | ||
![]() |
7cbe2f50a7 | ||
![]() |
6a381223fa | ||
![]() |
a039e75b22 | ||
![]() |
7f94c3bdcc | ||
![]() |
e5d170ef8b | ||
![]() |
85730b925c | ||
![]() |
55221029de | ||
![]() |
e0a6735667 | ||
![]() |
c9bbd3eee4 | ||
![]() |
5539377f1c | ||
![]() |
10cd5f6e1a | ||
![]() |
2a51e807d8 | ||
![]() |
df9804aa69 | ||
![]() |
68ad5efb35 | ||
![]() |
5e18d06f26 | ||
![]() |
ebf93ddfa6 | ||
![]() |
8bd8488c7f | ||
![]() |
420a74769d | ||
![]() |
527e2942e9 | ||
![]() |
8105b8f1ae | ||
![]() |
c625572f8c | ||
![]() |
a58fecd863 | ||
![]() |
435d3f662c | ||
![]() |
d9682ca0f6 | ||
![]() |
4b38088916 | ||
![]() |
766ff56e2e | ||
![]() |
3166cdca78 | ||
![]() |
02ab33b804 | ||
![]() |
0fd261e605 | ||
![]() |
4c39be01f9 | ||
![]() |
2dd85a84d6 | ||
![]() |
3a10d5a657 | ||
![]() |
95332e0877 |
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: "[BUG]"
|
||||
labels: bug, help wanted
|
||||
assignees: LdDl
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Describe the solution you'd like and provide pseudocode examples if you can**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: "[FEATURE REQUEST]"
|
||||
labels: enhancement
|
||||
assignees: LdDl
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is.
|
||||
|
||||
**Describe the solution you'd like and provide pseudocode examples if you can**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered and provide pseudocode examples if you can**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
16
.gitignore
vendored
16
.gitignore
vendored
@@ -1,8 +1,14 @@
|
||||
example/main
|
||||
example/sample.jpg
|
||||
example/coco.names
|
||||
example/yolov3.cfg
|
||||
example/yolov3.weights
|
||||
cmd/examples/main
|
||||
cmd/examples/base_example/main
|
||||
cmd/examples/coco.names
|
||||
cmd/examples/yolov3.cfg
|
||||
cmd/examples/yolov3.weights
|
||||
cmd/examples/yolov4.cfg
|
||||
cmd/examples/yolov4.weights
|
||||
cmd/examples/yolov4-tiny.cfg
|
||||
cmd/examples/yolov4-tiny.weights
|
||||
cmd/examples/yolov7-tiny.cfg
|
||||
cmd/examples/yolov7-tiny.weights
|
||||
darknet.h
|
||||
*.so
|
||||
predictions.png
|
||||
|
201
LICENSE
Normal file
201
LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [2020] LdDl Dimitrii Lopanov
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
104
Makefile
Normal file
104
Makefile
Normal file
@@ -0,0 +1,104 @@
|
||||
.ONESHELL:
|
||||
.PHONY: prepare_cuda prepare_cudnn download_darknet build_darknet build_darknet_gpu clean clean_cuda clean_cudnn sudo_install
|
||||
|
||||
# Latest battletested AlexeyAB version of Darknet commit
|
||||
# LATEST_COMMIT?=f056fc3b6a11528fa0522a468eca1e909b7004b7
|
||||
LATEST_COMMIT?=9d40b619756be9521bc2ccd81808f502daaa3e9a
|
||||
|
||||
# Temporary folder for building Darknet
|
||||
TMP_DIR?=/tmp/
|
||||
|
||||
# Manage cuda version
|
||||
CUDA_VERSION = 10.2
|
||||
CUDNN_VERSION = 7.6.5
|
||||
CUDNN_FULL_VERSION = 7.6.5.32
|
||||
OS_NAME_LOW_CASE = ubuntu
|
||||
OS_VERSION_CONCATENATED = 1804
|
||||
OS_ARCH = x86_64
|
||||
OS_ALTER_ARCH = linux-x64
|
||||
OS_FULLNAME = $(OS_NAME_LOW_CASE)$(OS_VERSION_CONCATENATED)
|
||||
# I guess *.pub is static for most of systems
|
||||
PUBNAME = 7fa2af80
|
||||
|
||||
# Install CUDA
|
||||
prepare_cuda:
|
||||
sudo apt-get install linux-headers-$(uname -r)
|
||||
rm -rf $(TMP_DIR)install_cuda
|
||||
mkdir $(TMP_DIR)install_cuda
|
||||
wget -P $(TMP_DIR)install_cuda https://developer.download.nvidia.com/compute/cuda/repos/$(OS_FULLNAME)/$(OS_ARCH)/cuda-$(OS_FULLNAME).pin
|
||||
cd $(TMP_DIR)install_cuda
|
||||
sudo mv cuda-$(OS_FULLNAME).pin /etc/apt/preferences.d/cuda-repository-pin-600
|
||||
sudo apt-key adv --fetch-keys https://developer.download.nvidia.com/compute/cuda/repos/$(OS_FULLNAME)/$(OS_ARCH)/$(PUBNAME).pub
|
||||
sudo add-apt-repository "deb http://developer.download.nvidia.com/compute/cuda/repos/$(OS_FULLNAME)/$(OS_ARCH)/ /"
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install cuda-$(subst .,-,$(CUDA_VERSION))
|
||||
cd -
|
||||
|
||||
# Install cuDNN
|
||||
# Notice: this valid instruction for cuDNN version from v7.2.1 up to 8.1.0.77
|
||||
prepare_cudnn:
|
||||
rm -rf $(TMP_DIR)install_cudnn
|
||||
mkdir $(TMP_DIR)install_cudnn
|
||||
wget -P $(TMP_DIR)install_cudnn https://developer.download.nvidia.com/compute/redist/cudnn/v${CUDNN_VERSION}/cudnn-${CUDA_VERSION}-${OS_ALTER_ARCH}-v${CUDNN_FULL_VERSION}.tgz
|
||||
cd $(TMP_DIR)install_cudnn
|
||||
tar -xzvf cudnn-${CUDA_VERSION}-${OS_ALTER_ARCH}-v${CUDNN_FULL_VERSION}.tgz
|
||||
sudo cp cuda/include/cudnn*.h /usr/local/cuda/include
|
||||
sudo cp -P cuda/lib64/libcudnn* /usr/local/cuda/lib64
|
||||
sudo chmod a+r /usr/local/cuda/include/cudnn*.h /usr/local/cuda/lib64/libcudnn*
|
||||
cd -
|
||||
|
||||
# Download AlexeyAB version of Darknet
|
||||
download_darknet:
|
||||
rm -rf $(TMP_DIR)install_darknet
|
||||
mkdir $(TMP_DIR)install_darknet
|
||||
git clone https://github.com/AlexeyAB/darknet.git $(TMP_DIR)install_darknet
|
||||
cd $(TMP_DIR)install_darknet
|
||||
git checkout $(LATEST_COMMIT)
|
||||
cd -
|
||||
|
||||
# Build AlexeyAB version of Darknet for usage with CPU only.
|
||||
build_darknet:
|
||||
cd $(TMP_DIR)install_darknet
|
||||
sed -i -e 's/GPU=1/GPU=0/g' Makefile
|
||||
sed -i -e 's/CUDNN=1/CUDNN=0/g' Makefile
|
||||
sed -i -e 's/LIBSO=0/LIBSO=1/g' Makefile
|
||||
$(MAKE) -j $(shell nproc --all)
|
||||
$(MAKE) preinstall
|
||||
cd -
|
||||
|
||||
# Build AlexeyAB version of Darknet for usage with both CPU and GPU (CUDA by NVIDIA).
|
||||
build_darknet_gpu:
|
||||
cd $(TMP_DIR)install_darknet
|
||||
sed -i -e 's/GPU=0/GPU=1/g' Makefile
|
||||
sed -i -e 's/CUDNN=0/CUDNN=1/g' Makefile
|
||||
sed -i -e 's/LIBSO=0/LIBSO=1/g' Makefile
|
||||
$(MAKE) -j $(shell nproc --all)
|
||||
$(MAKE) preinstall
|
||||
cd -
|
||||
|
||||
# Install system wide.
|
||||
sudo_install:
|
||||
cd $(TMP_DIR)install_darknet
|
||||
sudo cp libdarknet.so /usr/lib/libdarknet.so
|
||||
sudo cp include/darknet.h /usr/include/darknet.h
|
||||
sudo ldconfig
|
||||
cd -
|
||||
|
||||
# Cleanup temporary files for building process
|
||||
clean:
|
||||
rm -rf $(TMP_DIR)install_darknet
|
||||
|
||||
clean_cuda:
|
||||
rm -rf $(TMP_DIR)install_cuda
|
||||
|
||||
clean_cudnn:
|
||||
rm -rf $(TMP_DIR)install_cudnn
|
||||
|
||||
# Do every step for CPU-based only build.
|
||||
install_darknet: download_darknet build_darknet sudo_install clean
|
||||
|
||||
# Do every step for both CPU and GPU-based build.
|
||||
install_darknet_gpu: download_darknet build_darknet_gpu sudo_install clean
|
||||
|
||||
# Do every step for both CPU and GPU-based build if you haven't installed CUDA.
|
||||
install_darknet_gpu_cuda: prepare_cuda prepare_cudnn download_darknet build_darknet_gpu sudo_install clean clean_cuda clean_cudnn
|
235
README.md
235
README.md
@@ -1,42 +1,62 @@
|
||||
# go-darknet: Go bindings for Darknet
|
||||
|
||||
### This is fork of go-darknet https://github.com/gyonluks/go-darknet applied to FORK of Darknet https://github.com/AlexeyAB/darknet
|
||||
|
||||
[](https://godoc.org/github.com/LdDl/go-darknet)
|
||||
[](https://sourcegraph.com/github.com/LdDl/go-darknet?badge)
|
||||
[](https://goreportcard.com/report/github.com/LdDl/go-darknet)
|
||||
[](https://github.com/LdDl/go-darknet/releases)
|
||||
|
||||
go-darknet is a Go package, which uses Cgo to enable Go applications to use YOLO in [Darknet].
|
||||
# go-darknet: Go bindings for Darknet (Yolo V4, Yolo V7-tiny, Yolo V3)
|
||||
### go-darknet is a Go package, which uses Cgo to enable Go applications to use V4/V7-tiny/V3 in [Darknet].
|
||||
|
||||
#### Since this repository https://github.com/gyonluks/go-darknet is no longer maintained I decided to move on and make little different bindings for Darknet.
|
||||
#### This bindings aren't for [official implementation](https://github.com/pjreddie/darknet) but for [AlexeyAB's fork](https://github.com/AlexeyAB/darknet).
|
||||
|
||||
#### Paper Yolo v7: https://arxiv.org/abs/2207.02696 (WARNING: Only 'tiny' variation works currently)
|
||||
#### Paper Yolo v4: https://arxiv.org/abs/2004.10934
|
||||
#### Paper Yolo v3: https://arxiv.org/abs/1804.02767
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Why](#why)
|
||||
- [Requirements](#requirements)
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
- [Documentation](#documentation)
|
||||
- [License](#license)
|
||||
|
||||
## Why
|
||||
**Why does this repository exist?**
|
||||
|
||||
Because this repository https://github.com/gyonluks/go-darknet is no longer maintained.
|
||||
|
||||
**What is purpose of this bindings when you can have [GoCV](https://github.com/hybridgroup/gocv#gocv) (bindings to OpenCV) and it handle Darknet YOLO perfectly?**
|
||||
|
||||
Well, you don't need bunch of OpenCV dependencies and OpenCV itself sometimes.
|
||||
|
||||
Example of such project here: https://github.com/LdDl/license_plate_recognition#license-plate-recognition-with-go-darknet---- .
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
For proper codebase please use fork of [darknet](https://github.com/AlexeyAB/darknet). Latest commit I've tested [here](https://github.com/AlexeyAB/darknet/commit/64fb042c63637038671ae9d53c06165599b28912)
|
||||
You need to install fork of [darknet](https://github.com/AlexeyAB/darknet). Latest commit I've tested is [here](https://github.com/AlexeyAB/darknet/commit/9d40b619756be9521bc2ccd81808f502daaa3e9a). It corresponds last official [YOLOv4 release](https://github.com/AlexeyAB/darknet/releases/tag/yolov4)
|
||||
|
||||
In order to use go-darknet, `libdarknet.so` should be available in one of
|
||||
the following locations:
|
||||
Use provided [Makefile](Makefile).
|
||||
|
||||
* /usr/lib
|
||||
* /usr/local/lib
|
||||
* For CPU-based instalattion:
|
||||
```shell
|
||||
make install_darknet
|
||||
```
|
||||
* For both CPU and GPU-based instalattion if you HAVE CUDA installed:
|
||||
```shell
|
||||
make install_darknet_gpu
|
||||
```
|
||||
Note: I've tested CUDA [10.2](https://developer.nvidia.com/cuda-10.2-download-archive) and cuDNN is [7.6.5](https://developer.nvidia.com/rdp/cudnn-archive#a-collapse765-102))
|
||||
|
||||
Also, [darknet.h] should be available in one of the following locations:
|
||||
* For both CPU and GPU-based instalattion if you HAVE NOT CUDA installed:
|
||||
```shell
|
||||
make install_darknet_gpu_cuda
|
||||
```
|
||||
Note: There is some struggle in Makefile for cuDNN, but I hope it works in Ubuntu atleast. Do not forget provide proper CUDA and cuDNN versions.
|
||||
|
||||
* /usr/include
|
||||
* /usr/local/include
|
||||
|
||||
To achieve it, after Darknet compilation (via make) execute following command:
|
||||
```shell
|
||||
sudo cp libdarknet.so /usr/lib/libdarknet.so && sudo cp include/darknet.h /usr/local/include/darknet.h
|
||||
```
|
||||
Note: do not forget to set LIBSO=1 in Makefile before executing 'make':
|
||||
```Makefile
|
||||
LIBSO=1
|
||||
```
|
||||
## Installation
|
||||
|
||||
```shell
|
||||
@@ -45,56 +65,139 @@ go get github.com/LdDl/go-darknet
|
||||
|
||||
## Usage
|
||||
|
||||
Example Go program is provided in the [example] directory. Please refer to the code on how to use this Go package.
|
||||
Example Go program is provided in the [examples] directory. Please refer to the code on how to use this Go package.
|
||||
|
||||
Building and running program:
|
||||
|
||||
Navigate to [example] folder
|
||||
```shell
|
||||
cd $GOPATH/github.com/LdDl/go-darknet/example
|
||||
```
|
||||
* Navigate to [examples] folder
|
||||
```shell
|
||||
cd ${YOUR PATH}/github.com/LdDl/go-darknet/cmd/examples
|
||||
```
|
||||
|
||||
Download dataset (sample of image, coco.names, yolov3.cfg, yolov3.weights).
|
||||
```shell
|
||||
./download_data.sh
|
||||
```
|
||||
Note: you don't need *coco.data* file anymore, because sh-script above does insert *coco.names* into 'names' filed in *yolov3.cfg* file (so AlexeyAB's fork can deal with it properly)
|
||||
So last rows in yolov3.cfg file will look like:
|
||||
```bash
|
||||
......
|
||||
[yolo]
|
||||
mask = 0,1,2
|
||||
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
|
||||
classes=80
|
||||
num=9
|
||||
jitter=.3
|
||||
ignore_thresh = .7
|
||||
truth_thresh = 1
|
||||
random=1
|
||||
names = coco.names # this is path to coco.names file
|
||||
```
|
||||
* Download dataset (sample of image, coco.names, yolov4.cfg (or v3), yolov4.weights(or v3)).
|
||||
```shell
|
||||
#for yolo v4
|
||||
./download_data.sh
|
||||
#for yolo v4 tiny
|
||||
./download_data_v4_tiny.sh
|
||||
#for yolo v7 tiny
|
||||
./download_data_v7_tiny.sh
|
||||
#for yolo v3
|
||||
./download_data_v3.sh
|
||||
```
|
||||
* Note: you don't need *coco.data* file anymore, because sh-script above does insert *coco.names* into 'names' field in *yolov4.cfg* file (so AlexeyAB's fork can deal with it properly)
|
||||
So last rows in yolov4.cfg file will look like:
|
||||
```bash
|
||||
......
|
||||
[yolo]
|
||||
.....
|
||||
iou_loss=ciou
|
||||
nms_kind=greedynms
|
||||
beta_nms=0.6
|
||||
|
||||
Build and run program
|
||||
```
|
||||
go build main.go && ./main --configFile=yolov3.cfg --weightsFile=yolov3.weights --imageFile=sample.jpg
|
||||
```
|
||||
names = coco.names # this is path to coco.names file
|
||||
```
|
||||
|
||||
* Also do not forget change batch and subdivisions sizes from:
|
||||
```shell
|
||||
batch=64
|
||||
subdivisions=8
|
||||
```
|
||||
to
|
||||
```shell
|
||||
batch=1
|
||||
subdivisions=1
|
||||
```
|
||||
It will reduce amount of VRAM used for detector test.
|
||||
|
||||
|
||||
* Build and run example program
|
||||
|
||||
Yolo v7 tiny:
|
||||
```shell
|
||||
go build -o base_example/main base_example/main.go && ./base_example/main --configFile=yolov7-tiny.cfg --weightsFile=yolov7-tiny.weights --imageFile=sample.jpg
|
||||
```
|
||||
|
||||
Output should be something like this:
|
||||
```shell
|
||||
truck (7): 53.2890% | start point: (0,143) | end point: (89, 328)
|
||||
truck (7): 42.1364% | start point: (685,182) | end point: (800, 318)
|
||||
truck (7): 26.9703% | start point: (437,170) | end point: (560, 217)
|
||||
car (2): 87.7818% | start point: (509,189) | end point: (742, 329)
|
||||
car (2): 87.5633% | start point: (262,191) | end point: (423, 322)
|
||||
car (2): 85.4743% | start point: (427,198) | end point: (549, 309)
|
||||
car (2): 71.3772% | start point: (0,147) | end point: (87, 327)
|
||||
car (2): 62.5698% | start point: (98,151) | end point: (197, 286)
|
||||
car (2): 61.5811% | start point: (693,186) | end point: (799, 316)
|
||||
car (2): 49.6343% | start point: (386,206) | end point: (441, 286)
|
||||
car (2): 28.2012% | start point: (386,205) | end point: (440, 236)
|
||||
bicycle (1): 71.9609% | start point: (179,294) | end point: (249, 405)
|
||||
person (0): 85.4390% | start point: (146,130) | end point: (269, 351)
|
||||
```
|
||||
|
||||
Yolo v4:
|
||||
```shell
|
||||
go build -o base_example/main base_example/main.go && ./base_example/main --configFile=yolov4.cfg --weightsFile=yolov4.weights --imageFile=sample.jpg
|
||||
```
|
||||
|
||||
Output should be something like this:
|
||||
```shell
|
||||
traffic light (9): 73.5040% | start point: (238,73) | end point: (251, 106)
|
||||
truck (7): 96.6401% | start point: (95,79) | end point: (233, 287)
|
||||
truck (7): 96.4774% | start point: (662,158) | end point: (800, 321)
|
||||
truck (7): 96.1841% | start point: (0,77) | end point: (86, 333)
|
||||
truck (7): 46.8694% | start point: (434,173) | end point: (559, 216)
|
||||
car (2): 99.7370% | start point: (512,188) | end point: (741, 329)
|
||||
car (2): 99.2532% | start point: (260,191) | end point: (422, 322)
|
||||
car (2): 99.0333% | start point: (425,201) | end point: (547, 309)
|
||||
car (2): 83.3920% | start point: (386,210) | end point: (437, 287)
|
||||
car (2): 75.8621% | start point: (73,199) | end point: (102, 274)
|
||||
car (2): 39.1925% | start point: (386,206) | end point: (442, 240)
|
||||
bicycle (1): 76.3121% | start point: (189,298) | end point: (253, 402)
|
||||
person (0): 97.7213% | start point: (141,129) | end point: (283, 362)
|
||||
```
|
||||
|
||||
Yolo v4 tiny:
|
||||
```shell
|
||||
go build -o base_example/main base_example/main.go && ./base_example/main --configFile=yolov4-tiny.cfg --weightsFile=yolov4-tiny.weights --imageFile=sample.jpg
|
||||
```
|
||||
|
||||
Output should be something like this:
|
||||
```shell
|
||||
truck (7): 77.7936% | start point: (0,138) | end point: (90, 332)
|
||||
truck (7): 55.9773% | start point: (696,174) | end point: (799, 314)
|
||||
car (2): 53.1286% | start point: (696,184) | end point: (799, 319)
|
||||
car (2): 98.0222% | start point: (262,189) | end point: (424, 330)
|
||||
car (2): 97.8773% | start point: (430,190) | end point: (542, 313)
|
||||
car (2): 81.4099% | start point: (510,190) | end point: (743, 325)
|
||||
car (2): 43.3935% | start point: (391,207) | end point: (435, 299)
|
||||
car (2): 37.4221% | start point: (386,206) | end point: (429, 239)
|
||||
car (2): 32.0724% | start point: (109,196) | end point: (157, 289)
|
||||
person (0): 73.0868% | start point: (154,132) | end point: (284, 382)
|
||||
```
|
||||
|
||||
Yolo V3:
|
||||
```
|
||||
go build main.go && ./main --configFile=yolov3.cfg --weightsFile=yolov3.weights --imageFile=sample.jpg
|
||||
```
|
||||
|
||||
Output should be something like this:
|
||||
```shell
|
||||
truck (7): 49.5123% | start point: (0,136) | end point: (85, 311)
|
||||
car (2): 36.3694% | start point: (95,152) | end point: (186, 283)
|
||||
truck (7): 48.4177% | start point: (95,152) | end point: (186, 283)
|
||||
truck (7): 45.6520% | start point: (694,178) | end point: (798, 310)
|
||||
car (2): 76.8402% | start point: (1,145) | end point: (84, 324)
|
||||
truck (7): 25.5920% | start point: (107,89) | end point: (215, 263)
|
||||
car (2): 99.8782% | start point: (511,185) | end point: (748, 328)
|
||||
car (2): 99.8193% | start point: (261,189) | end point: (427, 322)
|
||||
car (2): 99.6405% | start point: (426,197) | end point: (539, 311)
|
||||
car (2): 74.5627% | start point: (692,186) | end point: (796, 316)
|
||||
car (2): 72.7975% | start point: (388,206) | end point: (437, 276)
|
||||
bicycle (1): 72.2760% | start point: (178,270) | end point: (268, 406)
|
||||
person (0): 97.3007% | start point: (143,135) | end point: (268, 343)
|
||||
```
|
||||
|
||||
Output should be something like this:
|
||||
```shell
|
||||
truck (7): 49.5197% | start point: (0,136) | end point: (85, 311)
|
||||
car (2): 36.3747% | start point: (95,152) | end point: (186, 283)
|
||||
truck (7): 48.4384% | start point: (95,152) | end point: (186, 283)
|
||||
truck (7): 45.6590% | start point: (694,178) | end point: (798, 310)
|
||||
car (2): 76.8379% | start point: (1,145) | end point: (84, 324)
|
||||
truck (7): 25.5731% | start point: (107,89) | end point: (215, 263)
|
||||
car (2): 99.8783% | start point: (511,185) | end point: (748, 328)
|
||||
car (2): 99.8194% | start point: (261,189) | end point: (427, 322)
|
||||
car (2): 99.6408% | start point: (426,197) | end point: (539, 311)
|
||||
car (2): 74.5610% | start point: (692,186) | end point: (796, 316)
|
||||
car (2): 72.8053% | start point: (388,206) | end point: (437, 276)
|
||||
bicycle (1): 72.2932% | start point: (178,270) | end point: (268, 406)
|
||||
person (0): 97.3026% | start point: (143,135) | end point: (268, 343)
|
||||
```
|
||||
## Documentation
|
||||
|
||||
See go-darknet's API documentation at [GoDoc].
|
||||
@@ -109,5 +212,5 @@ go-darknet follows [Darknet]'s [license].
|
||||
[darknet.h]: https://github.com/AlexeyAB/darknet/blob/master/include/darknet.h
|
||||
[include/darknet.h]: https://github.com/AlexeyAB/darknet/blob/master/include/darknet.h
|
||||
[Makefile]: https://github.com/alexeyab/darknet/blob/master/Makefile
|
||||
[example]: /example
|
||||
[examples]: cmd/examples/base_example
|
||||
[GoDoc]: https://godoc.org/github.com/LdDl/go-darknet
|
||||
|
54
cmd/examples/base_example/README.md
Normal file
54
cmd/examples/base_example/README.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Example Go application using go-darknet
|
||||
|
||||
This is an example Go application which uses go-darknet.
|
||||
|
||||
|
||||
## Run
|
||||
|
||||
Navigate to example folder:
|
||||
|
||||
```shell
|
||||
cd $GOPATH/github.com/LdDl/go-darknet/example/base_example
|
||||
```
|
||||
|
||||
Download dataset (sample of image, coco.names, yolov3.cfg, yolov3.weights).
|
||||
```shell
|
||||
./download_data_v3.sh
|
||||
```
|
||||
Note: you don't need *coco.data* file anymore, because script below does insert *coco.names* into 'names' filed in *yolov3.cfg* file (so AlexeyAB's fork can deal with it properly)
|
||||
So last rows in yolov3.cfg file will look like:
|
||||
```bash
|
||||
......
|
||||
[yolo]
|
||||
mask = 0,1,2
|
||||
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
|
||||
classes=80
|
||||
num=9
|
||||
jitter=.3
|
||||
ignore_thresh = .7
|
||||
truth_thresh = 1
|
||||
random=1
|
||||
names = coco.names # this is path to coco.names file
|
||||
```
|
||||
|
||||
Build and run program
|
||||
```
|
||||
go build main.go && ./main --configFile=yolov3.cfg --weightsFile=yolov3.weights --imageFile=sample.jpg
|
||||
```
|
||||
|
||||
Output should be something like this:
|
||||
```shell
|
||||
truck (7): 49.5197% | start point: (0,136) | end point: (85, 311)
|
||||
car (2): 36.3747% | start point: (95,152) | end point: (186, 283)
|
||||
truck (7): 48.4384% | start point: (95,152) | end point: (186, 283)
|
||||
truck (7): 45.6590% | start point: (694,178) | end point: (798, 310)
|
||||
car (2): 76.8379% | start point: (1,145) | end point: (84, 324)
|
||||
truck (7): 25.5731% | start point: (107,89) | end point: (215, 263)
|
||||
car (2): 99.8783% | start point: (511,185) | end point: (748, 328)
|
||||
car (2): 99.8194% | start point: (261,189) | end point: (427, 322)
|
||||
car (2): 99.6408% | start point: (426,197) | end point: (539, 311)
|
||||
car (2): 74.5610% | start point: (692,186) | end point: (796, 316)
|
||||
car (2): 72.8053% | start point: (388,206) | end point: (437, 276)
|
||||
bicycle (1): 72.2932% | start point: (178,270) | end point: (268, 406)
|
||||
person (0): 97.3026% | start point: (143,135) | end point: (268, 343)
|
||||
```
|
@@ -7,9 +7,12 @@ import (
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
|
||||
darknet "github.com/LdDl/go-darknet"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
)
|
||||
|
||||
var configFile = flag.String("configFile", "",
|
||||
@@ -59,13 +62,13 @@ func main() {
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
defer imgDarknet.Close()
|
||||
|
||||
dr, err := n.Detect(imgDarknet)
|
||||
if err != nil {
|
||||
printError(err)
|
||||
return
|
||||
}
|
||||
imgDarknet.Close()
|
||||
|
||||
log.Println("Network-only time taken:", dr.NetworkOnlyTimeTaken)
|
||||
log.Println("Overall time taken:", dr.OverallTimeTaken, len(dr.Detections))
|
||||
@@ -78,8 +81,20 @@ func main() {
|
||||
bBox.StartPoint.X, bBox.StartPoint.Y,
|
||||
bBox.EndPoint.X, bBox.EndPoint.Y,
|
||||
)
|
||||
|
||||
// Uncomment code below if you want save cropped objects to files
|
||||
// minX, minY := float64(bBox.StartPoint.X), float64(bBox.StartPoint.Y)
|
||||
// maxX, maxY := float64(bBox.EndPoint.X), float64(bBox.EndPoint.Y)
|
||||
// rect := image.Rect(round(minX), round(minY), round(maxX), round(maxY))
|
||||
// err := saveToFile(src, rect, fmt.Sprintf("crop_%d.jpeg", i))
|
||||
// if err != nil {
|
||||
// fmt.Println(err)
|
||||
// return
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
n.Close()
|
||||
}
|
||||
|
||||
func imageToBytes(img image.Image) ([]byte, error) {
|
||||
@@ -87,3 +102,24 @@ func imageToBytes(img image.Image) ([]byte, error) {
|
||||
err := jpeg.Encode(buf, img, nil)
|
||||
return buf.Bytes(), err
|
||||
}
|
||||
|
||||
func round(v float64) int {
|
||||
if v >= 0 {
|
||||
return int(math.Floor(v + 0.5))
|
||||
}
|
||||
return int(math.Ceil(v - 0.5))
|
||||
}
|
||||
|
||||
func saveToFile(imgSrc image.Image, bbox image.Rectangle, fname string) error {
|
||||
rectcropimg := imaging.Crop(imgSrc, bbox)
|
||||
f, err := os.Create(fname)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
err = jpeg.Encode(f, rectcropimg, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
5
cmd/examples/download_data.sh
Executable file
5
cmd/examples/download_data.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
wget --output-document=sample.jpg https://cdn-images-1.medium.com/max/800/1*EYFejGUjvjPcc4PZTwoufw.jpeg
|
||||
wget --output-document=coco.names https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names
|
||||
wget --output-document=yolov4.cfg https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov4.cfg
|
||||
sed -i -e "\$anames = coco.names" yolov4.cfg
|
||||
wget --output-document=yolov4.weights https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.weights
|
5
cmd/examples/download_data_v4_tiny.sh
Executable file
5
cmd/examples/download_data_v4_tiny.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
wget --output-document=sample.jpg https://cdn-images-1.medium.com/max/800/1*EYFejGUjvjPcc4PZTwoufw.jpeg
|
||||
wget --output-document=coco.names https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names
|
||||
wget --output-document=yolov4-tiny.cfg https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov4-tiny.cfg
|
||||
sed -i -e "\$anames = coco.names" yolov4-tiny.cfg
|
||||
wget --output-document=yolov4-tiny.weights https://github.com/AlexeyAB/darknet/releases/download/yolov4/yolov4-tiny.weights
|
5
cmd/examples/download_data_v7_tiny.sh
Executable file
5
cmd/examples/download_data_v7_tiny.sh
Executable file
@@ -0,0 +1,5 @@
|
||||
wget --output-document=sample.jpg https://cdn-images-1.medium.com/max/800/1*EYFejGUjvjPcc4PZTwoufw.jpeg
|
||||
wget --output-document=coco.names https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names
|
||||
wget --output-document=yolov7-tiny.cfg https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov7-tiny.cfg
|
||||
sed -i -e "\$anames = coco.names" yolov7-tiny.cfg
|
||||
wget --output-document=yolov7-tiny.weights https://github.com/AlexeyAB/darknet/releases/download/yolov4/yolov7-tiny.weights
|
221
cmd/examples/rest_example/README.md
Normal file
221
cmd/examples/rest_example/README.md
Normal file
@@ -0,0 +1,221 @@
|
||||
# Example Go application using go-darknet and REST
|
||||
|
||||
This is an example Go server application (in terms of REST) which uses go-darknet.
|
||||
|
||||
## Run
|
||||
|
||||
Navigate to example folder:
|
||||
|
||||
```shell
|
||||
cd $GOPATH/github.com/LdDl/go-darknet/example/rest_example
|
||||
```
|
||||
|
||||
Download dataset (sample of image, coco.names, yolov3.cfg, yolov3.weights).
|
||||
```shell
|
||||
./download_data_v3.sh
|
||||
```
|
||||
Note: you don't need *coco.data* file anymore, because script below does insert *coco.names* into 'names' filed in *yolov3.cfg* file (so AlexeyAB's fork can deal with it properly)
|
||||
So last rows in yolov3.cfg file will look like:
|
||||
```bash
|
||||
......
|
||||
[yolo]
|
||||
mask = 0,1,2
|
||||
anchors = 10,13, 16,30, 33,23, 30,61, 62,45, 59,119, 116,90, 156,198, 373,326
|
||||
classes=80
|
||||
num=9
|
||||
jitter=.3
|
||||
ignore_thresh = .7
|
||||
truth_thresh = 1
|
||||
random=1
|
||||
names = coco.names # this is path to coco.names file
|
||||
```
|
||||
|
||||
Build and run program
|
||||
```
|
||||
go build main.go && ./main --configFile=yolov3.cfg --weightsFile=yolov3.weights --port 8090
|
||||
```
|
||||
|
||||
After server started check if REST-requests works. We provide cURL-based example
|
||||
```shell
|
||||
curl -F 'image=@sample.jpg' 'http://localhost:8090/detect_objects'
|
||||
```
|
||||
|
||||
Servers response should be something like this:
|
||||
```json
|
||||
{
|
||||
"net_time": "43.269289ms",
|
||||
"overall_time": "43.551604ms",
|
||||
"num_detections": 44,
|
||||
"detections": [
|
||||
{
|
||||
"class_id": 7,
|
||||
"class_name": "truck",
|
||||
"probability": 49.51231,
|
||||
"start_point": {
|
||||
"x": 0,
|
||||
"y": 136
|
||||
},
|
||||
"end_point": {
|
||||
"x": 85,
|
||||
"y": 311
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 2,
|
||||
"class_name": "car",
|
||||
"probability": 36.36933,
|
||||
"start_point": {
|
||||
"x": 95,
|
||||
"y": 152
|
||||
},
|
||||
"end_point": {
|
||||
"x": 186,
|
||||
"y": 283
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 7,
|
||||
"class_name": "truck",
|
||||
"probability": 48.417683,
|
||||
"start_point": {
|
||||
"x": 95,
|
||||
"y": 152
|
||||
},
|
||||
"end_point": {
|
||||
"x": 186,
|
||||
"y": 283
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 7,
|
||||
"class_name": "truck",
|
||||
"probability": 45.652023,
|
||||
"start_point": {
|
||||
"x": 694,
|
||||
"y": 178
|
||||
},
|
||||
"end_point": {
|
||||
"x": 798,
|
||||
"y": 310
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 2,
|
||||
"class_name": "car",
|
||||
"probability": 76.8402,
|
||||
"start_point": {
|
||||
"x": 1,
|
||||
"y": 145
|
||||
},
|
||||
"end_point": {
|
||||
"x": 84,
|
||||
"y": 324
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 7,
|
||||
"class_name": "truck",
|
||||
"probability": 25.592052,
|
||||
"start_point": {
|
||||
"x": 107,
|
||||
"y": 89
|
||||
},
|
||||
"end_point": {
|
||||
"x": 215,
|
||||
"y": 263
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 2,
|
||||
"class_name": "car",
|
||||
"probability": 99.87823,
|
||||
"start_point": {
|
||||
"x": 511,
|
||||
"y": 185
|
||||
},
|
||||
"end_point": {
|
||||
"x": 748,
|
||||
"y": 328
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 2,
|
||||
"class_name": "car",
|
||||
"probability": 99.819336,
|
||||
"start_point": {
|
||||
"x": 261,
|
||||
"y": 189
|
||||
},
|
||||
"end_point": {
|
||||
"x": 427,
|
||||
"y": 322
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 2,
|
||||
"class_name": "car",
|
||||
"probability": 99.64055,
|
||||
"start_point": {
|
||||
"x": 426,
|
||||
"y": 197
|
||||
},
|
||||
"end_point": {
|
||||
"x": 539,
|
||||
"y": 311
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 2,
|
||||
"class_name": "car",
|
||||
"probability": 74.56263,
|
||||
"start_point": {
|
||||
"x": 692,
|
||||
"y": 186
|
||||
},
|
||||
"end_point": {
|
||||
"x": 796,
|
||||
"y": 316
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 2,
|
||||
"class_name": "car",
|
||||
"probability": 72.79756,
|
||||
"start_point": {
|
||||
"x": 388,
|
||||
"y": 206
|
||||
},
|
||||
"end_point": {
|
||||
"x": 437,
|
||||
"y": 276
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 1,
|
||||
"class_name": "bicycle",
|
||||
"probability": 72.27595,
|
||||
"start_point": {
|
||||
"x": 178,
|
||||
"y": 270
|
||||
},
|
||||
"end_point": {
|
||||
"x": 268,
|
||||
"y": 406
|
||||
}
|
||||
},
|
||||
{
|
||||
"class_id": 0,
|
||||
"class_name": "person",
|
||||
"probability": 97.30075,
|
||||
"start_point": {
|
||||
"x": 143,
|
||||
"y": 135
|
||||
},
|
||||
"end_point": {
|
||||
"x": 268,
|
||||
"y": 343
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
140
cmd/examples/rest_example/main.go
Normal file
140
cmd/examples/rest_example/main.go
Normal file
@@ -0,0 +1,140 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"image"
|
||||
_ "image/jpeg"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
darknet "github.com/LdDl/go-darknet"
|
||||
)
|
||||
|
||||
var configFile = flag.String("configFile", "",
|
||||
"Path to network layer configuration file. Example: cfg/yolov3.cfg")
|
||||
var weightsFile = flag.String("weightsFile", "",
|
||||
"Path to weights file. Example: yolov3.weights")
|
||||
var serverPort = flag.Int("port", 8090,
|
||||
"Listening port")
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if *configFile == "" || *weightsFile == "" {
|
||||
flag.Usage()
|
||||
return
|
||||
}
|
||||
|
||||
n := darknet.YOLONetwork{
|
||||
GPUDeviceIndex: 0,
|
||||
NetworkConfigurationFile: *configFile,
|
||||
WeightsFile: *weightsFile,
|
||||
Threshold: .25,
|
||||
}
|
||||
if err := n.Init(); err != nil {
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
defer n.Close()
|
||||
|
||||
http.HandleFunc("/detect_objects", detectObjects(&n))
|
||||
http.ListenAndServe(fmt.Sprintf(":%d", *serverPort), nil)
|
||||
}
|
||||
|
||||
// DarknetResp Response
|
||||
type DarknetResp struct {
|
||||
NetTime string `json:"net_time"`
|
||||
OverallTime string `json:"overall_time"`
|
||||
Detections []*DarknetDetection `json:"detections"`
|
||||
}
|
||||
|
||||
// DarknetDetection Information about single detection
|
||||
type DarknetDetection struct {
|
||||
ClassID int `json:"class_id"`
|
||||
ClassName string `json:"class_name"`
|
||||
Probability float32 `json:"probability"`
|
||||
StartPoint *DarknetPoint `json:"start_point"`
|
||||
EndPoint *DarknetPoint `json:"end_point"`
|
||||
}
|
||||
|
||||
// DarknetPoint image.Image point
|
||||
type DarknetPoint struct {
|
||||
X int `json:"x"`
|
||||
Y int `json:"y"`
|
||||
}
|
||||
|
||||
func detectObjects(n *darknet.YOLONetwork) func(w http.ResponseWriter, req *http.Request) {
|
||||
return func(w http.ResponseWriter, req *http.Request) {
|
||||
// Restrict file size up to 10mb
|
||||
req.ParseMultipartForm(10 << 20)
|
||||
|
||||
file, _, err := req.FormFile("image")
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, fmt.Sprintf("Error reading FormFile: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
fileBytes, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, fmt.Sprintf("Error reading bytes: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
imgSrc, _, err := image.Decode(bytes.NewReader(fileBytes))
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, fmt.Sprintf("Error decoding bytes to image: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
imgDarknet, err := darknet.Image2Float32(imgSrc)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, fmt.Sprintf("Error converting image.Image to darknet.DarknetImage: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
defer imgDarknet.Close()
|
||||
|
||||
dr, err := n.Detect(imgDarknet)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, fmt.Sprintf("Error detecting objects: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
resp := DarknetResp{
|
||||
NetTime: fmt.Sprintf("%v", dr.NetworkOnlyTimeTaken),
|
||||
OverallTime: fmt.Sprintf("%v", dr.OverallTimeTaken),
|
||||
Detections: []*DarknetDetection{},
|
||||
}
|
||||
|
||||
for _, d := range dr.Detections {
|
||||
for i := range d.ClassIDs {
|
||||
bBox := d.BoundingBox
|
||||
resp.Detections = append(resp.Detections, &DarknetDetection{
|
||||
ClassID: d.ClassIDs[i],
|
||||
ClassName: d.ClassNames[i],
|
||||
Probability: d.Probabilities[i],
|
||||
StartPoint: &DarknetPoint{
|
||||
X: bBox.StartPoint.X,
|
||||
Y: bBox.StartPoint.Y,
|
||||
},
|
||||
EndPoint: &DarknetPoint{
|
||||
X: bBox.EndPoint.X,
|
||||
Y: bBox.EndPoint.Y,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
respBytes, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
fmt.Fprintf(w, fmt.Sprintf("Error encoding response: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Fprintf(w, string(respBytes))
|
||||
}
|
||||
}
|
BIN
cmd/examples/sample.jpg
Normal file
BIN
cmd/examples/sample.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 134 KiB |
@@ -1,34 +0,0 @@
|
||||
# Example Go application using go-darknet
|
||||
|
||||
This is an example Go application which uses go-darknet.
|
||||
|
||||
## Install
|
||||
|
||||
```shell
|
||||
go get github.com/LdDl/go-darknet
|
||||
go install github.com/LdDl/go-darknet/example
|
||||
|
||||
# Alternatively
|
||||
go build github.com/LdDl/go-darknet/example
|
||||
```
|
||||
|
||||
An executable named `example` should be in your `$GOPATH/bin`, if using
|
||||
`go install`; otherwise it will be in your current working directory (`$PWD`),
|
||||
if using `go build`.
|
||||
|
||||
## Run
|
||||
|
||||
```shell
|
||||
$GOPATH/bin/example
|
||||
```
|
||||
or
|
||||
```go
|
||||
go run main.go -configFile=yolov3-320.cfg -dataConfigFile=coco.data -imageFile=sample.jpg -weightsFile=yolov3.weights
|
||||
```
|
||||
Please ensure that `libdarknet.so` is in your `$LD_LIBRARY_PATH`.
|
||||
|
||||
## Notes
|
||||
|
||||
Note that the bounding boxes' values are ratios. To get the actual values, use
|
||||
the ratios and multiply with either the image's width or height, depending on
|
||||
which ratio is used.
|
14
go.mod
Normal file
14
go.mod
Normal file
@@ -0,0 +1,14 @@
|
||||
module github.com/LdDl/go-darknet
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/disintegration/imaging v1.6.2
|
||||
github.com/pkg/errors v0.9.1
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/edsrzf/mmap-go v1.1.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect
|
||||
)
|
14
go.sum
Normal file
14
go.sum
Normal file
@@ -0,0 +1,14 @@
|
||||
github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1ei82L+c=
|
||||
github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4=
|
||||
github.com/edsrzf/mmap-go v1.1.0 h1:6EUwBLQ/Mcr1EYLE4Tn1VdW1A4ckqCQWZBw8Hr0kjpQ=
|
||||
github.com/edsrzf/mmap-go v1.1.0/go.mod h1:19H/e8pUPLicwkyNgOykDXkJ9F0MHE+Z52B8EIth78Q=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410 h1:hTftEOvwiOq2+O8k2D5/Q7COC7k5Qcrgc2TFURJYnvQ=
|
||||
golang.org/x/image v0.0.0-20211028202545-6944b10bf410/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
15
image.c
15
image.c
@@ -11,3 +11,18 @@ void set_data_f32_val(float* data, int index, float value) {
|
||||
data[index] = value;
|
||||
}
|
||||
|
||||
void to_float_and_fill_image(image* im, int w, int h, uint8_t* data) {
|
||||
int x, y, idx_source;
|
||||
int pixel_count = w * h;
|
||||
int idx = 0;
|
||||
|
||||
for (y = 0; y < h; y++) {
|
||||
for (x = 0; x < w; x++) {
|
||||
idx_source = (y*w + x) * 4;
|
||||
im->data[(pixel_count*0) + idx] = (float)data[idx_source] / 255;
|
||||
im->data[(pixel_count*1) + idx] = (float)data[idx_source+1] / 255;
|
||||
im->data[(pixel_count*2) + idx] = (float)data[idx_source+2] / 255;
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
44
image.go
44
image.go
@@ -23,35 +23,16 @@ func (img *DarknetImage) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/33186783/get-a-pixel-array-from-from-golang-image-image/59747737#59747737
|
||||
func imgTofloat32(src image.Image) []float32 {
|
||||
func Image2Float32(src image.Image) (*DarknetImage, error) {
|
||||
bounds := src.Bounds()
|
||||
width, height := bounds.Max.X, bounds.Max.Y
|
||||
srcRGBA := image.NewRGBA(src.Bounds())
|
||||
draw.Copy(srcRGBA, image.Point{}, src, src.Bounds(), draw.Src, nil)
|
||||
ans := []float32{}
|
||||
red := []float32{}
|
||||
green := []float32{}
|
||||
blue := []float32{}
|
||||
for y := 0; y < height; y++ {
|
||||
for x := 0; x < width; x++ {
|
||||
idxSource := (y*width + x) * 4
|
||||
pix := srcRGBA.Pix[idxSource : idxSource+4]
|
||||
rpix, gpix, bpix := float32(pix[0])/257.0, float32(pix[1])/257.0, float32(pix[2])/257.0
|
||||
red = append(red, rpix)
|
||||
green = append(green, gpix)
|
||||
blue = append(blue, bpix)
|
||||
}
|
||||
}
|
||||
ans = append(ans, red...)
|
||||
ans = append(ans, green...)
|
||||
ans = append(ans, blue...)
|
||||
return ans
|
||||
srcRGBA := image.NewRGBA(bounds)
|
||||
draw.Copy(srcRGBA, image.Point{}, src, bounds, draw.Src, nil)
|
||||
|
||||
return ImageRGBA2Float32(srcRGBA)
|
||||
}
|
||||
|
||||
// Image2Float32 Returns []float32 representation of image.Image
|
||||
func Image2Float32(img image.Image) (*DarknetImage, error) {
|
||||
ans := imgTofloat32(img)
|
||||
func ImageRGBA2Float32(img *image.RGBA) (*DarknetImage, error) {
|
||||
width := img.Bounds().Dx()
|
||||
height := img.Bounds().Dy()
|
||||
imgDarknet := &DarknetImage{
|
||||
@@ -59,6 +40,17 @@ func Image2Float32(img image.Image) (*DarknetImage, error) {
|
||||
Height: height,
|
||||
image: C.make_image(C.int(width), C.int(height), 3),
|
||||
}
|
||||
C.fill_image_f32(&imgDarknet.image, C.int(width), C.int(height), 3, (*C.float)(unsafe.Pointer(&ans[0])))
|
||||
C.to_float_and_fill_image(&imgDarknet.image, C.int(width), C.int(height), (*C.uint8_t)(unsafe.Pointer(&img.Pix[0])))
|
||||
return imgDarknet, nil
|
||||
}
|
||||
|
||||
// Float32ToDarknetImage Converts []float32 to darknet image
|
||||
func Float32ToDarknetImage(flatten []float32, width, height int) (*DarknetImage, error) {
|
||||
imgDarknet := &DarknetImage{
|
||||
Width: width,
|
||||
Height: height,
|
||||
image: C.make_image(C.int(width), C.int(height), 3),
|
||||
}
|
||||
C.fill_image_f32(&imgDarknet.image, C.int(width), C.int(height), 3, (*C.float)(unsafe.Pointer(&flatten[0])))
|
||||
return imgDarknet, nil
|
||||
}
|
||||
|
3
image.h
3
image.h
@@ -3,4 +3,5 @@
|
||||
#include <darknet.h>
|
||||
|
||||
extern void fill_image_f32(image *im, int w, int h, int c, float* data);
|
||||
extern void set_data_f32_val(float* data, int index, float value);
|
||||
extern void set_data_f32_val(float* data, int index, float value);
|
||||
extern void to_float_and_fill_image(image *im, int w, int h, uint8_t* data);
|
||||
|
@@ -14,10 +14,9 @@ struct network_box_result perform_network_detect(network *n, image *img, int cla
|
||||
sized = resize_image(*img, n->w, n->h);
|
||||
}
|
||||
struct network_box_result result = { NULL };
|
||||
float *X = sized.data;
|
||||
network_predict_ptr(n, X);
|
||||
// mleak at network_predict(), get_network_boxes() and network_predict_ptr()?
|
||||
network_predict_ptr(n, sized.data);
|
||||
int nboxes = 0;
|
||||
detection *dets = get_network_boxes(n, img->w, img->h, thresh, hier_thresh, 0, 1, &nboxes, letter_box);
|
||||
result.detections = get_network_boxes(n, img->w, img->h, thresh, hier_thresh, 0, 1, &result.detections_len, letter_box);
|
||||
if (nms) {
|
||||
do_nms_sort(result.detections, result.detections_len, classes, nms);
|
||||
|
85
network.go
85
network.go
@@ -7,9 +7,13 @@ package darknet
|
||||
// #include "network.h"
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/edsrzf/mmap-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// YOLONetwork represents a neural network using YOLO.
|
||||
@@ -53,12 +57,87 @@ func (n *YOLONetwork) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
/* EXPERIMENTAL */
|
||||
/*
|
||||
By default AlexeyAB's Darknet doesn't export any functions in darknet.h to give ability to create network from scratch via code.
|
||||
So I can't modify `parse_network_cfg_custom` to load `list *sections = read_cfg(filename);` from memory.
|
||||
|
||||
So, the point of this method is to be able create network configuration via Golang and then pass it to `C.load_network`
|
||||
|
||||
This code is portable for Windows/Linux/MacOS. See the ref.: https://github.com/edsrzf/mmap-go#mmap-go
|
||||
*/
|
||||
func (n *YOLONetwork) InitFromDefinedCfg() error {
|
||||
wFile := C.CString(n.WeightsFile)
|
||||
defer C.free(unsafe.Pointer(wFile))
|
||||
/* Prepare network sections via Go */
|
||||
/*
|
||||
instead of using:
|
||||
wFile := C.CString(n.WeightsFile)
|
||||
defer C.free(unsafe.Pointer(wFile))
|
||||
We call `load_network` that takes the first char* parameter (representing a file path to network configuration) with a Go function that takes an in-memory file
|
||||
*/
|
||||
cfgBytes, err := os.ReadFile(n.NetworkConfigurationFile)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Can't read file bytes")
|
||||
}
|
||||
|
||||
// Create a temporary file.
|
||||
tmpFile, err := ioutil.TempFile("", "")
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Can't create temporary file")
|
||||
}
|
||||
defer os.Remove(tmpFile.Name())
|
||||
// Write the file content to the temporary file.
|
||||
if _, err := tmpFile.Write(cfgBytes); err != nil {
|
||||
return errors.Wrap(err, "Can't write network's configuration into temporary file")
|
||||
}
|
||||
defer tmpFile.Close()
|
||||
|
||||
// Open the temporary file.
|
||||
// fd, err := syscall.Open(tmpFile.Name(), syscall.O_RDWR, 0)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "Can't re-open temporary file")
|
||||
// }
|
||||
// defer syscall.Close(fd)
|
||||
// Create a memory mapping of the file.
|
||||
// addr, err := syscall.Mmap(fd, 0, len(cfgBytes), syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_SHARED)
|
||||
// if err != nil {
|
||||
// return errors.Wrap(err, "Can't mmap on temporary file")
|
||||
// }
|
||||
// Unmap the memory-mapped file.
|
||||
// defer syscall.Munmap(addr)
|
||||
|
||||
// Map the temporary file to memory.
|
||||
mapping, err := mmap.Map(tmpFile, mmap.RDWR, 0)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "Can't mmap on temporary file")
|
||||
}
|
||||
defer mapping.Unmap() // Unmap the memory-mapped file.
|
||||
|
||||
// GPU device ID must be set before `load_network()` is invoked.
|
||||
C.cuda_set_device(C.int(n.GPUDeviceIndex))
|
||||
nCfg := C.CString(tmpFile.Name())
|
||||
defer C.free(unsafe.Pointer(nCfg))
|
||||
n.cNet = C.load_network(nCfg, wFile, 0)
|
||||
if n.cNet == nil {
|
||||
return errUnableToInitNetwork
|
||||
}
|
||||
C.srand(2222222)
|
||||
n.hierarchalThreshold = 0.5
|
||||
n.nms = 0.45
|
||||
metadata := C.get_metadata(nCfg)
|
||||
n.Classes = int(metadata.classes)
|
||||
n.ClassNames = makeClassNames(metadata.names, n.Classes)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close and release resources.
|
||||
func (n *YOLONetwork) Close() error {
|
||||
if n.cNet == nil {
|
||||
return errNetworkNotInit
|
||||
}
|
||||
C.free_network(*n.cNet)
|
||||
C.free_network_ptr(n.cNet)
|
||||
n.cNet = nil
|
||||
return nil
|
||||
}
|
||||
@@ -71,8 +150,8 @@ func (n *YOLONetwork) Detect(img *DarknetImage) (*DetectionResult, error) {
|
||||
startTime := time.Now()
|
||||
result := C.perform_network_detect(n.cNet, &img.image, C.int(n.Classes), C.float(n.Threshold), C.float(n.hierarchalThreshold), C.float(n.nms), C.int(0))
|
||||
endTime := time.Now()
|
||||
defer C.free_detections(result.detections, result.detections_len)
|
||||
ds := makeDetections(img, result.detections, int(result.detections_len), n.Threshold, n.Classes, n.ClassNames)
|
||||
C.free_detections(result.detections, result.detections_len)
|
||||
endTimeOverall := time.Now()
|
||||
out := DetectionResult{
|
||||
Detections: ds,
|
||||
|
58
section.go
Normal file
58
section.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package darknet
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Section represents a section in the configuration file.
|
||||
type Section struct {
|
||||
Type string
|
||||
Options []string
|
||||
}
|
||||
|
||||
// readCfg reads a configuration file and returns a list of sections.
|
||||
func readCfg(filename string) ([]Section, error) {
|
||||
// Open the configuration file.
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Create a list of sections.
|
||||
var sections []Section
|
||||
var current *Section
|
||||
|
||||
// Read each line in the file.
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
line := strings.TrimSpace(scanner.Text())
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
switch line[0] {
|
||||
case '[':
|
||||
if current != nil {
|
||||
sections = append(sections, *current)
|
||||
}
|
||||
current = &Section{Type: line}
|
||||
case '#', ';', '\x00':
|
||||
// Ignore comments and empty lines.
|
||||
default:
|
||||
if current == nil {
|
||||
current = &Section{}
|
||||
}
|
||||
current.Options = append(current.Options, line)
|
||||
}
|
||||
}
|
||||
if current != nil {
|
||||
sections = append(sections, *current)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sections, nil
|
||||
}
|
20
section_test.go
Normal file
20
section_test.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package darknet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestReadSectionsFromCfg(t *testing.T) {
|
||||
sections, err := readCfg("./cmd/examples/yolov7-tiny.cfg")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
for _, s := range sections {
|
||||
fmt.Println(s.Type)
|
||||
for _, o := range s.Options {
|
||||
fmt.Println("\t", o)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user