首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >未捕获TypeError:无法读取null的属性'addEventListener‘。无法启动视频源。Face Api.js和Rails 5

未捕获TypeError:无法读取null的属性'addEventListener‘。无法启动视频源。Face Api.js和Rails 5
EN

Stack Overflow用户
提问于 2020-08-08 06:10:03
回答 1查看 178关注 0票数 0

您好,我有一个使用Rails5的应用程序,我在其中添加了用于人脸识别的Face-api.js库。

在我看来,我有用于人脸检测和识别的脚本和视频,但当我转到浏览器并加载页面时,控制台返回以下错误。

代码语言:javascript
复制
Uncaught TypeError: Cannot read property 'addEventListener' of null
at new:161
(anonymous) @ new:161
new:149 NotReadableError: Could not start video source

包含脚本和网络摄像头视频的我的视图:

代码语言:javascript
复制
<head>
      <%= javascript_include_tag 'face_api'%>
      <%= javascript_include_tag "face-api.js/dist/face-api.min.js" %>
      <%= javascript_include_tag "face-api.js/dist/face-api.js" %>
      <script>
        const camfr = document.getElementById('camfr')
        
        const startVideo = () => {
        
            var constraints = { audio: true, video: { width: 1280, height: 720 } };
                navigator.mediaDevices.getUserMedia(constraints)
                .then(function(mediaStream) {
                    var video = document.querySelector('video');
                    video.srcObject = mediaStream;
                    video.onloadedmetadata = function(e) {
                        video.play();
                    };
                })
            .catch(function(err) { console.log(err.name + ": " + err.message); }); // always check for errors at the end.
        }
        
        Promise.all([
           faceapi.nets.tinyFaceDetector.loadFromUri("<%= asset_path('face-api.js/models/tiny_face_detector/tiny_face_detector_model-weights_manifest.json') %>"),
           faceapi.nets.faceLandmark68Net.loadFromUri("<%= asset_path('face-api.js/models/face_landmark_68/face_landmark_68_model-weights_manifest.json') %>"), //desenha os traços do rosto
           faceapi.nets.faceRecognitionNet.loadFromUri("<%= asset_path('face-api.js/models/face_recognition/face_recognition_model-weights_manifest.json') %>"),//faz o conhecimento do rosto
           faceapi.nets.faceExpressionNet.loadFromUri("<%= asset_path('face-api.js/models/face_expression/face_expression_model-weights_manifest.json') %>"),//detecta expressoes
           faceapi.nets.ageGenderNet.loadFromUri("<%= asset_path('face-api.js/models/age_gender_model/age_gender_model-weights_manifest.json') %>"),//idade e genero
           faceapi.nets.ssdMobilenetv1.loadFromUri("<%= asset_path('face-api.js/models/ssd_mobilenetv1/ssd_mobilenetv1_model-weights_manifest.json') %>") // usada para detectar rosto
        ]).then(startVideo)
        
        camfr.addEventListener('play', async () => {
        const canvas = faceapi.createCanvasFromMedia(camfr)
        const canvasSize = {
            width: camfr.width,
            height: camfr.height
        }
        faceapi.matchDimensions(canvas, canvasSize)
        document.body.appendChild(canvas)
        setInterval(async () => {
            const detections = await faceapi
            .detectAllFaces(
                camfr,
                new faceapi.TinyFaceDetectorOptions()
                )
                .withFaceLandmarks()
                .withFaceExpressions()
                .withAgeAndGender()
                const resizedDetections = faceapi.resizeResults(detections, canvasSize)
                canvas.getContext('2d').clearRect(0, 0, canvas.width, canvas.height)
                faceapi.draw.drawDetections(canvas, resizedDetections)
                faceapi.draw.drawFaceLandmarks(canvas, resizedDetections)
                faceapi.draw.drawFaceExpressions(canvas, resizedDetections)
        
                resizedDetections.forEach(detection => {
                    const {age, gender, genderProbability} = detection
                    new faceapi.draw.DrawTextField([
                                `${parseInt(age, 10)} years`,
                                `${gender} (${ parseInt(genderProbability * 100, 10)})`
                            ], detection.detection.box.topRight).draw(canvas)
        })
        
        }, 100)
        })
      </script>
    </head>

    <body>
      <video autopĺay id="camfr" width="400" height="400" muted></video>
    </body>

我不明白这有什么不起作用的--faceapi.js在供应商/资产/javascript上,在assets.rb中,我对新的javascript和faceapi.js模型进行了预编译。

我的脸-api.js

代码语言:javascript
复制
//= require face-api.js/dist/face-api 
//= require face-api.js/dist/face-api.js 
//= require face-api.js/dist/face-api.min.js
EN

回答 1

Stack Overflow用户

发布于 2020-08-08 07:44:33

<head>标记在页面的其余部分之前加载,因此在camfr = document.getElementById('camfr')运行时不会加载DOM。您需要将脚本包装在一个事件中,以确保DOM在执行之前已完全加载。如果你使用turbolinks:

代码语言:javascript
复制
document.addEventListener('turbolinks:load', () => {
  const camfr = document.getElementById('camfr');
  if (element) {
    ...
  }
});

如果不使用turbolink,那么可以使用onload事件而不是turbolinks:load

此外,使用Javascript的“Rails方式”是将代码提取到资产路径中的一个单独的.js文件中(如果使用的是Rails6,则为webpacker包),而不是直接嵌入到<script>标记中。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63309742

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档