Skip to content

Commit 13a51ec

Browse files
committed
Merge branch 'develop'
2 parents 2bf8680 + 1ae7103 commit 13a51ec

31 files changed

+1333
-134
lines changed

CONTRIBUTING.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
We use [Developer Certificate of Origin](https://developercertificate.org/).
2+
3+
To use DCO, you only need to add your signature into a Git commit:
4+
5+
```
6+
$ git commit -s -m "your commit message."
7+
```

README.md

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,16 +78,16 @@ For more details about dashboard configuration (e.g. how to add widgets), please
7878

7979
# Provide Image Input
8080

81-
To capture an image via Pi camera
81+
To capture an image via configured IP camera
8282

8383
```
84-
$ mosquitto_pub -h localhost -t berrynet/event/camera -m snapshot_picam
84+
$ mosquitto_pub -h localhost -t berrynet/event/camera -m snapshot_ipcam
8585
```
8686

87-
To capture an image via configured IP camera
87+
To capture an image via board-connected camera (RPi camera or USB webcam)
8888

8989
```
90-
$ mosquitto_pub -h localhost -t berrynet/event/camera -m snapshot_ipcam
90+
$ mosquitto_pub -h localhost -t berrynet/event/camera -m snapshot_boardcam
9191
```
9292

9393
To provide a local image
@@ -96,6 +96,49 @@ To provide a local image
9696
$ mosquitto_pub -h localhost -t berrynet/event/localImage -m <image_path>
9797
```
9898

99+
To start and stop streaming from board-connected camera
100+
101+
```
102+
$ mosquitto_pub -h localhost -t berrynet/event/camera -m stream_boardcam_start
103+
$ mosquitto_pub -h localhost -t berrynet/event/camera -m stream_boardcam_stop
104+
```
105+
106+
To start and stop streaming from Nest IP camera
107+
108+
```
109+
$ mosquitto_pub -h localhost -t berrynet/event/camera -m stream_nest_ipcam_start
110+
$ mosquitto_pub -h localhost -t berrynet/event/camera -m stream_nest_ipcam_stop
111+
```
112+
113+
114+
# Enable Data Collector
115+
116+
You might want to store the snapshot and inference results for data analysis.
117+
118+
To enable data collector, you can set the storage directory path in config.js:
119+
120+
```
121+
config.storageDirPath = '<data-storage-dirpath>';
122+
```
123+
124+
and restart BerryNet.
125+
126+
127+
# Use Your Data To Train
128+
129+
The original instruction of retraining YOLOv2 model see [github repository of darknet](https://github.com/AlexeyAB/darknet#how-to-train-to-detect-your-custom-objects)
130+
131+
In the current of BerryNet, TinyYolo is used instead of YOLOv2.
132+
The major differences are:
133+
134+
1. Create file yolo-obj.cfg with the same content as in `tiny-yolo.cfg`
135+
2. Download pre-trained weights of darknet reference model, `darknet.weights.12`, for the convolutional layers (6.1MB)
136+
https://drive.google.com/drive/folders/0B-oZJEwmkAObMzAtc2QzZDhyVGM?usp=sharing
137+
138+
The rest parts are the same as retraining YOLO.
139+
140+
If you use [LabelMe](http://labelme.csail.mit.edu/Release3.0/) to annotate data, `utils/xmlTotxt.py` can help convert the xml format to the text format that darknet uses.
141+
99142

100143
# Discussion
101144

berrynet-manager

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
#! /bin/sh
22
#
33
# Copyright 2017 DT42
4-
#
4+
#
55
# This file is part of BerryNet.
6-
#
6+
#
77
# BerryNet is free software: you can redistribute it and/or modify
88
# it under the terms of the GNU General Public License as published by
99
# the Free Software Foundation, either version 3 of the License, or
1010
# (at your option) any later version.
11-
#
11+
#
1212
# BerryNet is distributed in the hope that it will be useful,
1313
# but WITHOUT ANY WARRANTY; without even the implied warranty of
1414
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1515
# GNU General Public License for more details.
16-
#
16+
#
1717
# You should have received a copy of the GNU General Public License
1818
# along with BerryNet. If not, see <http://www.gnu.org/licenses/>.
1919

@@ -26,25 +26,34 @@ help() {
2626
exit 1
2727
}
2828

29-
if [ $# -lt 1 ]
30-
then
31-
help
29+
if [ $# -lt 1 ]; then
30+
help
3231
fi
3332

3433
case $1 in
35-
start | stop | status)
36-
sudo systemctl $1 detection_server.service agent.service broker.service dashboard.service localimg.service camera.service journal.service cleaner.timer
37-
;;
38-
log)
39-
sudo journalctl -x --no-pager -u detection_server.service
34+
start | stop | status)
35+
sudo systemctl $1 \
36+
detection_fast_server.service \
37+
agent.service \
38+
broker.service \
39+
dashboard.service \
40+
localimg.service \
41+
camera.service \
42+
journal.service \
43+
data_collector.service \
44+
line.service
45+
;;
46+
log)
47+
sudo journalctl -x --no-pager -u detection_fast_server.service
4048
sudo journalctl -x --no-pager -u agent.service
4149
sudo journalctl -x --no-pager -u broker.service
4250
sudo journalctl -x --no-pager -u dashboard.service
4351
sudo journalctl -x --no-pager -u localimg.service
4452
sudo journalctl -x --no-pager -u camera.service
4553
sudo journalctl -x --no-pager -u journal.service
46-
sudo journalctl -x --no-pager -u cleaner.timer
47-
;;
48-
*)
49-
help
50-
esac
54+
sudo journalctl -x --no-pager -u data_collector.service
55+
sudo journalctl -x --no-pager -u line.service
56+
;;
57+
*)
58+
help
59+
esac

camera.js

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const mqtt = require('mqtt');
2222
const request = require('request');
2323
const spawnsync = require('child_process').spawnSync;
2424
const config = require('./config');
25+
const cv = require('opencv');
2526

2627
const broker = config.brokerHost;
2728
const client = mqtt.connect(broker);
@@ -30,10 +31,21 @@ const topicActionInference = config.topicActionInference;
3031
const topicEventCamera = config.topicEventCamera;
3132
const cameraURI = config.ipcameraSnapshot;
3233
const snapshotFile = '/tmp/snapshot.jpg';
34+
const snapshotWidth = config.boardcameraImageWidth;
35+
const snapshotHeight = config.boardcameraImageHeight;
3336
const cameraCmd = '/usr/bin/raspistill';
3437
const cameraArgs = ['-vf', '-hf',
35-
'-w', '1024', '-h', '768',
38+
'-w', snapshotWidth,
39+
'-h', snapshotHeight,
3640
'-o', snapshotFile];
41+
const usbCameraCmd = '/usr/bin/fswebcam';
42+
const usbCameraArgs = ['-r', snapshotWidth + 'x' + snapshotHeight,
43+
'--no-banner', '-D', '0.5', snapshotFile];
44+
const fps = 30;
45+
var cameraIntervalID = null;
46+
var cameraInterval = 1000.0 / fps;
47+
var cameraCV = null;
48+
var frameCounter = 0;
3749

3850
function log(m) {
3951
client.publish(topicActionLog, m);
@@ -50,6 +62,13 @@ client.on('message', (t, m) => {
5062

5163
const action = m.toString();
5264
if (action == 'snapshot_picam') {
65+
/* NOTE: We use V4L2 to support RPi camera, so RPi camera's usage is
66+
* the same as USB camera. Both RPi and USB cameras are called
67+
* "board camera".
68+
*
69+
* This action is obsoleted and will be removed in the future.
70+
*/
71+
5372
// Take a snapshot from RPi3 camera. The snapshot will be displayed
5473
// on dashboard.
5574
spawnsync(cameraCmd, cameraArgs);
@@ -75,6 +94,75 @@ client.on('message', (t, m) => {
7594
}
7695
}
7796
);
97+
} else if (action == 'snapshot_boardcam') {
98+
// Take a snapshot from USB camera.
99+
spawnsync(usbCameraCmd, usbCameraArgs);
100+
fs.readFile(snapshotFile, function(err, data) {
101+
if (err) {
102+
log('camera client: cannot get image.');
103+
} else {
104+
log('camera client: publishing image.');
105+
client.publish(topicActionInference, data);
106+
}
107+
});
108+
} else if (action == 'stream_boardcam_start') {
109+
if ((!cameraCV) && (!cameraIntervalID)) {
110+
cameraCV = new cv.VideoCapture(0);
111+
cameraCV.setWidth(snapshotWidth);
112+
cameraCV.setHeight(snapshotHeight);
113+
cameraIntervalID = setInterval(function() {
114+
cameraCV.read(function(err, im) {
115+
if (err) {
116+
throw err;
117+
}
118+
if (frameCounter < fps * 2) {
119+
frameCounter++;
120+
} else {
121+
frameCounter = 0;
122+
im.save(snapshotFile);
123+
fs.readFile(snapshotFile, function(err, data) {
124+
if (err) {
125+
log('camera client: cannot get image.');
126+
} else {
127+
log('camera client: publishing image.');
128+
client.publish(topicActionInference, data);
129+
}
130+
});
131+
}
132+
im.release();
133+
});
134+
}, cameraInterval);
135+
}
136+
} else if (action == 'stream_boardcam_stop') {
137+
if (cameraCV) {
138+
cameraCV.release();
139+
cameraCV = null;
140+
}
141+
if (cameraIntervalID) {
142+
clearInterval(cameraIntervalID);
143+
cameraIntervalID = null;
144+
}
145+
} else if (action == 'stream_nest_ipcam_start') {
146+
if (!cameraIntervalID) {
147+
cameraIntervalID = setInterval(function() {
148+
request.get(
149+
{uri: cameraURI, encoding: null},
150+
(e, res, body) => {
151+
if (!e && res.statusCode == 200) {
152+
log('camera client: publishing image.');
153+
client.publish(topicActionInference, body);
154+
} else {
155+
log('camera client: cannot get image.');
156+
}
157+
}
158+
);
159+
}, cameraInterval);
160+
}
161+
} else if (action == 'stream_nest_ipcam_stop') {
162+
if (cameraIntervalID) {
163+
clearInterval(cameraIntervalID);
164+
cameraIntervalID = null;
165+
}
78166
} else {
79167
log('camera client: unkown action.');
80168
}

cleaner.sh

Lines changed: 0 additions & 5 deletions
This file was deleted.

client.js

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
var mqtt = require('mqtt')
2-
//var client = mqtt.connect('mqtt://test.mosquitto.org')
3-
var client = mqtt.connect('mqtt://localhost:1883')
1+
var mqtt = require('mqtt');
2+
//var client = mqtt.connect('mqtt://test.mosquitto.org');
3+
var client = mqtt.connect('mqtt://localhost:1883');
44

55
client.on('connect', function () {
6-
client.subscribe('presence')
7-
client.publish('presence', 'Hello mqtt')
8-
})
6+
client.subscribe('presence');
7+
client.publish('presence', 'Hello mqtt');
8+
});
99

1010
client.on('message', function (topic, message) {
1111
// message is Buffer
12-
console.log(message.toString())
13-
client.end()
14-
})
12+
console.log(message.toString());
13+
client.end();
14+
});

config.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,22 +41,36 @@ config.topicEventCamera = padTopicBase('event/camera');
4141
config.topicEventLocalImage = padTopicBase('event/localImage');
4242
config.topicNotifyEmail = padTopicBase('notify/email');
4343
config.topicNotifySMS = padTopicBase('notify/sms');
44+
config.topicNotifyLINE = padTopicBase('notify/line');
4445
config.topicDashboardLog = padTopicBase('dashboard/log');
4546
config.topicDashboardSnapshot = padTopicBase('dashboard/snapshot');
4647
config.topicDashboardInferenceResult = padTopicBase('dashboard/inferenceResult');
48+
config.topicJSONInferenceResult = padTopicBase('data/jsonInferenceResult');
4749

4850
// IP camera
4951
config.ipcameraSnapshot = '';
5052

53+
// Board camera, e.g. USB and RPi cameras
54+
config.boardcameraImageWidth = 640;
55+
config.boardcameraImageHeight = 480;
56+
57+
// data collector configs
58+
config.storageDirPath = '';
59+
5160
// email notification
52-
config.senderEmail = 'SENDER_EMAIL';
53-
config.senderPassword = 'SENDER_PASSWORD';
54-
config.receiverEmail = 'RECEIVER_EMAIL';
61+
config.senderEmail = '';
62+
config.senderPassword = '';
63+
config.receiverEmail = '';
5564

5665
// for compatibility
5766
config.sender_email = config.senderEmail;
5867
config.sender_password = config.senderPassword;
5968
config.receiver_email = config.receiverEmail;
6069

70+
// Authentication and channel information for LINE
71+
config.LINETargetUserID = '';
72+
config.LINEChannelSecret = '';
73+
config.LINEChannelAccessToken = '';
74+
6175
// make config importable
6276
module.exports = config;

config/bcm2835-v4l2.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# BerryNet supports accessing RPi camera access via OpenCV.
2+
3+
bcm2835_v4l2

0 commit comments

Comments
 (0)