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

Commit 6a794c4

Browse files
committedNov 12, 2017
caffe loader and single shot multibox detector example with ms coco
1 parent c50b674 commit 6a794c4

File tree

11 files changed

+321
-14
lines changed

11 files changed

+321
-14
lines changed
 

‎cc/core/Mat.cc

+24-10
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ NAN_MODULE_INIT(Mat::Init) {
2121
Nan::SetAccessor(ctor->InstanceTemplate(), Nan::New("dims").ToLocalChecked(), Mat::GetDims);
2222
Nan::SetAccessor(ctor->InstanceTemplate(), Nan::New("depth").ToLocalChecked(), Mat::GetDepth);
2323
Nan::SetAccessor(ctor->InstanceTemplate(), Nan::New("empty").ToLocalChecked(), Mat::GetIsEmpty);
24+
Nan::SetAccessor(ctor->InstanceTemplate(), Nan::New("sizes").ToLocalChecked(), Mat::GetSizes);
2425

2526
Nan::SetMethod(ctor, "eye", Eye);
27+
Nan::SetPrototypeMethod(ctor, "flattenFloat", FlattenFloat);
2628

2729
Nan::SetPrototypeMethod(ctor, "at", At);
2830
Nan::SetPrototypeMethod(ctor, "atRaw", AtRaw);
@@ -220,6 +222,28 @@ NAN_METHOD(Mat::New) {
220222
FF_RETURN(info.Holder());
221223
}
222224

225+
NAN_METHOD(Mat::Eye) {
226+
FF_METHOD_CONTEXT("Mat::Eye");
227+
FF_ARG_INT(0, int rows);
228+
FF_ARG_INT(1, int cols);
229+
FF_ARG_INT(2, int type);
230+
FF_OBJ jsEyeMat = FF_NEW_INSTANCE(Mat::constructor);
231+
FF_UNWRAP_MAT_AND_GET(jsEyeMat) = cv::Mat::eye(cv::Size(cols, rows), type);
232+
FF_RETURN(jsEyeMat);
233+
}
234+
235+
// squash multidimensional Mat into 2D Mat
236+
// TODO: figure out how to deal with multidim Mats
237+
NAN_METHOD(Mat::FlattenFloat) {
238+
FF_METHOD_CONTEXT("Mat::To2DFloat");
239+
FF_ARG_INT(0, int rows);
240+
FF_ARG_INT(1, int cols);
241+
242+
cv::Mat matSelf = FF_UNWRAP_MAT_AND_GET(info.This());
243+
cv::Mat mat2D(rows, cols, CV_32F, matSelf.ptr<float>());
244+
FF_RETURN(Mat::Converter::wrap(mat2D));
245+
}
246+
223247
NAN_METHOD(Mat::At) {
224248
FF_METHOD_CONTEXT("Mat::At");
225249
cv::Mat matSelf = FF_UNWRAP_MAT_AND_GET(info.This());
@@ -251,16 +275,6 @@ NAN_METHOD(Mat::At) {
251275
FF_RETURN(jsVal);
252276
}
253277

254-
NAN_METHOD(Mat::Eye) {
255-
FF_METHOD_CONTEXT("Mat::Eye");
256-
FF_ARG_INT(0, int rows);
257-
FF_ARG_INT(1, int cols);
258-
FF_ARG_INT(2, int type);
259-
FF_OBJ jsEyeMat = FF_NEW_INSTANCE(Mat::constructor);
260-
FF_UNWRAP_MAT_AND_GET(jsEyeMat) = cv::Mat::eye(cv::Size(cols, rows), type);
261-
FF_RETURN(jsEyeMat);
262-
}
263-
264278
NAN_METHOD(Mat::AtRaw) {
265279
FF_METHOD_CONTEXT("Mat::AtRaw");
266280
cv::Mat matSelf = FF_UNWRAP_MAT_AND_GET(info.This());

‎cc/core/Mat.h

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Mat : public Nan::ObjectWrap {
1616
static NAN_METHOD(New);
1717

1818
static NAN_METHOD(Eye);
19+
static NAN_METHOD(FlattenFloat);
1920

2021
static FF_GETTER(Mat, GetRows, mat.rows);
2122
static FF_GETTER(Mat, GetCols, mat.cols);
@@ -24,6 +25,14 @@ class Mat : public Nan::ObjectWrap {
2425
static FF_GETTER(Mat, GetDims, mat.dims);
2526
static FF_GETTER(Mat, GetDepth, mat.depth());
2627
static FF_GETTER(Mat, GetIsEmpty, mat.empty());
28+
static NAN_GETTER(GetSizes) {
29+
cv::Mat m = Converter::unwrap(info.This());
30+
std::vector<int> sizes;
31+
for (int s = 0; s < m.dims; s++) {
32+
sizes.push_back(m.size[s]);
33+
}
34+
info.GetReturnValue().Set(IntArrayConverter::wrap(sizes));
35+
};
2736

2837
static NAN_METHOD(At);
2938
static NAN_METHOD(AtRaw);

‎cc/modules/dnn/dnn.cc

+47
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ NAN_MODULE_INIT(Dnn::Init) {
1515

1616
Nan::SetMethod(target, "readNetFromTensorflow", ReadNetFromTensorflow);
1717
Nan::SetMethod(target, "readNetFromTensorflowAsync", ReadNetFromTensorflowAsync);
18+
Nan::SetMethod(target, "readNetFromCaffe", ReadNetFromCaffe);
19+
Nan::SetMethod(target, "readNetFromCaffeAsync", ReadNetFromCaffeAsync);
1820
Nan::SetMethod(target, "blobFromImage", BlobFromImage);
1921
Nan::SetMethod(target, "blobFromImageAsync", BlobFromImageAsync);
2022
Nan::SetMethod(target, "blobFromImages", BlobFromImages);
@@ -57,6 +59,51 @@ NAN_METHOD(Dnn::ReadNetFromTensorflowAsync) {
5759
FF_WORKER_ASYNC("Dnn::ReadNetFromTensorflowAsync", ReadNetFromTensorflowWorker, worker);
5860
}
5961

62+
63+
struct Dnn::ReadNetFromCaffeWorker : public SimpleWorker {
64+
public:
65+
std::string prototxt;
66+
std::string modelFile = "";
67+
68+
cv::dnn::Net net;
69+
70+
const char* execute() {
71+
net = cv::dnn::readNetFromCaffe(prototxt, modelFile);
72+
if (net.empty()) {
73+
return std::string("failed to prototxt: " + prototxt + ", modelFile: " + modelFile).data();
74+
}
75+
return "";
76+
}
77+
78+
v8::Local<v8::Value> getReturnValue() {
79+
return Net::Converter::wrap(net);
80+
}
81+
82+
bool unwrapRequiredArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
83+
return (
84+
StringConverter::arg(0, &prototxt, info)
85+
);
86+
}
87+
88+
bool unwrapOptionalArgs(Nan::NAN_METHOD_ARGS_TYPE info) {
89+
return (
90+
StringConverter::optArg(1, &modelFile, info)
91+
);
92+
}
93+
};
94+
95+
NAN_METHOD(Dnn::ReadNetFromCaffe) {
96+
ReadNetFromCaffeWorker worker;
97+
FF_WORKER_SYNC("Dnn::ReadNetFromCaffe", worker);
98+
info.GetReturnValue().Set(worker.getReturnValue());
99+
}
100+
101+
NAN_METHOD(Dnn::ReadNetFromCaffeAsync) {
102+
ReadNetFromCaffeWorker worker;
103+
FF_WORKER_ASYNC("Dnn::ReadNetFromCaffeAsync", ReadNetFromCaffeWorker, worker);
104+
}
105+
106+
60107
struct Dnn::BlobFromImageWorker : public SimpleWorker {
61108
public:
62109
bool isSingleImage;

‎cc/modules/dnn/dnn.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,17 @@ class Dnn {
1212
static NAN_METHOD(ReadNetFromTensorflow);
1313
static NAN_METHOD(ReadNetFromTensorflowAsync);
1414

15-
#if CV_VERSION_MINOR > 2
15+
struct ReadNetFromCaffeWorker;
16+
static NAN_METHOD(ReadNetFromCaffe);
17+
static NAN_METHOD(ReadNetFromCaffeAsync);
18+
1619
struct BlobFromImageWorker;
1720
static NAN_METHOD(BlobFromImage);
1821
static NAN_METHOD(BlobFromImageAsync);
1922

2023
struct BlobFromImagesWorker;
2124
static NAN_METHOD(BlobFromImages);
2225
static NAN_METHOD(BlobFromImagesAsync);
23-
#endif
2426
};
2527

2628
#endif

‎data/cars.jpeg

69.9 KB
Loading

‎data/dishes.jpg

147 KB
Loading

‎doc/core/Mat.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ Mat {
99
channels: Number,
1010
depth: Number,
1111
dims: Number,
12-
empty: Boolean
12+
empty: Boolean,
13+
sizes: [Number]
1314
}
1415
```
1516

‎doc/dnn/dnn.md

+15
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,21 @@ Net : readNetFromTensorflow(String modelPath)
1414
readNetFromTensorflowAsync(String modelPath, callback(Error err, Net net))
1515
```
1616

17+
<a name="readNetFromCaffe"></a>
18+
19+
### readNetFromCaffe
20+
``` javascript
21+
Net : readNetFromCaffe(String prototxt, String modelPath = '')
22+
```
23+
24+
<a name="readNetFromCaffeAsync"></a>
25+
26+
### readNetFromCaffeAsync
27+
``` javascript
28+
readNetFromCaffeAsync(String prototxt, callback(Error err, Net net))
29+
readNetFromCaffeAsync(String prototxt, String modelPath, callback(Error err, Net net))
30+
```
31+
1732
<a name="blobFromImage"></a>
1833

1934
### blobFromImage

‎examples/dnnCocoClassNames.js

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
module.exports = [
2+
'background',
3+
'person',
4+
'bicycle',
5+
'car',
6+
'motorcycle',
7+
'airplane',
8+
'bus',
9+
'train',
10+
'truck',
11+
'boat',
12+
'traffic light',
13+
'fire hydrant',
14+
'stop sign',
15+
'parking meter',
16+
'bench',
17+
'bird',
18+
'cat',
19+
'dog',
20+
'horse',
21+
'sheep',
22+
'cow',
23+
'elephant',
24+
'bear',
25+
'zebra',
26+
'giraffe',
27+
'backpack',
28+
'umbrella',
29+
'handbag',
30+
'tie',
31+
'suitcase',
32+
'frisbee',
33+
'skis',
34+
'snowboard',
35+
'sports ball',
36+
'kite',
37+
'baseball bat',
38+
'baseball glove',
39+
'skateboard',
40+
'surfboard',
41+
'tennis racket',
42+
'bottle',
43+
'wine glass',
44+
'cup',
45+
'fork',
46+
'knife',
47+
'spoon',
48+
'bowl',
49+
'banana',
50+
'apple',
51+
'sandwich',
52+
'orange',
53+
'broccoli',
54+
'carrot',
55+
'hot dog',
56+
'pizza',
57+
'donut',
58+
'cake',
59+
'chair',
60+
'couch',
61+
'potted plant',
62+
'bed',
63+
'dining table',
64+
'toilet',
65+
'tv',
66+
'laptop',
67+
'mouse',
68+
'remote',
69+
'keyboard',
70+
'cell phone',
71+
'microwave',
72+
'oven',
73+
'toaster',
74+
'sink',
75+
'refrigerator',
76+
'book',
77+
'clock',
78+
'vase',
79+
'scissors',
80+
'teddy bear',
81+
'hair drier',
82+
'toothbrush'
83+
];

‎examples/dnnSSDCoco.js

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
const cv = require('../');
2+
const fs = require('fs');
3+
const path = require('path');
4+
const classNames = require('./dnnCocoClassNames');
5+
6+
if (!cv.xmodules.dnn) {
7+
return console.log('exiting: opencv4nodejs compiled without dnn module');
8+
}
9+
10+
// replace with path where you unzipped inception model
11+
const ssdcocoModelPath = '../data/dnn/coco-SSD_300x300'
12+
13+
const prototxt = path.resolve(ssdcocoModelPath, 'deploy.prototxt');
14+
const modelFile = path.resolve(ssdcocoModelPath, 'VGG_coco_SSD_300x300_iter_400000.caffemodel');
15+
16+
if (!fs.existsSync(prototxt) || !fs.existsSync(modelFile)) {
17+
console.log('exiting: could not find ssdcoco model');
18+
console.log('download the model from: https://drive.google.com/file/d/0BzKzrI_SkD1_dUY1Ml9GRTFpUWc/view');
19+
return;
20+
}
21+
22+
// initialize ssdcoco model from prototxt and modelFile
23+
const net = cv.readNetFromCaffe(prototxt, modelFile);
24+
25+
const classifyImg = (img) => {
26+
const white = new cv.Vec(255, 255, 255);
27+
// ssdcoco model works with 300 x 300 images
28+
const imgResized = img.resize(300, 300);
29+
30+
// network accepts blobs as input
31+
const inputBlob = cv.blobFromImage(imgResized);
32+
net.setInput(inputBlob);
33+
34+
// forward pass input through entire network, will return
35+
// classification result as 1x1xNxM Mat
36+
let outputBlob = net.forward();
37+
// extract NxM Mat
38+
outputBlob = outputBlob.flattenFloat(outputBlob.sizes[2], outputBlob.sizes[3]);
39+
40+
const results = Array(outputBlob.rows).fill(0)
41+
.map((res, i) => {
42+
const className = classNames[outputBlob.at(i, 1)];
43+
const confidence = outputBlob.at(i, 2);
44+
const topLeft = new cv.Point(
45+
outputBlob.at(i, 3) * img.cols,
46+
outputBlob.at(i, 6) * img.rows
47+
);
48+
const bottomRight = new cv.Point(
49+
outputBlob.at(i, 5) * img.cols,
50+
outputBlob.at(i, 4) * img.rows
51+
);
52+
53+
return ({
54+
className,
55+
confidence,
56+
topLeft,
57+
bottomRight
58+
})
59+
});
60+
61+
return results;
62+
};
63+
64+
const makeDrawClassDetections = predictions => (drawImg, className, getColor, thickness = 2) => {
65+
predictions
66+
.filter(p => p.className === className)
67+
.forEach(p => {
68+
drawImg.drawRectangle(
69+
p.topLeft,
70+
p.bottomRight,
71+
getColor(),
72+
{ thickness }
73+
);
74+
});
75+
return drawImg;
76+
};
77+
78+
const runDetectDishesExample = () => {
79+
const img = cv.imread('../data/dishes.jpg');
80+
const minConfidence = 0.2;
81+
82+
const predictions = classifyImg(img).filter(res => res.confidence > minConfidence);
83+
84+
const drawClassDetections = makeDrawClassDetections(predictions);
85+
86+
const classColors = {
87+
fork: new cv.Vec(0, 255, 0),
88+
bowl: new cv.Vec(255, 0, 0),
89+
'wine glass': new cv.Vec(0, 0, 255),
90+
cup: new cv.Vec(0, 255, 255)
91+
};
92+
93+
const legendLeftTop = new cv.Point(550, 20);
94+
Object.keys(classColors).forEach((className, i) => {
95+
const color = classColors[className];
96+
97+
// const draw legend
98+
const offY = i * 30;
99+
img.drawCircle(
100+
legendLeftTop.add(new cv.Point(0, offY)),
101+
3,
102+
color,
103+
{ thickness: 4 }
104+
);
105+
img.putText(
106+
className,
107+
legendLeftTop.add(new cv.Point(20, offY + 8)),
108+
cv.FONT_ITALIC,
109+
0.8,
110+
color,
111+
{ thickness: 2 }
112+
);
113+
114+
// draw detections
115+
drawClassDetections(img, className, () => color);
116+
});
117+
118+
cv.imshowWait('img', img);
119+
};
120+
121+
const runDetectPeopleExample = () => {
122+
const img = cv.imread('../data/cars.jpeg');
123+
const minConfidence = 0.4;
124+
125+
const predictions = classifyImg(img).filter(res => res.confidence > minConfidence);
126+
127+
const drawClassDetections = makeDrawClassDetections(predictions);
128+
129+
const getRandomColor = () => new cv.Vec(Math.random() * 255, Math.random() * 255, 255);
130+
131+
drawClassDetections(img, 'car', getRandomColor);
132+
cv.imshowWait('img', img);
133+
};
134+
135+
runDetectDishesExample();
136+
runDetectPeopleExample();

‎examples/tensorflowInception.js renamed to ‎examples/dnnTensorflowInception.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ if (!cv.xmodules.dnn) {
77
}
88

99
// replace with path where you unzipped inception model
10-
const inceptionModelPath = '../data/dnn'
10+
const inceptionModelPath = '../data/dnn/tf-inception'
1111

1212
const modelFile = path.resolve(inceptionModelPath, 'tensorflow_inception_graph.pb');
1313
const classNamesFile = path.resolve(inceptionModelPath, 'imagenet_comp_graph_label_strings.txt');

0 commit comments

Comments
 (0)
This repository has been archived.