mirror of
				https://github.com/LdDl/go-darknet.git
				synced 2025-10-31 11:06:24 +08:00 
			
		
		
		
	Compare commits
	
		
			16 Commits
		
	
	
		
			add-licens
			...
			issue-15
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 40df8cce91 | ||
|   | 13a0697585 | ||
|   | 29e4d0d8bb | ||
|   | 165e59aaf3 | ||
|   | 81223ac67d | ||
|   | 7cbe2f50a7 | ||
|   | 6a381223fa | ||
|   | a039e75b22 | ||
|   | 7f94c3bdcc | ||
|   | e5d170ef8b | ||
|   | 85730b925c | ||
|   | 55221029de | ||
|   | e0a6735667 | ||
|   | c9bbd3eee4 | ||
|   | 5539377f1c | ||
|   | 10cd5f6e1a | 
							
								
								
									
										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. | ||||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,5 +1,4 @@ | |||||||
| example/main | example/main | ||||||
| example/sample.jpg |  | ||||||
| example/coco.names | example/coco.names | ||||||
| example/yolov3.cfg | example/yolov3.cfg | ||||||
| example/yolov3.weights | example/yolov3.weights | ||||||
|   | |||||||
							
								
								
									
										55
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | |||||||
|  | .ONESHELL: | ||||||
|  | .PHONY: download build clean | ||||||
|  |  | ||||||
|  | # Latest battletested AlexeyAB version of Darknet commit | ||||||
|  | LATEST_COMMIT?=f056fc3b6a11528fa0522a468eca1e909b7004b7 | ||||||
|  |  | ||||||
|  | # Temporary folder for building Darknet | ||||||
|  | TMP_DIR?=/tmp/ | ||||||
|  |  | ||||||
|  | # Download AlexeyAB version of Darknet | ||||||
|  | download: | ||||||
|  | 	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: | ||||||
|  | 	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_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 | ||||||
|  |  | ||||||
|  | # Do every step for CPU-based only build. | ||||||
|  | install: download build sudo_install clean | ||||||
|  |  | ||||||
|  | # Do every step for both CPU and GPU-based build. | ||||||
|  | install_gpu: download build_gpu sudo_install clean | ||||||
							
								
								
									
										183
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								README.md
									
									
									
									
									
								
							| @@ -3,7 +3,6 @@ | |||||||
| [](https://goreportcard.com/report/github.com/LdDl/go-darknet) | [](https://goreportcard.com/report/github.com/LdDl/go-darknet) | ||||||
| [](https://github.com/LdDl/go-darknet/releases) | [](https://github.com/LdDl/go-darknet/releases) | ||||||
|  |  | ||||||
|  |  | ||||||
| # go-darknet: Go bindings for Darknet (Yolo V4, Yolo V3) | # 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 is a Go package, which uses Cgo to enable Go applications to use YOLO V4/V3 in [Darknet]. | ||||||
|  |  | ||||||
| @@ -23,29 +22,20 @@ | |||||||
|  |  | ||||||
| ## Requirements | ## 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/9dc897d2c77d5ef43a6b237b717437375765b527) | 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/d65909fbea471d06e52a2e4a41132380dc2edaa6) | ||||||
|  |  | ||||||
| In order to use go-darknet, `libdarknet.so` should be available in one of | Use provided [Makefile](Makefile). | ||||||
| the following locations: |  | ||||||
|  |  | ||||||
| * /usr/lib | * For CPU-based instalattion: | ||||||
| * /usr/local/lib |     ```shell | ||||||
|  |     make install | ||||||
|  |     ``` | ||||||
|  | * For both CPU and GPU-based instalattion: | ||||||
|  |     ```shell | ||||||
|  |     make install_gpu | ||||||
|  |     ``` | ||||||
|  |     Note: If you want to have GPU-acceleration before running command above install [CUDA](https://developer.nvidia.com/cuda-downloads) and [cuDNN](https://developer.nvidia.com/cudnn) (Latest CUDA version I've tested is [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: |  | ||||||
|  |  | ||||||
| * /usr/include |  | ||||||
| * /usr/local/include |  | ||||||
|  |  | ||||||
| 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 | ## Installation | ||||||
|  |  | ||||||
| ```shell | ```shell | ||||||
| @@ -58,87 +48,88 @@ Example Go program is provided in the [example] directory. Please refer to the c | |||||||
|  |  | ||||||
| Building and running program: | Building and running program: | ||||||
|  |  | ||||||
| Navigate to [example] folder | * Navigate to [example] folder | ||||||
| ```shell |     ```shell | ||||||
| cd $GOPATH/github.com/LdDl/go-darknet/example |     cd $GOPATH/github.com/LdDl/go-darknet/example/base_example | ||||||
| ``` |     ``` | ||||||
|  |  | ||||||
| Download dataset (sample of image, coco.names, yolov4.cfg (or v3), yolov4.weights(or v3)). | * Download dataset (sample of image, coco.names, yolov4.cfg (or v3), yolov4.weights(or v3)). | ||||||
| ```shell |     ```shell | ||||||
| #for yolo v4 |     #for yolo v4 | ||||||
| ./download_data.sh |     ./download_data.sh | ||||||
| #for yolo v3 |     #for yolo v3 | ||||||
| ./download_data_v3.sh |     ./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) | * 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: |     So last rows in yolov4.cfg file will look like: | ||||||
| ```bash |     ```bash | ||||||
| ...... |     ...... | ||||||
| [yolo] |     [yolo] | ||||||
| ..... |     ..... | ||||||
| iou_loss=ciou |     iou_loss=ciou | ||||||
| nms_kind=greedynms |     nms_kind=greedynms | ||||||
| beta_nms=0.6 |     beta_nms=0.6 | ||||||
|  |  | ||||||
| names = coco.names # this is path to coco.names file |     names = coco.names # this is path to coco.names file | ||||||
| ``` |     ``` | ||||||
| Also do not forget change batch and subdivisions sizes from: |  | ||||||
| ```shell | * Also do not forget change batch and subdivisions sizes from: | ||||||
| batch=64 |     ```shell | ||||||
| subdivisions=8 |     batch=64 | ||||||
| ``` |     subdivisions=8 | ||||||
| to |     ``` | ||||||
| ```shell |     to | ||||||
| batch=1 |     ```shell | ||||||
| subdivisions=1 |     batch=1 | ||||||
| ``` |     subdivisions=1 | ||||||
| It will reduce amount of VRAM used for detector test. |     ``` | ||||||
|  |     It will reduce amount of VRAM used for detector test. | ||||||
|  |  | ||||||
|  |  | ||||||
| Build and run program | * Build and run program | ||||||
| Yolo V4: |     Yolo V4: | ||||||
| ```shell |     ```shell | ||||||
| go build main.go && ./main --configFile=yolov4.cfg --weightsFile=yolov4.weights --imageFile=sample.jpg |     go build main.go && ./main --configFile=yolov4.cfg --weightsFile=yolov4.weights --imageFile=sample.jpg | ||||||
| ``` |     ``` | ||||||
|  |  | ||||||
| Output should be something like this: |     Output should be something like this: | ||||||
| ```shell |     ```shell | ||||||
| traffic light (9): 73.5039% | start point: (238,73) | end point: (251, 106) |     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.6401% | start point: (95,79) | end point: (233, 287) | ||||||
| truck (7): 96.4774% | start point: (662,158) | end point: (800, 321) |     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): 96.1841% | start point: (0,77) | end point: (86, 333) | ||||||
| truck (7): 46.8695% | start point: (434,173) | end point: (559, 216) |     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.7370% | start point: (512,188) | end point: (741, 329) | ||||||
| car (2): 99.2533% | start point: (260,191) | end point: (422, 322) |     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): 99.0333% | start point: (425,201) | end point: (547, 309) | ||||||
| car (2): 83.3919% | start point: (386,210) | end point: (437, 287) |     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): 75.8621% | start point: (73,199) | end point: (102, 274) | ||||||
| car (2): 39.1925% | start point: (386,206) | end point: (442, 240) |     car (2): 39.1925% | start point: (386,206) | end point: (442, 240) | ||||||
| bicycle (1): 76.3121% | start point: (189,298) | end point: (253, 402) |     bicycle (1): 76.3121% | start point: (189,298) | end point: (253, 402) | ||||||
| person (0): 97.7213% | start point: (141,129) | end point: (283, 362) |     person (0): 97.7213% | start point: (141,129) | end point: (283, 362) | ||||||
| ``` |     ``` | ||||||
|  |  | ||||||
| Yolo V3: |     Yolo V3: | ||||||
| ``` |     ``` | ||||||
| go build main.go && ./main --configFile=yolov3.cfg --weightsFile=yolov3.weights --imageFile=sample.jpg |     go build main.go && ./main --configFile=yolov3.cfg --weightsFile=yolov3.weights --imageFile=sample.jpg | ||||||
| ``` |     ``` | ||||||
|  |  | ||||||
| Output should be something like this: |     Output should be something like this: | ||||||
| ```shell |     ```shell | ||||||
| truck (7): 49.5197% | start point: (0,136) | end point: (85, 311) |     truck (7): 49.5197% | start point: (0,136) | end point: (85, 311) | ||||||
| car (2): 36.3747% | start point: (95,152) | end point: (186, 283) |     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): 48.4384% | start point: (95,152) | end point: (186, 283) | ||||||
| truck (7): 45.6590% | start point: (694,178) | end point: (798, 310) |     truck (7): 45.6590% | start point: (694,178) | end point: (798, 310) | ||||||
| car (2): 76.8379% | start point: (1,145) | end point: (84, 324) |     car (2): 76.8379% | start point: (1,145) | end point: (84, 324) | ||||||
| truck (7): 25.5731% | start point: (107,89) | end point: (215, 263) |     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.8783% | start point: (511,185) | end point: (748, 328) | ||||||
| car (2): 99.8194% | start point: (261,189) | end point: (427, 322) |     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): 99.6408% | start point: (426,197) | end point: (539, 311) | ||||||
| car (2): 74.5610% | start point: (692,186) | end point: (796, 316) |     car (2): 74.5610% | start point: (692,186) | end point: (796, 316) | ||||||
| car (2): 72.8053% | start point: (388,206) | end point: (437, 276) |     car (2): 72.8053% | start point: (388,206) | end point: (437, 276) | ||||||
| bicycle (1): 72.2932% | start point: (178,270) | end point: (268, 406) |     bicycle (1): 72.2932% | start point: (178,270) | end point: (268, 406) | ||||||
| person (0): 97.3026% | start point: (143,135) | end point: (268, 343) |     person (0): 97.3026% | start point: (143,135) | end point: (268, 343) | ||||||
| ``` |     ``` | ||||||
|  |  | ||||||
| ## Documentation | ## Documentation | ||||||
|  |  | ||||||
| @@ -154,5 +145,5 @@ go-darknet follows [Darknet]'s [license]. | |||||||
| [darknet.h]: https://github.com/AlexeyAB/darknet/blob/master/include/darknet.h | [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 | [include/darknet.h]: https://github.com/AlexeyAB/darknet/blob/master/include/darknet.h | ||||||
| [Makefile]: https://github.com/alexeyab/darknet/blob/master/Makefile | [Makefile]: https://github.com/alexeyab/darknet/blob/master/Makefile | ||||||
| [example]: /example | [example]: /example/base_example | ||||||
| [GoDoc]: https://godoc.org/github.com/LdDl/go-darknet | [GoDoc]: https://godoc.org/github.com/LdDl/go-darknet | ||||||
|   | |||||||
| @@ -8,12 +8,12 @@ This is an example Go application which uses go-darknet. | |||||||
| Navigate to example folder: | Navigate to example folder: | ||||||
| 
 | 
 | ||||||
| ```shell | ```shell | ||||||
| cd $GOPATH/github.com/LdDl/go-darknet/example | cd $GOPATH/github.com/LdDl/go-darknet/example/base_example | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| Download dataset (sample of image, coco.names, yolov3.cfg, yolov3.weights). | Download dataset (sample of image, coco.names, yolov3.cfg, yolov3.weights). | ||||||
| ```shell | ```shell | ||||||
| ./download_data.sh | ./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) | 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: | So last rows in yolov3.cfg file will look like: | ||||||
| @@ -9,7 +9,6 @@ import ( | |||||||
| 	"log" | 	"log" | ||||||
| 	"math" | 	"math" | ||||||
| 	"os" | 	"os" | ||||||
| 
 |  | ||||||
| 	darknet "github.com/LdDl/go-darknet" | 	darknet "github.com/LdDl/go-darknet" | ||||||
| 	"github.com/disintegration/imaging" | 	"github.com/disintegration/imaging" | ||||||
| ) | ) | ||||||
| @@ -61,13 +60,13 @@ func main() { | |||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		panic(err.Error()) | 		panic(err.Error()) | ||||||
| 	} | 	} | ||||||
| 	defer imgDarknet.Close() |  | ||||||
| 	 | 	 | ||||||
| 	dr, err := n.Detect(imgDarknet) | 	dr, err := n.Detect(imgDarknet) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		printError(err) | 		printError(err) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
|  | 	imgDarknet.Close() | ||||||
| 
 | 
 | ||||||
| 	log.Println("Network-only time taken:", dr.NetworkOnlyTimeTaken) | 	log.Println("Network-only time taken:", dr.NetworkOnlyTimeTaken) | ||||||
| 	log.Println("Overall time taken:", dr.OverallTimeTaken, len(dr.Detections)) | 	log.Println("Overall time taken:", dr.OverallTimeTaken, len(dr.Detections)) | ||||||
| @@ -92,6 +91,8 @@ func main() { | |||||||
| 			// } | 			// } | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	n.Close() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func imageToBytes(img image.Image) ([]byte, error) { | func imageToBytes(img image.Image) ([]byte, error) { | ||||||
							
								
								
									
										221
									
								
								example/rest_example/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								example/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
									
								
								example/rest_example/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								example/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" | ||||||
|  |  | ||||||
|  | 	"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
										
									
								
								example/sample.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								example/sample.jpg
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 134 KiB | 
| @@ -14,7 +14,8 @@ struct network_box_result perform_network_detect(network *n, image *img, int cla | |||||||
|         sized = resize_image(*img, n->w, n->h); |         sized = resize_image(*img, n->w, n->h); | ||||||
|     } |     } | ||||||
|     struct network_box_result result = { NULL }; |     struct network_box_result result = { NULL }; | ||||||
|     network_predict(*n, sized.data); |     // mleak at network_predict(), get_network_boxes() and network_predict_ptr()? | ||||||
|  |     network_predict_ptr(n, sized.data); | ||||||
|     int nboxes = 0; |     int nboxes = 0; | ||||||
|     result.detections = get_network_boxes(n, img->w, img->h, thresh, hier_thresh, 0, 1, &result.detections_len, letter_box); |     result.detections = get_network_boxes(n, img->w, img->h, thresh, hier_thresh, 0, 1, &result.detections_len, letter_box); | ||||||
|     if (nms) { |     if (nms) { | ||||||
|   | |||||||
| @@ -58,7 +58,7 @@ func (n *YOLONetwork) Close() error { | |||||||
| 	if n.cNet == nil { | 	if n.cNet == nil { | ||||||
| 		return errNetworkNotInit | 		return errNetworkNotInit | ||||||
| 	} | 	} | ||||||
| 	C.free_network(*n.cNet) | 	C.free_network_ptr(n.cNet) | ||||||
| 	n.cNet = nil | 	n.cNet = nil | ||||||
| 	return nil | 	return nil | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user