Skip to content
This repository was archived by the owner on Oct 18, 2023. It is now read-only.

Commit 23e1f8f

Browse files
Merge pull request justadudewhohacks#464 from bookjan/master
cc: add dnn readNetFromDarknet API
2 parents 18d2cff + 289e589 commit 23e1f8f

File tree

8 files changed

+395
-34
lines changed

8 files changed

+395
-34
lines changed

cc/modules/dnn/dnn.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ NAN_MODULE_INIT(Dnn::Init) {
2020
Nan::SetMethod(target, "blobFromImages", BlobFromImages);
2121
Nan::SetMethod(target, "blobFromImagesAsync", BlobFromImagesAsync);
2222
#if CV_VERSION_MINOR > 3
23+
Nan::SetMethod(target, "readNetFromDarknet", readNetFromDarknet);
24+
Nan::SetMethod(target, "readNetFromDarknetAsync", readNetFromDarknetAsync);
2325
Nan::SetMethod(target, "NMSBoxes", NMSBoxes);
2426
#endif
2527
};
2628

29+
2730
NAN_METHOD(Dnn::ReadNetFromTensorflow) {
2831
FF::SyncBinding(
2932
std::make_shared<DnnBindings::ReadNetFromTensorflowWorker>(),
@@ -89,6 +92,22 @@ NAN_METHOD(Dnn::BlobFromImagesAsync) {
8992
}
9093

9194
#if CV_VERSION_MINOR > 3
95+
NAN_METHOD(Dnn::readNetFromDarknet)
96+
{
97+
FF::SyncBinding(
98+
std::make_shared<DnnBindings::readNetFromDarknetWorker>(),
99+
"readNetFromDarknet",
100+
info);
101+
}
102+
103+
NAN_METHOD(Dnn::readNetFromDarknetAsync)
104+
{
105+
FF::AsyncBinding(
106+
std::make_shared<DnnBindings::readNetFromDarknetWorker>(),
107+
"readNetFromDarknetAsync",
108+
info);
109+
}
110+
92111
NAN_METHOD(Dnn::NMSBoxes) {
93112
FF::SyncBinding(
94113
std::make_shared<DnnBindings::NMSBoxes>(),

cc/modules/dnn/dnn.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class Dnn {
2020
static NAN_METHOD(BlobFromImages);
2121
static NAN_METHOD(BlobFromImagesAsync);
2222
#if CV_VERSION_MINOR > 3
23+
static NAN_METHOD(readNetFromDarknet);
24+
static NAN_METHOD(readNetFromDarknetAsync);
2325
static NAN_METHOD(NMSBoxes);
2426
#endif
2527
};

cc/modules/dnn/dnnBindings.h

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,53 @@
55

66
namespace DnnBindings {
77

8+
#if CV_VERSION_MINOR > 3
9+
struct readNetFromDarknetWorker : public CatchCvExceptionWorker{
10+
public:
11+
std::string cfgFile;
12+
std::string darknetModelFile = "";
13+
14+
cv::dnn::Net net;
15+
16+
std::string executeCatchCvExceptionWorker() {
17+
net = cv::dnn::readNetFromDarknet(cfgFile, darknetModelFile);
18+
if (net.empty()) {
19+
return std::string("failed to cfgFile: " + cfgFile + ", darknetModelFile: " + darknetModelFile).data();
20+
}
21+
return "";
22+
}
23+
24+
v8::Local<v8::Value> getReturnValue() {
25+
return Net::Converter::wrap(net);
26+
}
27+
28+
bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
29+
return (
30+
StringConverter::arg(0, &cfgFile, info));
31+
}
32+
33+
bool unwrapOptionalArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
34+
return (
35+
StringConverter::optArg(1, &darknetModelFile, info));
36+
}
37+
};
38+
#endif
39+
840
struct ReadNetFromTensorflowWorker : public CatchCvExceptionWorker {
941
public:
1042
std::string modelFile;
43+
std::string configFile = "";
1144

1245
cv::dnn::Net net;
1346

1447
std::string executeCatchCvExceptionWorker() {
48+
#if CV_VERSION_MINOR > 3
49+
net = cv::dnn::readNetFromTensorflow(modelFile, configFile);
50+
#else
1551
net = cv::dnn::readNetFromTensorflow(modelFile);
52+
#endif
1653
if (net.empty()) {
17-
return std::string("failed to load net: " + modelFile).data();
54+
return std::string("failed to load net: " + modelFile + "failed to load config: " + configFile).data();
1855
}
1956
return "";
2057
}
@@ -25,7 +62,13 @@ namespace DnnBindings {
2562

2663
bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
2764
return (
28-
StringConverter::arg(0, &modelFile, info)
65+
StringConverter::arg(0, &modelFile, info)
66+
);
67+
}
68+
69+
bool unwrapOptionalArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
70+
return (
71+
StringConverter::optArg(1, &configFile, info)
2972
);
3073
}
3174
};
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/**
2+
* Please refer to the python version of "YOLO object detection with OpenCV" by Adrian Rosebrock.
3+
* For more detail: https://www.pyimagesearch.com/2018/11/12/yolo-object-detection-with-opencv/
4+
*/
5+
const fs = require("fs");
6+
const path = require("path");
7+
const { cv, drawBlueRect, runVideoDetection } = require("./utils");
8+
9+
if (!cv.xmodules.dnn) {
10+
throw new Error("exiting: opencv4nodejs compiled without dnn module");
11+
}
12+
13+
// replace with path where you unzipped darknet model
14+
const darknetPath = "../data/dnn/yolo-object-detection";
15+
16+
const cfgFile = path.resolve(darknetPath, "yolov3-tiny.cfg");
17+
const weightsFile = path.resolve(darknetPath, "yolov3-tiny.weights");
18+
const labelsFile = path.resolve(darknetPath, "coco.names");
19+
20+
if (
21+
!fs.existsSync(weightsFile) ||
22+
!fs.existsSync(cfgFile) ||
23+
!fs.existsSync(labelsFile)
24+
) {
25+
console.log("could not find darknet model");
26+
console.log("download the model from: https://pjreddie.com/darknet/yolo/");
27+
throw new Error("exiting");
28+
}
29+
30+
// set webcam port
31+
const webcamPort = 0;
32+
33+
const minConfidence = 0.5;
34+
const nmsThreshold = 0.3;
35+
36+
// read classNames and store them in an array
37+
const labels = fs
38+
.readFileSync(labelsFile)
39+
.toString()
40+
.split("\n");
41+
42+
// initialize tensorflow darknet model from modelFile
43+
const net = cv.readNetFromDarknet(cfgFile, weightsFile);
44+
45+
const classifyImg = img => {
46+
// object detection model works with 416 x 416 images
47+
const size = new cv.Size(416, 416);
48+
const vec3 = new cv.Vec(0, 0, 0);
49+
const [imgHeight, imgWidth] = img.sizes;
50+
51+
// network accepts blobs as input
52+
const inputBlob = cv.blobFromImage(img, 1 / 255.0, size, vec3, true, true);
53+
net.setInput(inputBlob);
54+
55+
// specify two layers "yolo_16" and "yolo_23"
56+
const layerNames = ["yolo_16", "yolo_23"];
57+
58+
console.time("net.forward");
59+
// forward pass input through entire network
60+
const layerOutputs = net.forward(layerNames);
61+
console.timeEnd("net.forward");
62+
63+
let boxes = [];
64+
let confidences = [];
65+
let classIDs = [];
66+
67+
layerOutputs.forEach(mat => {
68+
const output = mat.getDataAsArray();
69+
output.forEach(detection => {
70+
const scores = detection.slice(5);
71+
const classId = scores.indexOf(Math.max(...scores));
72+
const confidence = scores[classId];
73+
74+
if (confidence > minConfidence) {
75+
const box = detection.slice(0, 4);
76+
77+
const centerX = parseInt(box[0] * imgWidth);
78+
const centerY = parseInt(box[1] * imgHeight);
79+
const width = parseInt(box[2] * imgWidth);
80+
const height = parseInt(box[3] * imgHeight);
81+
82+
const x = parseInt(centerX - width / 2);
83+
const y = parseInt(centerY - height / 2);
84+
85+
boxes.push(new cv.Rect(x, y, width, height));
86+
confidences.push(confidence);
87+
classIDs.push(classId);
88+
89+
const indices = cv.NMSBoxes(
90+
boxes,
91+
confidences,
92+
minConfidence,
93+
nmsThreshold
94+
);
95+
96+
indices.forEach(i => {
97+
const rect = boxes[i];
98+
const imgRect = new cv.Rect(rect.x, rect.y, rect.width, rect.height);
99+
drawBlueRect(img, imgRect);
100+
const text = labels[classIDs[i]];
101+
img.putText(
102+
text,
103+
new cv.Point(rect.x, rect.y + 0.1 * imgHeight),
104+
cv.FONT_ITALIC,
105+
2,
106+
{
107+
color: new cv.Vec(255, 0, 0),
108+
thickness: 2
109+
}
110+
);
111+
drawBlueRect(img, imgRect);
112+
});
113+
}
114+
});
115+
});
116+
117+
cv.imshow("Darknet YOLO Object Detection", img);
118+
};
119+
120+
runVideoDetection(webcamPort, classifyImg);
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/**
2+
* Please refer to the python version of "ExploreOpencvDnn" by Saumya Shovan Roy.
3+
* For more detail: https://github.com/rdeepc/ExploreOpencvDnn
4+
*/
5+
const fs = require("fs");
6+
const path = require("path");
7+
const classNames = require("./dnnTensorflowObjectDetectionClassNames");
8+
const { cv, drawBlueRect, runVideoDetection } = require("./utils");
9+
10+
if (!cv.xmodules.dnn) {
11+
throw new Error("exiting: opencv4nodejs compiled without dnn module");
12+
}
13+
14+
// replace with path where you unzipped detection model
15+
const detectionModelPath = "../data/dnn/tf-detection";
16+
17+
const pbFile = path.resolve(detectionModelPath, "frozen_inference_graph.pb");
18+
const pbtxtFile = path.resolve(
19+
detectionModelPath,
20+
"ssd_mobilenet_v2_coco_2018_03_29.pbtxt"
21+
);
22+
23+
if (!fs.existsSync(pbFile) || !fs.existsSync(pbtxtFile)) {
24+
console.log("could not find detection model");
25+
console.log(
26+
"download the model from: https://github.com/opencv/opencv/wiki/TensorFlow-Object-Detection-API#use-existing-config-file-for-your-model"
27+
);
28+
throw new Error("exiting");
29+
}
30+
31+
// set webcam port
32+
const webcamPort = 0;
33+
34+
// initialize tensorflow darknet model from modelFile
35+
const net = cv.readNetFromTensorflow(pbFile, pbtxtFile);
36+
37+
const classifyImg = img => {
38+
// object detection model works with 300 x 300 images
39+
const size = new cv.Size(300, 300);
40+
const vec3 = new cv.Vec(0, 0, 0);
41+
42+
// network accepts blobs as input
43+
const inputBlob = cv.blobFromImage(img, 1, size, vec3, true, true);
44+
net.setInput(inputBlob);
45+
46+
console.time("net.forward");
47+
// forward pass input through entire network, will return
48+
// classification result as 1x1xNxM Mat
49+
const outputBlob = net.forward();
50+
console.timeEnd("net.forward");
51+
52+
// get height and width from the image
53+
const [imgHeight, imgWidth] = img.sizes;
54+
const numRows = outputBlob.sizes.slice(2,3);
55+
56+
for (let y = 0; y < numRows; y += 1) {
57+
const confidence = outputBlob.at([0, 0, y, 2]);
58+
if (confidence > 0.5) {
59+
const classId = outputBlob.at([0, 0, y, 1]);
60+
const className = classNames[classId];
61+
const boxX = imgWidth * outputBlob.at([0, 0, y, 3]);
62+
const boxY = imgHeight * outputBlob.at([0, 0, y, 4]);
63+
const boxWidht = imgWidth * outputBlob.at([0, 0, y, 5]);
64+
const boxHeight = imgHeight * outputBlob.at([0, 0, y, 6]);
65+
const imgRect = new cv.Rect(boxX, boxY, boxWidht, boxHeight);
66+
67+
// draw the blue rect for the object
68+
drawBlueRect(img, imgRect);
69+
70+
// put text on the object
71+
img.putText(
72+
className,
73+
new cv.Point(boxX, boxY + 0.1 * imgHeight),
74+
cv.FONT_ITALIC,
75+
2,
76+
{
77+
color: new cv.Vec(255, 0, 0),
78+
thickness: 2
79+
}
80+
);
81+
}
82+
}
83+
84+
cv.imshow("Temsorflow Object Detection", img);
85+
};
86+
87+
runVideoDetection(webcamPort, classifyImg);

0 commit comments

Comments
 (0)