【问题标题】:Posting An Image from Webcam to Azure Face Api将图像从网络摄像头发布到 Azure Face Api
【发布时间】:2018-03-24 22:36:37
【问题描述】:

我正在尝试将从网络摄像头获取的图像上传到 Microsoft Azure Face Api。我从包含数据 Uri 的 canvas.toDataUrl('image/png') 获取图像。我将 Content Type 更改为 application/octet-stream,当我将 Data Uri 附加到 post 请求时,我收到一个 Bad Request (400) Invalid Face Image。如果我将附加数据更改为 Blob,我将停止接收错误,但是我只会返回一个空数组而不是 JSON 对象。我非常感谢您为我指明正确方向的任何帮助。

谢谢!

【问题讨论】:

  • toDataUrl 的结果已经是一个有效的 URL。尝试使用 application/json 并将其发送到带有该结果的 url 属性
  • 当我只附加从 toDataUrl 获得的内容并将 Content-Type 更改为应用程序时,我收到 JSON 解析错误。
  • 你需要发送json。 { "url": <your-data-url-here> }
  • 我仍然收到 JSON 解析错误。
  • 我将它切换为 blob 格式并且它有效。将您从 canvas.toDataUrl() 获取的数据输入到 fetch(data) .then(res => res.blob()).then(blobData => { 然后将 blobData 发送到 api }

标签: azure microsoft-cognitive


【解决方案1】:

哦,你真幸运,我 2 天前刚刚(成功!)尝试了这个。

将 base64 编码的 JPEG 发送到 Face API 效率非常低,编码输出字节与输入字节的比率为 4:3(33% 开销)。只需发送一个字节数组,它就可以工作,文档mention it briefly

并尝试读取为 JPEG 而不是 PNG,这只会浪费网络摄像头素材的带宽。

    ...

    var dataUri = canvas.toDataURL('image/' + format);
    var data = dataUri.split(',')[1];
    var mimeType = dataUri.split(';')[0].slice(5)

    var bytes = window.atob(data);
    var buf = new ArrayBuffer(bytes.length);
    var byteArr = new Uint8Array(buf);

    for (var i = 0; i < bytes.length; i++) {
        byteArr[i] = bytes.charCodeAt(i);
    }

    return byteArr;

现在在$.ajax() 中使用byteArr 作为您的有效负载 (data:) 用于 jQuery 或 iDontUnderStandHowWeGotHereAsAPeople() 在人们现在使用的任何其他时髦 JS 框架中。

反向时髦的做法是:

var payload = byteArr;

var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://SERVICE_URL');
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
xhr.send(payload);

【讨论】:

  • 感谢您对 JPEG 的评论!我尝试了您的解决方案,但是当我发布到 Microsoft 的 api 时出现 400: Invalid face image 错误。你也遇到过这个问题吗?
  • 没有。使用 requestb.in 或 Fiddler 之类的东西来查看您提出的原始请求。正文在前两行的某处使用JFIF 字符串在肉眼看来应该是“二进制”的(如果您现在确实在发送JPEG)。
  • 我的答案是这里描述的 makeblob 函数stackoverflow.com/questions/34047648/… 我无法让这个方法工作
  • 谢谢伙计。你刚刚拯救了我的一天!
【解决方案2】:

为了扩展 Dalvor 的回答:这是适用于我的 AJAX 调用:

fetch(data)
.then(res => res.blob())
.then(blobData => {
  $.post({
      url: "https://westus.api.cognitive.microsoft.com/face/v1.0/detect",
      contentType: "application/octet-stream",
      headers: {
        'Ocp-Apim-Subscription-Key': '<YOUR-KEY-HERE>'
      },
      processData: false,
      data: blobData
    })
    .done(function(data) {
      $("#results").text(JSON.stringify(data));

    })
    .fail(function(err) {
      $("#results").text(JSON.stringify(err));
    })

完整的演示代码在这里:https://jsfiddle.net/miparnisari/b1zzpvye/

【讨论】:

    【解决方案3】:

    为了节省某人的 6 小时,我附加了正确的代码。 希望这段代码对你有所帮助。

    工具

    代码

    index.tsx

    常量和引用

    /**
     * Constants
     */
    const videoConstraints = {
      width: 1280,
      height: 720,
      facingMode: 'user',
    };
    /**
     * Refs
     */
    const webcamRef = React.useRef<Webcam>(null);
    

    回调函数

    const capture = React.useCallback(() => {
      const base64Str = webcamRef.current!.getScreenshot() || '';
      const s = base64Str.split(',');
      const blob = b64toBlob(s[1]);
      callCognitiveApi(blob);
    }, [webcamRef]);
    

    在渲染中

    <Webcam audio={false} ref={webcamRef} screenshotFormat="image/jpeg" videoConstraints={videoConstraints} />
    <button onClick={capture}>Capture photo</button>
    

    base64toBlob

    感谢creating-a-blob-from-a-base64-string-in-javascript

    export const b64toBlob = (b64DataStr: string, contentType = '', sliceSize = 512) => {
      const byteCharacters = atob(b64DataStr);
      const byteArrays = [];
    
      for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
        const slice = byteCharacters.slice(offset, offset + sliceSize);
    
        const byteNumbers = new Array(slice.length);
        for (let i = 0; i < slice.length; i++) {
          byteNumbers[i] = slice.charCodeAt(i);
        }
    
        const byteArray = new Uint8Array(byteNumbers);
        byteArrays.push(byteArray);
      }
    
      const blob = new Blob(byteArrays, { type: contentType });
      return blob;
    };
    

    调用CognitiveApi

    import axios from 'axios';
    
    const subscriptionKey: string = 'This_is_your_subscription_key';
    const url: string = 'https://this-is-your-site.cognitiveservices.azure.com/face/v1.0/detect';
    export const callCognitiveApi = (data: any) => {
      const config = {
        headers: { 'content-type': 'application/octet-stream', 'Ocp-Apim-Subscription-Key': subscriptionKey },
      };
      const response = axios
        .post(url, data, config)
        .then((res) => {
          console.log(res);
        })
        .catch((error) => {
          console.error(error);
        });
    };
    

    结果

    【讨论】:

      【解决方案4】:

      所以我最终通过将图像作为 blob 对象发送得到了答案。你首先从画布中抓取图像:

      let data = canvas.toDataURL('image/jpeg');
      

      之后,您可以通过运行将其重新格式化为 blob 数据对象:

      fetch(data)
        .then(res => res.blob())
        .then(blobData => {
          // attach blobData as the data for the post request
        }
      

      您还需要将 post 请求的 Content-Type 切换为“application/octet-stream”

      【讨论】:

        猜你喜欢
        • 2020-07-06
        • 2012-09-27
        • 1970-01-01
        • 2013-02-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多