1. 程式人生 > >目標檢測光流法(三):opencv下光流Farneback法

目標檢測光流法(三):opencv下光流Farneback法

上節說到過的calcOpticalFlowPyrLK光流演算法,可以看到它實際上是一種稀疏特徵點的光流演算法,也就是說我們先找到那些(特徵)點需要進行處理,然後再處理,該節介紹下一個全域性性的密集光流演算法,也就是對每一個點都進行光流計算,函式為calcOpticalFlowFarneback。

引數一大推,得看一會。有些引數可能帶來的影響不是很大,那麼使用它推薦的引數即可。完整的引數達10個。按順序:

prevImg:輸入第一個圖
nextImg:輸入第二個圖
Flow:輸出的光流矩陣。矩陣大小同輸入的影象一樣大,但是矩陣中的每一個元素可不是一個值,而是兩個值,分別表示這個點在x方向與y方向的運動量(偏移量)。所以要把這個光流場矩陣顯示出來還真的需要費點力。那麼上面說的兩幅影象與這個光流場是什麼關係呢?如下:
這裡寫圖片描述


pyrScale:一個構造影象金字塔的引數,一般就認為是0.5最好了,也就是將影象縮小一半。那麼為什麼要構造金字塔呢?這應該是與演算法本身的設計有關,其實很多地方在檢測特徵的時候都會涉及到影象的金字塔,設想下如果有個特徵點在原始尺寸與其縮小的尺寸下都是特徵點的話,那麼這個特徵點就很有效了吧。
Levels:依然是與金字塔有關引數,常設值1.
Winsize:相當於一個均值濾波的作用,視窗大小決定了其噪聲的抑制能力什麼的。
Iterations:在每層金字塔上的迭代次數。
polyN:點與附近領域點之間的聯絡作用,一般為5,7等等即可。
polySigma :畫素點的一個平滑水平,一般1-1.5即可。
Flags
:一個標記,決定計算方法。

具體怎麼影響結果的,可以自己去嘗試。
下面對上節使用到的兩幅圖,通過這個方法來計算這兩幀影象中存在的光流場,也就是把上述的Flow找出來,那些引數也決定了Flow找出來的不一樣。簡單的程式如下:

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/video/video.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/types_c.h>
#include <iostream> #include <cstdio> using namespace std; using namespace cv; #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; //Scalar r,g,b if (colorwheel.empty()) makecolorwheel(colorwheel); // determine motion range: float maxrad = -1; // Find max flow to normalize fx and 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; // uncomment to see original color wheel 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); // increase saturation with radius else col *= .75; // out of range data[2 - b] = (int)(255.0 * col); } } } } int main() { Mat I1; Mat I2; Mat flow; //讀取兩個影象---相鄰幀 I1 = imread("I1.jpg",0);//讀取為灰度影象 I2 = imread("I2.jpg",0); calcOpticalFlowFarneback(I1,I2,flow,0.5,3,20,3,5,1.2,0); //cout<<I1.size()<<flow.size()<<flow.at<Vec2f>(10,10)<<endl; //flow = abs(flow); Mat motion2color; motionToColor(flow, motion2color); imshow("flow",motion2color); waitKey(0); return 0; }

可以看到程式的大部分是在如何把計算的光流flow可視化出來,雖然我們已經知道它是一個矩陣,而且矩陣中每個元素都包括2個值。但是顯示出來也比較費勁,顯示的函式是參考部落格:

該部落格裡面的內容也是值得一看的。
那麼我們這裡的一個結果如下(原始圖見上篇):
這裡寫圖片描述

顏色越深表示該部分存在的運動變化越大。

早點版本(3.0之前)的opencv中還有好幾個光流計算函式,什麼塊匹配BM法,HS法,LK法等等,每一種方法幾乎都對應一篇相關文章而來。後幾種方法的結果無非也都是計算出光流場(在x方向的光流與在y方向的光流)。3.0的opencv似乎把塊匹配、HS等方法捨棄了?沒有找到,想使用那些方法的恐怕還要使用以前的opencv版本才行。

相關推薦

目標檢測opencvFarneback

上節說到過的calcOpticalFlowPyrLK光流演算法,可以看到它實際上是一種稀疏特徵點的光流演算法,也就是說我們先找到那些(特徵)點需要進行處理,然後再處理,該節介紹下一個全域性性的密集光流演算法,也就是對每一個點都進行光流計算,函式為calcOpti

目標檢測opencvL-K演算法

後續將簡單介紹光流法的一些簡單實現包,包括opencv下的光流演算法與matlab下的光流演算法。該節主要介紹opencv下的光流實現。 Opencv的光流實現由好幾個方法可以(也就是說有好幾個函式可以用),每個函式當然也對應著不同的原理,那麼它的效果以及演算

caffe目標檢測模型訓練全過程目標檢測第一步

遍歷整圖查詢蝴蝶位置 2018/04/22 訓練模型對於識別背景和蝴蝶有比較好的效果,基本對不會識別錯誤,接下來,將通過整圖遍歷的原始而又野蠻的方式對一張原始圖片進行處理,進而查詢到蝴蝶的具體位置。具體思路如下圖。對原圖進行縮放成理想大小,例如, 最小邊長縮放為227*6畫素,最大邊長等比

Java數據結構和算常用排序算與經典題型

bre 操作 五步 增量排序 計算 -- clu 冒泡 i+1 常用的八種排序算法 1.直接插入排序 我們經常會到這樣一類排序問題:把新的數據插入到已經排好的數據列中。將第一個數和第二個數排序,然後構成一個有序序列將第三個數插入進去,構成一個新的有序序列。對第四

高斯消元用Python簡單實現順序消元

# coding:utf-8 import numpy as np import sys # 設定矩陣 def set_matrix(): # 設定係數矩陣A matrix_a =np.mat([ [2.0, 1.0, 2.0],

自動化服務部署Linux安裝Git

ima yum lan 參考 lease 指令 mage sta shu Git是一個開源的分布式版本控制系統,可以有效、高速的處理從很小到非常大的項目版本管理,是目前使用範圍最廣的版本管理工具。 這篇博客,介紹下Linux下安裝Git的步驟,僅供參考,當然,還是yum安裝

Docker學習系列Ubuntu使用Docker的基本指令記錄及一些注意事項

1.Dockerhub下載映象 有兩種方式可以獲得新的映象 直接從dockerhub下載編譯好的image(該編譯過程在docker hub的雲端完成)(見3.1) 下載docekrfile檔案,在本機進行build 直接在docker

目標檢測與分割SSD詳解

SSD github : https://github.com/weiliu89/caffe/tree/ssd SSD paper : https://arxiv.org/abs/1512.02325 SSD eccv2016 slide pdf : http://d

計算機視覺目標檢測與識別

1 - 引言 目標檢測和識別,是計算機視覺最常見的挑戰之一。 目標檢測和識別的區別在於:目標檢測是用來確定影象的某個區域是否含有要識別的物件,而識別是程式識別物件的能力。識別通常只處理已檢測到物件的區域。 在計算機視覺中有很多目標檢測和識別的技術 梯度直方圖(Hist

二元選擇排序

二元選擇排序二元選擇排序在簡單選擇排序的基礎上,一輪中同時比較出最大值與最小值lst1 = [ [1, 8, 9, 5, 6, 7, 4, 3, 2], [9, 8, 7, 6, 5, 4, 3, 2, 1], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1,

圖解排序算之堆排序

穩定 for 根據 設計 編號 簡單的 重新 heapsort 其中 預備知識 堆排序   堆排序是利用堆這種數據結構而設計的一種排序算法,堆排序是一種選擇排序,它的最壞,最好,平均時間復雜度均為O(nlogn),它也是不穩定排序。首先簡單了解下堆結構。 堆   堆是具有以

Java數據結構和算——冒泡、選擇、插入排序算

我們 逆序排列 pub 多少 img 目錄 http 最小 數據結構 目錄 1、冒泡排序 2、選擇排序 3、插入排序 4、總結   上一篇博客我們實現的數組結構是無序的,也就是純粹按照插入順序進行排列,那麽如何進行元素排序,本篇博客我們介紹幾種簡單的排序算

ShaderLab學習小結漫反射+高+點光源

均值 mod fsp 世界坐標 type specular dsp 法線向量 sat 場景中有一個平行光,一個×××點光源,設高光顏色為綠,效果如下:Shader代碼: Shader "Custom/DifSpecPoint" { Properties {

Paxos一致性算

-s rop 作者 googl accep ogl Go center 世界 一、概述: Google Chubby的作者說過這個世界只有一種一致性算法,那就Paxos算法,其他的都是殘次品。 二、Paxos算法: 一種基於消息傳遞的高度容錯性的一致性算法。 Paxos:少

程序設計與算第九周測驗(2018春季)

gif AS 自己的 AC 其他人 greate comm play man 題目網址:http://cxsjsxmooc.openjudge.cn/2018t3springw9/ 【1:Set】 用multiset記錄當前整數集數據信息 用set記錄曾被加入集合的數

Java虛擬機GC算和種類

完成 垃圾 過程 回收 對象復制 沒有響應 rip 加法 內存 一、介紹 GC(Garbage Collection),垃圾收集 Java中,GC的對象是堆空間和永久區 二、GC算法 1. 引用計數法 老牌垃圾回收算法 通過引用計算來回收垃圾 Java中未使用,使用者

並不對勁的圖論專題SPFA算的優化

a算法 bubuko 等於 dfs size iomanip 最小 bre else if 1.bzoj1489-> 這是個新套路。 我們希望找到最小的x,那麽可以二分x,然後判斷是否存在圈的邊權的平均值小於等於x。 設圈的邊權依次為w1,w2,w3,…,wk,平均值

數值分析C++實現線性方程組的高斯-賽德爾迭代

線性方程組的直接解法之後,就輪到迭代解法了,直接解法針對的是低階稠密矩陣,資料量較少,而工程上有更多的是高階係數矩陣,使用迭代法效率更高,佔用的空間較小。 迭代法的最基本思想就是由初始條件,比如說初始解向量隨便列舉一個,就0向量也行,然後進行迭代,k到k+1,一步一步從k=1開始去逼近真實解

目標檢測之模型篇4【EAST】

文章目錄 1. 前言 2. 實現 2.1 Pipeline 2.2 網路設計 2.3 標籤生成 2.4 損失函式 2.5 訓練 2.6 位置感知的NMS 3. 結果 4. 總結 5.

目標檢測之模型篇3【DMPNet】

文章目錄 1. 前言 2. 實現 2.1 Roughly recall text with quadrilateral sliding window 2.2 Finely localize text with quadrangle