<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      來看看機智的前端童鞋怎么防盜

      很多開發的童鞋都是只身混江湖、夜宿城中村,如果居住的地方安保欠缺,那么出門在外難免擔心屋里的財產安全。

      事實上世面上有很多高大上的防盜設備,但對于機智的前端童鞋來說,只要有一臺附帶攝像頭的電腦,就可以簡單地實現一個防盜監控系統~

      純 JS 的“防盜”能力很大程度借助于 H5 canvas 的力量,且非常有意思。如果你對 canvas 還不熟悉,可以先點這里閱讀我的系列教程。

      step1. 調用攝像頭

      我們需要先在瀏覽器上訪問和調用攝像頭,用來監控屋子里的一舉一動。不同瀏覽器中調用攝像頭的 API 都略有出入,在這里我們以 chrome 做示例:

      <video width="640" height="480" autoplay></video>
      
      <script>
          var video = document.querySelector('video');
      
          navigator.webkitGetUserMedia({
                      video: true
                  }, success, error);
      
          function success(stream) {
              video.src = window.webkitURL.createObjectURL(stream);
              video.play();
          }
      
          function error(err) {
              alert('video error: ' + err)
          }
      </script>

      運行頁面后,瀏覽器出于安全性考慮,會詢問是否允許當前頁面訪問你的攝像頭設備,點擊“允許”后便能直接在 <video> 上看到攝像頭捕獲到的畫面了:

      step2. 捕獲 video 幀畫面

      光是開著攝像頭監視房間可沒有任何意義,瀏覽器不會幫你對監控畫面進行分析。所以這里我們得手動用腳本捕獲 video 上的幀畫面,用于在后續進行數據分析。

      從這里開始咱們就要借助 canvas 力量了。在 Canvas入門(五)一文我們介紹過 ctx.drawImage() 方法,通過它可以捕獲 video 幀畫面并渲染到畫布上。

      我們需要創建一個畫布,然后這么寫:

      <video width="640" height="480" autoplay></video>
      <canvas width="640" height="480"></canvas>
      
      <script>
          var video = document.querySelector('video');
          var canvas = document.querySelector('canvas');
      
          // video捕獲攝像頭畫面
          navigator.webkitGetUserMedia({
                      video: true
                  }, success, error);
      
          function success(stream) {
              video.src = window.webkitURL.createObjectURL(stream);
              video.play();
          }
      
          function error(err) {
              alert('video error: ' + err)
          }
      
          //canvas
          var context = canvas.getContext('2d');
      
          setTimeout(function(){
              //把當前視頻幀內容渲染到畫布上
              context.drawImage(video, 0, 0, 640, 480);
          }, 5000);
      
      </script>

      如上代碼所示,5秒后把視頻幀內容渲染到畫布上(下方右圖)

      step3. 對捕獲的兩個幀畫面執行差異混合

      在上面我們提到過,要有效地識別某個場景,需要對視頻畫面進行數據分析。

      那么要怎么識別咱們的房子是否有人突然闖入了呢?答案很簡單 —— 定時地捕獲 video 畫面,然后對比前后兩幀內容是否存在較大變化。

      我們先簡單地寫一個定時捕獲的方法,并將捕獲到的幀數據存起來:

          //canvas
          var context = canvas.getContext('2d');
          var preFrame,   //前一幀
              curFrame;   //當前幀
      
          //捕獲并保存幀內容
          function captureAndSaveFrame(){ console.log(context);
              preFrame = curFrame;
              context.drawImage(video, 0, 0, 640, 480);
              curFrame = canvas.toDataURL;  //轉為base64并保存
          }
      
          //定時捕獲
          function timer(delta){
              setTimeout(function(){
                  captureAndSaveFrame();
                  timer(delta)
              }, delta || 500);
          }
      
          timer();

      如上代碼所示,畫布會每隔500毫秒捕獲并渲染一次 video 的幀內容(夭壽哇,做完這個動作不小心把餅干灑了一地。。。\("▔□▔)/)

      留意這里我們使用了 canvas.toDataURL 方法來保存幀畫面。

      接著就是數據分析處理了,我們可以通過對比前后捕獲的幀畫面來判斷攝像頭是否監控到變化,那么怎么做呢?

      熟悉設計的同學肯定常常使用一個圖層功能 —— 混合模式:

      當有兩個圖層時,對頂層圖層設置“差值/Difference”的混合模式,可以一目了然地看到兩個圖層的差異:

      “圖A”是我去年在公司樓下拍的照片,然后我把它稍微調亮了一點點,并在上面畫了一個 X 和 O 得到“圖B”。接著我把它們以“差值”模式混合在一起,得到了最右的這張圖。

      “差值”模式原理:要混合圖層雙方的RGB值中每個值分別進行比較,用高值減去低值作為合成后的顏色,通常用白色圖層合成一圖像時,可以得到負片效果的反相圖像。用黑色的話不發生任何變化(黑色亮度最低,下層顏色減去最小顏色值0,結果和原來一樣),而用白色會得到反相效果(下層顏色被減去,得到補值),其它顏色則基于它們的亮度水平

      在CSS3中,已經有 blend-mode 特性來支持這個有趣的混合模式,不過我們發現,在主流瀏覽器上,canvas 的 globalCompositeOperation 接口也已經良好支持了圖像混合模式:

      于是我們再建多一個畫布來展示前后兩幀差異:

      <video width="640" height="480" autoplay></video>
      <canvas width="640" height="480"></canvas>
      <canvas width="640" height="480"></canvas>
      
      <script>
          var video = document.querySelector('video');
          var canvas = document.querySelectorAll('canvas')[0];
          var canvasForDiff = document.querySelectorAll('canvas')[1];
      
          // video捕獲攝像頭畫面
          navigator.webkitGetUserMedia({
                      video: true
                  }, success, error);
      
          function success(stream) {
              video.src = window.URL.createObjectURL(stream);
              video.play();
          }
      
          function error(err) {
              alert('video error: ' + err)
          }
      
          //canvas
          var context = canvas.getContext('2d'),
              diffCtx = canvasForDiff.getContext('2d');
          //將第二個畫布混合模式設為“差異”
          diffCtx.globalCompositeOperation = 'difference';
      
          var preFrame,   //前一幀
              curFrame;   //當前幀
      
          //捕獲并保存幀內容
          function captureAndSaveFrame(){
              preFrame = curFrame;
              context.drawImage(video, 0, 0, 640, 480);
              curFrame = canvas.toDataURL();  //轉為base64并保存
          }
      
          //繪制base64圖像到畫布上
          function drawImg(src, ctx){
              ctx = ctx || diffCtx;
              var img = new Image();
              img.src = src;
              ctx.drawImage(img, 0, 0, 640, 480);
          }
      
          //渲染前后兩幀差異
          function renderDiff(){
              if(!preFrame || !curFrame) return; 
              diffCtx.clearRect(0, 0, 640, 480);
              drawImg(preFrame);
              drawImg(curFrame);
          }
      
          //定時捕獲
          function timer(delta){
              setTimeout(function(){
                  captureAndSaveFrame();
                  renderDiff();
                  timer(delta)
              }, delta || 500);
          }
      
          timer();
      
      </script>

      效果如下(夭壽啊,做完這個動作我又把雪碧灑在鍵盤上了。。。(#--)/ )

      可以看到,當前后兩幀差異不大時,第三個畫布幾乎是黑乎乎的一片,只有當攝像頭捕獲到動作了,第三個畫布才有明顯的高亮內容出現。

      因此,我們只需要對第三個畫布渲染后的圖像進行像素分析——判斷其高亮閾值是否達到某個指定預期:

          var context = canvas.getContext('2d'),
              diffCtx = canvasForDiff.getContext('2d');
          //將第二個畫布混合模式設為“差異”
          diffCtx.globalCompositeOperation = 'difference';
      
          var preFrame,   //前一幀
              curFrame;   //當前幀
      
          var diffFrame;  //存放差異幀的imageData
      
          //捕獲并保存幀內容
          function captureAndSaveFrame(){
              preFrame = curFrame;
              context.drawImage(video, 0, 0, 640, 480);
              curFrame = canvas.toDataURL();  //轉為base64并保存
          }
      
          //繪制base64圖像到畫布上
          function drawImg(src, ctx){
              ctx = ctx || diffCtx;
              var img = new Image();
              img.src = src;
              ctx.drawImage(img, 0, 0, 640, 480);
          }
      
          //渲染前后兩幀差異
          function renderDiff(){
              if(!preFrame || !curFrame) return;
              diffCtx.clearRect(0, 0, 640, 480);
              drawImg(preFrame);
              drawImg(curFrame);
              diffFrame = diffCtx.getImageData( 0, 0, 640, 480 );  //捕獲差異幀的imageData對象
          }
      
          //計算差異
          function calcDiff(){
              if(!diffFrame) return 0;
              var cache = arguments.callee,
                  count = 0;
              cache.total = cache.total || 0; //整個畫布都是白色時所有像素的值的總和
              for (var i = 0, l = diffFrame.width * diffFrame.height * 4; i < l; i += 4) {
                  count += diffFrame.data[i] + diffFrame.data[i + 1] + diffFrame.data[i + 2];
                  if(!cache.isLoopEver){  //只需在第一次循環里執行
                      cache.total += 255 * 3;   //單個白色像素值
                  }
              }
              cache.isLoopEver = true;
              count *= 3;  //亮度放大
              //返回“差異畫布高亮部分像素總值”占“畫布全亮情況像素總值”的比例
              return Number(count/cache.total).toFixed(2);
          }
      
          //定時捕獲
          function timer(delta){
              setTimeout(function(){
                  captureAndSaveFrame();
                  renderDiff();
                  setTimeout(function(){
                      console.log(calcDiff());
                  }, 10);
      
                  timer(delta)
              }, delta || 500);
          }
      
          timer();

      注意這里我們使用了 count *= 3 來放大差異高亮像素的亮度值,不然得出的數值實在太小了。我們運行下頁面(圖片較大加載會有點慢)

      經過試(xia)驗(bai),個人覺得如果 calcDiff() 返回的比值如果大于 0.20,那么就可以定性為“一間空屋子,突然有人闖進來”的情況了。

      step4. 上報異常圖片

      當上述的計算發現有狀況時,需要有某種途徑通知我們。有錢有精力的話可以部署個郵件服務器,直接發郵件甚至短信通知到自己,but 本文走的吃吐少年路線,就不搞的那么高端了。

      那么要如何簡單地實現異常圖片的上報呢?我暫且想到的是 —— 直接把問題圖片發送到某個站點中去。

      這里我們選擇博客園的“日記”功能,它可以隨意上傳相關內容。

      p.s.,其實這里原本是想直接把圖片傳到博客園相冊上的,可惜POST請求的圖片實體要求走 file 格式,即無法通過腳本更改文件的 input[type=file],轉 Blob 再上傳也沒用,只好作罷。

      糾正上述p.s.內容~ 后續發現 formData.append 支持第三個參數作為 filename 屬性,所以其實是可以轉 blob 上傳的。

      我們在管理后臺創建日記時,通過 Fiddler 抓包可以看到其請求參數非常簡單:

      從而可以直接構造一個請求:

          //異常圖片上傳處理
          function submit(){
      
              //ajax 提交form
              $.ajax({
                  url : 'http://i.cnblogs.com/EditDiary.aspx?opt=1',
                  type : "POST",
                  data : {
                      '__VIEWSTATE': '',
                      '__VIEWSTATEGENERATOR': '4773056F',
                      'Editor$Edit$txbTitle': '告警' + Date.now(),
                      'Editor$Edit$EditorBody': '<img src="' + curFrame + '" />',
                      'Editor$Edit$lkbPost': '保存'
                  },
                  success: function(){
                      console.log('submit done')
                  }
              });
          }

      當然如果請求頁面跟博客園域名不同,是無法發送 cookie 導致請求跨域而失效,不過這個很好解決,直接修改 host 即可(怎么修改就不介紹了,自行百度吧)

      我這邊改完 host,通過 http://i.cnblogs.com/h5monitor/final.html 的地址訪問頁面,發現攝像頭竟然失效了~

      通過谷歌的文檔可以得知,這是為了安全性考慮,非 HTTPS 的服務端請求都不能接入攝像頭。不過解決辦法也是有的,以 window 系統為例,打開 cmd 命令行面板并定位到 chrome 安裝文件夾下,然后執行:

      chrome --unsafely-treat-insecure-origin-as-secure="http://i.cnblogs.com/h5monitor/final.html"  --user-data-dir=C:\testprofile

      此舉將以沙箱模式打開一個獨立的 chrome 進程,并對指定的站點去掉安全限制。注意咱們在新開的 chrome 中得重新登錄博客園。

      這時候便能正常訪問攝像頭了,我們對代碼做下處理,當差異檢測發現異常時,創建一份日記,最小間隔時間為5秒(不過后來發現沒必要,因為博客園已經有做了時間限制,差不多10秒后才能發布新的日記)

          //定時捕獲
          function timer(delta){
              setTimeout(function(){
                  captureAndSaveFrame();
                  renderDiff();
                  if(calcDiff() > 0.2){  //監控到異常,發日志
                      submit()
                  }
      
                  timer(delta)
              }, delta || 500);
          }
      
          setTimeout(timer, 60000 * 10);  //設定打開頁面十分鐘后才開始監控
      
      
          //異常圖片上傳處理
          function submit(){
              var cache = arguments.callee,
                  now = Date.now();
              if(cache.reqTime && (now - cache.reqTime < 5000)) return;  //日記創建最小間隔為5秒
      
              cache.reqTime = now;
      
              //ajax 提交form
              $.ajax({
                  url : 'http://i.cnblogs.com/EditDiary.aspx?opt=1',
                  type : "POST",
                  timeout : 5000,
                  data : {
                      '__VIEWSTATE': '',
                      '__VIEWSTATEGENERATOR': '4773056F',
                      'Editor$Edit$txbTitle': '告警' + Date.now(),
                      'Editor$Edit$EditorBody': '<img src="' + curFrame + '" />',
                      'Editor$Edit$lkbPost': '保存'
                  },
                  success: function(){
                      console.log('submit done')
                  },
                  error: function(err){
                      cache.reqTime = 0;
                      console.log('error: ' + err)
                  }
              });
          }

      執行效果:

      日記也是妥妥的出來了:

      點開就能看到異常的那張圖片了:

      要留意的是,博客園對日記發布數量是有做每日額度限制來防刷的,達到限額的話會導致當天的隨筆和文章也無法發布,所以得謹慎使用:

      不過這種形式僅能上報異常圖片,暫時無法讓我們及時收悉告警,有興趣的童鞋可以試著再寫個 chrome 插件,定時去拉取日記列表做判斷,如果有新增日記則觸發頁面 alert。

      另外我們當然希望能直接對闖入者進行警告,這塊比較好辦 —— 搞個警示的音頻,在異常的時候觸發播放即可:

          //播放音頻
          function fireAlarm(){
              audio.play()
          }
      
      
          //定時捕獲
          function timer(delta){
              setTimeout(function(){
                  captureAndSaveFrame();
                  if(preFrame && curFrame){
                      renderDiff();
                      if(calcDiff() > 0.2){  //監控到異常
                          //發日記
                          submit();
                          //播放音頻告警
                          fireAlarm();
                      }
                  }
                  timer(delta)
              }, delta || 500);
          }
      
          setTimeout(timer, 60000 * 10);  //設定打開頁面十分鐘后才開始監控

      最后說一下,本文代碼均掛在我的github上,有興趣的童鞋可以自助下載。共勉~

       

      posted @ 2016-07-10 12:19  vajoy  閱讀(18177)  評論(82)    收藏  舉報
      Copyright © 2014 - 2022 VaJoy Studio
      主站蜘蛛池模板: 成年女人午夜毛片免费视频| 99久久机热/这里只有精品| 国产精品青草久久久久福利99 | 国产成人亚洲综合| 国模雨珍浓密毛大尺度150p| 一区二区三区人妻无码| 昔阳县| 极品尤物被啪到呻吟喷水| 制服丝袜美腿一区二区| 丰满的女邻居2| 日本A级视频在线播放| 国产丰满乱子伦无码专区| 日本精品aⅴ一区二区三区| 色视频在线观看免费视频 | 一区二区三区在线 | 欧洲| 资源新版在线天堂偷自拍| 99久久99久久久精品久久| 久久天天躁狠狠躁夜夜躁| 免费十八禁一区二区三区| 亚洲av日韩av永久无码电影| 日韩免费无码视频一区二区三区| 国产中文字幕精品视频| 日日摸夜夜添夜夜添国产三级| 九九久久自然熟的香蕉图片| 国产一区二区三中文字幕| 亚洲AV日韩AV综合在线观看| 又大又粗又硬又爽黄毛少妇| 日韩女同一区二区三区久久| 女人被爽到高潮视频免费国产| 性视频一区| 国产精品人妻| 亚洲乱熟女一区二区三区| 男女性杂交内射女bbwxz| 国产激情一区二区三区不卡| 福利一区二区在线观看| 制服丝袜中文字幕在线| 狠狠色噜噜狼狼狼色综合久| 国内不卡一区二区三区| 西平县| 国产女人看国产在线女人| 在线高清理伦片a|