├── .gitignore
├── .gitmodules
├── .npmignore
├── CHANGELOG.md
├── CMakeLists.txt
├── LICENSE
├── Makefile
├── README.md
├── binding.gyp
├── index.js
├── package.json
├── src
├── module.cpp
├── module.h
├── napi_yolo_errors.c
└── napi_yolo_errors.h
├── util
└── has_lib.js
└── yolo
└── src
├── libyolo.cpp
├── libyolo.h
├── private_structs.h
├── yolo_error.c
└── yolo_error.h
/.gitignore:
--------------------------------------------------------------------------------
1 | # Prerequisites
2 | *.d
3 |
4 | # Compiled Object files
5 | *.slo
6 | *.lo
7 | *.o
8 | *.obj
9 |
10 | # Precompiled Headers
11 | *.gch
12 | *.pch
13 |
14 | # Compiled Dynamic libraries
15 | *.so
16 | *.dylib
17 | *.dll
18 |
19 | # Fortran module files
20 | *.mod
21 | *.smod
22 |
23 | # Compiled Static libraries
24 | *.lai
25 | *.la
26 | *.a
27 | *.lib
28 |
29 | # Executables
30 | *.exe
31 | *.out
32 | *.app
33 |
34 | # Cmake
35 | cmake-build-debug/
36 |
37 | # Clion
38 | .idea/
39 | .gitconfig
40 |
41 | #libyolo build folder
42 | obj/
43 | *.weights
44 | weights/
45 | data/
46 |
47 | #NodeJS
48 | build/
49 | node_modules/
50 | package-lock.json
51 | vapi-node-yolo*.tgz
52 |
53 | #macOS
54 | .DS_Store
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "darknet"]
2 | path = darknet
3 | url = https://github.com/rcaceiro/darknet.git
4 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | CMakeLists.txt
3 | weights/
4 | *.weights
5 | *.a
6 | *.dylib
7 | *.o
8 | *.so
9 | darknet/cfg
10 | darknet/data
11 | darknet/examples
12 | darknet/python
13 | cmake-build-debug/
14 | node_modules/
15 | data/
16 | build/
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | **Note**: In this project the version semantic will be x.y.z, when:
3 | - **z** represent, backwards compatible bug fixes are introduced
4 | - **y** represent, new backwards compatible functionality are introduced
5 | - **x** represent, any backwards incompatible changes are introduced, and/or a big bundle of bug fixes and new functionalities are introduced.
6 |
7 | ## [v2.1.2](https://github.com/rcaceiro/node-yolo/tree/v2.1.2) (24-12-2018)
8 | [Full Changelog](https://github.com/rcaceiro/node-yolo/compare/v2.1.1...v2.1.2)
9 |
10 | **Fixed bugs:**
11 | - Fix a bug then make with sudo, the which not run on sudo.
12 |
13 | ## [v2.1.1](https://github.com/rcaceiro/node-yolo/tree/v2.1.1) (24-12-2018)
14 | [Full Changelog](https://github.com/rcaceiro/node-yolo/compare/v2.1.0...v2.1.1)
15 |
16 | **Fixed bugs:**
17 | - Removed some extra code that allow gather timings.
18 |
19 | ## [v2.1.0](https://github.com/rcaceiro/node-yolo/tree/v2.1.0) (23-12-2018)
20 | [Full Changelog](https://github.com/rcaceiro/node-yolo/compare/v2.0.0...v2.1.0)
21 |
22 | **New Features**:
23 | - node-yolo now can process only x number of frames. 1/3 means process 1 frames for each 3, the default behaviour is process every frame.
24 | - node-yolo now allow the developer can specify the threshold, the default behavior is 0.5.
25 |
26 | **Implemented enhancements:**
27 | - now on reject the node-yolo no longer kill nodeJS.
28 |
29 | ## [v2.0.1](https://github.com/rcaceiro/node-yolo/tree/v2.0.1) (23-12-2018)
30 | [Full Changelog](https://github.com/rcaceiro/node-yolo/compare/v2.0.0...v2.0.1)
31 |
32 | **Fixed bugs:**
33 | - Small fix then yolo_status_decode is called, it wasn't linked on libyolo
34 |
35 | **Closed issues:**
36 | Detect only first object from same class [\#4](https://github.com/rcaceiro/node-yolo/issues/4)
37 |
38 | ## [v2.0.0](https://github.com/rcaceiro/node-yolo/tree/v2.0.0) (15-11-2018)
39 | [Full Changelog](https://github.com/rcaceiro/node-yolo/compare/previous_to_v2.0.0...v2.0.0)
40 |
41 | **New Features**:
42 | - node-yolo classify videos, but for now only video files, not a camera stream.
43 | - added to results of classification the time that took to be classified.
44 |
45 | **Implemented enhancements:**
46 | - Creation of a changelog
47 | - Added a capability on Makefile to detect OpenMP, only on Linux, if macOs users has it installed has to change manually the parameter OPENMP in Makefile.
48 | - Added constraints on CPU and OS to install this module in package.json
49 |
50 | **Fixed bugs:**
51 | - Fix on Makefile to include more new object files, needed
52 |
53 | **Backwards Incompatibility:**
54 | - The versions prior 2.0.0 of the module has the [ImageMagick](https://www.imagemagick.org) as a dependency, but with OpenCV we can archive the desired goal. And by this we remove one dependency of the project.
55 |
56 | **Closed issues:**
57 | - Getting Empty Array In Detections Instead Of Object [\#1](https://github.com/rcaceiro/node-yolo/issues/1)
58 | - Built with GPU stuff enabled but using CPU [\#3](https://github.com/rcaceiro/node-yolo/issues/3)
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
2 | PROJECT(node-yolo)
3 |
4 | SET(CMAKE_CXX_STANDARD 17)
5 |
6 | INCLUDE_DIRECTORIES(.)
7 | INCLUDE_DIRECTORIES(darknet/src)
8 | INCLUDE_DIRECTORIES(darknet/include)
9 | INCLUDE_DIRECTORIES(yolo/src)
10 | INCLUDE_DIRECTORIES(/usr/local/include/node)
11 | INCLUDE_DIRECTORIES(/usr/include/node)
12 | INCLUDE_DIRECTORIES(/usr/local/Cellar/opencv/3.4.3_1/include/opencv)
13 | INCLUDE_DIRECTORIES(/usr/local/Cellar/opencv/3.4.3_1/include)
14 | ADD_COMPILE_DEFINITIONS(OPENCV)
15 |
16 | ADD_EXECUTABLE(node-yolo
17 | yolo/src/libyolo.h
18 | yolo/src/libyolo.cpp src/module.cpp src/module.h yolo/src/yolo_error.c yolo/src/yolo_error.h yolo/src/private_structs.h src/napi_yolo_errors.c src/napi_yolo_errors.h)
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Rúben Caceiro
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | GPU=0
2 | CUDNN=0
3 | OPENCV=1
4 | OPENMP=0
5 | DEBUG=0
6 |
7 | NVCC = $(shell find /usr -iname "nvcc" 2> /dev/null)
8 | NVCC_TEST := $(notdir $(NVCC))
9 |
10 | ifeq ($(NVCC_TEST),nvcc)
11 | GPU=1
12 | endif
13 |
14 | ARCH= -gencode arch=compute_35,code=sm_35 \
15 | -gencode arch=compute_50,code=[sm_50,compute_50] \
16 | -gencode arch=compute_52,code=[sm_52,compute_52] \
17 | -gencode arch=compute_61,code=sm_61 \
18 | -gencode arch=compute_62,code=sm_62 \
19 | -gencode arch=compute_70,code=sm_70
20 |
21 | # This is what I use, uncomment if you know your arch and want to specify
22 | # ARCH= -gencode arch=compute_52,code=compute_52
23 |
24 | SHARE_LIB_OPT=
25 |
26 | MAC_OS_LOCAL_FOLDER=
27 |
28 | LIB_RAW_NAME=libyolo
29 | SLIB=
30 | SLIB_DIR=
31 |
32 | ALIB=libyolo.a
33 | ALIB_DIR=$(addprefix yolo/, $(ALIB))
34 |
35 | UNAME_S := $(shell uname -s)
36 | ifeq ($(UNAME_S),Linux)
37 | SHARE_LIB_OPT += -shared
38 | SLIB=$(addprefix $(LIB_RAW_NAME),.so)
39 | OPENMP=$(shell ldconfig -p | grep gomp > /dev/null 2> /dev/null && echo 1 || echo 0)
40 | endif
41 | ifeq ($(UNAME_S),Darwin)
42 | SHARE_LIB_OPT += -dynamiclib
43 | MAC_OS_LOCAL_FOLDER=local/
44 | SLIB=$(addprefix $(LIB_RAW_NAME),.dylib)
45 | endif
46 |
47 | SLIB_DIR=$(addprefix yolo/, $(SLIB))
48 |
49 | ROOT=
50 | #ifeq ($(shell id -u), 0)
51 | # ROOT=sudo
52 | #endif
53 |
54 | OBJDIR=./obj/
55 | VPATH=./darknet/src/:./yolo/src/:./stack/
56 |
57 | CC=gcc
58 | CPP=g++
59 | AR=ar
60 | ARFLAGS=rcs
61 | OPTS=
62 | LDFLAGS= -lm -pthread
63 | COMMON= -I./darknet/include/ -I./darknet/src/
64 | CFLAGS=-Wall -Wno-unused-result -Wno-unknown-pragmas -Wfatal-errors -fPIC
65 |
66 | ifeq ($(OPENMP), 1)
67 | CFLAGS+= -fopenmp
68 | endif
69 |
70 | ifeq ($(DEBUG), 1)
71 | OPTS+=-O0 -g
72 | else
73 | OPTS+=-Ofast
74 | endif
75 |
76 | CFLAGS+=$(OPTS)
77 |
78 | ifeq ($(OPENCV), 1)
79 | COMMON+= -DOPENCV
80 | CFLAGS+= -DOPENCV
81 | LDFLAGS+= `pkg-config --libs opencv` -lstdc++
82 | COMMON+= `pkg-config --cflags opencv`
83 | endif
84 |
85 | ifeq ($(GPU), 1)
86 | COMMON+= -DGPU -I/usr/local/cuda/include/
87 | CFLAGS+= -DGPU
88 | LDFLAGS+= -L/usr/local/cuda/lib64 -L/usr/lib/x86_64-linux-gnu/ -lcuda -lcudart -lcublas -lcurand
89 | endif
90 |
91 | ifeq ($(CUDNN), 1)
92 | COMMON+= -DCUDNN
93 | CFLAGS+= -DCUDNN
94 | LDFLAGS+= -lcudnn
95 | endif
96 |
97 | OBJ=libyolo.o yolo_error.o gemm.o utils.o cuda.o deconvolutional_layer.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 detection_layer.o route_layer.o upsample_layer.o box.o normalization_layer.o avgpool_layer.o layer.o local_layer.o shortcut_layer.o logistic_layer.o activation_layer.o rnn_layer.o gru_layer.o crnn_layer.o demo.o batchnorm_layer.o region_layer.o reorg_layer.o tree.o lstm_layer.o l2norm_layer.o yolo_layer.o iseg_layer.o image_opencv.o
98 | EXECOBJA=captcha.o lsd.o super.o art.o tag.o cifar.o go.o rnn.o segmenter.o regressor.o classifier.o coco.o yolo.o detector.o nightmare.o instance-segmenter.o darknet.o
99 | ifeq ($(GPU), 1)
100 | LDFLAGS+= -lstdc++
101 | OBJ+=convolutional_kernels.o deconvolutional_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 avgpool_layer_kernels.o
102 | endif
103 |
104 | EXECOBJ = $(addprefix $(OBJDIR), $(EXECOBJA))
105 | OBJS = $(addprefix $(OBJDIR), $(OBJ))
106 | DEPS = $(wildcard src/*.h) Makefile ./darknet/include/darknet.h
107 |
108 | all: obj $(SLIB_DIR) $(ALIB_DIR)
109 | #all: obj results $(SLIB) $(ALIB) $(EXEC)
110 |
111 | $(EXEC): $(EXECOBJ) $(ALIB)
112 | $(ROOT) $(CC) $(COMMON) $(CFLAGS) $^ -o $@ $(LDFLAGS) $(ALIB)
113 |
114 | $(ALIB_DIR): $(OBJS)
115 | $(ROOT) $(AR) $(ARFLAGS) $@ $^
116 |
117 | $(SLIB_DIR): $(OBJS)
118 | $(ROOT) $(CC) $(CFLAGS) -shared $^ -o $@ $(LDFLAGS)
119 |
120 | $(OBJDIR)%.o: %.cpp $(DEPS)
121 | $(ROOT) $(CPP) $(COMMON) $(CFLAGS) -std=c++17 -c $< -o $@
122 |
123 | $(OBJDIR)%.o: %.c $(DEPS)
124 | $(ROOT) $(CC) $(COMMON) $(CFLAGS) -c $< -o $@
125 |
126 | $(OBJDIR)%.o: %.cu $(DEPS)
127 | $(ROOT) $(NVCC) $(ARCH) $(COMMON) --compiler-options "$(CFLAGS)" -c $< -o $@
128 |
129 | obj:
130 | $(ROOT) mkdir -p obj
131 | backup:
132 | mkdir -p backup
133 | results:
134 | mkdir -p results
135 |
136 | .PHONY: clean
137 |
138 | clean_all: clean
139 | $(ROOT) rm -rf $(SLIB_DIR) $(ALIB_DIR)
140 |
141 | clean:
142 | $(ROOT) rm -rf obj
143 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # node-yolo
2 | This Node.js C++ addon allow you to use a state-of-the-art, real-time object detection system called [Yolo](https://pjreddie.com/darknet/yolo/).
3 |
This addon came out from a computer engineering final project, [VAPi](https://github.com/freakstatic/vapi-server), guided by [Patrício Domingues](https://scholar.google.com/citations?user=LPwSQ2EAAAAJ&hl=en) at [Institute Polytechnic of Leiria](https://www.ipleiria.pt/).
4 |
The version 1.x.x was developed by [Rúben Caceiro](https://github.com/rcaceiro) and [Ricardo Maltez](https://github.com/freakstatic) during the final project.
5 |
The version 2.x.x was sponsored by [Instituto de Telecomunicações](https://www.it.pt) developed by [Rúben Caceiro](https://github.com/rcaceiro) and guided by [Patrício Domingues](https://scholar.google.com/citations?user=LPwSQ2EAAAAJ&hl=en).
6 |
7 | ### Pre-requirements
8 | * C/C++ Compiler (tested with gcc & g++)
9 | * nVidia graphic card (Only if you want to use GPU acceleration):
10 | * [CUDA](https://developer.nvidia.com/cuda-zone)
11 | * [CuDNN](https://developer.nvidia.com/cudnn)
12 | * [Node.js](https://nodejs.org/en/) (tested on node.js>= 8)
13 | * [node-gyp](https://www.npmjs.com/package/node-gyp)
14 | * [OpenCV](https://opencv.org)
15 |
16 | **Note 1**: Before any update please see the [changelog](https://github.com/rcaceiro/node-yolo/blob/master/CHANGELOG.md).
17 | **Note 2**: The versions prior 2.0.0 of the module has the [ImageMagick](https://www.imagemagick.org) as a dependency, but with OpenCV we can archive the desired goal. And by this we remove one dependency of the project.
18 | ### Recommended* hardware requirements
19 | * Quad-core processor**
20 | * 10 GB to run node-yolo
21 | * At least 4GB of GPU memory***, if you want use GPU acceleration
22 | ### Minimum* hardware requirements
23 | * Dual-core processor**
24 | * 8 GB to run node-yolo
25 | * At least 4GB of GPU memory***, if you want use GPU acceleration
26 | ## Installation
27 | ```sh
28 | npm i @vapi/node-yolo --save
29 | ```
30 |
31 | ## How To Use
32 |
33 | ```javascript
34 | const Yolo = require('@vapi/node-yolo');
35 | const detector = new Yolo("darknet_configs", "cfg/coco.data", "cfg/yolov3.cfg", "yolov3.weights");
36 | detector.detectImage(path,threshold,frames_to_process)
37 | .then(detections =>
38 | {
39 | // here you receive the detections
40 | })
41 | .catch(error =>
42 | {
43 | // here you can handle the errors. Ex: Out of memory
44 | });
45 |
46 | detector.detectVideo(path,threshold,frames_to_process)
47 | .then(detections =>
48 | {
49 | // here you receive the detections
50 | })
51 | .catch(error =>
52 | {
53 | // here you can handle the errors. Ex: Out of memory
54 | });
55 | ```
56 | **path**, required, represents the path to the file
57 |
58 | **threshold**, not required, default behaviour is 0.5, represents the threshold to yolo filter the detections
59 |
60 | **frames_to_process**, not required, default behaviour is 1/1, represents the number of frames that developer wants to process, this means 1/3 process 1 frame for each 3.
61 |
62 | **darknet_configs** is a folder where you should put the Yolo [weights](https://pjreddie.com/darknet/yolo/), [cfg](https://github.com/pjreddie/darknet/tree/master/cfg) and [data files](https://github.com/pjreddie/darknet/tree/master/data).
63 | You need to create two folder, cfg and data and put the files for each one. Like this:
64 |
65 | .
66 | ├── darknet_configs # The folder for the Yolo weight, cfg and data files
67 | │ ├── cfg # cfg folder
68 | | |── coco.data
69 | | |── yolov3.cfg
70 | │ ├── data # data folder
71 | | | |── coco.names
72 | │ └── yolov3.weights # YoloV3 weights file
73 | └── ...
74 |
75 | **Note 1**: Our suggestion for better accuracy use [coco.data](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/coco.data), [coco.names](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/coco.names), [yolov3-spp.cfg](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3-spp.cfg) and [yolov3-spp.weights](https://pjreddie.com/media/files/yolov3-spp.weights).
76 |
**Note 2**: Our suggestion for faster detection use [coco.data](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/coco.data), [coco.names](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/coco.names), [yolov3-tiny.cfg](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3-tiny.cfg) and [yolov3-tiny.weights](https://pjreddie.com/media/files/yolov3-tiny.weights).
77 |
**Note 3**: Our suggestion for best of two worlds use [coco.data](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/coco.data), [coco.names](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/coco.names), [yolov3.cfg](https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov3.cfg) and [yolov3.weights](https://pjreddie.com/media/files/yolov3.weights).
78 |
79 | #### video detection object
80 | | **Field** | **Type** | **Description**
81 | |:----------|:---------|:-----------------------------------------------------
82 | | `frame` | `long/int64` | number of the frame
83 | | `millisecond` | `double` | the millisecond that frame appear on video
84 | | `timeSpentForClassification` | `double` | time used to classifies one frame
85 | | `detections` | `array` | array of `detection` object, containing all detections
86 |
87 | #### image detection object
88 | | **Field** | **Type** | **Description**
89 | |:----------|:---------|:-----------------------------------------------------
90 | | `timeSpentForClassification` | `double` | time used to classifies one image
91 | | `detections` | `array` | array of `detection` object, containing all detections
92 |
93 | #### detection object
94 | | **Field** | **Type** | **Description**
95 | |:----------|:---------|:-----------------------------------------------------
96 | | `className` | `string` | name of the class of the object detected
97 | | `probability` | `double` | the probability that this className is correct
98 | | `box` | `box` | object that contains box info of the object
99 |
100 | #### box object
101 | | **Field** | **Type** | **Description**
102 | |:----------|:---------|:-----------------------------------------------------
103 | | `x` | `double` | x coordinate in pixels of the picture
104 | | `y` | `double` | y coordinate in pixels of the picture
105 | | `w` | `double` | width from x point in pixels
106 | | `h` | `double` | height from y point in pixels
107 |
108 | \* To get that metrics we calculate the usage for video with 3 hours at 60fps.
109 |
\**If you do not use gpu, may should consider a processor with higher number of cores.
110 |
\***The weaker graphics card used was a nVidia GTX960M
111 |
--------------------------------------------------------------------------------
/binding.gyp:
--------------------------------------------------------------------------------
1 | {
2 | "variables":{
3 | "with_openmp%":"=9"
33 | },
34 | "os":[
35 | "darwin",
36 | "linux"
37 | ],
38 | "cpu":[
39 | "x64"
40 | ],
41 | "author":"Rúben Caceiro & Ricardo Maltez ",
42 | "license":"MIT"
43 | }
44 |
--------------------------------------------------------------------------------
/src/module.cpp:
--------------------------------------------------------------------------------
1 | #include "module.h"
2 | #include "napi_yolo_errors.h"
3 | #include
4 |
5 | napi_status get_string_value(napi_env env, napi_value args[], size_t index, char **value, size_t value_size)
6 | {
7 | napi_status status;
8 | napi_valuetype value_type;
9 | size_t length=0;
10 | status=napi_typeof(env, args[index], &value_type);
11 | if(status != napi_ok)
12 | {
13 | return napi_invalid_arg;
14 | }
15 |
16 | if(value_type != napi_string)
17 | {
18 | return napi_string_expected;
19 | }
20 |
21 | status=napi_get_value_string_utf8(env, args[index], *value, value_size, &length);
22 | assert(status == napi_ok);
23 | ++length;
24 | if(length>value_size)
25 | {
26 | (*value)=static_cast(realloc(*value, length));
27 | assert((*value) != nullptr);
28 | }
29 | status=napi_get_value_string_utf8(env, args[index], *value, length, &length);
30 | assert(status == napi_ok);
31 |
32 | return napi_ok;
33 | }
34 |
35 | napi_status get_double_value(napi_env env, napi_value args[], size_t index, double *value)
36 | {
37 | napi_status status;
38 | napi_valuetype value_type;
39 | status=napi_typeof(env, args[index], &value_type);
40 | if(status != napi_ok)
41 | {
42 | return napi_invalid_arg;
43 | }
44 |
45 | if(value_type != napi_number)
46 | {
47 | return napi_number_expected;
48 | }
49 |
50 | status=napi_get_value_double(env, args[index], value);
51 | assert(status == napi_ok);
52 | return napi_ok;
53 | }
54 |
55 | napi_status get_int_value(napi_env env, napi_value args[], size_t index, int *value)
56 | {
57 | napi_status status;
58 | napi_valuetype value_type;
59 | status=napi_typeof(env, args[index], &value_type);
60 | if(status != napi_ok)
61 | {
62 | return napi_invalid_arg;
63 | }
64 |
65 | if(value_type != napi_number)
66 | {
67 | return napi_number_expected;
68 | }
69 |
70 | status=napi_get_value_int32(env, args[index], value);
71 | assert(status == napi_ok);
72 | return napi_ok;
73 | }
74 |
75 | yolo_napi_status load_box_object(napi_env env, box img_box, napi_value jsbox)
76 | {
77 | napi_status status;
78 | napi_value x, y, w, h;
79 |
80 | status=napi_create_double(env, img_box.x, &x);
81 | if(status != napi_ok)
82 | {
83 | return yolo_napi_create_box_x_double_failed;
84 | }
85 | status=napi_set_named_property(env, jsbox, "x", x);
86 | if(status != napi_ok)
87 | {
88 | return yolo_napi_create_box_x_named_property_failed;
89 | }
90 |
91 | status=napi_create_double(env, img_box.y, &y);
92 | if(status != napi_ok)
93 | {
94 | return yolo_napi_create_box_y_double_failed;
95 | }
96 | status=napi_set_named_property(env, jsbox, "y", y);
97 | if(status != napi_ok)
98 | {
99 | return yolo_napi_create_box_y_named_property_failed;
100 | }
101 |
102 | status=napi_create_double(env, img_box.w, &w);
103 | if(status != napi_ok)
104 | {
105 | return yolo_napi_create_box_w_double_failed;
106 | }
107 | status=napi_set_named_property(env, jsbox, "w", w);
108 | if(status != napi_ok)
109 | {
110 | return yolo_napi_create_box_w_named_property_failed;
111 | }
112 |
113 | status=napi_create_double(env, img_box.h, &h);
114 | if(status != napi_ok)
115 | {
116 | return yolo_napi_create_box_h_double_failed;
117 | }
118 | status=napi_set_named_property(env, jsbox, "h", h);
119 | if(status != napi_ok)
120 | {
121 | return yolo_napi_create_box_h_named_property_failed;
122 | }
123 | return yolo_napi_ok;
124 | }
125 |
126 | yolo_napi_status load_detections(napi_env env, yolo_detection_image *img_detections, napi_value jsarray)
127 | {
128 | napi_status status;
129 | napi_value jsobj, box_object, classes, prob;
130 | detect det;
131 | for(size_t i=0; inum_boxes; ++i)
132 | {
133 | det=img_detections->detection[i];
134 | status=napi_create_object(env, &jsobj);
135 | if(status != napi_ok)
136 | {
137 | return yolo_napi_create_object_failed;
138 | }
139 |
140 | status=napi_create_string_utf8(env, det.class_name, strlen(det.class_name), &classes);
141 | if(status != napi_ok)
142 | {
143 | return yolo_napi_create_class_name_string_failed;
144 | }
145 | status=napi_set_named_property(env, jsobj, "className", classes);
146 | if(status != napi_ok)
147 | {
148 | return yolo_napi_set_class_name_property_failed;
149 | }
150 |
151 | status=napi_create_double(env, det.probability, &prob);
152 | if(status != napi_ok)
153 | {
154 | return yolo_napi_create_probability_double_failed;
155 | }
156 | status=napi_set_named_property(env, jsobj, "probability", prob);
157 | if(status != napi_ok)
158 | {
159 | return yolo_napi_set_probability_property_failed;
160 | }
161 |
162 | status=napi_create_object(env, &box_object);
163 | if(status != napi_ok)
164 | {
165 | return yolo_napi_create_box_object_failed;
166 | }
167 | status=napi_set_named_property(env, jsobj, "box", box_object);
168 | if(status != napi_ok)
169 | {
170 | return yolo_napi_set_box_property_failed;
171 | }
172 |
173 | if(load_box_object(env, det.bbox, box_object) == yolo_napi_ok)
174 | {
175 | status=napi_set_element(env, jsarray, (uint32_t)i, jsobj);
176 | if(status != napi_ok)
177 | {
178 | return yolo_napi_set_object_to_array_failed;
179 | }
180 | }
181 | }
182 | return yolo_napi_ok;
183 | }
184 |
185 | yolo_napi_status load_detection_object(napi_env env, yolo_detection_image *img_detections, napi_value object)
186 | {
187 | napi_value js_detections_array;
188 | napi_value js_time_spent_for_classification;
189 | yolo_napi_status yolo_stats;
190 |
191 | if(napi_create_double(env, img_detections->time_spent_for_classification, &js_time_spent_for_classification) != napi_ok)
192 | {
193 | return yolo_napi_create_object_time_spent_for_classification_double_failed;
194 | }
195 |
196 | if(napi_set_named_property(env, object, "timeSpentForClassification", js_time_spent_for_classification) != napi_ok)
197 | {
198 | return yolo_napi_create_object_time_spent_for_classification_named_property_failed;
199 | }
200 |
201 | if(napi_create_array_with_length(env, static_cast(img_detections->num_boxes), &js_detections_array) != napi_ok)
202 | {
203 | return yolo_napi_create_array_failed;
204 | }
205 |
206 | yolo_stats=load_detections(env, img_detections, js_detections_array);
207 |
208 | if(yolo_stats != yolo_napi_ok)
209 | {
210 | return yolo_stats;
211 | }
212 |
213 | if(napi_set_named_property(env, object, "detections", js_detections_array) != napi_ok)
214 | {
215 | return yolo_napi_create_object_time_spent_for_classification_named_property_failed;
216 | }
217 |
218 | return yolo_napi_ok;
219 | }
220 |
221 | yolo_napi_status load_video_detection_object(napi_env env, yolo_detection_video *video_detections, napi_value frames_array)
222 | {
223 | yolo_napi_status yolo_stats;
224 |
225 | for(size_t i=0; icount; ++i)
226 | {
227 | napi_value object;
228 | napi_value frame_id;
229 | napi_value milisecond;
230 |
231 | if(napi_create_object(env, &object) != napi_ok)
232 | {
233 | return yolo_napi_create_main_object_failed;
234 | }
235 |
236 | if(napi_create_int64(env, video_detections->frame_detections[i].frame, &frame_id) != napi_ok)
237 | {
238 | return yolo_napi_create_frame_failed;
239 | }
240 |
241 | if(napi_create_double(env, video_detections->frame_detections[i].milisecond, &milisecond) != napi_ok)
242 | {
243 | return yolo_napi_create_second_failed;
244 | }
245 |
246 | if(napi_set_named_property(env, object, "frame_number", frame_id) != napi_ok)
247 | {
248 | return yolo_napi_set_frame_to_object_failed;
249 | }
250 |
251 | if(napi_set_named_property(env, object, "milisecond", milisecond) != napi_ok)
252 | {
253 | return yolo_napi_set_second_to_object_failed;
254 | }
255 |
256 | yolo_stats=load_detection_object(env, &video_detections->frame_detections[i].detection_frame, object);
257 | if(yolo_stats != yolo_napi_ok)
258 | {
259 | return yolo_napi_create_main_object_failed;
260 | }
261 |
262 | if(napi_set_element(env, frames_array, static_cast(i), object) != napi_ok)
263 | {
264 | return yolo_napi_set_array_property_failed;
265 | }
266 | }
267 |
268 | return yolo_napi_ok;
269 | }
270 |
271 | void reject(napi_env env, yolo_napi_status yolo_stats, data_holder *holder)
272 | {
273 | napi_value error;
274 | yolo_napi_status_detailed status_detailed=yolo_napi_status_decode(yolo_stats, &holder->yolo_stats);
275 | if(napi_create_object(env, &error) == napi_ok)
276 | {
277 | napi_value string_error;
278 | if(napi_create_string_utf8(env, status_detailed.error_message, strlen(status_detailed.error_message), &string_error) == napi_ok)
279 | {
280 | napi_set_named_property(env, error, "errorMessage", string_error);
281 | }
282 | napi_value error_code;
283 | if(napi_create_int32(env, status_detailed.error_code, &error_code) == napi_ok)
284 | {
285 | napi_set_named_property(env, error, "errorCode", error_code);
286 | }
287 | napi_value error_prefix;
288 | if(napi_create_string_utf8(env, status_detailed.error_prefix, strlen(status_detailed.error_message), &error_prefix) == napi_ok)
289 | {
290 | napi_set_named_property(env, error, "errorPrefix", error_prefix);
291 | }
292 | }
293 | napi_reject_deferred(env, holder->deferred, error);
294 | }
295 |
296 | void release_async_work(napi_env env, data_holder *holder)
297 | {
298 | napi_async_work work=holder->work;
299 |
300 | free(holder->image_path);
301 | free(holder);
302 |
303 | napi_delete_async_work(env, work);
304 | }
305 |
306 | void complete_async_detect(napi_env env, napi_status status, void *data)
307 | {
308 | auto *holder=static_cast(data);
309 | napi_value return_value;
310 | yolo_napi_status yolo_stats;
311 |
312 | if(holder->yolo_stats != yolo_ok)
313 | {
314 | reject(env, yolo_napi_error_from_libyolo, holder);
315 | release_async_work(env, holder);
316 | return;
317 | }
318 |
319 | if(status != napi_ok)
320 | {
321 | reject(env, yolo_napi_unknow_error, holder);
322 | release_async_work(env, holder);
323 | return;
324 | }
325 |
326 | if(holder->img_detection == nullptr && holder->video_detection == nullptr)
327 | {
328 | reject(env, yolo_napi_unknow_error, holder);
329 | release_async_work(env, holder);
330 | return;
331 | }
332 |
333 | if(holder->img_detection != nullptr)
334 | {
335 | if(napi_create_object(env, &return_value) != napi_ok)
336 | {
337 | reject(env, yolo_napi_create_main_object_failed, holder);
338 | }
339 | else
340 | {
341 | yolo_stats=load_detection_object(env, holder->img_detection, return_value);
342 |
343 | if(yolo_stats == yolo_napi_ok)
344 | {
345 | napi_resolve_deferred(env, holder->deferred, return_value);
346 | }
347 | else
348 | {
349 | reject(env, yolo_stats, holder);
350 | }
351 | }
352 | yolo_detection_image_free(&holder->img_detection);
353 | }
354 | else
355 | {
356 | if(napi_create_array_with_length(env, holder->video_detection->count, &return_value) != napi_ok)
357 | {
358 | reject(env, yolo_napi_create_main_object_failed, holder);
359 | }
360 | else
361 | {
362 | yolo_stats=load_video_detection_object(env, holder->video_detection, return_value);
363 |
364 | if(yolo_stats == yolo_napi_ok)
365 | {
366 | napi_resolve_deferred(env, holder->deferred, return_value);
367 | }
368 | else
369 | {
370 | reject(env, yolo_stats, holder);
371 | }
372 | }
373 | yolo_detection_video_free(&holder->video_detection);
374 | }
375 |
376 | release_async_work(env, holder);
377 | }
378 |
379 | void async_detect_image(napi_env env, void *data)
380 | {
381 | (void)env;
382 | auto *holder=static_cast(data);
383 | if(holder->yolo->created)
384 | {
385 | holder->yolo->mutex_lock();
386 | holder->yolo_stats=yolo_detect_image(holder->yolo->yolo, &holder->img_detection, holder->image_path, holder->thresh_value);
387 | holder->yolo->mutex_unlock();
388 | }
389 | else
390 | {
391 | holder->yolo_stats=yolo_instanciation;
392 | }
393 | }
394 |
395 | void async_detect_video(napi_env env, void *data)
396 | {
397 | (void)env;
398 | auto *holder=static_cast(data);
399 | if(holder->yolo->created)
400 | {
401 | holder->yolo->mutex_lock();
402 | holder->yolo_stats=yolo_detect_video(holder->yolo->yolo, &holder->video_detection, holder->image_path, holder->thresh_value, holder->fraction_frames_to_process);
403 | holder->yolo->mutex_unlock();
404 | }
405 | else
406 | {
407 | holder->yolo_stats=yolo_instanciation;
408 | }
409 | }
410 |
411 | napi_ref Yolo::constructor;
412 |
413 | Yolo::Yolo(char *working_directory, char *datacfg, char *cfgfile, char *weightfile) : env_(nullptr), wrapper_(nullptr)
414 | {
415 | this->yolo=nullptr;
416 | yolo_status yolo_stats=yolo_init(&this->yolo, working_directory, datacfg, cfgfile, weightfile);
417 | if(yolo_stats != yolo_ok)
418 | {
419 | this->created=false;
420 | return;
421 | }
422 | pthread_mutex_init(&this->mutex, nullptr);
423 | this->created=true;
424 | }
425 |
426 | Yolo::~Yolo()
427 | {
428 | pthread_mutex_destroy(&this->mutex);
429 | yolo_cleanup(this->yolo);
430 | napi_delete_reference(env_, wrapper_);
431 | }
432 |
433 | void Yolo::Destructor(napi_env env, void *nativeObject, void * /*finalize_hint*/)
434 | {
435 | (void)env;
436 | reinterpret_cast(nativeObject)->~Yolo();
437 | }
438 |
439 | napi_value Yolo::Init(napi_env env, napi_value exports)
440 | {
441 | napi_status status;
442 | napi_property_descriptor properties[]={{"detectImage\0", nullptr, Yolo::DetectImage, nullptr, nullptr, nullptr, napi_default, nullptr},
443 | {"detectVideo\0", nullptr, Yolo::DetectVideo, nullptr, nullptr, nullptr, napi_default, nullptr}};
444 |
445 | napi_value cons;
446 | status=napi_define_class(env, "Yolo\0", NAPI_AUTO_LENGTH, Yolo::New, nullptr, 2, properties, &cons);
447 | assert(status == napi_ok);
448 |
449 | status=napi_create_reference(env, cons, 1, &Yolo::constructor);
450 | assert(status == napi_ok);
451 |
452 | status=napi_set_named_property(env, exports, "Yolo", cons);
453 | assert(status == napi_ok);
454 | return exports;
455 | }
456 |
457 | napi_value Yolo::New(napi_env env, napi_callback_info info)
458 | {
459 | napi_status status;
460 | napi_value target;
461 | status=napi_get_new_target(env, info, &target);
462 | assert(status == napi_ok);
463 | bool is_constructor=target != nullptr;
464 |
465 | if(is_constructor)
466 | {
467 | // Invoked as constructor: `new MyObject(...)`
468 | size_t argc=4;
469 | napi_value args[4];
470 | napi_value jsthis;
471 | status=napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr);
472 | assert(status == napi_ok);
473 | assert(argc>=4);
474 | char *darknet_path=nullptr;
475 | char *datacfg=nullptr;
476 | char *cfgfile=nullptr;
477 | char *weightfile=nullptr;
478 |
479 | get_string_value(env, args, 0, &darknet_path, 0);
480 | get_string_value(env, args, 1, &datacfg, 0);
481 | get_string_value(env, args, 2, &cfgfile, 0);
482 | get_string_value(env, args, 3, &weightfile, 0);
483 |
484 | auto obj=new Yolo(darknet_path, datacfg, cfgfile, weightfile);
485 | obj->env_=env;
486 | status=napi_wrap(env, jsthis, reinterpret_cast(obj), Yolo::Destructor, nullptr, &obj->wrapper_);
487 | assert(status == napi_ok);
488 |
489 | return jsthis;
490 | }
491 | else
492 | {
493 | // Invoked as plain function `MyObject(...)`, turn into construct call.
494 | size_t argc_=4;
495 | napi_value args[4];
496 | status=napi_get_cb_info(env, info, &argc_, args, nullptr, nullptr);
497 | assert(status == napi_ok);
498 |
499 | const size_t argc=4;
500 | napi_value argv[4]={args[0], args[1], args[2], args[3]};
501 |
502 | napi_value cons;
503 | status=napi_get_reference_value(env, Yolo::constructor, &cons);
504 | assert(status == napi_ok);
505 |
506 | napi_value instance;
507 | status=napi_new_instance(env, cons, argc, argv, &instance);
508 | assert(status == napi_ok);
509 |
510 | return instance;
511 | }
512 | }
513 |
514 | napi_value Yolo::DetectImage(napi_env env, napi_callback_info info)
515 | {
516 | napi_status status;
517 | napi_deferred deferred;
518 | napi_value promise;
519 | napi_value jsthis;
520 | size_t argc=2;
521 | napi_value args[2];
522 |
523 | status=napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr);
524 | if(status != napi_ok)
525 | {
526 | napi_throw_error(env, "00", "Cannot get arguments");
527 | return nullptr;
528 | }
529 |
530 | if(argc<2)
531 | {
532 | napi_throw_error(env, "01", "You have to pass the path to image and thresh value as parameters");
533 | return nullptr;
534 | }
535 |
536 | char *image_path=nullptr;
537 | status=get_string_value(env, args, 0, &image_path, 0);
538 | assert(status == napi_ok);
539 | if(image_path == nullptr)
540 | {
541 | napi_throw_error(env, "02", "Cannot get image path");
542 | return nullptr;
543 | }
544 |
545 | double thresh=0.5;
546 | status=get_double_value(env, args, 1, &thresh);
547 | if(status != napi_ok)
548 | {
549 | napi_throw_error(env, "04", "Cannot get thresh value");
550 | return nullptr;
551 | }
552 |
553 | void *obj=nullptr;
554 | status=napi_unwrap(env, jsthis, &obj);
555 | assert(status == napi_ok);
556 | auto *yolo_obj=static_cast(obj);
557 |
558 | napi_value resource_name;
559 | napi_value resource;
560 | status=napi_create_string_utf8(env, "nodeyolo.detect_image", 18, &resource_name);
561 | assert(status == napi_ok);
562 | status=napi_create_object(env, &resource);
563 | assert(status == napi_ok);
564 |
565 | auto *holder=static_cast(calloc(1, sizeof(data_holder)));
566 | if(holder == nullptr)
567 | {
568 | napi_throw_error(env, "03", "Cannot allocate a struct in memory");
569 | return nullptr;
570 | }
571 |
572 | status=napi_create_promise(env, &deferred, &promise);
573 | assert(status == napi_ok);
574 |
575 | holder->deferred=deferred;
576 | holder->image_path=image_path;
577 | holder->thresh_value=(float)thresh;
578 | holder->yolo=yolo_obj;
579 | holder->resource=resource;
580 |
581 | status=napi_create_async_work(env, resource, resource_name, async_detect_image, complete_async_detect, holder, &holder->work);
582 | assert(status == napi_ok);
583 | status=napi_queue_async_work(env, holder->work);
584 | assert(status == napi_ok);
585 |
586 | return promise;
587 | }
588 |
589 | napi_value Yolo::DetectVideo(napi_env env, napi_callback_info info)
590 | {
591 | napi_status status;
592 | napi_deferred deferred;
593 | napi_value promise;
594 | napi_value jsthis;
595 | size_t argc=3;
596 | napi_value args[3];
597 |
598 | status=napi_get_cb_info(env, info, &argc, args, &jsthis, nullptr);
599 | if(status != napi_ok)
600 | {
601 | napi_throw_error(env, "00", "Cannot get arguments");
602 | return nullptr;
603 | }
604 |
605 | if(argc<1)
606 | {
607 | napi_throw_error(env, "01", "You have to pass the path to image as parameters");
608 | return nullptr;
609 | }
610 |
611 | char *video_path=nullptr;
612 | status=get_string_value(env, args, 0, &video_path, 0);
613 | if(status != napi_ok || video_path == nullptr)
614 | {
615 | napi_throw_error(env, "02", "Cannot get video path");
616 | return nullptr;
617 | }
618 |
619 | double thresh=0.5;
620 | if(argc>1)
621 | {
622 | status=get_double_value(env, args, 1, &thresh);
623 | if(status != napi_ok)
624 | {
625 | napi_throw_error(env, "04", "Cannot get thresh value");
626 | return nullptr;
627 | }
628 | }
629 |
630 | double fraction_frames_to_process=1;
631 | if(argc>2)
632 | {
633 | status=get_double_value(env, args, 2, &fraction_frames_to_process);
634 | if(status != napi_ok)
635 | {
636 | napi_throw_error(env, "05", "Cannot get fraction to process frames value");
637 | return nullptr;
638 | }
639 | }
640 |
641 | void *obj=nullptr;
642 | status=napi_unwrap(env, jsthis, &obj);
643 | assert(status == napi_ok);
644 | auto *yolo_obj=static_cast(obj);
645 |
646 | napi_value resource_name;
647 | napi_value resource;
648 | status=napi_create_string_utf8(env, "nodeyolo.detect_video", 18, &resource_name);
649 | assert(status == napi_ok);
650 | status=napi_create_object(env, &resource);
651 | assert(status == napi_ok);
652 |
653 | auto *holder=static_cast(calloc(1, sizeof(data_holder)));
654 | if(holder == nullptr)
655 | {
656 | napi_throw_error(env, "03", "Cannot allocate a struct in memory");
657 | return nullptr;
658 | }
659 |
660 | status=napi_create_promise(env, &deferred, &promise);
661 | if(status != napi_ok)
662 | {
663 | napi_throw_error(env, "06", "Cannot create promise");
664 | return nullptr;
665 | }
666 |
667 | holder->deferred=deferred;
668 | holder->image_path=video_path;
669 | holder->thresh_value=(float)thresh;
670 | holder->yolo=yolo_obj;
671 | holder->resource=resource;
672 | holder->fraction_frames_to_process=fraction_frames_to_process;
673 |
674 | status=napi_create_async_work(env, resource, resource_name, async_detect_video, complete_async_detect, holder, &holder->work);
675 | assert(status == napi_ok);
676 | status=napi_queue_async_work(env, holder->work);
677 | assert(status == napi_ok);
678 |
679 | return promise;
680 | }
681 |
682 | void Yolo::mutex_lock()
683 | {
684 | pthread_mutex_lock(&this->mutex);
685 | }
686 |
687 | void Yolo::mutex_unlock()
688 | {
689 | pthread_mutex_unlock(&this->mutex);
690 | }
691 |
692 | NAPI_MODULE(NodeYolo, Yolo::Init);
--------------------------------------------------------------------------------
/src/module.h:
--------------------------------------------------------------------------------
1 | #ifndef NODE_YOLO_MODULE_H
2 | #define NODE_YOLO_MODULE_H
3 |
4 | #include
5 | #include
6 |
7 | class Yolo
8 | {
9 | public:
10 | static napi_value Init(napi_env env, napi_value exports);
11 |
12 | static void Destructor(napi_env env, void *nativeObject, void *finalize_hint);
13 |
14 | void mutex_lock();
15 | void mutex_unlock();
16 | yolo_object *yolo;
17 | bool created;
18 | private:
19 | explicit Yolo(char *working_directory, char *datacfg, char *cfgfile, char *weightfile);
20 | ~Yolo();
21 |
22 | static napi_value New(napi_env env, napi_callback_info info);
23 |
24 | static napi_value DetectImage(napi_env env, napi_callback_info info);
25 | static napi_value DetectVideo(napi_env env, napi_callback_info info);
26 |
27 | static napi_ref constructor;
28 |
29 | pthread_mutex_t mutex;
30 | napi_env env_;
31 | napi_ref wrapper_;
32 | };
33 |
34 | typedef struct
35 | {
36 | Yolo *yolo;
37 | char *image_path;
38 | float thresh_value;
39 | double fraction_frames_to_process;
40 | napi_deferred deferred;
41 | napi_async_work work;
42 | napi_value resource;
43 | yolo_detection_image *img_detection;
44 | yolo_detection_video *video_detection;
45 | yolo_status yolo_stats;
46 | }data_holder;
47 |
48 | #endif
--------------------------------------------------------------------------------
/src/napi_yolo_errors.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include "napi_yolo_errors.h"
3 |
4 | void yolo_napi_fill_error_message(yolo_napi_status status, yolo_napi_status_detailed *status_detailed)
5 | {
6 | switch(status)
7 | {
8 | case yolo_napi_create_object_time_spent_for_classification_double_failed:
9 | status_detailed->error_message="image file is corrupted";
10 | break;
11 | case yolo_napi_create_object_time_spent_for_classification_named_property_failed:
12 | status_detailed->error_message="image file is corrupted";
13 | break;
14 | case yolo_napi_set_array_property_failed:
15 | status_detailed->error_message="image file is corrupted";
16 | break;
17 | case yolo_napi_create_main_object_failed:
18 | status_detailed->error_message="image file is corrupted";
19 | break;
20 | default:
21 | status_detailed->error_message="Unknow error";
22 | }
23 | }
24 |
25 | yolo_napi_status_detailed yolo_napi_status_decode(yolo_napi_status status, yolo_status *status2)
26 | {
27 | yolo_napi_status_detailed status_detailed;
28 | if(status == yolo_napi_error_from_libyolo)
29 | {
30 | if(status2 != NULL)
31 | {
32 | return yolo_napi_error_wrap(*status2);
33 | }
34 | else
35 | {
36 | status=yolo_napi_unknow_error;
37 | }
38 | }
39 | status_detailed.error_code=status;
40 | status_detailed.error_prefix="yolo_napi";
41 | yolo_napi_fill_error_message(status, &status_detailed);
42 | return status_detailed;
43 | }
44 |
45 | yolo_napi_status_detailed yolo_napi_error_wrap(yolo_status status)
46 | {
47 | yolo_napi_status_detailed napi_status_detailed;
48 | yolo_status_detailed status_detailed=yolo_status_decode(status);
49 | napi_status_detailed.error_code=status_detailed.error_code;
50 | napi_status_detailed.error_message=status_detailed.error_message;
51 | napi_status_detailed.error_prefix="yolo";
52 | return napi_status_detailed;
53 | }
--------------------------------------------------------------------------------
/src/napi_yolo_errors.h:
--------------------------------------------------------------------------------
1 | #ifndef NODE_YOLO_NAPI_YOLO_ERRORS_H
2 | #define NODE_YOLO_NAPI_YOLO_ERRORS_H
3 |
4 | #include "../yolo/src/yolo_error.h"
5 |
6 | #ifdef __cplusplus
7 | extern "C" {
8 | #endif
9 |
10 | typedef struct
11 | {
12 | int error_code;
13 | char *error_prefix;
14 | char *error_message;
15 | }yolo_napi_status_detailed;
16 |
17 | typedef enum
18 | {
19 | yolo_napi_ok,
20 | yolo_napi_create_main_object_failed,
21 | yolo_napi_create_array_failed,
22 | yolo_napi_set_array_property_failed,
23 | yolo_napi_create_object_failed,
24 | yolo_napi_set_object_to_array_failed,
25 | yolo_napi_create_class_name_string_failed,
26 | yolo_napi_set_class_name_property_failed,
27 | yolo_napi_create_probability_double_failed,
28 | yolo_napi_set_probability_property_failed,
29 | yolo_napi_create_box_object_failed,
30 | yolo_napi_set_box_property_failed,
31 | yolo_napi_create_frame_failed,
32 | yolo_napi_set_frame_to_object_failed,
33 | yolo_napi_create_second_failed,
34 | yolo_napi_set_second_to_object_failed,
35 |
36 | yolo_napi_create_box_x_double_failed,
37 | yolo_napi_create_box_x_named_property_failed,
38 | yolo_napi_create_box_y_double_failed,
39 | yolo_napi_create_box_y_named_property_failed,
40 | yolo_napi_create_box_w_double_failed,
41 | yolo_napi_create_box_w_named_property_failed,
42 | yolo_napi_create_box_h_double_failed,
43 | yolo_napi_create_box_h_named_property_failed,
44 | yolo_napi_create_object_time_spent_for_classification_double_failed,
45 | yolo_napi_create_object_time_spent_for_classification_named_property_failed,
46 |
47 | yolo_napi_error_from_libyolo,
48 | yolo_napi_unknow_error
49 | }yolo_napi_status;
50 |
51 | yolo_napi_status_detailed yolo_napi_status_decode(yolo_napi_status status, yolo_status *status2);
52 |
53 | yolo_napi_status_detailed yolo_napi_error_wrap(yolo_status status);
54 |
55 | #ifdef __cplusplus
56 | }
57 | #endif
58 |
59 | #endif //NODE_YOLO_NAPI_YOLO_ERRORS_H
--------------------------------------------------------------------------------
/util/has_lib.js:
--------------------------------------------------------------------------------
1 | /**
2 | taken from https://github.com/Automattic/node-canvas/blob/master/util/has_lib.js
3 | License
4 |
5 | (The MIT License)
6 |
7 | Copyright (c) 2010 LearnBoost, and contributors
8 |
9 | Copyright (c) 2014 Automattic, Inc and contributors
10 |
11 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
16 | */
17 | var query = process.argv[2]
18 | var fs = require('fs')
19 | var childProcess = require('child_process')
20 |
21 | var SYSTEM_PATHS = [
22 | '/lib',
23 | '/usr/lib',
24 | '/usr/local/lib',
25 | '/opt/local/lib',
26 | '/usr/lib/x86_64-linux-gnu',
27 | '/usr/lib/i386-linux-gnu'
28 | ]
29 |
30 | /**
31 | * Checks for lib using ldconfig if present, or searching SYSTEM_PATHS
32 | * otherwise.
33 | * @param String library name, e.g. 'jpeg' in 'libjpeg64.so' (see first line)
34 | * @return Boolean exists
35 | */
36 | function hasSystemLib(lib) {
37 | var libName = 'lib' + lib + '.+(so|dylib)'
38 | var libNameRegex = new RegExp(libName)
39 |
40 | // Try using ldconfig on linux systems
41 | if (hasLdconfig()) {
42 | try {
43 | if (childProcess.execSync('ldconfig -p 2>/dev/null | grep -E "' + libName + '"').length) {
44 | return true
45 | }
46 | } catch (err) {
47 | // noop -- proceed to other search methods
48 | }
49 | }
50 |
51 | // Try checking common library locations
52 | return SYSTEM_PATHS.some(function (systemPath) {
53 | try {
54 | var dirListing = fs.readdirSync(systemPath)
55 | return dirListing.some(function (file) {
56 | return libNameRegex.test(file)
57 | })
58 | } catch (err) {
59 | return false
60 | }
61 | })
62 | }
63 |
64 | /**
65 | * Checks for ldconfig on the path and /sbin
66 | * @return Boolean exists
67 | */
68 | function hasLdconfig() {
69 | try {
70 | if (os.platform()=='win32') {
71 | return false
72 | }
73 | // Add /sbin to path as ldconfig is located there on some systems -- e.g.
74 | // Debian (and it can still be used by unprivileged users):
75 | childProcess.execSync('export PATH="$PATH:/sbin"')
76 | process.env.PATH = '...'
77 | // execSync throws on nonzero exit
78 | childProcess.execSync('hash ldconfig 2>/dev/null')
79 | return true
80 | } catch (err) {
81 | return false
82 | }
83 | }
84 |
85 | /**
86 | * Check if cuda is present
87 | * @return Boolean exists
88 | */
89 | function hasCuda() {
90 | try {
91 | return childProcess.execSync('[ -d /usr/local/cuda ] && echo "Yes"').length > 0;
92 | } catch (err) {
93 | return false
94 | }
95 | }
96 |
97 | function main(query) {
98 | switch (query) {
99 | case 'openmp':
100 | return hasSystemLib("omp")
101 | case 'opencv':
102 | return hasSystemLib(query)
103 | case 'cuda':
104 | return hasCuda();
105 | default:
106 | throw new Error('Unknown library: ' + query)
107 | }
108 | }
109 |
110 | process.stdout.write(main(query).toString())
111 |
--------------------------------------------------------------------------------
/yolo/src/libyolo.cpp:
--------------------------------------------------------------------------------
1 | #include "libyolo.h"
2 | #include "private_structs.h"
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 | void fill_detect(yolo_object *yolo, detection *network_detection, int network_detection_index, detect *yolo_detect)
12 | {
13 | size_t strlength=strlen(yolo->names[network_detection_index]);
14 | yolo->names[network_detection_index][strlength]='\0';
15 | yolo_detect->class_name=(char *)calloc(strlength+1, sizeof(char));
16 | strcpy(yolo_detect->class_name, yolo->names[network_detection_index]);
17 | yolo_detect->probability=network_detection->prob[network_detection_index]*100;
18 | yolo_detect->bbox=network_detection->bbox;
19 | box *bbox=&yolo_detect->bbox;
20 | bbox->x=bbox->x-(bbox->w/2);
21 | bbox->y=bbox->y-(bbox->h/2);
22 | if(bbox->x<0)
23 | {
24 | bbox->x=0;
25 | }
26 | if(bbox->y<0)
27 | {
28 | bbox->y=0;
29 | }
30 | }
31 |
32 | yolo_status fill_detection(yolo_object *yolo, detection *dets, yolo_detection_image *yolo_detect, float time_spent_for_classification, int nboxes, float thresh)
33 | {
34 | yolo_detect->time_spent_for_classification=time_spent_for_classification;
35 | yolo_detect->num_boxes=0;
36 | int class_index;
37 | detection *det;
38 |
39 | for(int i=0; i=thresh)
46 | {
47 | if(det == nullptr || (dets[i].prob[j]>det->prob[class_index]))
48 | {
49 | class_index=j;
50 | det=dets+i;
51 | }
52 | }
53 | }
54 | if(class_index>-1 && det != nullptr)
55 | {
56 | void *temp_pointer=realloc(yolo_detect->detection, sizeof(detect)*(yolo_detect->num_boxes+1));
57 | if(temp_pointer == nullptr)
58 | {
59 | return yolo_cannot_realloc_detect;
60 | }
61 | yolo_detect->detection=(detect *)temp_pointer;
62 | fill_detect(yolo, det, class_index, yolo_detect->detection+yolo_detect->num_boxes);
63 | yolo_detect->num_boxes++;
64 | }
65 | }
66 |
67 | return yolo_ok;
68 | }
69 |
70 | yolo_status parse_detections_image(yolo_object *yolo, detection *dets, yolo_detection_image **yolo_detect, float time_spent_for_classification, int nboxes, float thresh)
71 | {
72 | if((*yolo_detect) == nullptr)
73 | {
74 | (*yolo_detect)=(yolo_detection_image *)calloc(1, sizeof(yolo_detection_image));
75 | if((*yolo_detect) == nullptr)
76 | {
77 | return yolo_cannot_alloc_yolo_detection;
78 | }
79 | }
80 |
81 | return fill_detection(yolo, dets, (*yolo_detect), time_spent_for_classification, nboxes, thresh);
82 | }
83 |
84 | yolo_status parse_detections_video(yolo_object *yolo, detection *dets, yolo_detection_video **yolo_detect, float time_spent_for_classification, long frame_id, double milisecond, int nboxes, float thresh)
85 | {
86 | if((*yolo_detect) == nullptr)
87 | {
88 | (*yolo_detect)=(yolo_detection_video *)calloc(1, sizeof(yolo_detection_video *));
89 | if((*yolo_detect) == nullptr)
90 | {
91 | return yolo_cannot_alloc_yolo_detection;
92 | }
93 | }
94 | yolo_detection_video *video_detection=*yolo_detect;
95 | auto *temp=(yolo_detection_frame *)realloc(video_detection->frame_detections, sizeof(yolo_detection_frame)*(video_detection->count+1));
96 | if(temp == nullptr)
97 | {
98 | return yolo_cannot_alloc_yolo_detection;
99 | }
100 | memset(temp+video_detection->count, 0, sizeof(yolo_detection_frame));
101 | video_detection->frame_detections=temp;
102 | video_detection->frame_detections[video_detection->count].frame=frame_id;
103 | video_detection->frame_detections[video_detection->count].milisecond=milisecond;
104 | yolo_status yolo_stats=fill_detection(yolo, dets, &video_detection->frame_detections[video_detection->count].detection_frame, time_spent_for_classification, nboxes, thresh);
105 | ++video_detection->count;
106 | return yolo_stats;
107 | }
108 |
109 | image libyolo_ipl_to_image(IplImage *src)
110 | {
111 | int h=src->height;
112 | int w=src->width;
113 | int c=src->nChannels;
114 | image im=make_image(w, h, c);
115 | auto *data=(unsigned char *)src->imageData;
116 | int step=src->widthStep;
117 | int i, j, k;
118 |
119 | for(i=0; imutex))
164 | {
165 | continue;
166 | }
167 |
168 | if(!thread_data->video->isOpened())
169 | {
170 | thread_data->image_queue->common->end=true;
171 | pthread_mutex_unlock(&thread_data->mutex);
172 | break;
173 | }
174 |
175 | if(!thread_data->video->grab())
176 | {
177 | thread_data->image_queue->common->end=true;
178 | pthread_mutex_unlock(&thread_data->mutex);
179 | break;
180 | }
181 |
182 | if(!thread_data->number_frames_to_drop)
183 | {
184 | if(!thread_data->video->retrieve(mat))
185 | {
186 | thread_data->image_queue->common->end=true;
187 | pthread_mutex_unlock(&thread_data->mutex);
188 | break;
189 | }
190 | thread_data->number_frames_to_drop=thread_data->number_frames_to_process_simultaneously;
191 | queue_image.milisecond=thread_data->video->get(CV_CAP_PROP_POS_MSEC);
192 | queue_image.frame_number=(long)thread_data->video->get(CV_CAP_PROP_POS_FRAMES);
193 | }
194 | else
195 | {
196 | skip=true;
197 | --thread_data->number_frames_to_drop;
198 | }
199 | pthread_mutex_unlock(&thread_data->mutex);
200 |
201 | if(skip)
202 | {
203 | continue;
204 | }
205 |
206 | if(mat.empty())
207 | {
208 | thread_data->image_queue->common->end=true;
209 | break;
210 | }
211 | image yolo_image=libyolo_mat_to_image(mat);
212 | mat.release();
213 |
214 | queue_image.frame=yolo_image;
215 |
216 | sem_wait(thread_data->image_queue->empty);
217 |
218 | if(pthread_mutex_lock(&thread_data->image_queue->mutex))
219 | {
220 | sem_post(thread_data->image_queue->empty);
221 | continue;
222 | }
223 | thread_data->image_queue->queue.push_back(queue_image);
224 | pthread_mutex_unlock(&thread_data->image_queue->mutex);
225 | sem_post(thread_data->image_queue->full);
226 | }
227 | return nullptr;
228 | }
229 |
230 | void *thread_detect(void *data)
231 | {
232 | if(data == nullptr)
233 | {
234 | return nullptr;
235 | }
236 | auto *th_data=(thread_processing_image_t *)data;
237 | while(true)
238 | {
239 | if(sem_trywait(th_data->image_queue->full))
240 | {
241 | if(th_data->image_queue->common->end)
242 | {
243 | break;
244 | }
245 | continue;
246 | }
247 |
248 | queue_image_t queue_image;
249 | bool im_got_sucessfull;
250 | if(pthread_mutex_lock(&th_data->image_queue->mutex))
251 | {
252 | continue;
253 | }
254 | im_got_sucessfull=!th_data->image_queue->queue.empty();
255 | if(im_got_sucessfull)
256 | {
257 | queue_image=th_data->image_queue->queue.front();
258 | th_data->image_queue->queue.pop_front();
259 | }
260 | pthread_mutex_unlock(&th_data->image_queue->mutex);
261 | sem_post(th_data->image_queue->empty);
262 |
263 | if(!im_got_sucessfull)
264 | {
265 | continue;
266 | }
267 |
268 | layer l=th_data->yolo->net->layers[th_data->yolo->net->n-1];
269 | unsigned long long time;
270 | float nms=0.45;
271 |
272 | image sized=resize_image(queue_image.frame, th_data->yolo->net->w, th_data->yolo->net->h);
273 | float *X=sized.data;
274 | time=unixTimeMilis();
275 | network_predict(th_data->yolo->net, X);
276 |
277 | int nboxes=0;
278 | detection *dets=get_network_boxes(th_data->yolo->net, queue_image.frame.w, queue_image.frame.h, th_data->thresh, 0, nullptr, 0, &nboxes);
279 | if(nms>0)
280 | {
281 | do_nms_sort(dets, l.side*l.side*l.n, l.classes, nms);
282 | }
283 |
284 | parse_detections_video(th_data->yolo, dets, th_data->yolo_detect, (unixTimeMilis()-time), queue_image.frame_number, queue_image.milisecond, nboxes, th_data->thresh);
285 | free_detections(dets, nboxes);
286 |
287 | free_image(queue_image.frame);
288 | free_image(sized);
289 | }
290 | return nullptr;
291 | }
292 |
293 | yolo_status yolo_check_before_process_filename(yolo_object *yolo, char *filename)
294 | {
295 | if(yolo == nullptr)
296 | {
297 | return yolo_object_is_not_initialized;
298 | }
299 |
300 | if(access(filename, F_OK) == -1)
301 | {
302 | fprintf(stderr, "error yolo_detect: %s\n", strerror(errno));
303 | return yolo_image_file_is_not_exists;
304 | }
305 |
306 | if(access(filename, R_OK) == -1)
307 | {
308 | fprintf(stderr, "error yolo_detect: %s\n", strerror(errno));
309 | return yolo_image_file_is_not_readable;
310 | }
311 | return yolo_ok;
312 | }
313 |
314 | void yolo_cleanup(yolo_object *yolo)
315 | {
316 | if(yolo == nullptr)
317 | {
318 | return;
319 | }
320 |
321 | if(yolo->net != nullptr)
322 | {
323 | free_network(yolo->net);
324 | }
325 |
326 | if(yolo->names != nullptr)
327 | {
328 | for(int i=0; iclass_number; i++)
329 | {
330 | if(yolo->names[i] != nullptr)
331 | {
332 | free(yolo->names[i]);
333 | }
334 | }
335 | free(yolo->names);
336 | }
337 | free(yolo);
338 | yolo_object **ptr_yolo=&yolo;
339 | (*ptr_yolo)=nullptr;
340 | }
341 |
342 | yolo_status yolo_init(yolo_object **yolo_obj, char *workingDir, char *datacfg, char *cfgfile, char *weightfile)
343 | {
344 | clock_t time=clock();
345 |
346 | yolo_cleanup((*yolo_obj));
347 |
348 | (*yolo_obj)=(yolo_object *)malloc(sizeof(yolo_object));
349 |
350 | yolo_object *yolo=(*yolo_obj);
351 | if(!yolo)
352 | {
353 | return yolo_cannot_alloc_node_yolo_object;
354 | }
355 | memset(yolo, 0, sizeof(yolo_object));
356 |
357 | if(access(workingDir, F_OK) == -1)
358 | {
359 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
360 | return yolo_working_dir_is_not_exists;
361 | }
362 |
363 | if(access(workingDir, R_OK) == -1)
364 | {
365 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
366 | return yolo_working_dir_is_not_readable;
367 | }
368 | char cur_dir[1024];
369 | getcwd(cur_dir, sizeof(cur_dir));
370 | if(chdir(workingDir) == -1)
371 | {
372 | fprintf(stderr, "%s\n", strerror(errno));
373 | return yolo_cannot_change_to_working_dir;
374 | }
375 |
376 | if(access(cfgfile, F_OK) == -1)
377 | {
378 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
379 | return yolo_cfgfile_is_not_exists;
380 | }
381 | if(access(cfgfile, R_OK) == -1)
382 | {
383 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
384 | return yolo_cfgfile_is_not_readable;
385 | }
386 | if(access(weightfile, F_OK) == -1)
387 | {
388 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
389 | return yolo_weight_file_is_not_exists;
390 | }
391 | if(access(weightfile, R_OK) == -1)
392 | {
393 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
394 | return yolo_weight_file_is_not_readable;
395 | }
396 | yolo->net=load_network(cfgfile, weightfile, 0);
397 |
398 | if(access(datacfg, F_OK) == -1)
399 | {
400 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
401 | return yolo_datacfg_is_not_exists;
402 | }
403 |
404 | if(access(datacfg, R_OK) == -1)
405 | {
406 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
407 | return yolo_datacfg_is_not_readable;
408 | }
409 |
410 | list *options=read_data_cfg(datacfg);
411 | char *name_list=option_find_str(options, "names", "data/names.list");
412 |
413 | if(access(name_list, F_OK) == -1)
414 | {
415 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
416 | return yolo_names_file_is_not_exists;
417 | }
418 | if(access(name_list, R_OK) == -1)
419 | {
420 | fprintf(stderr, "error yolo_init: %s\n", strerror(errno));
421 | return yolo_names_file_is_not_readable;
422 | }
423 | yolo->names=get_labels(name_list);
424 | char *classes=option_find_str(options, "classes", "data/names.list");
425 | char *bad_ptr=nullptr;
426 | long value=strtol(classes, &bad_ptr, 10);
427 | if(valueclass_number=(int)value;
430 | }
431 |
432 | set_batch_network(yolo->net, 1);
433 | srand(2222222);
434 |
435 | printf("Network configured and loaded in %f seconds\n", sec(clock()-time));
436 | chdir(cur_dir);
437 | return yolo_ok;
438 | }
439 |
440 | yolo_status yolo_detect_image(yolo_object *yolo, yolo_detection_image **detect, char *filename, float thresh)
441 | {
442 | yolo_status status=yolo_check_before_process_filename(yolo, filename);
443 | if(status != yolo_ok)
444 | {
445 | return status;
446 | }
447 |
448 | cv::Mat mat=cv::imread(filename, CV_LOAD_IMAGE_COLOR);
449 | if(mat.empty())
450 | {
451 | fprintf(stderr, "error yolo_detect: %s\n", strerror(errno));
452 | return yolo_image_file_is_corrupted;
453 | }
454 |
455 | layer l=yolo->net->layers[yolo->net->n-1];
456 | unsigned long long time;
457 | float nms=0.45;
458 |
459 | image im=libyolo_mat_to_image(mat);
460 | mat.release();
461 |
462 | image sized=resize_image(im, yolo->net->w, yolo->net->h);
463 | float *X=sized.data;
464 | time=unixTimeMilis();
465 | network_predict(yolo->net, X);
466 |
467 | int nboxes=0;
468 | detection *dets=get_network_boxes(yolo->net, im.w, im.h, thresh, 0.5, nullptr, 0, &nboxes);
469 | if(nms>0)
470 | {
471 | do_nms_sort(dets, l.side*l.side*l.n, l.classes, nms);
472 | }
473 |
474 | status=parse_detections_image(yolo, dets, detect, unixTimeMilis()-time, nboxes, thresh);
475 | if(status != yolo_ok)
476 | {
477 | return status;
478 | }
479 |
480 | free_detections(dets, nboxes);
481 | free_image(im);
482 | free_image(sized);
483 |
484 | return yolo_ok;
485 | }
486 |
487 | yolo_status yolo_detect_video(yolo_object *yolo, yolo_detection_video **detect, char *filename, float thresh, double fraction_frames_to_process)
488 | {
489 | yolo_status status=yolo_check_before_process_filename(yolo, filename);
490 | if(status != yolo_ok)
491 | {
492 | return status;
493 | }
494 | const size_t num_capture_image_threads=2;
495 | pthread_t *capture_image_thread;
496 | pthread_t process_image_thread;
497 | cv::VideoCapture *capture;
498 |
499 | thread_image_queue_t image_queue;
500 | thread_common_t data_image_common;
501 | thread_get_frame_t data_get_image;
502 | thread_processing_image_t data_process_image;
503 |
504 | data_image_common.end=false;
505 | image_queue.queue=std::deque();
506 | image_queue.common=&data_image_common;
507 |
508 | data_get_image.image_queue=data_process_image.image_queue=&image_queue;
509 |
510 | data_process_image.yolo=yolo;
511 | data_process_image.thresh=thresh;
512 | data_process_image.yolo_detect=detect;
513 |
514 | data_get_image.number_frames_to_process_simultaneously=data_get_image.number_frames_to_drop=(unsigned int)floor((1/fraction_frames_to_process)-1);
515 |
516 | if(pthread_mutex_init(&data_get_image.mutex, nullptr))
517 | {
518 | return yolo_video_cannot_alloc_base_structure;
519 | }
520 |
521 | if(pthread_mutex_init(&image_queue.mutex, nullptr))
522 | {
523 | return yolo_video_cannot_alloc_base_structure;
524 | }
525 |
526 | image_queue.empty=sem_open("/image_empty", O_CREAT, 0644, 20);
527 | if(image_queue.empty == SEM_FAILED)
528 | {
529 | return yolo_video_cannot_alloc_base_structure;
530 | }
531 | image_queue.full=sem_open("/image_full", O_CREAT, 0644, 0);
532 | if(image_queue.full == SEM_FAILED)
533 | {
534 | return yolo_video_cannot_alloc_base_structure;
535 | }
536 |
537 | capture=new cv::VideoCapture(filename);
538 | if(!capture->isOpened())
539 | {
540 | return yolo_cannot_open_video_stream;
541 | }
542 | data_get_image.video=capture;
543 |
544 | capture_image_thread=(pthread_t *)calloc(num_capture_image_threads, sizeof(pthread_t));
545 | if(capture_image_thread == nullptr)
546 | {
547 | return yolo_video_cannot_alloc_base_structure;
548 | }
549 |
550 | for(size_t i=0; irelease();
561 | delete capture;
562 | free(capture_image_thread);
563 |
564 | pthread_join(process_image_thread, nullptr);
565 |
566 | sem_close(image_queue.full);
567 | sem_close(image_queue.empty);
568 | pthread_mutex_destroy(&image_queue.mutex);
569 | image_queue.queue.clear();
570 |
571 | pthread_mutex_destroy(&data_get_image.mutex);
572 | return yolo_ok;
573 | }
574 |
575 | void yolo_detect_free(yolo_detection_image *yolo_det)
576 | {
577 | for(size_t i=0; inum_boxes; i++)
578 | {
579 | free(yolo_det->detection[i].class_name);
580 | }
581 | free(yolo_det->detection);
582 | }
583 |
584 | void yolo_detection_image_free(yolo_detection_image **yolo)
585 | {
586 | if((*yolo) == nullptr)
587 | {
588 | return;
589 | }
590 | yolo_detect_free(*yolo);
591 | free(*yolo);
592 | (*yolo)=nullptr;
593 | }
594 |
595 | void yolo_detection_video_free(yolo_detection_video **yolo)
596 | {
597 | yolo_detection_video *yolo_det=*yolo;
598 | if(yolo_det == nullptr)
599 | {
600 | return;
601 | }
602 | for(size_t i=0; icount; ++i)
603 | {
604 | yolo_detect_free(&yolo_det->frame_detections[i].detection_frame);
605 | }
606 | free(yolo_det->frame_detections);
607 | free(yolo_det);
608 | (*yolo)=nullptr;
609 | }
610 |
--------------------------------------------------------------------------------
/yolo/src/libyolo.h:
--------------------------------------------------------------------------------
1 | #ifndef LIBYOLO_H
2 | #define LIBYOLO_H
3 |
4 | #include "darknet.h"
5 | #include "yolo_error.h"
6 |
7 | #ifdef __cplusplus
8 | extern "C" {
9 | #endif
10 |
11 | typedef struct
12 | {
13 | char *class_name;
14 | float probability;
15 | box bbox;
16 | }detect;
17 |
18 | typedef struct
19 | {
20 | detect *detection;
21 | size_t num_boxes;
22 | float time_spent_for_classification;
23 | }yolo_detection_image;
24 |
25 | typedef struct
26 | {
27 | yolo_detection_image detection_frame;
28 | double milisecond;
29 | long frame;
30 | }yolo_detection_frame;
31 |
32 | typedef struct
33 | {
34 | yolo_detection_frame *frame_detections;
35 | size_t count;
36 | }yolo_detection_video;
37 |
38 | typedef struct
39 | {
40 | int class_number;
41 | char **names;
42 | float nms;
43 | network *net;
44 | }yolo_object;
45 |
46 | yolo_status yolo_init(yolo_object **yolo_obj, char *workingDir, char *datacfg, char *cfgfile, char *weightfile);
47 | yolo_status yolo_detect_image(yolo_object *yolo, yolo_detection_image **detect, char *filename, float thresh);
48 | yolo_status yolo_detect_video(yolo_object *yolo, yolo_detection_video **detect, char *filename, float thresh, double fraction_frames_to_process);
49 |
50 | void yolo_detection_image_free(yolo_detection_image **yolo);
51 | void yolo_detection_video_free(yolo_detection_video **yolo);
52 | void yolo_cleanup(yolo_object *yolo);
53 |
54 | #ifdef __cplusplus
55 | };
56 | #endif
57 |
58 | #endif // LIBYOLO_H
--------------------------------------------------------------------------------
/yolo/src/private_structs.h:
--------------------------------------------------------------------------------
1 | #ifndef NODE_YOLO_PRIVATE_STRUCTS_H
2 | #define NODE_YOLO_PRIVATE_STRUCTS_H
3 |
4 | #include "libyolo.h"
5 |
6 | #include
7 |
8 | #include
9 | #include
10 |
11 | typedef struct
12 | {
13 | long frame_number;
14 | double milisecond;
15 | image frame;
16 | }queue_image_t;
17 |
18 | typedef struct
19 | {
20 | bool end;
21 | }thread_common_t;
22 |
23 | typedef struct
24 | {
25 | sem_t *full;
26 | sem_t *empty;
27 | pthread_mutex_t mutex;
28 | std::deque queue;
29 |
30 | thread_common_t *common;
31 | }thread_image_queue_t;
32 |
33 | typedef struct
34 | {
35 | thread_image_queue_t *image_queue;
36 | cv::VideoCapture *video;
37 |
38 | unsigned int number_frames_to_process_simultaneously;
39 | unsigned int number_frames_to_drop;
40 | pthread_mutex_t mutex;
41 | }thread_get_frame_t;
42 |
43 | typedef struct
44 | {
45 | thread_image_queue_t *image_queue;
46 |
47 | yolo_object *yolo;
48 | float thresh;
49 | yolo_detection_video **yolo_detect;
50 | }thread_processing_image_t;
51 |
52 | #endif //NODE_YOLO_PRIVATE_STRUCTS_H
--------------------------------------------------------------------------------
/yolo/src/yolo_error.c:
--------------------------------------------------------------------------------
1 | #include "yolo_error.h"
2 |
3 | yolo_status_detailed yolo_status_decode(yolo_status status)
4 | {
5 | yolo_status_detailed status_detailed;
6 | status_detailed.error_code=status;
7 | switch(status)
8 | {
9 | case yolo_instanciation:
10 | status_detailed.error_message="Cannot instantiate due an error.";
11 | break;
12 | case yolo_cannot_realloc_detect:
13 | status_detailed.error_message="Cannot allocate detect in memory";
14 | break;
15 | case yolo_cannot_alloc_yolo_detection:
16 | status_detailed.error_message="Cannot allocate yolo_detection in memory";
17 | break;
18 | case yolo_cannot_alloc_node_yolo_object:
19 | status_detailed.error_message="Cannot allocate node_yolo_object in memory";
20 | break;
21 | case yolo_cannot_alloc_map:
22 | status_detailed.error_message="Cannot allocate map in memory";
23 | break;
24 | case yolo_cannot_change_to_working_dir:
25 | status_detailed.error_message="Cannot change to working directory";
26 | break;
27 | case yolo_object_is_not_initialized:
28 | status_detailed.error_message="yolo_object isn't allocated in memory";
29 | break;
30 | case yolo_working_dir_is_not_exists:
31 | status_detailed.error_message="working directory don't exists";
32 | break;
33 | case yolo_datacfg_is_not_exists:
34 | status_detailed.error_message="datacfg don't exists";
35 | break;
36 | case yolo_cfgfile_is_not_exists:
37 | status_detailed.error_message="cfgfile don't exists";
38 | break;
39 | case yolo_weight_file_is_not_exists:
40 | status_detailed.error_message="weight file don't exists";
41 | break;
42 | case yolo_working_dir_is_not_readable:
43 | status_detailed.error_message="working directory isn't readable";
44 | break;
45 | case yolo_datacfg_is_not_readable:
46 | status_detailed.error_message="datacfg isn't readable";
47 | break;
48 | case yolo_cfgfile_is_not_readable:
49 | status_detailed.error_message="cfgfile isn't readable";
50 | break;
51 | case yolo_weight_file_is_not_readable:
52 | status_detailed.error_message="weight file isn't readable";
53 | break;
54 | case yolo_names_file_is_not_exists:
55 | status_detailed.error_message="names file don't exists";
56 | break;
57 | case yolo_names_file_is_not_readable:
58 | status_detailed.error_message="names file isn't readable";
59 | break;
60 | case yolo_image_file_is_not_exists:
61 | status_detailed.error_message="image file isn't exists";
62 | break;
63 | case yolo_image_file_is_not_readable:
64 | status_detailed.error_message="image file isn't readable";
65 | break;
66 | case yolo_image_file_is_corrupted:
67 | status_detailed.error_message="image file is corrupted";
68 | break;
69 | // case yolo_napi_create_object_time_spent_for_classification_double_failed:
70 | // status_detailed.error_message="image file is corrupted";
71 | // break;
72 | // case yolo_napi_create_object_time_spent_for_classification_named_property_failed:
73 | // status_detailed.error_message="image file is corrupted";
74 | // break;
75 | // case yolo_napi_set_array_property_failed:
76 | // status_detailed.error_message="image file is corrupted";
77 | // break;
78 | // case yolo_napi_create_main_object_failed:
79 | // status_detailed.error_message="image file is corrupted";
80 | // break;
81 | default:
82 | status_detailed.error_message="Unknow error";
83 | }
84 | return status_detailed;
85 | }
--------------------------------------------------------------------------------
/yolo/src/yolo_error.h:
--------------------------------------------------------------------------------
1 | #ifndef NODE_YOLO_YOLO_ERROR_H
2 | #define NODE_YOLO_YOLO_ERROR_H
3 |
4 | #ifdef __cplusplus
5 | extern "C" {
6 | #endif
7 |
8 | typedef struct
9 | {
10 | int error_code;
11 | char *error_message;
12 | }yolo_status_detailed;
13 |
14 | typedef enum
15 | {
16 | yolo_ok,
17 | yolo_instanciation,
18 | yolo_cannot_alloc_node_yolo_object,
19 | yolo_cannot_alloc_map,
20 | yolo_cannot_alloc_yolo_detection,
21 | yolo_cannot_realloc_detect,
22 | yolo_cannot_change_to_working_dir,
23 | yolo_object_is_not_initialized,
24 | yolo_working_dir_is_not_exists,
25 | yolo_datacfg_is_not_exists,
26 | yolo_cfgfile_is_not_exists,
27 | yolo_weight_file_is_not_exists,
28 | yolo_working_dir_is_not_readable,
29 | yolo_datacfg_is_not_readable,
30 | yolo_cfgfile_is_not_readable,
31 | yolo_weight_file_is_not_readable,
32 | yolo_names_file_is_not_exists,
33 | yolo_names_file_is_not_readable,
34 | yolo_image_file_is_not_exists,
35 | yolo_image_file_is_not_readable,
36 | yolo_image_file_is_corrupted,
37 |
38 | yolo_video_cannot_alloc_base_structure,
39 | yolo_cannot_open_video_stream, yolo_error_getting_fps,
40 |
41 | yolo_unknow_error
42 | }yolo_status;
43 |
44 | yolo_status_detailed yolo_status_decode(yolo_status status);
45 |
46 | #ifdef __cplusplus
47 | }
48 | #endif
49 |
50 | #endif //NODE_YOLO_YOLO_ERROR_H
51 |
--------------------------------------------------------------------------------