PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/research/MotionTracker/Main.as

http://in-spirit.googlecode.com/
ActionScript | 499 lines | 369 code | 80 blank | 50 comment | 39 complexity | 053facc2b547e31b5e04942e3dd52e93 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. package
  2. {
  3. import ru.inspirit.motion.MotionBlob;
  4. import ru.inspirit.motion.MotionTracker;
  5. import com.bit101.components.HUISlider;
  6. import com.bit101.components.Label;
  7. import com.bit101.components.Panel;
  8. import com.bit101.components.Style;
  9. import flash.display.Bitmap;
  10. import flash.display.BitmapData;
  11. import flash.display.Graphics;
  12. import flash.display.Shape;
  13. import flash.display.Sprite;
  14. import flash.display.StageScaleMode;
  15. import flash.events.AsyncErrorEvent;
  16. import flash.events.Event;
  17. import flash.events.NetStatusEvent;
  18. import flash.events.SecurityErrorEvent;
  19. import flash.events.TimerEvent;
  20. import flash.geom.Matrix;
  21. import flash.geom.Point;
  22. import flash.geom.Rectangle;
  23. import flash.media.Video;
  24. import flash.net.NetConnection;
  25. import flash.net.NetStream;
  26. import flash.ui.ContextMenu;
  27. import flash.ui.ContextMenuItem;
  28. import flash.utils.Timer;
  29. import flash.utils.getTimer;
  30. /**
  31. * @author Eugene Zatepyakin
  32. */
  33. public class Main extends Sprite
  34. {
  35. private var view:Sprite;
  36. private var tracker:MotionTracker;
  37. private var camera:CameraBitmap;
  38. private var _vid:Video;
  39. private var videoURL:String = "track.mov";
  40. private var connection:NetConnection;
  41. private var stream:NetStream;
  42. private const VID_W:int = 352;
  43. private const VID_H:int = 288;
  44. private var currFrame:BitmapData;
  45. private var prevFrame:BitmapData;
  46. private var edgeFrame:BitmapData;
  47. private var scaleFactor:uint = 2;
  48. private var w:int = 640;
  49. private var h:int = 480;
  50. private var oldVelocity:Vector.<Point>;
  51. private var canvas:Shape;
  52. private var panel:Panel;
  53. private var detectMode:int = 0;
  54. private var _timer : uint;
  55. private var _fps : uint;
  56. private var _ms : uint;
  57. private var _ms_prev : uint;
  58. public function Main()
  59. {
  60. if(stage) init();
  61. else addEventListener(Event.ADDED_TO_STAGE, init);
  62. }
  63. private function init(e:Event = null):void
  64. {
  65. initStage();
  66. view = new Sprite();
  67. camera = new CameraBitmap(w, h, 15, true);
  68. camera.addEventListener(Event.RENDER, renderCamera);
  69. view.addChild(new Bitmap(camera.bitmapData));
  70. //initFlv();
  71. tracker = new MotionTracker(w, h, scaleFactor, 20);
  72. currFrame = new BitmapData(int(w / scaleFactor + .5), int(h / scaleFactor + .5), false, 0x00);
  73. prevFrame = currFrame.clone();
  74. edgeFrame = currFrame.clone();
  75. var b:Bitmap = new Bitmap(currFrame);
  76. b.scaleX = b.scaleY = scaleFactor;
  77. b.x = 320;
  78. //view.addChild(b);
  79. b = new Bitmap(prevFrame);
  80. b.scaleX = b.scaleY = scaleFactor;
  81. b.y = 240;
  82. //view.addChild(b);
  83. b = new Bitmap(edgeFrame);
  84. b.scaleX = b.scaleY = scaleFactor;
  85. b.x = 320;
  86. b.y = 240;
  87. //view.addChild(b);
  88. addChild(view);
  89. canvas = new Shape();
  90. addChild(canvas);
  91. canvas.y = view.y = 40;
  92. initControls();
  93. //stage.addEventListener(MouseEvent.CLICK, nextMode);
  94. }
  95. private function initControls():void
  96. {
  97. Style.PANEL = 0x333333;
  98. Style.BUTTON_FACE = 0x333333;
  99. Style.LABEL_TEXT = 0xF6F6F6;
  100. panel = new Panel(this);
  101. panel.width = 640;
  102. panel.height = 40;
  103. var lb:Label = new Label(panel, 10, 5);
  104. lb.name = 'fps_txt';
  105. var sl:HUISlider = new HUISlider(panel, 90, 5, 'MAX BLOBS', onMaxBlobChange);
  106. sl.setSliderParams(1, 50, 10);
  107. sl.labelPrecision = 0;
  108. sl.width = 200;
  109. sl = new HUISlider(panel, 90, 18, 'SENSITIVITY', onThresholdChange);
  110. sl.setSliderParams(5, 70, 50);
  111. sl.labelPrecision = 0;
  112. sl.width = 200;
  113. sl = new HUISlider(panel, 280, 5, 'MIN BLOB SIZE', onMinBlobSizeChange);
  114. sl.setSliderParams(.01, 0.1, 0.015);
  115. sl.labelPrecision = 3;
  116. sl.width = 230;
  117. sl = new HUISlider(panel, 280, 18, 'MAX BLOB SIZE', onMaxBlobSizeChange);
  118. sl.setSliderParams(0.1, 1.0, 0.3);
  119. sl.labelPrecision = 3;
  120. sl.width = 230;
  121. addEventListener(Event.ENTER_FRAME, countFrameTime);
  122. }
  123. private function onMaxBlobChange(e:Event):void
  124. {
  125. tracker.maxBlobs = HUISlider(e.currentTarget).value;
  126. }
  127. private function onThresholdChange(e:Event):void
  128. {
  129. tracker.thresholdValue = 70 - HUISlider(e.currentTarget).value;
  130. }
  131. private function onMinBlobSizeChange(e:Event):void
  132. {
  133. tracker.minBlobSize = tracker.frameSize * HUISlider(e.currentTarget).value;
  134. }
  135. private function onMaxBlobSizeChange(e:Event):void
  136. {
  137. tracker.maxBlobSize = tracker.frameSize * HUISlider(e.currentTarget).value;
  138. }
  139. private function renderCamera(e:Event = null):void
  140. {
  141. //var tt:int = getTimer();
  142. tracker.trackFrame(camera.bitmapData);
  143. //tracker.drawPreviousFrame(prevFrame);
  144. //tracker.drawCurrentFrame(currFrame);
  145. //tracker.detectEdges(edgeFrame);
  146. if(detectMode == 0)
  147. {
  148. drawBlobs2();
  149. }
  150. else if(detectMode == 1)
  151. {
  152. drawRects(tracker.getBlobs());
  153. }
  154. //trace(getTimer() - tt);
  155. }
  156. private function renderVideo(e:Event = null):void
  157. {
  158. currFrame.draw(_vid);
  159. tracker.trackFrame(currFrame);
  160. //tracker.drawCurrentFrame(prevFrame);
  161. //tracker.drawPreviousFrame(prevFrame);
  162. //tracker.drawCurrentFrame(currFrame);
  163. if(detectMode == 0)
  164. {
  165. drawBlobs2();
  166. }
  167. else if(detectMode == 1)
  168. {
  169. drawRects(tracker.getBlobs());
  170. }
  171. }
  172. private function drawBlobs2():void
  173. {
  174. canvas.graphics.clear();
  175. canvas.graphics.lineStyle(1, 0xFFFF00);
  176. tracker.getBlobs(true);
  177. var t:int = tracker._blobs.length;
  178. var mb:MotionBlob;
  179. var cp:Point = new Point();
  180. var dir:Point = new Point();
  181. for(var i:int = 0; i < t; ++i)
  182. {
  183. mb = tracker._blobs[i];
  184. cp.x = mb.cx * scaleFactor;
  185. cp.y = mb.cy * scaleFactor;
  186. /*var w:Number = mb.width * scaleFactor;
  187. var h:Number = mb.height * scaleFactor;
  188. var rect:Rectangle = new Rectangle(cp.x - w * .5, cp.y - h * .5, w, h);
  189. var angle:Number = mb.angle;
  190. var tl:Point = getRotatedRectPoint(angle, rect.topLeft, cp);
  191. var br:Point = getRotatedRectPoint(angle, rect.bottomRight, cp);
  192. var tr:Point = getRotatedRectPoint(angle, new Point(rect.right, rect.top), cp);
  193. var bl:Point = getRotatedRectPoint(angle, new Point(rect.left, rect.bottom), cp);*/
  194. canvas.graphics.moveTo(mb.tl.x * scaleFactor, mb.tl.y * scaleFactor);
  195. canvas.graphics.lineTo(mb.tr.x * scaleFactor, mb.tr.y * scaleFactor);
  196. canvas.graphics.lineTo(mb.br.x * scaleFactor, mb.br.y * scaleFactor);
  197. canvas.graphics.lineTo(mb.bl.x * scaleFactor, mb.bl.y * scaleFactor);
  198. canvas.graphics.lineTo(mb.tl.x * scaleFactor, mb.tl.y * scaleFactor);
  199. //canvas.graphics.drawRect(cp.x - w * .5, cp.y - h * .5, w, h);
  200. dir.x = mb.vel.x;
  201. dir.y = mb.vel.y;
  202. //dir.normalize(5);
  203. if(dir.x == 0 && dir.y == 0) continue;
  204. drawArrow(canvas.graphics, cp, dir, dir.length*10, 7);
  205. }
  206. }
  207. public function getRotatedRectPoint( angle:Number, point:Point, rotationPoint:Point = null):Point
  208. {
  209. var ix:Number = (rotationPoint) ? rotationPoint.x : 0;
  210. var iy:Number = (rotationPoint) ? rotationPoint.y : 0;
  211. var m:Matrix = new Matrix( 1,0,0,1, point.x - ix, point.y - iy);
  212. m.rotate(angle);
  213. return new Point( m.tx + ix, m.ty + iy);
  214. }
  215. private function drawRects(rects:Vector.<Rectangle> = null):void
  216. {
  217. canvas.graphics.clear();
  218. if (rects) {
  219. var rc:Rectangle;
  220. var i:int;
  221. var j:int;
  222. /*for (i = 0;i < rects.length - 1; ++i) {
  223. for (j = i + 1;j < rects.length; ++j) {
  224. if (rects[i].containsRect(rects[j])) {
  225. rects = rects.splice(j, 1);
  226. j--;
  227. }
  228. else if (rects[j].containsRect(rects[i])) {
  229. rects[i] = rects[j].clone();
  230. rects = rects.splice(j, 1);
  231. j--;
  232. }
  233. else if (intersects(rects[i], rects[j])) {
  234. rects[i] = rects[i].union(rects[j]);
  235. rects = rects.splice(j, 1);
  236. j--;
  237. //j = i + 1;
  238. }
  239. }
  240. }*/
  241. canvas.graphics.lineStyle(1, 0xFFFF00);
  242. var currf:Point;
  243. var prevf:Point;
  244. var ind:int;
  245. var n:int;
  246. var cx:Number, cy:Number;
  247. var mw:Number, mh:Number;
  248. var vx:Number, vy:Number;
  249. var avx:Number, avy:Number;
  250. for(i = 0; i < rects.length; ++i){
  251. rc = rects[i];
  252. //currf = tracker.getAreaForce(rc.x, rc.y, rc.width, rc.height);
  253. currf = tracker.force(rc.x, rc.y, rc.width, rc.height);
  254. if(currf.x == 0 && currf.y == 0) continue;
  255. mw = rc.width * .5;
  256. mh = rc.height * .5;
  257. cx = rc.x + mw;
  258. cy = rc.y + mh;
  259. avx = 0;
  260. avy = 0;
  261. var sx:int = int(cx - mw * .5);
  262. var sy:int = int(cy - mh * .5);
  263. var ex:int = int(sx + mw);
  264. var ey:int = Math.min(int(sy + mh), tracker.frameHeight);
  265. for(j = sy; j < ey; ++j)
  266. {
  267. ind = int(sx + tracker.frameWidth * j);
  268. for(n = sx; n < ex; ++n)
  269. {
  270. prevf = oldVelocity[ind];
  271. vx = prevf.x + (currf.x - prevf.x) * .5;
  272. vy = prevf.y + (currf.y - prevf.y) * .5;
  273. prevf.x = vx;
  274. prevf.y = vy;
  275. oldVelocity[ind] = prevf;
  276. avx += vx;
  277. avy += vy;
  278. ++ind;
  279. }
  280. }
  281. ind = mw * mh;
  282. avx /= ind;
  283. avy /= ind;
  284. if(avx == 0 && avy == 0) continue;
  285. //avx = currf.x;
  286. //avy = currf.y;
  287. currf.normalize(1);
  288. canvas.graphics.drawRect(rc.x * scaleFactor, rc.y * scaleFactor, rc.width * scaleFactor, rc.height * scaleFactor);
  289. drawArrow(canvas.graphics, new Point(cx * scaleFactor, cy * scaleFactor), new Point(avx, avy), currf.length*50, 7);
  290. }
  291. dumpVectors();
  292. }
  293. }
  294. private function dumpVectors():void
  295. {
  296. var i:int = oldVelocity.length;
  297. while( --i > -1 ){
  298. oldVelocity[i].x *= .9;
  299. oldVelocity[i].y *= .9;
  300. }
  301. }
  302. public function drawArrow(graphics:Graphics, start:Point, direction:Point = null, length:Number = 50, arrowSize:int = 8, angle:Number = -1):void
  303. {
  304. var endx:Number;
  305. var endy:Number;
  306. if(direction){
  307. var dirx:Number = direction.x;
  308. var diry:Number = direction.y;
  309. var mag:Number = 1 / Math.sqrt(dirx * dirx + diry * diry);
  310. endx = dirx * mag * length + start.x;
  311. endy = diry * mag * length + start.y;
  312. } else {
  313. endx = start.x + Math.cos(angle) * length;
  314. endy = start.y + Math.sin(angle) * length;
  315. }
  316. graphics.moveTo(start.x, start.y);
  317. graphics.lineTo(endx, endy);
  318. var diffx:Number = endx - start.x;
  319. var diffy:Number = endy - start.y;
  320. var ln:Number = Math.sqrt(diffx * diffx + diffy * diffy);
  321. if (ln <= 0) return;
  322. diffx = diffx / ln;
  323. diffy = diffy / ln;
  324. graphics.moveTo(endx, endy);
  325. graphics.lineTo(endx - arrowSize * diffx - arrowSize * -diffy, endy - arrowSize * diffy - arrowSize * diffx);
  326. graphics.moveTo(endx, endy);
  327. graphics.lineTo(endx - arrowSize * diffx + arrowSize * -diffy, endy - arrowSize * diffy + arrowSize * diffx);
  328. }
  329. public function intersects(rect1:Rectangle, rect2:Rectangle):Boolean
  330. {
  331. if(!((rect1.right < rect2.left) || (rect1.left > rect2.right)))
  332. if(!((rect1.bottom < rect2.top) || (rect1.top > rect2.bottom)))
  333. return true;
  334. return false;
  335. }
  336. private function getGroupBounds(group:Array):Object
  337. {
  338. var minx:Number = Number.POSITIVE_INFINITY;
  339. var miny:Number = Number.POSITIVE_INFINITY;
  340. var maxx:Number = Number.NEGATIVE_INFINITY;
  341. var maxy:Number = Number.NEGATIVE_INFINITY;
  342. var rc:Rectangle;
  343. var i:int = group.length;
  344. while (--i > -1) {
  345. rc = group[i];
  346. minx = Math.min(minx, rc.left);
  347. miny = Math.min(miny, rc.top);
  348. maxx = Math.max(maxx, rc.right);
  349. maxy = Math.max(maxy, rc.bottom);
  350. }
  351. return {minx:minx, miny:miny, maxx:maxx, maxy:maxy};
  352. }
  353. private function initFlv():void
  354. {
  355. w = VID_W;
  356. h = VID_H;
  357. connection = new NetConnection();
  358. connection.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
  359. connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
  360. connection.connect(null);
  361. }
  362. private function netStatusHandler(event:NetStatusEvent):void {
  363. switch (event.info.code) {
  364. case "NetConnection.Connect.Success":
  365. connectStream();
  366. break;
  367. case "NetStream.Play.Stop":
  368. stream.seek(0);
  369. stream.resume();
  370. break;
  371. case "NetStream.Play.StreamNotFound":
  372. trace("Unable to locate video: " + videoURL);
  373. break;
  374. }
  375. }
  376. private function connectStream():void {
  377. stream = new NetStream(connection);
  378. stream.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
  379. stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
  380. _vid = new Video(VID_W, VID_H);
  381. _vid.attachNetStream(stream);
  382. stream.play(videoURL);
  383. view.addChild(_vid);
  384. var vt:Timer = new Timer(150);
  385. vt.addEventListener(TimerEvent.TIMER, renderVideo);
  386. vt.start();
  387. }
  388. private function securityErrorHandler(event:SecurityErrorEvent):void {
  389. trace("securityErrorHandler: " + event);
  390. }
  391. private function asyncErrorHandler(event:AsyncErrorEvent):void {
  392. // ignore AsyncErrorEvent events.
  393. }
  394. private function countFrameTime(e:Event = null):void
  395. {
  396. _timer = getTimer();
  397. var lab:Label = Label(panel.getChildByName('fps_txt'));
  398. if( _timer - 1000 >= _ms_prev )
  399. {
  400. _ms_prev = _timer;
  401. lab.text = 'FPS: ' + _fps + ' / ' + stage.frameRate + '\nMS:';
  402. _fps = 0;
  403. }
  404. _fps ++;
  405. lab.text = lab.text.split('MS:')[0] + 'MS: ' + (_timer - _ms);
  406. _ms = _timer;
  407. }
  408. private function initStage():void
  409. {
  410. stage.scaleMode = StageScaleMode.NO_SCALE;
  411. //stage.align = StageAlign.TOP_LEFT;
  412. var myContextMenu:ContextMenu = new ContextMenu();
  413. myContextMenu.hideBuiltInItems();
  414. var copyr:ContextMenuItem = new ContextMenuItem("Š inspirit.ru", true, false);
  415. myContextMenu.customItems.push(copyr);
  416. contextMenu = myContextMenu;
  417. }
  418. }
  419. }