mirror of
https://github.com/LdDl/go-darknet.git
synced 2025-10-04 15:22:44 +08:00
Compare commits
4 Commits
master
...
yolov4-rel
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5af007241e | ||
![]() |
c5367f6cff | ||
![]() |
3c09be397e | ||
![]() |
0d6caabb1a |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -5,10 +5,6 @@ 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
|
||||
|
55
README.md
55
README.md
@@ -3,13 +3,12 @@
|
||||
[](https://goreportcard.com/report/github.com/LdDl/go-darknet)
|
||||
[](https://github.com/LdDl/go-darknet/releases)
|
||||
|
||||
# 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].
|
||||
# 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].
|
||||
|
||||
#### 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
|
||||
|
||||
@@ -36,7 +35,7 @@ Example of such project here: https://github.com/LdDl/license_plate_recognition#
|
||||
|
||||
## Requirements
|
||||
|
||||
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)
|
||||
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/f056fc3b6a11528fa0522a468eca1e909b7004b7)
|
||||
|
||||
Use provided [Makefile](Makefile).
|
||||
|
||||
@@ -78,10 +77,6 @@ Building and running program:
|
||||
```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
|
||||
```
|
||||
@@ -112,30 +107,7 @@ Building and running program:
|
||||
|
||||
|
||||
* 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:
|
||||
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
|
||||
```
|
||||
@@ -157,25 +129,6 @@ Building and running program:
|
||||
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
|
||||
|
@@ -4,14 +4,13 @@ import (
|
||||
"bytes"
|
||||
"flag"
|
||||
"fmt"
|
||||
darknet "go-darknet"
|
||||
"image"
|
||||
"image/jpeg"
|
||||
"log"
|
||||
"math"
|
||||
"os"
|
||||
|
||||
darknet "github.com/LdDl/go-darknet"
|
||||
|
||||
"github.com/disintegration/imaging"
|
||||
)
|
||||
|
||||
|
@@ -1,5 +0,0 @@
|
||||
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
|
@@ -1,5 +0,0 @@
|
||||
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
|
@@ -11,7 +11,7 @@ import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
darknet "github.com/LdDl/go-darknet"
|
||||
"go-darknet"
|
||||
)
|
||||
|
||||
var configFile = flag.String("configFile", "",
|
||||
|
8
go.mod
8
go.mod
@@ -1,14 +1,8 @@
|
||||
module github.com/LdDl/go-darknet
|
||||
module 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
|
||||
)
|
||||
|
6
go.sum
6
go.sum
@@ -1,14 +1,8 @@
|
||||
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,18 +11,3 @@ 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
40
image.go
40
image.go
@@ -14,33 +14,61 @@ import (
|
||||
type DarknetImage struct {
|
||||
Width int
|
||||
Height int
|
||||
ans []float32
|
||||
image C.image
|
||||
}
|
||||
|
||||
// Close and release resources.
|
||||
func (img *DarknetImage) Close() error {
|
||||
C.free_image(img.image)
|
||||
img.ans = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func Image2Float32(src image.Image) (*DarknetImage, error) {
|
||||
// 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()
|
||||
srcRGBA := image.NewRGBA(bounds)
|
||||
draw.Copy(srcRGBA, image.Point{}, src, bounds, draw.Src, nil)
|
||||
width, height := bounds.Max.X, bounds.Max.Y
|
||||
srcRGBA := image.NewRGBA(src.Bounds())
|
||||
draw.Copy(srcRGBA, image.Point{}, src, src.Bounds(), draw.Src, nil)
|
||||
|
||||
return ImageRGBA2Float32(srcRGBA)
|
||||
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)
|
||||
}
|
||||
}
|
||||
srcRGBA = 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
|
||||
}
|
||||
|
||||
// Image2Float32 Returns []float32 representation of image.Image
|
||||
func ImageRGBA2Float32(img *image.RGBA) (*DarknetImage, error) {
|
||||
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),
|
||||
}
|
||||
C.to_float_and_fill_image(&imgDarknet.image, C.int(width), C.int(height), (*C.uint8_t)(unsafe.Pointer(&img.Pix[0])))
|
||||
C.fill_image_f32(&imgDarknet.image, C.int(width), C.int(height), 3, (*C.float)(unsafe.Pointer(&imgDarknet.ans[0])))
|
||||
return imgDarknet, nil
|
||||
}
|
||||
|
||||
|
1
image.h
1
image.h
@@ -4,4 +4,3 @@
|
||||
|
||||
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 to_float_and_fill_image(image *im, int w, int h, uint8_t* data);
|
||||
|
81
network.go
81
network.go
@@ -7,13 +7,9 @@ package darknet
|
||||
// #include "network.h"
|
||||
import "C"
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"errors"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/edsrzf/mmap-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// YOLONetwork represents a neural network using YOLO.
|
||||
@@ -57,81 +53,6 @@ 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 {
|
||||
|
58
section.go
58
section.go
@@ -1,58 +0,0 @@
|
||||
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
|
||||
}
|
@@ -1,20 +0,0 @@
|
||||
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