obniz公式サイトにある動作例の一つ
顔検出扇風機
ですが、ソースコードが少し古いようで、そのまま動かないです!
内容がとても面白そうですから
どうしても動かしてみたいです。

動くプログラムはここに!
opencv.jsも利用して、顔を検出して、追跡する訳ですから、とても動作して欲しかったです。
もし、あなたも同じことで悩んでいるのならば
もう、ここに来てよかったです!
はい、前置きはこのぐらいにして、動くソースコードはこちらです!どうぞ!
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Video Capture Example</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
<script src="https://docs.opencv.org/3.4/opencv.js"></script>
<script src="https://obniz.io/js/jquery-3.2.1.min.js"></script>
<script src="https://unpkg.com/obniz@1.5.2/obniz.js"></script>
<style>
.refrect-lr{
-webkit-transform: scaleX(-1);
-o-transform: scaleX(-1);
-moz-transform: scaleX(-1);
transform: scaleX(-1);
filter: FlipH;
-ms-filter: "FlipH";
}
</style>
</head>
<body>
<div id="obniz-debug"></div>
<div>
<div class="control">
<button id="startAndStop">Start</button>
</div>
</div>
<p class="err" id="errorMessage"></p>
<div>
<table cellpadding="0" cellspacing="0" width="0" border="0">
<tr>
<td>
<video id="videoInput" autoplay playsinline width=320 height=240 class="refrect-lr"></video>
</td>
<td>
<canvas id="canvasOutput" width=320 height=240 style="-webkit-font-smoothing:none"
class="refrect-lr"></canvas>
</td>
<td></td>
<td></td>
</tr>
<tr>
<td>
<div class="caption">videoInput</div>
</td>
<td>
<div class="caption">canvasOutput</div>
</td>
<td></td>
<td></td>
</tr>
</table>
</div>
<script src="https://webrtc.github.io/adapter/adapter-5.0.4.js" type="text/javascript"></script>
<script src="https://docs.opencv.org/3.4/utils.js" type="text/javascript"></script>
<script type="text/javascript">
var servo;
obniz = new Obniz("YOUR_OBNIZ_ID");
obniz.onconnect = async () => {
obniz.display.print("ready")
var usb = obniz.wired("USB" , {gnd:11, vcc:8} );
usb.on();
servo = obniz.wired("ServoMotor", {signal:0,vcc:1, gnd:2});
}
let utils = new Utils('errorMessage');
let faceCascadeFile = 'haarcascade_frontalface_default.xml';
utils.createFileFromUrl(faceCascadeFile, 'https://raw.githubusercontent.com/opencv/opencv/master/data/haarcascades/haarcascade_frontalface_default.xml', () => {
startAndStop.removeAttribute('disabled');
});
let streaming = false;
let videoInput = document.getElementById('videoInput');
let startAndStop = document.getElementById('startAndStop');
let canvasOutput = document.getElementById('canvasOutput');
let canvasContext = canvasOutput.getContext('2d');
function successCallback(stream) {
document.getElementById("videoInput").srcObject = stream;
onVideoStarted();
};
function errorCallback(err) {
console.error('mediaDevice.getUserMedia() error:', error);
};
startAndStop.addEventListener('click', () => {
if (!streaming) {
utils.clearError();
const medias = {
audio: false, video: {
facingMode: "user"
}
};
navigator.mediaDevices = navigator.mediaDevices || ((navigator.mozGetUserMedia || navigator.webkitGetUserMedia) ? {
getUserMedia: function(c) {
return new Promise(function(y, n) {
(navigator.mozGetUserMedia ||
navigator.webkitGetUserMedia).call(navigator, c, y, n);
});
}
} : null);
if (!navigator.mediaDevices) {
console.log("getUserMedia() not supported.");
return;
}
// Prefer camera resolution nearest to 1280x720.
var constraints = { audio: true, video: true };
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
streaming=true;
var video = document.querySelector('video');
video.src = window.URL.createObjectURL(stream);
video.onloadedmetadata = function(e) {
video.play();
start();
};
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
});
} else {
utils.stopCamera();
onVideoStopped();
}
});
function onVideoStarted() {
streaming = true;
startAndStop.innerText = 'Stop';
start();
}
function onVideoStopped() {
streaming = false;
canvasContext.clearRect(0, 0, canvasOutput.width, canvasOutput.height);
startAndStop.innerText = 'Start';
}
async function start() {
let video = document.getElementById('videoInput');
let src = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let gray = new cv.Mat();
let cap = new cv.VideoCapture(video);
let faces = new cv.RectVector();
let classifier = new cv.CascadeClassifier();
let result = classifier.load("haarcascade_frontalface_default.xml");
const FPS = 30;
function processVideo() {
try {
if (!streaming) {
// clean and stop.
src.delete();
dst.delete();
gray.delete();
faces.delete();
classifier.delete();
return;
}
let begin = Date.now();
// start processing.
cap.read(src);
src.copyTo(dst);
cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0);
// detect faces.
classifier.detectMultiScale(gray, faces, 1.1, 3, 0);
// draw faces.
for (let i = 0; i < faces.size(); ++i) {
let face = faces.get(i);
let point1 = new cv.Point(face.x, face.y);
let point2 = new cv.Point(face.x + face.width, face.y + face.height);
cv.rectangle(dst, point1, point2, [255, 0, 0, 255]);
}
cv.imshow('canvasOutput', dst);
if(servo && faces.size() > 0){
let face = faces.get(0);
console.log('servo.angle((320-(face.x + face.width/2)) * 180 / 320) -->',(320-(face.x + face.width/2)) * 180 / 320);
servo.angle((320-(face.x + face.width/2)) * 180 / 320)
}
// schedule the next one.
let delay = 100 / FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
console.error(err);
}
};
// schedule the first one.
setTimeout(processVideo, 0);
}
</script>
</body>
</html>
他のハードウェア接続などは
公式の説明に参照してください。そのままです。
実行
- いつものやり方で、ブラウザーで実行してください。
- 上のプログラムにYOUR_OBNIZ_IDのところに、あたなのobniz個体のIDを上書きしてください。
- その前もちろん、obnizの方も電源を接続して置いてください。
起動すると、カメラの許可を求められます。
もちろん、許可してください。セキュリティー関係はご自身の責任で確認してから行ってください。
許可すると
パソコンのカメラのインジケータが点灯します。
カメラが使用中ですよという合図です。
ちなみに、私は、chromeとsafariが上手くいかず
Firefoxでちゃんとカメラが起動して、動作しました。
そうすると、あなたの顔が検出されて、サーボの回転する角度に変換されます!
いかがですか?
動くと嬉しいですね。
しかも顔を検出して、追跡するという動作まで
本当に簡単に実現できたことに驚きばかりです!
obnizが本当にすごいです!これでウェブエンジニアもすぐIoTができてしまいます!
(ソースコードが動くとは言え、だいぶ急いで殴り書きになっておりまして、もっと綺麗に書ける余地があるかと思います、何か気づいたことがあれば、ご連絡いただければ、嬉しいです。)
[amazonjs asin=”B07DD6FK8G” locale=”JP” title=”obniz (オブナイズ)”]
[amazonjs asin=”B010SLRAAS” locale=”JP” title=”MG996R メタルギア・デジタルサーボ”]