Djangoの機能追加
解決したいこと
DjangoのコードにJavaScriptの追加をするとエラーが発生する
Djangoで、クイズのアプリを作成しています。
その過程で、JavaScriptの顔認識機能を作成しましたが作動しません
発生している問題・エラー
Failed to load resource: the server responded with a status of 404 (Not Found)
face-api.min.js:1
Failed to load resource: the server responded with a status of 404 (Not Found)
1/:1 Refused to execute script from 'http://127.0.0.1:8000/students/quiz/1/js/face-api.min.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
1/:1 Refused to execute script from 'http://127.0.0.1:8000/students/quiz/1/js/script.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
31/:89 Uncaught ReferenceError: OnButtonClick is not defined
at HTMLInputElement.onclick (1/:89:63)
または、問題・エラーが起きている画像をここにドラッグアンドドロップ
該当するソースコード
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block content %}
<div class="progress mb-3">
<div class="progress-bar" role="progressbar" aria-valuenow="{{ progress }}" aria-valuemin="0" aria-valuemax="100" style="width: {{ progress }}%"></div>
</div>
<h2 class="mb-3">{{ quiz.name }}</h2>
<p class="lead">{{ question.text }}</p>
<form method="post" novalidate>
{% csrf_token %}
{{ form|crispy }}
<button type="submit" class="btn btn-primary">Next →</button>
</form>
{% endblock %}
上記のコードに、以下のコードを追加しようと試みています
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>media element</title>
<script src="js/face-api.min.js" type="text/javascript"></script>
<script src="js/script.js" type="text/javascript"></script>
<style>
div.wait{
margin:0;
padding:0;
box-sizing:border-box;
position:fixed;
width:100vw;
height:100vh;
left:0;
top:0;
right:0;
bottom:0;
display:none;
background:rgba(255,255,255,0.8);
z-index:30000;
font-size:18px;
}
div.wait>img{
position:relative;
display:block;
left:50%;
top:50%;
transform:translate(-50%,-50%);
}
#preview{
max-width:100%;
width:640px;
height:auto;
}
#back{
max-width:100%;
width:800px;
height:auto;
background:rgba(255,255,255,0.8);
}
</style>
</head>
<body>
<div class="wait"><img src="./img/loading.gif"></div>
<input type="button" value="開始" onclick="OnButtonClick();"/><br />
<div style="position: relative;">
<canvas id="back" width="800" height="600" style="position: absolute; top: 0px; left: 0px;"></canvas>
<video id="video" width="640" height="480" style="position: absolute; top: 60px; left: 80px; transform: scaleX(-1);"></video>
<canvas id="preview" width="640" height="480" style="position: absolute; top: 60px; left: 80px; transform: scaleX(-1);"></canvas>
</div>
</body>
</html>
var video,prev,prev_ctx,prevW,prevH;
var detect;
var irisC = [];
let nowBlinking = false;
let blinkCount = 0;
async function loadImage(src){
return new Promise(function(resolve,reject){
let img=new Image();
img.onload=function(){resolve(img);}
img.onerror=function(e){reject(e);}
img.src=src;
});
}
window.addEventListener('DOMContentLoaded',async function(event){
//ロード中画像の表示
ShowWait();
detect=0;
prev=document.querySelector("#preview");
prev_ctx=prev.getContext("2d" ,{willReadFrequently:false});
back=document.querySelector("#back");
back_ctx=back.getContext("2d" ,{willReadFrequently:false});
//alert=document.querySelector("#alert");
//alert_ctx=back.getContext("2d" ,{willReadFrequently:false});
// 画像読み込み
mAlertImage = new Image();
if(mAlertImage){
mAlertImage.src = "/img/alert.png";
}
// 音声読み込み
mBlinkSound = new Audio("/sound/alert.mp3");
await Promise.all([
//顔認識とランドマーク用の学習モデルを読み込む
faceapi.nets.tinyFaceDetector.loadFromUri('./models'),
faceapi.nets.faceLandmark68TinyNet.loadFromUri("./models"),
]);
//<video>エレメントの取得と設定
video = document.getElementById("video");
video.setAttribute("autoplay","");
video.setAttribute("muted","");
video.setAttribute("playsinline","");
video.onloadedmetadata = function(e){video.play();};
prev=document.getElementById("preview");
prev_ctx=prev.getContext("2d", {willReadFrequently:true,alpha:false});
//左右反転表示させる
prev.style.transform="scaleX(-1)";
//ロード中画像の非表示
HideWait();
});
function OnButtonClick() {
//カメラ使用の許可ダイアログが表示される
navigator.mediaDevices.getUserMedia(
//マイクはオフ, カメラの設定 前面カメラを希望する 640×480を希望する
//参考:背面は"environment"、全面は"user"
{"audio":false,"video":{"facingMode":"user","width":{"ideal":640},"height":{"ideal":480}}}
).then( //許可された場合
function(stream){
video.srcObject = stream;
//0.5秒後にスキャンする
setTimeout(Scan,500,true);
}
).catch(
//許可されなかった場合
function(){
//ロード中画像の非表示
HideWait();
}
);
}
async function Scan(first){
if(first){
//初回のみ設定を行う(最終的に選択されたカメラ映像のサイズが不明の為)
//選択された幅高さ
prevW=video.videoWidth;
prevH=video.videoHeight;
//内部のサイズ
prev.setAttribute("width",prevW);
prev.setAttribute("height",prevH);
//ロード中画像の非表示
HideWait();
}
// webカメラの映像から顔検出を行う
const useTinyModel = true;
const detection = await faceapi.detectSingleFace(
video ,
new faceapi.TinyFaceDetectorOptions({
inputSize:160, //検出する最大ピクセル数、32だと最大で32x32ピクセルの顔まで検出する
})
).withFaceLandmarks(true);
prev_ctx.clearRect(0, 0, prevW, prevH);
prev_ctx.drawImage(video,0,0,prevW,prevH);
var frame = prev_ctx.getImageData(0,0,prevW,prevH);
if(detection){
//アラート非表示
HideAlert();
detect=0;
// 背景を青にする
document.getElementById('back').style.backgroundColor = "blue";
// 認識データをリサイズ
const resizedDetection = faceapi.resizeResults(detection, {
width: video.width,
height: video.height,
});
// ランドマークをキャンバスに描画
faceapi.draw.drawFaceLandmarks(prev, resizedDetection);
// 以後使用するランドマーク座標
const landmarks = resizedDetection.landmarks;
//const nose = landmarks.getNose()[3];
//const leftEye = landmarks.getLeftEye()[0];
//const rightEye = landmarks.getRightEye()[3];
//const jaw = landmarks.getJawOutline()[8];
//const leftMouth = landmarks.getMouth()[0];
//const rightMouth = landmarks.getMouth()[6];
//const leftOutline = landmarks.getJawOutline()[0];
//const rightOutline = landmarks.getJawOutline()[16];
const landmarkPositions = landmarks.positions;
//--- Iric mark ---//
//ctx_bg.clearRect(0, 0, canvas_bg.width, canvas_bg.height)
var x_ = landmarkPositions[38-1].x
var y_ = landmarkPositions[38-1].y
var w_ = landmarkPositions[39-1].x - landmarkPositions[38-1].x
var h_ = landmarkPositions[42-1].y - landmarkPositions[38-1].y
//ctx_bg.fillStyle = "rgb(255,0,0)";
//ctx_bg.fillRect(x_, y_, w_, h_)
x_ = landmarkPositions[44-1].x
y_ = landmarkPositions[44-1].y
w_ = landmarkPositions[45-1].x - landmarkPositions[44-1].x
h_ = landmarkPositions[48-1].y - landmarkPositions[44-1].y
//ctx_bg.fillRect(x_, y_, w_, h_)
//--- Iris value ---//
var p_ = Math.floor(x_+w_/2) + Math.floor(y_+h_/2) * video.width
//console.log("eye_RGB:"+[frame.data[p_*4+0], frame.data[p_*4+1], frame.data[p_*4+2]]);
var v_ = Math.floor( (frame.data[p_*4+0] + frame.data[p_*4+1] + frame.data[p_*4+2])/3 );
//console.log("irisC:"+v_);
irisC.push(v_);
if(irisC.length>100){
irisC.shift();
}//
let meanIrisC = irisC.reduce(function(sum, element){
return sum + element;
}, 0);
meanIrisC = meanIrisC / irisC.length;
let vThreshold = 1.5;
let currentIrisC = irisC[irisC.length-1];
if(irisC.length==100){
if(nowBlinking==false){
if(currentIrisC>=meanIrisC*vThreshold){
nowBlinking = true;
if(mBlinkSound){
mBlinkSound.pause();
}
// 背景を青にする
document.getElementById('back').style.backgroundColor = "blue";
}//
}//
else{
if(currentIrisC<meanIrisC*vThreshold){
nowBlinking = false;
blinkCount += 1;
if(mBlinkSound){
if(mBlinkSound.paused){
mBlinkSound.currentTime = 0;
mBlinkSound.play();
}
}
// 背景を紫にする
document.getElementById('back').style.backgroundColor = "purple";
}//
}//
}//
}else{
detect=detect+1;
if(detect>50){
// 背景色を赤にする
document.getElementById('back').style.backgroundColor = 'red';
//アラート表示
ShowAlert();
}else if(detect>10){
// 背景色を黄にする
document.getElementById('back').style.backgroundColor = 'yellow';
}
}
setTimeout(Scan,50,false);
}
function drawPath(arr,ctx,lineWidth,color){
ctx.lineWidth=lineWidth;
ctx.strokeStyle=color;
ctx.beginPath();
ctx.moveTo(arr[0].x,arr[0].y);
for(let i=1;i<arr.length;i++){
ctx.lineTo(arr[i].x,arr[i].y);
}
ctx.stroke();
}
function ShowWait(){
document.querySelector(".wait").style.display="block";
}
function HideWait(interval){
setTimeout(function(){
document.querySelector(".wait").style.display="none";
},interval);
}
function ShowAlert(){
//alert.style.visibility="visible";
//alert_ctx.drawImage(mAlertImage, 0, 0, 800, 600);
if(mAlertImage){
prev_ctx.drawImage(mAlertImage, 0, 0, 640, 480);
}
if(mBlinkSound.paused){
mBlinkSound.currentTime = 0;
mBlinkSound.play();
}
}
function HideAlert(interval){
//alert.style.visibility="hidden";
//alert_ctx.clearRect(0, 0, 800, 600);
prev_ctx.clearRect(0, 0, 640, 480);
mBlinkSound.pause();
}
自分で試したこと
コードをDjangoに対応できるように、{% extends 'base.html' %}{% load crispy_forms_tags %}{% block content %}を追加しました。
また、対応するJavaScriptのフォルダを追加しました
0 likes