40 Commits

Author SHA1 Message Date
Dimitrii Lopanov
df9804aa69 Merge pull request #9 from LdDl/issue-8
network_predict
2020-08-11 12:11:04 +03:00
Dimitrii
68ad5efb35 network_predict 2020-08-11 12:08:59 +03:00
Dimitrii Lopanov
5e18d06f26 badges 2020-06-25 16:31:13 +03:00
Dimitrii Lopanov
ebf93ddfa6 minor 2020-06-19 10:28:20 +03:00
Dimitrii Lopanov
8bd8488c7f minor 2020-06-18 10:40:02 +03:00
Dimitrii Lopanov
420a74769d Merge pull request #7 from LdDl/mleak
Closes #6
2020-05-15 16:07:41 +03:00
Dimitrii
527e2942e9 clean up 2020-05-15 16:05:02 +03:00
Dimitrii
8105b8f1ae chechk latest alexeyab fork + yolov4 upd 2020-05-07 13:02:31 +03:00
Dimitrii
c625572f8c Merge branch 'master' of github.com:LdDl/go-darknet 2020-05-05 20:30:36 +03:00
Dimitrii
a58fecd863 clear newrgba memory and slice leaks 2020-05-05 20:30:25 +03:00
Dimitrii Lopanov
435d3f662c Merge pull request #5 from x0rzkov/docker
add docker container for cpu/gpu

Thanks a lot.
2020-04-10 15:43:03 +03:00
lucmichalski
d9682ca0f6 fix libcuda.so.1 missing 2020-04-10 04:58:21 +00:00
lucmichalski
4b38088916 fix commit, add golang to dockerfile.gpu 2020-04-08 08:16:20 +00:00
lucmichalski
766ff56e2e fix dockerfile.gpu 2020-04-08 08:02:03 +00:00
lucmichalski
3166cdca78 add docker container for cpu/gpu 2020-04-08 07:52:55 +00:00
Dimitrii Lopanov
02ab33b804 Merge pull request #3 from LdDl/new_example
Example of saving detected objects
2020-04-08 09:43:39 +03:00
Dimitrii Lopanov
0fd261e605 upd 2020-04-08 09:41:32 +03:00
Dimitrii
4c39be01f9 ptr causes segfault 2020-03-24 11:50:07 +03:00
Dimitrii
2dd85a84d6 rdm 2020-02-26 08:41:26 +03:00
Dimitrii
3a10d5a657 Merge branch 'master' of github.com:LdDl/go-darknet 2020-02-26 08:40:40 +03:00
Dimitrii
95332e0877 upd readmes 2020-02-26 08:34:03 +03:00
Dimitrii Lopanov
630ded761f Update README.md 2020-02-25 18:11:31 +03:00
Dimitrii Lopanov
674ff110d5 Update README.md 2020-02-25 08:26:00 +03:00
Dimitrii
f70cb0f1e6 upd readme 2020-02-21 15:52:39 +03:00
Dimitrii
49f6b85ba6 gitignore 2020-02-21 15:51:24 +03:00
Dimitrii
1f72563ea0 gitignore 2020-02-21 15:51:12 +03:00
Dimitrii
2c8e594cc7 vscode 2020-02-21 15:50:41 +03:00
Dimitrii
8e0371f19a upd readme 2020-02-21 15:50:10 +03:00
Dimitrii
380db18c1e upd gitignore 2020-02-21 15:48:02 +03:00
Dimitrii
feb1a0353d upd readme 2020-02-21 15:47:21 +03:00
Dimitrii
e486364a2b excess files 2020-02-20 18:10:34 +03:00
Dimitrii
bc4192f727 GOD SAVE STACKOVERFLOW 2020-02-20 18:10:11 +03:00
Dimitrii
48544ab339 got segfault 2020-02-20 17:02:08 +03:00
Dimitrii
fd2b030c94 ? 2020-02-20 13:17:29 +03:00
Dimitrii
f9e8a32a9e ? 2020-02-20 13:16:58 +03:00
Dimitrii
1fad0385f3 readme 2020-02-20 09:38:36 +03:00
Dimitrii
9d89162235 need to check what happens to im.data 2020-02-20 09:35:57 +03:00
Dimitrii
2b2f3f159c need to deal with image 2020-02-19 14:52:19 +03:00
Dimitrii
30fbbb9949 add network 2020-02-18 15:36:17 +03:00
Dimitrii
87175172a2 upd git ignore 2020-02-18 13:21:18 +03:00
31 changed files with 886 additions and 242 deletions

15
.gitignore vendored
View File

@@ -1,10 +1,15 @@
example/main
example/sample.jpg
example/coco.data
example/coco.names
example/yolov3-320.cfg
example/yolov3-320.weights
example/yolov3-416.cfg
example/yolov3-416.weights
example/yolov3.cfg
example/yolov3.weights
example/yolov4.cfg
example/yolov4.weights
darknet.h
*.so
predictions.png
predictions.jpg
main
bad.list
data
.vscode

150
README.md
View File

@@ -1,19 +1,29 @@
# FORK of go-darknet https://github.com/gyonluks/go-darknet
# go-darknet: Go bindings for Darknet
[![GoDoc](https://godoc.org/github.com/LdDl/go-darknet?status.svg)](https://godoc.org/github.com/LdDl/go-darknet)
[![Sourcegraph](https://sourcegraph.com/github.com/LdDl/go-darknet/-/badge.svg)](https://sourcegraph.com/github.com/LdDl/go-darknet?badge)
[![Go Report Card](https://goreportcard.com/badge/github.com/LdDl/go-darknet)](https://goreportcard.com/report/github.com/LdDl/go-darknet)
[![GitHub tag](https://img.shields.io/github/tag/LdDl/go-darknet.svg)](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].
## License
# go-darknet: Go bindings for Darknet (Yolo V4, Yolo V3)
### go-darknet is a Go package, which uses Cgo to enable Go applications to use YOLO V4/V3 in [Darknet].
go-darknet follows [Darknet]'s [license].
#### 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 v4: https://arxiv.org/abs/2004.10934
#### Paper Yolo v3: https://arxiv.org/abs/1804.02767
## Table of Contents
- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)
- [Documentation](#documentation)
- [License](#license)
## Requirements
For proper codebase please use fork of [darknet](https://github.com/LdDl/darknet)
There are instructions for defining GPU/CPU + function for loading image from memory.
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/9dc897d2c77d5ef43a6b237b717437375765b527)
In order to use go-darknet, `libdarknet.so` should be available in one of
the following locations:
@@ -26,53 +36,123 @@ Also, [darknet.h] should be available in one of the following locations:
* /usr/include
* /usr/local/include
## Install
To achieve it, after Darknet compilation (via make) execute following command:
```shell
# Copy *.so to /usr/lib + /usr/include (or /usr/local/lib + /usr/local/include)
sudo cp libdarknet.so /usr/lib/libdarknet.so && sudo cp include/darknet.h /usr/include/darknet.h
# sudo cp libdarknet.so /usr/local/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
go get github.com/LdDl/go-darknet
```
The package name is `darknet`.
## Usage
## Use
Example Go program is provided in the [example] directory. Please refer to the code on how to use this Go package.
Example Go code/program is provided in the [example] directory. Please
refer to the code on how to use this Go package.
Building and running the example program is easy:
Building and running program:
Navigate to [example] folder
```shell
cd $GOPATH/github.com/LdDl/go-darknet/example
#download dataset (coco.names, coco.data, weights and configuration file)
```
Download dataset (sample of image, coco.names, yolov4.cfg (or v3), yolov4.weights(or v3)).
```shell
#for yolo v4
./download_data.sh
#build program
go build main.go
#run it
./main -configFile yolov3.cfg --dataConfigFile coco.data -imageFile sample.jpg -weightsFile yolov3.weights
#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
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 program
Yolo V4:
```shell
go build main.go && ./main --configFile=yolov4.cfg --weightsFile=yolov4.weights --imageFile=sample.jpg
```
Output should be something like this:
```shell
truck (7): 95.6232% | start point: (78,69) | end point: (222, 291)
truck (7): 81.5451% | start point: (0,114) | end point: (90, 329)
car (2): 99.8129% | start point: (269,192) | end point: (421, 323)
car (2): 99.6615% | start point: (567,188) | end point: (743, 329)
car (2): 99.5795% | start point: (425,196) | end point: (544, 309)
car (2): 96.5765% | start point: (678,185) | end point: (797, 320)
car (2): 91.5156% | start point: (391,209) | end point: (441, 291)
car (2): 88.1737% | start point: (507,193) | end point: (660, 324)
car (2): 83.6209% | start point: (71,199) | end point: (102, 281)
bicycle (1): 59.4000% | start point: (183,276) | end point: (257, 407)
person (0): 96.3393% | start point: (142,119) | end point: (285, 356)
traffic light (9): 73.5039% | 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.8695% | start point: (434,173) | end point: (559, 216)
car (2): 99.7370% | start point: (512,188) | end point: (741, 329)
car (2): 99.2533% | start point: (260,191) | end point: (422, 322)
car (2): 99.0333% | start point: (425,201) | end point: (547, 309)
car (2): 83.3919% | 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 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.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].
## License
go-darknet follows [Darknet]'s [license].
[Darknet]: https://github.com/pjreddie/darknet
[license]: https://github.com/pjreddie/darknet/blob/master/LICENSE
[darknet.h]: https://github.com/pjreddie/darknet/blob/master/include/darknet.h
[include/darknet.h]: https://github.com/pjreddie/darknet/blob/master/include/darknet.h
[Makefile]: https://github.com/pjreddie/darknet/blob/master/Makefile
[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
[GoDoc]: https://godoc.org/github.com/LdDl/go-darknet

8
classes.c Normal file
View File

@@ -0,0 +1,8 @@
#include <stdlib.h>
char *get_class_name(char **names, int index, int names_len) {
if (index >= names_len) {
return NULL;
}
return names[index];
}

14
classes.go Normal file
View File

@@ -0,0 +1,14 @@
package darknet
// #include <stdlib.h>
// #include "classes.h"
import "C"
func makeClassNames(names **C.char, classes int) []string {
out := make([]string, classes)
for i := 0; i < classes; i++ {
n := C.get_class_name(names, C.int(i), C.int(classes))
out[i] = C.GoString(n)
}
return out
}

3
classes.h Normal file
View File

@@ -0,0 +1,3 @@
#pragma once
extern char *get_class_name(char **names, int index, int names_len);

View File

@@ -1,24 +0,0 @@
#include <stdlib.h>
#include <darknet.h>
void free_class_names(char **names)
{
free(names);
}
char ** read_class_names(char *data_cfg)
{
list *options = read_data_cfg(data_cfg);
char *name_list = option_find_str(options, "names", "data/names.list");
return get_labels(name_list);
}
char * get_class_name(char **names, int index, int names_len)
{
if (index >= names_len) {
return NULL;
}
return names[index];
}

View File

@@ -1,28 +0,0 @@
package darknet
// #include <stdlib.h>
// #include "classnames.h"
import "C"
import "unsafe"
func freeClassNames(names **C.char) {
C.free_class_names(names)
}
func loadClassNames(dataConfigFile string) **C.char {
d := C.CString(dataConfigFile)
defer C.free(unsafe.Pointer(d))
return C.read_class_names(d)
}
func makeClassNames(names **C.char, classes int) []string {
out := make([]string, classes)
for i := 0; i < classes; i++ {
n := C.get_class_name(names, C.int(i), C.int(classes))
s := C.GoString(n)
out[i] = s
}
return out
}

View File

@@ -1,5 +0,0 @@
#pragma once
extern void free_class_names(char **names);
extern char ** read_class_names(char *data_cfg);
extern char * get_class_name(char **names, int index, int names_len);

View File

@@ -1,5 +1,5 @@
package darknet
// #cgo CFLAGS: -I/usr/local/include -I/usr/local/cuda/include
// #cgo LDFLAGS: -L/usr/local/lib -ldarknet -lm
// #cgo LDFLAGS: -L/usr/lib -ldarknet -lm
import "C"

View File

@@ -1,19 +1,17 @@
#include <darknet.h>
detection * get_detection(detection *dets, int index, int dets_len)
{
#include "detection.h"
detection *get_detection(detection *dets, int index, int dets_len) {
if (index >= dets_len) {
return NULL;
}
return dets + index;
}
float get_detection_probability(detection *det, int index, int prob_len)
{
float get_detection_probability(detection *det, int index, int prob_len) {
if (index >= prob_len) {
return .0;
}
return det->prob[index];
}

View File

@@ -25,19 +25,15 @@ type DetectionResult struct {
OverallTimeTaken time.Duration
}
func makeDetection(img *Image, det *C.detection, threshold float32, classes int,
classNames []string) *Detection {
func makeDetection(img *DarknetImage, det *C.detection, threshold float32, classes int, classNames []string) *Detection {
if det == nil {
return &Detection{}
}
dClassIDs := make([]int, 0)
dClassNames := make([]string, 0)
dProbs := make([]float32, 0)
for i := 0; i < int(classes); i++ {
dProb := float32(
C.get_detection_probability(det, C.int(i), C.int(classes)))
dProb := float32(C.get_detection_probability(det, C.int(i), C.int(classes)))
if dProb > threshold {
dClassIDs = append(dClassIDs, i)
cN := classNames[i]
@@ -45,7 +41,6 @@ func makeDetection(img *Image, det *C.detection, threshold float32, classes int,
dProbs = append(dProbs, dProb*100)
}
}
fImgW := C.float(img.Width)
fImgH := C.float(img.Height)
halfRatioW := det.bbox.w / 2.0
@@ -66,19 +61,16 @@ func makeDetection(img *Image, det *C.detection, threshold float32, classes int,
ClassNames: dClassNames,
Probabilities: dProbs,
}
return &out
}
func makeDetections(img *Image, detections *C.detection, detectionsLength int,
threshold float32, classes int, classNames []string) []*Detection {
func makeDetections(img *DarknetImage, detections *C.detection, detectionsLength int, threshold float32, classes int, classNames []string) []*Detection {
// Make list of detection objects.
ds := make([]*Detection, detectionsLength)
for i := 0; i < int(detectionsLength); i++ {
det := C.get_detection(detections, C.int(i), C.int(classes))
det := C.get_detection(detections, C.int(i), C.int(detectionsLength))
d := makeDetection(img, det, threshold, classes, classNames)
ds[i] = d
}
return ds
}

View File

@@ -2,5 +2,5 @@
#include <darknet.h>
extern detection * get_detection(detection *dets, int index, int dets_len);
extern detection *get_detection(detection *dets, int index, int dets_len);
extern float get_detection_probability(detection *det, int index, int prob_len);

1
docker/.env Normal file
View File

@@ -0,0 +1 @@
NAMESPACE=darknet

40
docker/Dockerfile Normal file
View File

@@ -0,0 +1,40 @@
# Build phase
FROM ubuntu:18.04 as builder
ENV darknet_commit=a234a5022333c930de08f2470184ef4e0c68356e
WORKDIR /root/build
COPY Makefile.cpu .
RUN apt-get -y update && \
apt-get -y install --no-install-recommends git build-essential ca-certificates && \
git clone https://github.com/AlexeyAB/darknet && \
cd darknet && \
git checkout $darknet_commit && \
cp -f /root/build/Makefile.cpu Makefile && \
make
# Final Image
FROM golang:1.14
RUN apt-get -y update && \
apt-get -y install --no-install-recommends nano bash jq
WORKDIR /root
COPY --from=builder /root/build/darknet/darknet \
/root/build/darknet/libdarknet.so \
/root/build/darknet/include/darknet.h \
./staging/
RUN mv staging/darknet /usr/local/bin && \
mv staging/darknet.h /usr/include && \
mv staging/libdarknet.so /usr/lib && \
rm -rf staging
RUN go get -u github.com/LdDl/go-darknet \
&& go get -u github.com/disintegration/imaging
WORKDIR /darknet
COPY download_data.sh .
CMD ["/bin/bash"]

52
docker/Dockerfile.gpu Normal file
View File

@@ -0,0 +1,52 @@
# Build phase
FROM nvidia/cuda:10.0-cudnn7-devel-ubuntu18.04 as builder
ENV darknet_commit=a234a5022333c930de08f2470184ef4e0c68356e
WORKDIR /root/build
COPY Makefile.gpu .
RUN apt-get -y update && \
apt-get -y install git build-essential && \
git clone https://github.com/AlexeyAB/darknet.git && \
cd darknet && \
git checkout $darknet_commit && \
cp -f /root/build/Makefile.gpu Makefile && \
make
# Final Image
FROM nvidia/cuda:10.0-cudnn7-runtime-ubuntu18.04
WORKDIR /root
COPY --from=builder /root/build/darknet/darknet \
/root/build/darknet/libdarknet.so \
/root/build/darknet/include/darknet.h \
./staging/
RUN mv staging/darknet /usr/local/bin && \
mv staging/darknet.h /usr/include && \
mv staging/libdarknet.so /usr/lib && \
rm -rf staging
WORKDIR /tmp
RUN cd /tmp \
&& apt-get -y update \
&& apt-get install -y wget git gcc \
&& wget https://dl.google.com/go/go1.14.linux-amd64.tar.gz \
&& tar -xvf go1.14.linux-amd64.tar.gz \
&& mv go /usr/local
RUN cp /usr/local/cuda-10.0/compat/* /usr/local/cuda-10.0/targets/x86_64-linux/lib/
ENV GOROOT=/usr/local/go
ENV GOPATH=/go
ENV PATH=$GOPATH/bin:$GOROOT/bin:$PATH
ENV LIBRARY_PATH=$LIBRARY_PATH:/usr/local/cuda-10.0/compat/
RUN go get -u github.com/LdDl/go-darknet \
&& go get -u github.com/disintegration/imaging
WORKDIR /darknet
COPY download_data.sh .
CMD ["/bin/bash"]

185
docker/Makefile.cpu Normal file
View File

@@ -0,0 +1,185 @@
GPU=0
CUDNN=0
CUDNN_HALF=0
OPENCV=0
AVX=1
OPENMP=1
LIBSO=1
ZED_CAMERA=0 # ZED SDK 3.0 and above
ZED_CAMERA_v2_8=0 # ZED SDK 2.X
# set GPU=1 and CUDNN=1 to speedup on GPU
# set CUDNN_HALF=1 to further speedup 3 x times (Mixed-precision on Tensor Cores) GPU: Volta, Xavier, Turing and higher
# set AVX=1 and OPENMP=1 to speedup on CPU (if error occurs then set AVX=0)
USE_CPP=0
DEBUG=0
ARCH= -gencode arch=compute_30,code=sm_30 \
-gencode arch=compute_35,code=sm_35 \
-gencode arch=compute_50,code=[sm_50,compute_50] \
-gencode arch=compute_52,code=[sm_52,compute_52] \
-gencode arch=compute_61,code=[sm_61,compute_61]
OS := $(shell uname)
# Tesla V100
# ARCH= -gencode arch=compute_70,code=[sm_70,compute_70]
# GeForce RTX 2080 Ti, RTX 2080, RTX 2070, Quadro RTX 8000, Quadro RTX 6000, Quadro RTX 5000, Tesla T4, XNOR Tensor Cores
# ARCH= -gencode arch=compute_75,code=[sm_75,compute_75]
# Jetson XAVIER
# ARCH= -gencode arch=compute_72,code=[sm_72,compute_72]
# GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4
# ARCH= -gencode arch=compute_61,code=sm_61 -gencode arch=compute_61,code=compute_61
# GP100/Tesla P100 - DGX-1
# ARCH= -gencode arch=compute_60,code=sm_60
# For Jetson TX1, Tegra X1, DRIVE CX, DRIVE PX - uncomment:
# ARCH= -gencode arch=compute_53,code=[sm_53,compute_53]
# For Jetson Tx2 or Drive-PX2 uncomment:
# ARCH= -gencode arch=compute_62,code=[sm_62,compute_62]
# VPATH=./src/
VPATH=./src/:./examples
SLIB=libdarknet.so
EXEC=darknet
OBJDIR=./obj/
ifeq ($(LIBSO), 1)
LIBNAMESO=libdarknet.so
APPNAMESO=uselib
endif
ifeq ($(USE_CPP), 1)
CC=g++
else
CC=gcc
endif
CPP=g++ -std=c++11
NVCC=nvcc
OPTS=-Ofast
LDFLAGS= -lm -pthread
COMMON= -Iinclude/ -I3rdparty/stb/include
CFLAGS=-Wall -Wfatal-errors -Wno-unused-result -Wno-unknown-pragmas -fPIC
ifeq ($(DEBUG), 1)
#OPTS= -O0 -g
#OPTS= -Og -g
COMMON+= -DDEBUG
CFLAGS+= -DDEBUG
else
ifeq ($(AVX), 1)
CFLAGS+= -ffp-contract=fast -mavx -mavx2 -msse3 -msse4.1 -msse4.2 -msse4a
endif
endif
CFLAGS+=$(OPTS)
ifneq (,$(findstring MSYS_NT,$(OS)))
LDFLAGS+=-lws2_32
endif
ifeq ($(OPENCV), 1)
COMMON+= -DOPENCV
CFLAGS+= -DOPENCV
LDFLAGS+= `pkg-config --libs opencv4 2> /dev/null || pkg-config --libs opencv`
COMMON+= `pkg-config --cflags opencv4 2> /dev/null || pkg-config --cflags opencv`
endif
ifeq ($(OPENMP), 1)
CFLAGS+= -fopenmp
LDFLAGS+= -lgomp
endif
ifeq ($(GPU), 1)
COMMON+= -DGPU -I/usr/local/cuda/include/
CFLAGS+= -DGPU
ifeq ($(OS),Darwin) #MAC
LDFLAGS+= -L/usr/local/cuda/lib -lcuda -lcudart -lcublas -lcurand
else
LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand
endif
endif
ifeq ($(CUDNN), 1)
COMMON+= -DCUDNN
ifeq ($(OS),Darwin) #MAC
CFLAGS+= -DCUDNN -I/usr/local/cuda/include
LDFLAGS+= -L/usr/local/cuda/lib -lcudnn
else
CFLAGS+= -DCUDNN -I/usr/local/cudnn/include
LDFLAGS+= -L/usr/local/cudnn/lib64 -lcudnn
endif
endif
ifeq ($(CUDNN_HALF), 1)
COMMON+= -DCUDNN_HALF
CFLAGS+= -DCUDNN_HALF
ARCH+= -gencode arch=compute_70,code=[sm_70,compute_70]
endif
ifeq ($(ZED_CAMERA), 1)
CFLAGS+= -DZED_STEREO -I/usr/local/zed/include
ifeq ($(ZED_CAMERA_v2_8), 1)
LDFLAGS+= -L/usr/local/zed/lib -lsl_core -lsl_input -lsl_zed
#-lstdc++ -D_GLIBCXX_USE_CXX11_ABI=0
else
LDFLAGS+= -L/usr/local/zed/lib -lsl_zed
#-lstdc++ -D_GLIBCXX_USE_CXX11_ABI=0
endif
endif
OBJ=image_opencv.o http_stream.o gemm.o utils.o dark_cuda.o convolutional_layer.o list.o image.o activations.o im2col.o col2im.o blas.o crop_layer.o dropout_layer.o maxpool_layer.o softmax_layer.o data.o matrix.o network.o connected_layer.o cost_layer.o parser.o option_list.o darknet.o detection_layer.o captcha.o route_layer.o writing.o box.o nightmare.o normalization_layer.o avgpool_layer.o coco.o dice.o yolo.o detector.o layer.o compare.o classifier.o local_layer.o swag.o shortcut_layer.o activation_layer.o rnn_layer.o gru_layer.o rnn.o rnn_vid.o crnn_layer.o demo.o tag.o cifar.o go.o batchnorm_layer.o art.o region_layer.o reorg_layer.o reorg_old_layer.o super.o voxel.o tree.o yolo_layer.o gaussian_yolo_layer.o upsample_layer.o lstm_layer.o conv_lstm_layer.o scale_channels_layer.o sam_layer.o
ifeq ($(GPU), 1)
LDFLAGS+= -lstdc++
OBJ+=convolutional_kernels.o activation_kernels.o im2col_kernels.o col2im_kernels.o blas_kernels.o crop_layer_kernels.o dropout_layer_kernels.o maxpool_layer_kernels.o network_kernels.o avgpool_layer_kernels.o
endif
OBJS = $(addprefix $(OBJDIR), $(OBJ))
DEPS = $(wildcard src/*.h) Makefile include/darknet.h
all: $(OBJDIR) backup results setchmod $(EXEC) $(LIBNAMESO) $(APPNAMESO)
ifeq ($(LIBSO), 1)
CFLAGS+= -fPIC
$(LIBNAMESO): $(OBJDIR) $(OBJS) include/yolo_v2_class.hpp src/yolo_v2_class.cpp
$(CPP) -shared -std=c++11 -fvisibility=hidden -DLIB_EXPORTS $(COMMON) $(CFLAGS) $(OBJS) src/yolo_v2_class.cpp -o $@ $(LDFLAGS)
$(APPNAMESO): $(LIBNAMESO) include/yolo_v2_class.hpp src/yolo_console_dll.cpp
$(CPP) -std=c++11 $(COMMON) $(CFLAGS) -o $@ src/yolo_console_dll.cpp $(LDFLAGS) -L ./ -l:$(LIBNAMESO)
endif
$(EXEC): $(OBJS)
$(CPP) -std=c++11 $(COMMON) $(CFLAGS) $^ -o $@ $(LDFLAGS)
$(OBJDIR)%.o: %.c $(DEPS)
$(CC) $(COMMON) $(CFLAGS) -c $< -o $@
$(OBJDIR)%.o: %.cpp $(DEPS)
$(CPP) -std=c++11 $(COMMON) $(CFLAGS) -c $< -o $@
$(OBJDIR)%.o: %.cu $(DEPS)
$(NVCC) $(ARCH) $(COMMON) --compiler-options "$(CFLAGS)" -c $< -o $@
$(OBJDIR):
mkdir -p $(OBJDIR)
backup:
mkdir -p backup
results:
mkdir -p results
setchmod:
chmod +x *.sh
.PHONY: clean
clean:
rm -rf $(OBJS) $(EXEC) $(LIBNAMESO) $(APPNAMESO)

186
docker/Makefile.gpu Normal file
View File

@@ -0,0 +1,186 @@
GPU=1
CUDNN=1
CUDNN_HALF=0
OPENCV=0
AVX=0
OPENMP=0
LIBSO=1
ZED_CAMERA=0 # ZED SDK 3.0 and above
ZED_CAMERA_v2_8=0 # ZED SDK 2.X
# set GPU=1 and CUDNN=1 to speedup on GPU
# set CUDNN_HALF=1 to further speedup 3 x times (Mixed-precision on Tensor Cores) GPU: Volta, Xavier, Turing and higher
# set AVX=1 and OPENMP=1 to speedup on CPU (if error occurs then set AVX=0)
USE_CPP=0
DEBUG=0
ARCH= -gencode arch=compute_30,code=sm_30 \
-gencode arch=compute_35,code=sm_35 \
-gencode arch=compute_50,code=[sm_50,compute_50] \
-gencode arch=compute_52,code=[sm_52,compute_52] \
-gencode arch=compute_61,code=[sm_61,compute_61]
OS := $(shell uname)
# Tesla V100
# ARCH= -gencode arch=compute_70,code=[sm_70,compute_70]
# GeForce RTX 2080 Ti, RTX 2080, RTX 2070, Quadro RTX 8000, Quadro RTX 6000, Quadro RTX 5000, Tesla T4, XNOR Tensor Cores
# ARCH= -gencode arch=compute_75,code=[sm_75,compute_75]
# Jetson XAVIER
# ARCH= -gencode arch=compute_72,code=[sm_72,compute_72]
# GTX 1080, GTX 1070, GTX 1060, GTX 1050, GTX 1030, Titan Xp, Tesla P40, Tesla P4
# ARCH= -gencode arch=compute_61,code=sm_61 -gencode arch=compute_61,code=compute_61
# GP100/Tesla P100 - DGX-1
# ARCH= -gencode arch=compute_60,code=sm_60
# For Jetson TX1, Tegra X1, DRIVE CX, DRIVE PX - uncomment:
# ARCH= -gencode arch=compute_53,code=[sm_53,compute_53]
# For Jetson Tx2 or Drive-PX2 uncomment:
# ARCH= -gencode arch=compute_62,code=[sm_62,compute_62]
# VPATH=./src/
VPATH=./src/:./examples
SLIB=libdarknet.so
EXEC=darknet
OBJDIR=./obj/
ifeq ($(LIBSO), 1)
LIBNAMESO=libdarknet.so
APPNAMESO=uselib
endif
ifeq ($(USE_CPP), 1)
CC=g++
else
CC=gcc
endif
CPP=g++ -std=c++11
NVCC=nvcc
OPTS=-Ofast
LDFLAGS= -lm -pthread
COMMON= -Iinclude/ -I3rdparty/stb/include
CFLAGS=-Wall -Wfatal-errors -Wno-unused-result -Wno-unknown-pragmas -fPIC
ifeq ($(DEBUG), 1)
#OPTS= -O0 -g
#OPTS= -Og -g
COMMON+= -DDEBUG
CFLAGS+= -DDEBUG
else
ifeq ($(AVX), 1)
CFLAGS+= -ffp-contract=fast -mavx -mavx2 -msse3 -msse4.1 -msse4.2 -msse4a
endif
endif
CFLAGS+=$(OPTS)
ifneq (,$(findstring MSYS_NT,$(OS)))
LDFLAGS+=-lws2_32
endif
ifeq ($(OPENCV), 1)
COMMON+= -DOPENCV
CFLAGS+= -DOPENCV
LDFLAGS+= `pkg-config --libs opencv4 2> /dev/null || pkg-config --libs opencv`
COMMON+= `pkg-config --cflags opencv4 2> /dev/null || pkg-config --cflags opencv`
endif
ifeq ($(OPENMP), 1)
CFLAGS+= -fopenmp
LDFLAGS+= -lgomp
endif
ifeq ($(GPU), 1)
COMMON+= -DGPU -I/usr/local/cuda/include/
CFLAGS+= -DGPU
ifeq ($(OS),Darwin) #MAC
LDFLAGS+= -L/usr/local/cuda/lib -lcuda -lcudart -lcublas -lcurand
else
LDFLAGS+= -L/usr/local/cuda/lib64 -lcuda -lcudart -lcublas -lcurand
endif
endif
ifeq ($(CUDNN), 1)
COMMON+= -DCUDNN
ifeq ($(OS),Darwin) #MAC
CFLAGS+= -DCUDNN -I/usr/local/cuda/include
LDFLAGS+= -L/usr/local/cuda/lib -lcudnn
else
CFLAGS+= -DCUDNN -I/usr/local/cudnn/include
LDFLAGS+= -L/usr/local/cudnn/lib64 -lcudnn
endif
endif
ifeq ($(CUDNN_HALF), 1)
COMMON+= -DCUDNN_HALF
CFLAGS+= -DCUDNN_HALF
ARCH+= -gencode arch=compute_70,code=[sm_70,compute_70]
endif
ifeq ($(ZED_CAMERA), 1)
CFLAGS+= -DZED_STEREO -I/usr/local/zed/include
ifeq ($(ZED_CAMERA_v2_8), 1)
LDFLAGS+= -L/usr/local/zed/lib -lsl_core -lsl_input -lsl_zed
#-lstdc++ -D_GLIBCXX_USE_CXX11_ABI=0
else
LDFLAGS+= -L/usr/local/zed/lib -lsl_zed
#-lstdc++ -D_GLIBCXX_USE_CXX11_ABI=0
endif
endif
OBJ=image_opencv.o http_stream.o gemm.o utils.o dark_cuda.o convolutional_layer.o list.o image.o activations.o im2col.o col2im.o blas.o crop_layer.o dropout_layer.o maxpool_layer.o softmax_layer.o data.o matrix.o network.o connected_layer.o cost_layer.o parser.o option_list.o darknet.o detection_layer.o captcha.o route_layer.o writing.o box.o nightmare.o normalization_layer.o avgpool_layer.o coco.o dice.o yolo.o detector.o layer.o compare.o classifier.o local_layer.o swag.o shortcut_layer.o activation_layer.o rnn_layer.o gru_layer.o rnn.o rnn_vid.o crnn_layer.o demo.o tag.o cifar.o go.o batchnorm_layer.o art.o region_layer.o reorg_layer.o reorg_old_layer.o super.o voxel.o tree.o yolo_layer.o gaussian_yolo_layer.o upsample_layer.o lstm_layer.o conv_lstm_layer.o scale_channels_layer.o sam_layer.o
ifeq ($(GPU), 1)
LDFLAGS+= -lstdc++
OBJ+=convolutional_kernels.o activation_kernels.o im2col_kernels.o col2im_kernels.o blas_kernels.o crop_layer_kernels.o dropout_layer_kernels.o maxpool_layer_kernels.o network_kernels.o avgpool_layer_kernels.o
endif
OBJS = $(addprefix $(OBJDIR), $(OBJ))
DEPS = $(wildcard src/*.h) Makefile include/darknet.h
all: $(OBJDIR) backup results setchmod $(EXEC) $(LIBNAMESO) $(APPNAMESO)
ifeq ($(LIBSO), 1)
CFLAGS+= -fPIC
$(LIBNAMESO): $(OBJDIR) $(OBJS) include/yolo_v2_class.hpp src/yolo_v2_class.cpp
$(CPP) -shared -std=c++11 -fvisibility=hidden -DLIB_EXPORTS $(COMMON) $(CFLAGS) $(OBJS) src/yolo_v2_class.cpp -o $@ $(LDFLAGS)
$(APPNAMESO): $(LIBNAMESO) include/yolo_v2_class.hpp src/yolo_console_dll.cpp
$(CPP) -std=c++11 $(COMMON) $(CFLAGS) -o $@ src/yolo_console_dll.cpp $(LDFLAGS) -L ./ -l:$(LIBNAMESO)
endif
$(EXEC): $(OBJS)
$(CPP) -std=c++11 $(COMMON) $(CFLAGS) $^ -o $@ $(LDFLAGS)
$(OBJDIR)%.o: %.c $(DEPS)
$(CC) $(COMMON) $(CFLAGS) -c $< -o $@
$(OBJDIR)%.o: %.cpp $(DEPS)
$(CPP) -std=c++11 $(COMMON) $(CFLAGS) -c $< -o $@
$(OBJDIR)%.o: %.cu $(DEPS)
$(NVCC) $(ARCH) $(COMMON) --compiler-options "$(CFLAGS)" -c $< -o $@
$(OBJDIR):
mkdir -p $(OBJDIR)
backup:
mkdir -p backup
results:
mkdir -p results
setchmod:
chmod +x *.sh
.PHONY: clean
clean:
rm -rf $(OBJS) $(EXEC) $(LIBNAMESO) $(APPNAMESO)

32
docker/docker-compose.yml Normal file
View File

@@ -0,0 +1,32 @@
---
version: '3.7'
services:
sidekiq: &darknet_base
container_name: ${NAMESPACE}-sidekiq
build:
context: .
dockerfile: Dockerfile
image: go-darknet:latest
working_dir: /darknet
volumes:
- darknet-data:/darknet/models
command: /darknet/download_data.sh
darknet:
<<: *darknet_base
container_name: ${NAMESPACE}-api
ports:
- "9003:9003"
restart: unless-stopped
depends_on:
- sidekiq
command: ["/bin/bash"]
# command: ["darknet-server"]
volumes:
darknet-data:
driver_opts:
type: none
o: bind
device: ${PWD}/models

10
docker/download_data.sh Executable file
View File

@@ -0,0 +1,10 @@
#!/bin/sh
# set -x
# set -e
wget -nc --output-document=sample.jpg https://cdn-images-1.medium.com/max/800/1*EYFejGUjvjPcc4PZTwoufw.jpeg
wget -nc --output-document=./models/coco.names https://raw.githubusercontent.com/AlexeyAB/darknet/master/data/coco.names
wget -nc --output-document=./models/yolov3.cfg https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3.cfg
sed -i -e "\$anames = coco.names" ./models/yolov3.cfg
wget -nc --output-document=./models/yolov3.weights https://pjreddie.com/media/files/yolov3.weights

2
docker/models/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*
!.gitignore

View File

@@ -2,33 +2,53 @@
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
Navigate to example folder:
```shell
$GOPATH/bin/example
cd $GOPATH/github.com/LdDl/go-darknet/example
```
or
```go
go run main.go -configFile=yolov3-320.cfg -dataConfigFile=coco.data -imageFile=sample.jpg -weightsFile=yolov3.weights
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 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
```
Please ensure that `libdarknet.so` is in your `$LD_LIBRARY_PATH`.
## Notes
Build and run program
```
go build main.go && ./main --configFile=yolov3.cfg --weightsFile=yolov3.weights --imageFile=sample.jpg
```
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.
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)
```

View File

@@ -1,6 +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/pjreddie/darknet/master/data/coco.names
wget --output-document=coco.data https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/coco.data
sed -i 's#data/coco.names#coco.names#g' coco.data
wget --output-document=yolov3.cfg https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3.cfg
wget --output-document=yolov3.weights https://pjreddie.com/media/files/yolov3.weights
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
example/download_data_v3.sh Executable file
View 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=yolov3.cfg https://raw.githubusercontent.com/AlexeyAB/darknet/master/cfg/yolov3.cfg
sed -i -e "\$anames = coco.names" yolov3.cfg
wget --output-document=yolov3.weights https://pjreddie.com/media/files/yolov3.weights

View File

@@ -1,15 +1,19 @@
package main
import (
"bytes"
"flag"
"fmt"
"image"
"image/jpeg"
"log"
"math"
"os"
darknet "github.com/LdDl/go-darknet"
"github.com/disintegration/imaging"
)
var dataConfigFile = flag.String("dataConfigFile", "",
"Path to data configuration file. Example: cfg/coco.data")
var configFile = flag.String("configFile", "",
"Path to network layer configuration file. Example: cfg/yolov3.cfg")
var weightsFile = flag.String("weightsFile", "",
@@ -24,7 +28,7 @@ func printError(err error) {
func main() {
flag.Parse()
if *dataConfigFile == "" || *configFile == "" || *weightsFile == "" ||
if *configFile == "" || *weightsFile == "" ||
*imageFile == "" {
flag.Usage()
@@ -33,10 +37,9 @@ func main() {
n := darknet.YOLONetwork{
GPUDeviceIndex: 0,
DataConfigurationFile: *dataConfigFile,
NetworkConfigurationFile: *configFile,
WeightsFile: *weightsFile,
Threshold: .5,
Threshold: .25,
}
if err := n.Init(); err != nil {
printError(err)
@@ -44,14 +47,23 @@ func main() {
}
defer n.Close()
img, err := darknet.ImageFromPath(*imageFile)
infile, err := os.Open(*imageFile)
if err != nil {
printError(err)
return
panic(err.Error())
}
defer infile.Close()
src, err := jpeg.Decode(infile)
if err != nil {
panic(err.Error())
}
defer img.Close()
dr, err := n.Detect(img)
imgDarknet, err := darknet.Image2Float32(src)
if err != nil {
panic(err.Error())
}
defer imgDarknet.Close()
dr, err := n.Detect(imgDarknet)
if err != nil {
printError(err)
return
@@ -60,7 +72,6 @@ func main() {
log.Println("Network-only time taken:", dr.NetworkOnlyTimeTaken)
log.Println("Overall time taken:", dr.OverallTimeTaken, len(dr.Detections))
for _, d := range dr.Detections {
for i := range d.ClassIDs {
bBox := d.BoundingBox
fmt.Printf("%s (%d): %.4f%% | start point: (%d,%d) | end point: (%d, %d)\n",
@@ -69,6 +80,43 @@ 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
// }
}
}
}
func imageToBytes(img image.Image) ([]byte, error) {
buf := new(bytes.Buffer)
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
}

13
image.c Normal file
View File

@@ -0,0 +1,13 @@
#include <darknet.h>
void fill_image_f32(image* im, int w, int h, int c, float* data) {
int i;
for (i = 0; i < w*h*c; i++) {
im->data[i] = data[i];
}
}
void set_data_f32_val(float* data, int index, float value) {
data[index] = value;
}

100
image.go
View File

@@ -1,66 +1,84 @@
package darknet
// #include <darknet.h>
// #include <stdlib.h>
// #include "image.h"
import "C"
import (
"errors"
"image"
"unsafe"
"golang.org/x/image/draw"
)
// Image represents the image buffer.
type Image struct {
// DarknetImage represents the image buffer.
type DarknetImage struct {
Width int
Height int
ans []float32
image C.image
}
var (
errUnableToLoadImage = errors.New("unable to load image")
)
// Close and release resources.
func (img *Image) Close() error {
func (img *DarknetImage) Close() error {
C.free_image(img.image)
img.ans = nil
return nil
}
// ImageFromPath reads image file specified by path.
func ImageFromPath(path string) (*Image, error) {
p := C.CString(path)
defer C.free(unsafe.Pointer(p))
// https://stackoverflow.com/questions/33186783/get-a-pixel-array-from-from-golang-image-image/59747737#59747737
func imgTofloat32(src image.Image) []float32 {
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)
img := Image{
image: C.load_image_color(p, 0, 0),
red := make([]float32, 0, width*height)
green := make([]float32, 0, width*height)
blue := make([]float32, 0, width*height)
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)
}
if img.image.data == nil {
return nil, errUnableToLoadImage
}
srcRGBA = nil
img.Width = int(img.image.w)
img.Height = int(img.image.h)
return &img, nil
ans := make([]float32, len(red)+len(green)+len(blue))
copy(ans[:len(red)], red)
copy(ans[len(red):len(red)+len(green)], green)
copy(ans[len(red)+len(green):], blue)
red = nil
green = nil
blue = nil
return ans
}
// ImageFromMemory reads image file data represented by the specified byte
// slice.
func ImageFromMemory(buf []byte) (*Image, error) {
cBuf := C.CBytes(buf)
defer C.free(cBuf)
img := Image{
image: C.load_image_from_memory_color((*C.uchar)(cBuf),
C.int(len(buf)), 0, 0),
// Image2Float32 Returns []float32 representation of image.Image
func Image2Float32(img image.Image) (*DarknetImage, error) {
// ans := imgTofloat32(img)
width := img.Bounds().Dx()
height := img.Bounds().Dy()
imgDarknet := &DarknetImage{
Width: width,
Height: height,
ans: imgTofloat32(img),
image: C.make_image(C.int(width), C.int(height), 3),
}
if img.image.data == nil {
return nil, errUnableToLoadImage
}
img.Width = int(img.image.w)
img.Height = int(img.image.h)
return &img, nil
C.fill_image_f32(&imgDarknet.image, C.int(width), C.int(height), 3, (*C.float)(unsafe.Pointer(&imgDarknet.ans[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
}

6
image.h Normal file
View File

@@ -0,0 +1,6 @@
#pragma once
#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);

View File

@@ -4,19 +4,23 @@
#include "network.h"
int get_network_layer_classes(network *n, int index) {
return n->layers[index].classes;
}
#include "detection.h"
struct network_box_result perform_network_detect(network *n, image *img, int classes, float thresh, float hier_thresh, float nms) {
image sized = letterbox_image(*img, n->w, n->h);
struct network_box_result perform_network_detect(network *n, image *img, int classes, float thresh, float hier_thresh, float nms, int letter_box) {
image sized;
if (letter_box) {
sized = letterbox_image(*img, n->w, n->h);
} else {
sized = resize_image(*img, n->w, n->h);
}
struct network_box_result result = { NULL };
float *X = sized.data;
network_predict(n, X);
result.detections = get_network_boxes(n, img->w, img->h,thresh, hier_thresh, 0, 1, &result.detections_len);
network_predict(*n, sized.data);
int nboxes = 0;
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);
}
free_image(sized);
return result;
}

View File

@@ -15,7 +15,6 @@ import (
// YOLONetwork represents a neural network using YOLO.
type YOLONetwork struct {
GPUDeviceIndex int
DataConfigurationFile string
NetworkConfigurationFile string
WeightsFile string
Threshold float32
@@ -29,8 +28,8 @@ type YOLONetwork struct {
}
var (
errNetworkNotInit = errors.New("network not initialised")
errUnableToInitNetwork = errors.New("unable to initialise")
errNetworkNotInit = errors.New("Network not initialised")
errUnableToInitNetwork = errors.New("Unable to initialise")
)
// Init the network.
@@ -39,29 +38,18 @@ func (n *YOLONetwork) Init() error {
defer C.free(unsafe.Pointer(nCfg))
wFile := C.CString(n.WeightsFile)
defer C.free(unsafe.Pointer(wFile))
// GPU device ID must be set before `load_network()` is invoked.
C.cuda_set_device(C.int(n.GPUDeviceIndex))
n.cNet = C.load_network(nCfg, wFile, 0)
if n.cNet == nil {
return errUnableToInitNetwork
}
C.set_batch_network(n.cNet, 1)
C.srand(2222222)
// Currently, hierarchal threshold is always 0.5.
n.hierarchalThreshold = .5
// Currently NMS is always 0.4.
n.nms = .4
n.Classes = int(C.get_network_layer_classes(n.cNet, n.cNet.n-1))
cClassNames := loadClassNames(n.DataConfigurationFile)
defer freeClassNames(cClassNames)
n.ClassNames = makeClassNames(cClassNames, n.Classes)
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
}
@@ -70,34 +58,26 @@ func (n *YOLONetwork) Close() error {
if n.cNet == nil {
return errNetworkNotInit
}
C.free_network(n.cNet)
C.free_network(*n.cNet)
n.cNet = nil
return nil
}
// Detect specified image.
func (n *YOLONetwork) Detect(img *Image) (*DetectionResult, error) {
// Detect specified image
func (n *YOLONetwork) Detect(img *DarknetImage) (*DetectionResult, error) {
if n.cNet == nil {
return nil, errNetworkNotInit
}
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))
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)
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,
NetworkOnlyTimeTaken: endTime.Sub(startTime),
OverallTimeTaken: endTimeOverall.Sub(startTime),
}
return &out, nil
}

View File

@@ -8,4 +8,4 @@ struct network_box_result {
};
extern int get_network_layer_classes(network *n, int index);
extern struct network_box_result perform_network_detect(network *n, image *img, int classes, float thresh, float hier_thresh, float nms);
extern struct network_box_result perform_network_detect(network *n, image *img, int classes, float thresh, float hier_thresh, float nms, int letter_box);