mirror of
https://github.com/LdDl/go-darknet.git
synced 2025-10-03 23:06:35 +08:00
need to deal with image
This commit is contained in:
6
.vscode/settings.json
vendored
Normal file
6
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"detection.h": "c",
|
||||||
|
"network.h": "c"
|
||||||
|
}
|
||||||
|
}
|
8
classes.c
Normal file
8
classes.c
Normal 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];
|
||||||
|
}
|
15
classes.go
Normal file
15
classes.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
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))
|
||||||
|
s := C.GoString(n)
|
||||||
|
out[i] = s
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
3
classes.h
Normal file
3
classes.h
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern char * get_class_name(char **names, int index, int names_len);
|
@@ -1,5 +1,5 @@
|
|||||||
package darknet
|
package darknet
|
||||||
|
|
||||||
// #cgo CFLAGS: -I/usr/local/include -I/usr/local/cuda/include
|
// #cgo CFLAGS: -I/usr/local/include -I/usr/local/cuda/include
|
||||||
// #cgo LDFLAGS: -L./lib -ldark -lm
|
// #cgo LDFLAGS: -L./lib -ldarknet -lm
|
||||||
import "C"
|
import "C"
|
||||||
|
5
data/names.list
Normal file
5
data/names.list
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
person
|
||||||
|
car
|
||||||
|
motorcycle
|
||||||
|
bus
|
||||||
|
truck
|
22
detection.c
Normal file
22
detection.c
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#include <darknet.h>
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
if (index >= prob_len) {
|
||||||
|
return .0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return det->prob[index];
|
||||||
|
}
|
75
detection.go
75
detection.go
@@ -1,10 +1,81 @@
|
|||||||
package darknet
|
package darknet
|
||||||
|
|
||||||
import "time"
|
// #include <darknet.h>
|
||||||
|
//
|
||||||
|
// #include "detection.h"
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"image"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Detection represents a detection.
|
||||||
|
type Detection struct {
|
||||||
|
BoundingBox
|
||||||
|
|
||||||
|
ClassIDs []int
|
||||||
|
ClassNames []string
|
||||||
|
Probabilities []float32
|
||||||
|
}
|
||||||
|
|
||||||
// DetectionResult represents the inference results from the network.
|
// DetectionResult represents the inference results from the network.
|
||||||
type DetectionResult struct {
|
type DetectionResult struct {
|
||||||
// Detections []*Detection
|
Detections []*Detection
|
||||||
NetworkOnlyTimeTaken time.Duration
|
NetworkOnlyTimeTaken time.Duration
|
||||||
OverallTimeTaken time.Duration
|
OverallTimeTaken time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)))
|
||||||
|
if dProb > threshold {
|
||||||
|
dClassIDs = append(dClassIDs, i)
|
||||||
|
cN := classNames[i]
|
||||||
|
dClassNames = append(dClassNames, cN)
|
||||||
|
dProbs = append(dProbs, dProb*100)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fImgW := C.float(img.Width)
|
||||||
|
fImgH := C.float(img.Height)
|
||||||
|
halfRatioW := det.bbox.w / 2.0
|
||||||
|
halfRatioH := det.bbox.h / 2.0
|
||||||
|
out := Detection{
|
||||||
|
BoundingBox: BoundingBox{
|
||||||
|
StartPoint: image.Point{
|
||||||
|
X: int((det.bbox.x - halfRatioW) * fImgW),
|
||||||
|
Y: int((det.bbox.y - halfRatioH) * fImgH),
|
||||||
|
},
|
||||||
|
EndPoint: image.Point{
|
||||||
|
X: int((det.bbox.x + halfRatioW) * fImgW),
|
||||||
|
Y: int((det.bbox.y + halfRatioH) * fImgH),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
ClassIDs: dClassIDs,
|
||||||
|
ClassNames: dClassNames,
|
||||||
|
Probabilities: dProbs,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &out
|
||||||
|
}
|
||||||
|
|
||||||
|
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(detectionsLength))
|
||||||
|
d := makeDetection(img, det, threshold, classes, classNames)
|
||||||
|
ds[i] = d
|
||||||
|
}
|
||||||
|
return ds
|
||||||
|
}
|
||||||
|
7
detection.h
Normal file
7
detection.h
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <darknet.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern detection * get_detection(detection *dets, int index, int dets_len);
|
||||||
|
extern float get_detection_probability(detection *det, int index, int prob_len);
|
@@ -2,6 +2,7 @@ package main
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"flag"
|
"flag"
|
||||||
|
"fmt"
|
||||||
"image/jpeg"
|
"image/jpeg"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@@ -37,7 +38,7 @@ func main() {
|
|||||||
DataConfigurationFile: *dataConfigFile,
|
DataConfigurationFile: *dataConfigFile,
|
||||||
NetworkConfigurationFile: *configFile,
|
NetworkConfigurationFile: *configFile,
|
||||||
WeightsFile: *weightsFile,
|
WeightsFile: *weightsFile,
|
||||||
Threshold: .5,
|
Threshold: .25,
|
||||||
}
|
}
|
||||||
if err := n.Init(); err != nil {
|
if err := n.Init(); err != nil {
|
||||||
printError(err)
|
printError(err)
|
||||||
@@ -54,6 +55,7 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
panic(err.Error())
|
||||||
}
|
}
|
||||||
|
_ = src
|
||||||
|
|
||||||
imgDarknet, err := darknet.Image2Float32(src)
|
imgDarknet, err := darknet.Image2Float32(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -67,18 +69,18 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = dr
|
_ = dr
|
||||||
// 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 {
|
log.Println("Network-only time taken:", dr.NetworkOnlyTimeTaken)
|
||||||
// bBox := d.BoundingBox
|
log.Println("Overall time taken:", dr.OverallTimeTaken, len(dr.Detections))
|
||||||
// fmt.Printf("%s (%d): %.4f%% | start point: (%d,%d) | end point: (%d, %d)\n",
|
for _, d := range dr.Detections {
|
||||||
// d.ClassNames[i], d.ClassIDs[i],
|
for i := range d.ClassIDs {
|
||||||
// d.Probabilities[i],
|
bBox := d.BoundingBox
|
||||||
// bBox.StartPoint.X, bBox.StartPoint.Y,
|
fmt.Printf("%s (%d): %.4f%% | start point: (%d,%d) | end point: (%d, %d)\n",
|
||||||
// bBox.EndPoint.X, bBox.EndPoint.Y,
|
d.ClassNames[i], d.ClassIDs[i],
|
||||||
// )
|
d.Probabilities[i],
|
||||||
// }
|
bBox.StartPoint.X, bBox.StartPoint.Y,
|
||||||
// }
|
bBox.EndPoint.X, bBox.EndPoint.Y,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
18
example/out-sample.png
Normal file
18
example/out-sample.png
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"frame_id":1,
|
||||||
|
"filename":"/home/dimitrii/Downloads/mega.jpg",
|
||||||
|
"objects": [
|
||||||
|
{"class_id":3, "name":"bus", "relative_coordinates":{"center_x":0.475497, "center_y":0.317034, "width":0.175112, "height":0.104746}, "confidence":0.686032},
|
||||||
|
{"class_id":3, "name":"bus", "relative_coordinates":{"center_x":0.278355, "center_y":0.302800, "width":0.087061, "height":0.052067}, "confidence":0.562420},
|
||||||
|
{"class_id":1, "name":"car", "relative_coordinates":{"center_x":0.799558, "center_y":0.643484, "width":0.388328, "height":0.539759}, "confidence":0.942335},
|
||||||
|
{"class_id":1, "name":"car", "relative_coordinates":{"center_x":0.365836, "center_y":0.431383, "width":0.267126, "height":0.156932}, "confidence":0.776083},
|
||||||
|
{"class_id":1, "name":"car", "relative_coordinates":{"center_x":0.513763, "center_y":0.475799, "width":0.301966, "height":0.240549}, "confidence":0.684380},
|
||||||
|
{"class_id":1, "name":"car", "relative_coordinates":{"center_x":0.717148, "center_y":0.516788, "width":0.456320, "height":0.313704}, "confidence":0.584288},
|
||||||
|
{"class_id":1, "name":"car", "relative_coordinates":{"center_x":0.217955, "center_y":0.379872, "width":0.212185, "height":0.101100}, "confidence":0.468769},
|
||||||
|
{"class_id":1, "name":"car", "relative_coordinates":{"center_x":0.126970, "center_y":0.337752, "width":0.035609, "height":0.022990}, "confidence":0.452899},
|
||||||
|
{"class_id":0, "name":"person", "relative_coordinates":{"center_x":0.051506, "center_y":0.369395, "width":0.056224, "height":0.175025}, "confidence":0.978385},
|
||||||
|
{"class_id":0, "name":"person", "relative_coordinates":{"center_x":0.097309, "center_y":0.370574, "width":0.048715, "height":0.142128}, "confidence":0.801452}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
5
image.c
5
image.c
@@ -15,3 +15,8 @@ image prepare_image(image img, int w, int h, int c){
|
|||||||
img.c=c;
|
img.c=c;
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
image new_image(int w, int h, int c){
|
||||||
|
image out = make_image(w, h, c);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
8
image.go
8
image.go
@@ -46,12 +46,14 @@ func Image2Float32(img image.Image) (DarknetImage, error) {
|
|||||||
imgDarknet := DarknetImage{
|
imgDarknet := DarknetImage{
|
||||||
Width: width,
|
Width: width,
|
||||||
Height: height,
|
Height: height,
|
||||||
image: C.new_darknet_image(),
|
// image: C.new_darknet_image(),
|
||||||
}
|
}
|
||||||
|
|
||||||
imgDarknet.image = C.prepare_image(imgDarknet.image, C.int(width), C.int(height), 3)
|
// imgDarknet.image = C.prepare_image(imgDarknet.image, C.int(width), C.int(height), 3)
|
||||||
imgDarknet.image.data = float_p(ans)
|
// imgDarknet.image.data = float_p(ans)
|
||||||
// imgDarknet.image = C.resize_image(imgDarknet.image, 416, 416) // Do we need resize? (detection function actually does it)
|
// imgDarknet.image = C.resize_image(imgDarknet.image, 416, 416) // Do we need resize? (detection function actually does it)
|
||||||
|
|
||||||
|
imgDarknet.image = C.load_image_color(C.CString("/home/dimitrii/Downloads/mega.jpg"), 416, 416)
|
||||||
|
|
||||||
return imgDarknet, nil
|
return imgDarknet, nil
|
||||||
}
|
}
|
||||||
|
1
image.h
1
image.h
@@ -4,3 +4,4 @@
|
|||||||
|
|
||||||
extern image new_darknet_image();
|
extern image new_darknet_image();
|
||||||
extern image prepare_image(image img, int w, int h, int c);
|
extern image prepare_image(image img, int w, int h, int c);
|
||||||
|
extern image new_image(int w, int h, int c);
|
10
network.c
10
network.c
@@ -4,19 +4,19 @@
|
|||||||
|
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
|
||||||
// int get_network_layer_classes(network *n, int index) {
|
#include "detection.h"
|
||||||
// return n->layers[index].classes;
|
|
||||||
// }
|
|
||||||
|
|
||||||
struct network_box_result perform_network_detect(network *n, image *img, int classes, float thresh, float hier_thresh, float nms) {
|
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);
|
image sized = letterbox_image(*img, n->w, n->h);
|
||||||
struct network_box_result result = { NULL };
|
struct network_box_result result = { NULL };
|
||||||
float *X = sized.data;
|
float *X = sized.data;
|
||||||
network_predict(*n, X);
|
int letter_box = 0;
|
||||||
result.detections = get_network_boxes(n, img->w, img->h,thresh, hier_thresh, 0, 1, &result.detections_len, 0);
|
network_predict_ptr(n, X);
|
||||||
|
result.detections = get_network_boxes(n, img->w, img->h, thresh, hier_thresh, 0, 1, &result.detections_len, letter_box);
|
||||||
if (nms) {
|
if (nms) {
|
||||||
do_nms_sort(result.detections, result.detections_len, classes, nms);
|
do_nms_sort(result.detections, result.detections_len, classes, nms);
|
||||||
}
|
}
|
||||||
free_image(sized);
|
free_image(sized);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
39
network.go
39
network.go
@@ -41,7 +41,18 @@ func (n *YOLONetwork) Init() error {
|
|||||||
wFile := C.CString(n.WeightsFile)
|
wFile := C.CString(n.WeightsFile)
|
||||||
defer C.free(unsafe.Pointer(wFile))
|
defer C.free(unsafe.Pointer(wFile))
|
||||||
|
|
||||||
// GPU device ID must be set before `load_network()` is invoked.
|
// data := C.CString(n.DataConfigurationFile)
|
||||||
|
// defer C.free(unsafe.Pointer(data))
|
||||||
|
|
||||||
|
// inptim := C.CString("/home/dimitrii/Downloads/mega.jpg")
|
||||||
|
// defer C.free(unsafe.Pointer(inptim))
|
||||||
|
|
||||||
|
// outputim := C.CString("/home/dimitrii/work/src/github.com/LdDl/go-darknet/example/out-sample.png")
|
||||||
|
// defer C.free(unsafe.Pointer(outputim))
|
||||||
|
|
||||||
|
// C.test_detector(data, nCfg, wFile, inptim, 0.4, 0.5, 1, 1, 0, outputim, 0, 0)
|
||||||
|
|
||||||
|
// // GPU device ID must be set before `load_network()` is invoked.
|
||||||
C.cuda_set_device(C.int(n.GPUDeviceIndex))
|
C.cuda_set_device(C.int(n.GPUDeviceIndex))
|
||||||
n.cNet = C.load_network(nCfg, wFile, 0)
|
n.cNet = C.load_network(nCfg, wFile, 0)
|
||||||
|
|
||||||
@@ -56,12 +67,11 @@ func (n *YOLONetwork) Init() error {
|
|||||||
n.hierarchalThreshold = .5
|
n.hierarchalThreshold = .5
|
||||||
|
|
||||||
// Currently NMS is always 0.4.
|
// Currently NMS is always 0.4.
|
||||||
n.nms = .4
|
n.nms = .45
|
||||||
|
|
||||||
// n.Classes = int(C.get_network_layer_classes(n.cNet, n.cNet.n-1))
|
metadata := C.get_metadata(nCfg)
|
||||||
// cClassNames := loadClassNames(n.DataConfigurationFile)
|
n.Classes = int(metadata.classes)
|
||||||
// defer freeClassNames(cClassNames)
|
n.ClassNames = makeClassNames(metadata.names, n.Classes)
|
||||||
// n.ClassNames = makeClassNames(cClassNames, n.Classes)
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -77,28 +87,21 @@ func (n *YOLONetwork) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect specified image.
|
// Detect specified image
|
||||||
func (n *YOLONetwork) Detect(img *DarknetImage) (*DetectionResult, error) {
|
func (n *YOLONetwork) Detect(img *DarknetImage) (*DetectionResult, error) {
|
||||||
if n.cNet == nil {
|
if n.cNet == nil {
|
||||||
return nil, errNetworkNotInit
|
return nil, errNetworkNotInit
|
||||||
}
|
}
|
||||||
|
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
C.network_predict_image(n.cNet, img.image)
|
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))
|
|
||||||
endTime := time.Now()
|
endTime := time.Now()
|
||||||
// defer C.free_detections(result.detections, result.detections_len)
|
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)
|
|
||||||
|
|
||||||
endTimeOverall := time.Now()
|
endTimeOverall := time.Now()
|
||||||
|
|
||||||
out := DetectionResult{
|
out := DetectionResult{
|
||||||
// Detections: ds,
|
Detections: ds,
|
||||||
NetworkOnlyTimeTaken: endTime.Sub(startTime),
|
NetworkOnlyTimeTaken: endTime.Sub(startTime),
|
||||||
OverallTimeTaken: endTimeOverall.Sub(startTime),
|
OverallTimeTaken: endTimeOverall.Sub(startTime),
|
||||||
}
|
}
|
||||||
|
|
||||||
return &out, nil
|
return &out, nil
|
||||||
}
|
}
|
||||||
|
BIN
predictions.jpg
Normal file
BIN
predictions.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 MiB |
Reference in New Issue
Block a user