OpenCV学习之光流法跟踪物体C++

光流法(Optical Flow)早在1950年就提出

光流法具体实现有很多,OpenCV中就有

  1. calcOpticalFlowPyrLK
  2. calcOpticalFlowFarneback

本篇主要展示使用稠密光流法calcOpticalFlowFarneback展现一个完整的视频追踪例子。

主要目的

使用OpenCV calcOpticalFlowFarneback方法进行物体的跟踪。

思路

  1. 使用光流法计算光流
  2. 过滤光流,找到光流聚集的位置
  3. 通过光流点,生成mask 图像,使用find contours方法找到运动物体边缘
  4. 使用矩形等框出物体

代码效果图:

代码

主要部分代码

[C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
/*
Created by starsplendid on 15/6/18.
Copyright (c) 2015年 starsplendid. All rights reserved.
代码基础来源:http://blog.sina.com.cn/s/blog_662c78590100yyeg.html
*
*/

#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;

// 其他函数,见下部分

int main()
{


Mat prevgray, gray, flow, cflow, frame,binaryPic,binaryPic2;
vector<vector<Point> > contours;

do
{
VideoCapture cap("out.avi");

if (!cap.isOpened())
{
cout<< "Error Acquireing video feed\n";
return -1;
}
while (cap.get(CV_CAP_PROP_POS_FRAMES)< cap.get(CV_CAP_PROP_FRAME_COUNT)-1) {
cap>>frame;
cvtColor(frame, gray, CV_BGR2GRAY);

if (prevgray.data)
{
calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3,15, 3, 5, 1.2, 0);
cvtColor(prevgray, cflow, CV_GRAY2RGB);

float diff_XY= 0.0 ;
// 用来计算平均 flow 速度
int numOfSelectedPoint = 0 ;
float sumX = 0.0 ;
float sumY = 0.0 ;

binaryPic = Mat::zeros(prevgray.size(), prevgray.type());
for (int y = 0; y < cflow.rows; y += 10 )
{
for (int x = 0; x < cflow.cols; x += 10)
{
Point2f fxy = flow.at<Point2f>(y, x);
/*
选取光流明显的点
*/

diff_XY =abs(fxy.x)+abs(fxy.y);
if (diff_XY > 6) {
binaryPic.at<uchar>(y,x) = 128 ;

numOfSelectedPoint++ ;
sumX += fxy.x ;
sumY += fxy.y ;
}

arrowedLine(cflow, Point(x, y), Point(cvRound(x+fxy.x), cvRound(y+fxy.y)), CV_RGB(0,255,0));

circle(cflow, Point(x,y), 2, CV_RGB(255, 0, 0), -1);
}
}

Mat dilateElement = getStructuringElement( MORPH_RECT,Size(10,10));

dilate(binaryPic,binaryPic2,dilateElement);
// binaryPic2 to binary
threshold(binaryPic2, binaryPic2, 127.0, 255.0, THRESH_BINARY);

drawBiggestContours(binaryPic2,cflow,sumX/numOfSelectedPoint,sumY/numOfSelectedPoint);


imshow("FLOW", cflow);
}
if (waitKey(100) >= 0)
{
break;
}

swap(prevgray, gray);
}
cap.release();

} while (1);
return 0;
}
其余部分函数
[C++]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
string intToString(int number){


std::stringstream ss;
ss << number;
return ss.str();
}
string floatToString(float number){


std::stringstream ss;
ss << number;
return ss.str();
}

int drawBiggestContours(Mat& inputMat,Mat& orignialMat,float vx , float vy){
int largest_area=0;
int largest_contour_index=0;
Rect bounding_rect;
vector<vector<Point>> contours; // Vector for storing contour
vector<Vec4i> hierarchy;

findContours( inputMat, contours, hierarchy,CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); // Find the contours in the image

for( int i = 0; i< contours.size(); i++ ) // iterate through each contour.
{
double a=contourArea( contours[i],false);//  Find the area of contour
if(a>largest_area){
largest_area=a;
largest_contour_index=i;//Store the index of largest contour
bounding_rect=boundingRect(contours[i]); // Find the bounding rectangle for biggest contour
}
}
Scalar color( 255,255,255);
drawContours( orignialMat, contours,largest_contour_index, color, 1, 8, hierarchy ); // Draw the largest contour using previously stored index.
rectangle(orignialMat, bounding_rect,Scalar(0,255,0),2, 8,0);

// 画中心点,并且标注速度 参考:http://docs.opencv.org/doc/tutorials/imgproc/shapedescriptors/moments/moments.html
Scalar color1(0,0,255);
Moments mu = moments(contours[largest_contour_index],false);
float x = mu.m10/mu.m00;
float y =mu.m01/mu.m00 ;
circle( orignialMat, Point2f(x , y ), 4, CV_RGB(0,255,255), -1, 8, 0 );
arrowedLine(orignialMat, Point2f(x, y), Point2f(x+vx, y+vy), CV_RGB(0,255,255),2);

putText(orignialMat,"at ("+intToString(x)+","+intToString(y)+") with vector ("+floatToString(vx)+","+floatToString(vy)+")",bounding_rect.br(),1,1,Scalar(0,255,0),2);
return 0 ;
}

参考资料

  1. Moments 找中心点
  2. 找最大的contour

MacOS 搭建 OpenCV环境

最近准备使用OpenCV做些追踪的研究,遂安装配置开发环境。

源码编译安装

具体参考了youtube 视频OpenCV Installation Tutorial Mac

1. download source code

2. install cmake

 brew install cmake

3. make and install

在opencv 源码文件夹中创建一个build 文件夹

makedir build 
cd build
make -G 'Unix Makefiles' .. 
等待
make -j8
等待
sudo make install
   

之前装过 2.4.11 之后有转换成3.0 在xcode build 报错
感谢这篇post 对xcode linker进行配置解决了问题。

参考资料

  1. OpenCV Installation Tutorial Mac
  2. Install OpenCV 3 on OSX
  3. 中文博客Develop Opencv on mac

Angular学习笔记之几种常见的对话框总结

接触学习Angular这么长时间,项目里面经常碰到会使用弹出对话框(Modal或者Dialog)用起来简单使用,适合对象的创建,修改和提醒等操作。

1 UI Bootstrap 的modal

UI Bootstrap 是AngularUI Team 用AngularJS 编写的 Bootstrap components. 所以常见的 bootstrap 组件都可以尝试在 UI Bootstrap中寻找.
大概样子如此。

由于项目中会用到多个对话框,通常是使用angular 事件机制($broadcast/$on)来触发modal 的展示。所以一般架构是,view层,专门有个总的dialog.ejs(后台使用nodejs开发)里面以ng-template形式存储多个dialog

[html]
1
2
3
4
5
6
7
<script type="text/ng-template" id="dialog.XXXDialog">
<%include dialog.XXXDialog.ejs%>
</script>


<script type="text/ng-template" id="dialog.XXXDialog">
<%include dialog.XXXDialog.ejs%>
</script>

同理,controller层,专门有dialogController 来负责监听($on)所有modal事件。 具体触发事件只需要使用$rootScope.$broadcast(“eventname”) 总的控制controller 内容如下:

[javascript]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
app.controller("dialogController",[function(...){
$scope.$on("new.friend",function(event){
var modalInstance = $modal.open({
backdrop:'static',
templateUrl:'dialog.XXXDialog',// dialog.ejs 里面模板id
controller :"dialog.XXXController",//对应具体modal的controller
windowClass:"colored-header",
resolve : { // 通过resolve 来向具体XXXController注入数据service
yourService:function(){
return XXX ;
}
}
// 其他字段参考官网
})
})
$scope.$on(...) // 其他的触发modal 的事件
}])

具体的每个modal 的处理逻辑只需要写在相应的 controller里面即可。
_记得不要忘记
把相关的模板以及js文件 include到 页面中。

2 angular-strap 的modal

[AngularStrap] 是另一套为AngularJS写的Bootstrap Directives。有一些指令还是比较炫酷好看的。由于modal service名称冲突,angular-strap 里面的modal不能和ui-bootstrap 的modal一起使用。
使用时先引入相应的module

1
angular.module('myApp', ['mgcrea.ngStrap']);

个人感觉angular-strap 实现的modal service 不是太好,Modal show 的时候,在DOM生成是以兄弟节点的形式在触发Button后面插入,这样CSS样式会受到相应父节点的影响。
同时 modal.$hide()不提供 promise服务,无法知道$hide完整 remove的事件从而导致一些样式问题
。同时没有提供resolve 接口可以注入数据,所以几次使用都是直接使用继承触发modal时button所在的Controller $scope

3 angular material 中的 dialog

Angular Material 使用angularjs实现的基于google material design的样式组件。也是最近才发现接触的,感觉做的更是炫酷。提供$mdDialog service 效果如下:

使用起来和ui-bootstrap modal 相似,同时可以和ui-bootstrap的 modal共同使用。

1
2
3
4
5
6
7
8
9
10
11
12
// 记得在相应dialog.ejs 里面添加 ng-template : dialog.XXXDialog
// 以及生成新的 dialog.XXXDialogController
$mdDialog.show({
controller: 'dialog.XXXDialogController',
templateUrl: 'dialog.XXXDialog',
clickOutsideToClose: true ,
resolve : {
dataService : function(){
return XXX;
}
}
})

先写这些,很是零碎。

mac php开发工具及环境配置

安装MAMP环境

安装MAMP开发环境,一键安装install Apache 2, current PHP and MySQL.

安装phpstorm

jetBrains官网官网直接下载phpstorm安装。

从svn加载项目

之后从svn加载工程,发现一致报错 Received fatal alert: handshake_failure Please check Subversion SSL settings (Settings | Version Control | Subversion | Network) Maybe you should specify SSL protocol manually - SSLv3 or TLSv1

最后经过查询找到了解决方案


1.- Go to Preferences > Project settings > Version Control > Subversion
2.- In network tab, select TLSv1
3.- In general tab, click "Clear auth cache" and it will ask you again the credentials for the svn repositories.
4.- restart phpstorm

安装ecshop

把ecshop项目加载到phpstorm,进行运行配置,配置apache 服务器地址,项目路径,运行。 在浏览器输入URL ,会看到ecshop项目初始化install的配置导航,点击下一步,之后设置数据库,后台admin的账户,点击完成,即可看到ecshop默认的商城页面了。

当然可能会遇到php报错的问题,需要调整一下php版本,自己使用php 5.3.29 可以解决问题。

参考文献:

  1. 配置环境
  2. 解决svn错误
  3. svn 命令更新

Ubuntu 14.04 配置LAMP开发环境

阿里云新手各种活动,领了好几张优惠劵,就开始0¥免费使用ECS服务器,同时使用优惠券开通了外网带宽。配置Ubuntu 14.04 64位,准备搭个LAMP环境玩耍一番。

登陆

直接使用ssh ssh root@ip_address登陆即可。

安装

参考这篇安装 就不细说了。

之后在浏览器输入 公网 IP_ADDRESS,看到apache2的 Default Page 就表示apache安装成功

遇到的问题

之后访问phpAdmin 出现错误 : The json extension is missing. Please check your PHP configuration.

查询一下发现只需要前往 /etc/php5/mods-available/json.inipriority=20 注释去掉,重启服务service apache2 restart

vim基本操作

按Esc 输入:help 查看帮助文档

  1. 按Esc 之后输入 :q! 直接退出 不保存
  2. 按Esc 之后输入 :wq 保存并退出 不保存

其他参考

  1. LAMP
  2. The json extension is missing错误解决
  3. how-to-exit-the-vim-editor

nodewebkit 打包发布程序

用nodejs+express 开发完的程序,想使用node-webkit 现在已经改名nwjs打包进行发布。

mac osx

简单说就是把之前的程序代码,index.html,nw描述的package.json 文件打包为 app.nw 即:


zip -r -q app.nw *

之后把 app.nw (当然,为了方便节省时间,你也可以不用zip 只需要把上述文件放到名称为app.nw的文件夹中也是可以的)放到之前下载好的nodewebkit.app/Contents/Resources/ 文件夹下,这样点击 原来的nodewekit.app 就可以运行自己的打包的app.nw程序了,当然可以修改添加自己程序的icon及名称。

直接发布 nodewebkit.app 就可以了

window

待续…

参考链接

  1. nwjs github 主页How to package and distribute your apps

hexo搭建博客小记

本文记录搭建hexo过程中的零零碎碎的事情,遇到的问题,留个参考。

去年在老广的通知下,趁着github education活动获得了一堆优惠。Namecheap 申请了一个免费域名。Digitial Ocean搞到了几百美元的优惠。于是乎准备搞个Blog,逛了一圈,发现直接用github pages 托管静态资源这个解决方案不错,选用了Hexo Blog框架。

Blog搭起来之后就没管它。过完年回来,想想未完成的志事。决定还要坚持下去。发现hexo已经更新到3.0版本,按照网站指导从2.X整合到3.0 结果发现 _config.yml 被还原了,重新配置,部署安装终于搞定。

Blog搭起来之后,无外乎两个方向,开始写,开始优化Blog配置。

优化Blog配置方面,首先解决网页请求一些访问慢的静态资源,font 还有 jquery。参考这篇文章HEXO个人博客速度优化

添加了多说评论

添加了百度统计

使用Google Anaalytics 登陆注册,之后添加要跟踪网站,获得跟踪代码,其实只需要知道 媒体跟踪ID 一般是UA-XXXX-Y 结尾。赋值给模板_config.yml 里面的google_analytics 即可。

安装 sitemap插件

Sitemap 可方便网站管理员通知搜索引擎他们网站上有哪些可供抓取的网页。最简单的 Sitemap 形式,就是XML 文件,在其中列出网站中的网址以及关于每个网址的其他元数据(上次更新的时间、更改的频率以及相对于网站上其他网址的重要程度为何等),以便搜索引擎可以更加智能地抓取网站。

未完待续。

参考资料

  1. Markdown 语法介绍

nodejs 学习笔记(一)path

今天在项目中遇到问一个问题,就是想设置项目使用数据库路径为系统指定路径。由于自己的操作系统位Mac OSX,查看了一下Mac File System介绍,自己做的app的数据(数据库tingodb)位置一般应该位于$HOME/Library/Application Support/APP_NAME目录下.

那么问题来了,我在js代码中如何设置数据库的路径呢。

直接设置 path = '~/Library/Application\ Support/APP_NAME/db'发现是不行的,path = '$HOME/Library/Application\ Support/APP_NAME/db'也同样不行。

之后发现可以使用node path module 进行路径的操作,如何找到user home path 仍然是个问题,在终端terminal 里面直接 cd ~ 就可以了,但是在程序中如何得到呢。经过不懈努力查找,在这个答案中找到解决方案
var home = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE; 成功拿到 user home path 。 之后问题就应迎刃而解了。
path.join(home,'/Library/Application\ Support/APP_NAME/db')就设置成功。

其他参考有用的资料:

  1. nodejs path normalize 与 resolve的区别
  2. OSX Library Directory Details
  3. chromium user data directory
知识共享许可协议