OpenCV学习(三)目标检测之光流法

光流法是传统的目标检测算法之一,此类算法层出不群,但是都遵循如下三个步骤:
1)利用低通或带通滤波器预滤波,以增强信噪比并提取单一的目标信号;
2)利用基本算法提取目标;
3)利用整合算法生成2维运动流场。
参考https://blog.csdn.net/Lemon_jay/article/details/89476029,编写程序如下:


#include <iostream>
#include "opencv2/opencv.hpp"
 
using namespace cv;
using namespace std;
 
#define UNKNOWN_FLOW_THRESH 1e9
 
void makecolorwheel(vector<Scalar> &colorwheel)
{
 int RY = 15;
 int YG = 6;
 int GC = 4;
 int CB = 11;
 int BM = 13;
 int MR = 6;
 
 int i;
 
 for (i = 0; i < RY; i++) colorwheel.push_back(Scalar(255, 255 * i / RY, 0));
 for (i = 0; i < YG; i++) colorwheel.push_back(Scalar(255 - 255 * i / YG, 255, 0));
 for (i = 0; i < GC; i++) colorwheel.push_back(Scalar(0, 255, 255 * i / GC));
 for (i = 0; i < CB; i++) colorwheel.push_back(Scalar(0, 255 - 255 * i / CB, 255));
 for (i = 0; i < BM; i++) colorwheel.push_back(Scalar(255 * i / BM, 0, 255));
 for (i = 0; i < MR; i++) colorwheel.push_back(Scalar(255, 0, 255 - 255 * i / MR));
}
 
void motionToColor(Mat flow, Mat &color)
{
 if (color.empty())
  color.create(flow.rows, flow.cols, CV_8UC3);
 
 //定义颜色的容器
 static vector<Scalar> colorwheel; 
 if (colorwheel.empty())
  makecolorwheel(colorwheel);
 
 //确定运动范围
 float maxrad = -1;
 
 //找到最大流动来标准化fx和fy
 for (int i = 0; i < flow.rows; ++i)
 {
  for (int j = 0; j < flow.cols; ++j)
  {
   Vec2f flow_at_point = flow.at<Vec2f>(i, j);
   float fx = flow_at_point[0];
   float fy = flow_at_point[1];
   if ((fabs(fx) >  UNKNOWN_FLOW_THRESH) || (fabs(fy) >  UNKNOWN_FLOW_THRESH))
    continue;
   float rad = sqrt(fx * fx + fy * fy);
   maxrad = maxrad > rad ? maxrad : rad;
  }
 }
 
 for (int i = 0; i < flow.rows; ++i)
 {
  for (int j = 0; j < flow.cols; ++j)
  {
   uchar *data = color.data + color.step[0] * i + color.step[1] * j;
   Vec2f flow_at_point = flow.at<Vec2f>(i, j);
 
   float fx = flow_at_point[0] / maxrad;
   float fy = flow_at_point[1] / maxrad;
   if ((fabs(fx) >  UNKNOWN_FLOW_THRESH) || (fabs(fy) >  UNKNOWN_FLOW_THRESH))
   {
    data[0] = data[1] = data[2] = 0;
    continue;
   }
   float rad = sqrt(fx * fx + fy * fy);
 
   float angle = atan2(-fy, -fx) / CV_PI;
   float fk = (angle + 1.0) / 2.0 * (colorwheel.size() - 1);
   int k0 = (int)fk;
   int k1 = (k0 + 1) % colorwheel.size();
   float f = fk - k0;
   //f = 0; // 取消注释可查看原始色轮l
 
   for (int b = 0; b < 3; b++)
   {
    float col0 = colorwheel[k0][b] / 255.0;
    float col1 = colorwheel[k1][b] / 255.0;
    float col = (1 - f) * col0 + f * col1;
    if (rad <= 1)
     col = 1 - rad * (1 - col); //随半径增大饱和度
    else
     col *= .75; //超过范围处理
    data[2 - b] = (int)(255.0 * col);
   }
  }
 }
}
 
int main(int argc, char* argv[])
{
 //opencv中的读取视频
 VideoCapture cap;
 cap.open("../people.avi");
 
 if (!cap.isOpened())
  return -1;
 
 Mat prevgray, gray, flow, cflow, frame;
 namedWindow("flow", 1);
 
 Mat motion2color;
 
 for (;;)
 {
  double t = (double)cvGetTickCount();
 
  cap >> frame;
  if (frame.empty()) {
   break;
  }
  cvtColor(frame, gray, CV_BGR2GRAY);
  imshow("original", frame);
 
  if (prevgray.data)
  {
   calcOpticalFlowFarneback(prevgray, gray, flow, 0.5, 3, 15, 3, 5, 1.2, 0);
   motionToColor(flow, motion2color);
   imshow("flow", motion2color);
  }
  if (waitKey(10) >= 0)
   break;
  std::swap(prevgray, gray);
 
  t = (double)cvGetTickCount() - t;
  cout << "cost time: " << t / ((double)cvGetTickFrequency()*1000.) << endl;
 }
 return 0;
}

处理结果截图如下:
在这里插入图片描述
和前两种算法相比,光流算法的处理速度明显比较慢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值