整合營銷服務商

          電腦端+手機端+微信端=數據同步管理

          免費咨詢熱線:

          前端系列:在線認識貝塞爾曲線的運動軌跡(中文版網站)

          ss3中常用的幾個動畫效果:

          ease: cubic-bezier(0.25, 0.1, 0.25, 1.0)

          linear: cubic-bezier(0.0, 0.0, 1.0, 1.0)

          ease-in: cubic-bezier(0.42, 0, 1.0, 1.0)

          ease-out: cubic-bezier(0, 0, 0.58, 1.0)

          ease-in-out: cubic-bezier(0.42, 0, 0.58, 1.0)

          下面上圖看效果:

          網站截圖

          效果

          效果

          效果

          在線預覽網站:http://yisibl.github.io/cubic-bezier/#0,0,1,1

          如果想交流的可以打開下面的網站:http://www.mackxin.com/xininn.html

          一起學習,一起交流(前端,PS,分享)

          關注分享,體驗樂趣

          分享是一種態度

          import numpy as np 
          import argparse
          import time
          import cv2 
          # construct the argument parse and parse the arguments
          ap = argparse.ArgumentParser()
          ap.add_argument("-v", "--video",
           help = "path to the (optional) video file")
          args = vars(ap.parse_args())
          # define the upper and lower boundaries for a color
          # to be considered "blue"
          blueLower = np.array([100,67,0],dtype="uint8")
          blueUpper = np.array([255,128,50],dtype="uint8")
          # load the video
          if not args.get("video"):
           camera = cv2.VideoCapture(0)
          else:
           camera = cv2.VideoCapture(args["video"])
          

          們將使用NumPy進行數值處理,使用argparse解析命令行參數,使用cv2進行OpenCV綁定。time包是可選的。

          我們只需要一個命令行參數,--video,也就是我們視頻的路徑。

          我們將在視頻中追蹤的對象是藍色物體。由于除了該物體外,藍色在視頻中的任何其他位置都不常見,因此我們希望跟蹤藍色陰影。為了完成這種顏色跟蹤,我們定義了藍色陰影的下限和上限。請記住,OpenCV表示RGB顏色空間中的像素,但順序相反。

          在這種情況下,如果大于R=0,G=67,B=100且小于R=50,G=128,B=255,則將顏色定義為“藍色”。

          最后,我們打開視頻文件并使用cv2.VideoCapture函數獲取對它的引用。我們將此引用賦值給變量camera。

          # keep looping 
          while True:
           # grab the current frame 
           (grabbed,frame) = camera.read()
           # check to see if we have reached the end of the video
           if args.get("video") and not grabbed:
           break 
           # determine which pixels fall within the blue boundaries
           # and then blur the binary image
           blue = cv2.inRange(frame,blueLower,blueUpper)
           blue = cv2.GaussianBlur(blue,(3,3),0)
          

          現在我們有了對視頻的引用,便可以開始處理幀。

          我們開始循環遍歷幀,一次一個。調用read()方法的調用抓取視頻中的下一幀,返回具有兩個值的元組。第一個是grabbed,是一個布爾值,表示是否從視頻文件中成功讀取了幀。第二個frame,是幀本身。

          然后,我們檢查frame是否成功讀取。如果未讀取框架,則表示已到達視頻的末尾,我們break掉while循環。

          為了在frame中找到藍色陰影,我們必須使用cv2.inRange函數。該函數有三個參數。第一個是我們想要檢查的frame。第二個是RGB像素的lower threshold,第三個是上限閾值(upper threshold)。調用此函數的結果是閾值圖像,像素落在上下范圍內設置為白色,像素不屬于此范圍 設為黑色。

          最后,我們對閾值圖像進行高斯模糊處理,以使查找輪廓更準確。

           # find contours in the image 
           (_,cnts,_) = cv2.findContours(blue.copy(),cv2.RETR_EXTERNAL,
           cv2.CHAIN_APPROX_SIMPLE)
           # check to see if any contours were found
           if len(cnts) > 0:
           # sort the contours and find the largest one --
           # we will assume this contour coorespondes to the 
           # area of my phone 
           cnt = sorted(cnts,key=cv2.contourArea,reverse=True)[0]
           # compute the (rotated) bounding box around then 
           # contour and then draw it 
           rect = np.int32(cv2.boxPoints(cv2.minAreaRect(cnt)))
           cv2.drawContours(frame,[rect],-1,(0,255,0),2)
           # show the frame and the binary image
           cv2.imshow("Traccking",frame)
           cv2.imshow("Binary",blue)
           # if your machine is fast, it may display the frames in
           # what appears to be 'fast forward' since more than 32
           # frames per second are being displayed -- a simple hack
           # is just to sleep for a tiny bit in between frames;
           # however, if your computer is slow, you probably want to
           # comment out this line
           time.sleep(0.025)
           # if the 'q' key is pressed, stop the loop
           if cv2.waitKey(1) & 0xFF == ord("q"):
           break
          # cleanup the camera and close any open windows
          camera.release()
          cv2.destroyAllWindows()
          

          現在我們有了閾值圖像,那么我們需要找到圖像中最大的輪廓,假設最大輪廓對應于我們想要跟蹤的藍色物體輪廓。

          我們調用cv2.findContours會在閾值圖像中找到輪廓。我們使用copy()方法克隆閾值圖像,因為cv2.findContour函數對傳入的NumPy數組具有破壞性。

          然后檢查以確保實際發現輪廓。如果輪廓列表的長度為零,則沒有找到藍色區域。如果輪廓列表的長度大于零,那么我們需要找到最大的輪廓。這里,輪廓按相反的順序排序(最大的第一個),使用cv2.contourArea函數來 計算輪廓的面積。具有較大區域的輪廓存儲在列表的前面。在這種情況下,抓住具有最大面積的輪廓,再次假設該輪廓對應于藍色物體的輪廓。

          現在我們有了藍色的輪廓,但我們需要在它周圍繪制一個邊界框。

          調用cv2.minAreaRect計算輪廓周圍的最小邊界框。然后,cv2.boxPoints將邊界框重新定義為點列表。

          注意:在OpenCV 2.4.X中,我們將使用cv2.BoxPoints函數來計算輪廓的旋轉邊界框。但是,在OpenCV 3.0+中,此函數已移至cv2.boxPoints。兩個函數執行相同的任務,只是略有不同的命名空間。

          最后,我們使用cv2.drawContours函數繪制邊界框。

          具有檢測到的藍色物體的frame顯示在第一個imshow,并且閾值圖像(落入藍色像素的下/上范圍的像素)顯示在第二個imshow。

          上面,time.sleep(0.025)可選的。在許多較新型號的機器上,系統可能足夠快以處理>32幀/秒。如果是這種情況,找到可接受的睡眠時間將減慢處理速度并將其降低到更正常的速度。

          執行我們的腳本

          python track.py
          

          結果:

          或者指定視頻路徑

          python track.py --video "video\2018-11-27 18-38-15-927.mp4"
          

          也是可以的。

          <script src="https://lf3-cdn-tos.bytescm.com/obj/cdn-static-resource/tt_player/tt.player.js?v=20160723"></script>

          博客地址(有完整代碼):https://0leo0.github.io/2018/case_study_03.html

          關注不迷路哦??!

          現(軌跡回放)方式有兩種:

          • 第一種是使用 JS APIAMap.PolyLine(折線)等圖形配合實現。
          • 第二種是使用 JS APIAMapUI 組件庫 配合使用,利用 PathSimplifier軌跡展示組件)繪制出行動軌跡。

          方案選擇

          以上兩種實現方式我們可以根據兩個因素 來決定哪一種更加適合自己:節點數量 的多少、排布的密集度 。

          前者適合節點數量較少,排布比較稀松,例如,出租車軌跡回放,出租車行駛速度快,周期上報的時間也會相對較長。后者更加針對節點數量巨大、排布密集的路徑,按秒記錄位置的飛機行進軌跡,精細的地理邊界等等。

          實現流程

          無論選擇兩種方式,我們都需要先收集到客戶端上報的信息,這些信息可以自定義,通常我們會包含:經緯度、速度、逆編碼之后的地理位置、方向、海拔 等基本地理信息,同時我們也可以加入一些自定義 的信息,例如:人員信息(頭像昵稱等)、出行信息(訂單等)。

          實現的流程:

          • 客戶端按(時間)周期上報地理信息以及自定義信息。
          • 服務端按時間軸存儲客戶上報的信息。
          • 按(時間等)條件查詢出用戶的軌跡,并通過簡化算法去除一部分節點(例如,節點距離十分微小、或者多個點都在同一條直線、3點之間,其中一點略有偏差無法繪制成直線等等),最終獲得適合繪制的路徑(數組)。
          • 根據路徑去繪制用戶的行動軌跡。

          路徑簡化算法(可選)

          客戶端上報的數據是按時間周期上報的,也就是說每個時間都對應了一個經緯度,經緯度在地圖上就是一個又一個點,將這些點連接時,我們會得到 N 多條折線,為了繪制的軌跡更加美觀,行動路線更加明確平滑,通常我們需要一個算法來簡化折線。

          例如:

          • A 點和 B 點,兩者距離不到 1 像素,則可以去掉 B 點,只留 A 點。
          • A,B,C 三點在一條直線上,或者,B 點僅僅稍微偏離 A 點和 C 點構成的線段,那么 B 點就可以去掉。

          這里官方也推薦了一種算法庫 simplify.js供大家參考,這里不做過多的闡述。

          實現示例

          車輛軌跡回放

          這里我們使用第一種方式來實現 - 利用 JS APIAMap.PolyLine。

          實現原理:

          • 在地圖上繪制車輛標記AMap.Marker)。
          • 利用 AMap.PolyLine 繪制出兩條軌跡:歷史軌跡駕駛途徑過的軌跡,以顏色區分。
          • 按照一定的速度使車輛前進,并監聽 Maker 移動的事件,在事件回調中,將車輛(Marker)位置設置為地圖中心點,給使用者視覺主觀上一種車輛在前進的感覺,同時延長駕駛途徑過的軌跡
          • 對于實現場景比較復雜的,需要進行自定義處理的比如:
          1. 查看每個節點的數據,我們可以把每個節點給繪制出來,節點被點擊時顯示該節點的數據。
          2. 移動倍速播放,首先按上報的時間間隔來播放,選擇倍速之后,改變 MarKer 移動的 duration。
          3. 其他自定義。

          自定義 API

          我們可以讓車輛:

          • 開始移動
          • 暫停移動
          • 恢復移動
          • 停止移動

          代碼示例

          AMap.plugin('AMap.MoveAnimation', function(){
            var marker, lineArr = [[116.478935,39.997761],[116.478939,39.997825],[116.478912,39.998549],[116.478912,39.998549],[116.478998,39.998555],[116.478998,39.998555],[116.479282,39.99856],[116.479658,39.998528],[116.480151,39.998453],[116.480784,39.998302],[116.480784,39.998302],[116.481149,39.998184],[116.481573,39.997997],[116.481863,39.997846],[116.482072,39.997718],[116.482362,39.997718],[116.483633,39.998935],[116.48367,39.998968],[116.484648,39.999861]];
          
            var map = new AMap.Map("container", {
              resizeEnable: true,
              center: [116.397428, 39.90923],
              zoom: 17
            });
          
            marker = new AMap.Marker({
              map: map,
              position: [116.478935,39.997761],
              icon: "https://a.amap.com/jsapi_demos/static/demo-center-v2/car.png",
              offset: new AMap.Pixel(-13, -26),
            });
          
            // 繪制歷史軌跡
            var polyline = new AMap.Polyline({
              map: map,
              path: lineArr,
              showDir:true,
              strokeColor: "#28F",  //線顏色
              // strokeOpacity: 1,     //線透明度
              strokeWeight: 6,      //線寬
              // strokeStyle: "solid"  //線樣式
            });  
          	// 駕駛途徑過的軌跡
            var passedPolyline = new AMap.Polyline({
              map: map,
              strokeColor: "#AF5",  //線顏色
              strokeWeight: 6,      //線寬
            });
          
          	// 監聽車輛移動事件
            marker.on('moving', function (e) {
          	  // 延長駕駛途徑過的軌跡
              passedPolyline.setPath(e.passedPath);
              // 將車輛位置設置為地圖中心點
              map.setCenter(e.target.getPosition(),true)
            });
          
            map.setFitView();
          	
          	// 開始移動
            window.startAnimation = function startAnimation () {
              marker.moveAlong(lineArr, {
                // 每一段的時長
                duration: 500,//可根據實際采集時間間隔設置
                // JSAPI2.0 是否延道路自動設置角度在 moveAlong 里設置
                autoRotation: true,
              });
            };
            // 暫停移動
            window.pauseAnimation = function () {
            	marker.pauseMove();
            };
          	// 恢復移動
            window.resumeAnimation = function () {
            	marker.resumeMove();
            };
          	// 停止移動
            window.stopAnimation = function () {
            	marker.stopMove();
            };
          });
          

          參考鏈接:https://lbs.amap.com/demo/jsapi-v2/example/marker/replaying-historical-running-data

          飛機航班的軌跡回放

          使用 JS APIAMapUI 組件庫 配合使用,利用 PathSimplifier軌跡展示組件)繪制出行動軌跡,這種方案比較簡單,只需要進行一些配置即可,例如說方案一中的倍速播放就需要計算,同時還存在不能動態改變倍速的弊端,但是方案二卻不會存在。

          實現原理:

          • 在地圖上繪制飛機標記AMap.Marker)。
          • 利用 AMap.PolyLine 繪制出兩條軌跡:歷史軌跡駕駛途徑過的軌跡,以顏色區分。
          • 配置軌跡的顏色,動畫的速度等等。
          • 對于實現場景比較復雜的,需要進行自定義處理的,可以在PathSimplifier 提供的回調中進行配置及處理。

          示例代碼

          //加載PathSimplifier,loadUI的路徑參數為模塊名中 'ui/' 之后的部分 
          AMapUI.load(['ui/misc/PathSimplifier'], function(PathSimplifier) {
          
              if (!PathSimplifier.supportCanvas) {
                  alert('當前環境不支持 Canvas!');
                  return;
              }
          
              //啟動頁面
              initPage(PathSimplifier);
          });
          
          function initPage(PathSimplifier) {
              //創建組件實例
              var pathSimplifierIns = new PathSimplifier({
                  zIndex: 100,
                  map: map, //所屬的地圖實例
                  getPath: function(pathData, pathIndex) {
                      //返回軌跡數據中的節點坐標信息,[AMap.LngLat, AMap.LngLat...] 或者 [[lng|number,lat|number],...]
                      return pathData.path;
                  },
                  getHoverTitle: function(pathData, pathIndex, pointIndex) {
                      //返回鼠標懸停時顯示的信息
                      if (pointIndex >= 0) {
                          //鼠標懸停在某個軌跡節點上
                          return pathData.name + ',點:' + pointIndex + '/' + pathData.path.length;
                      }
                      //鼠標懸停在節點之間的連線上
                      return pathData.name + ',點數量' + pathData.path.length;
                  },
                  renderOptions: {
                      //軌跡線的樣式
                      pathLineStyle: {
                          strokeStyle: 'red',
                          lineWidth: 6,
                          dirArrowStyle: true
                      }
                  }
              });
          
              //這里構建兩條簡單的軌跡,僅作示例
              pathSimplifierIns.setData([{
                  name: '軌跡0',
                  path: [
                      [100.340417, 27.376994],
                      [108.426354, 37.827452],
                      [113.392174, 31.208439],
                      [124.905846, 42.232876]
                  ]
              }, {
                  name: '大地線',
                  //創建一條包括500個插值點的大地線
                  path: PathSimplifier.getGeodesicPath([116.405289, 39.904987], [87.61792, 43.793308], 500)
              }]);
          
              //創建一個巡航器
              var navg0 = pathSimplifierIns.createPathNavigator(0, //關聯第1條軌跡
                  {
                      loop: true, //循環播放
                      speed: 1000000
                  });
          
              navg0.start();
          }
          

          參考鏈接:https://lbs.amap.com/demo/amap-ui/demos/amap-ui-pathsimplifier/index


          主站蜘蛛池模板: 精品少妇人妻AV一区二区| 亚洲爆乳精品无码一区二区| 国模无码视频一区| 搡老熟女老女人一区二区| 国产无人区一区二区三区| 无码视频一区二区三区| 国产精品亚洲不卡一区二区三区 | 嫩B人妻精品一区二区三区| 国产伦精品一区二区三区在线观看 | 中文字幕av日韩精品一区二区| 亚洲狠狠久久综合一区77777 | 性色AV一区二区三区无码| 无码乱人伦一区二区亚洲| 亚洲AV无码一区二区二三区入口| 精品视频在线观看你懂的一区 | 无码少妇一区二区性色AV | www一区二区www免费| 日本一区二区三区在线观看| 久久无码精品一区二区三区| 国产精品视频一区二区三区| 国产一区二区三区在线视頻| 无码人妻精品一区二区三区不卡| 人妻体内射精一区二区三区| 国产AV午夜精品一区二区三| 在线日产精品一区| 亚洲一区免费观看| 午夜福利一区二区三区在线观看 | 亚洲一区二区三区深夜天堂| 国产aⅴ精品一区二区三区久久| 国产伦一区二区三区高清| 国精品无码一区二区三区在线蜜臀 | 国产乱码精品一区二区三区四川人| 夜夜嗨AV一区二区三区| 久久久91精品国产一区二区| 久久精品国产一区二区电影| 无码av免费毛片一区二区| 美女视频一区二区三区| 精品一区精品二区制服| 日韩精品区一区二区三VR| 久久久精品一区二区三区| 国产一区二区三区免费|