7
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

OpenCV3におけるパーティクルフィルタ(粒子フィルタ)

Last updated at Posted at 2018-01-09

はじめに

  • OpenCV2.Xまでは、OpenCV1.X系の書き方でパーティクルフィルタが扱えていたのですが(ここ)、OpenCV3からは無くなっていたので、色々調べてみてC++とOpenCV3.Xシリーズで記述してみました。

  • 使用してもらっても構いませんが、保証はしかねます。

  • 赤色を追跡するパーティクルフィルタの実装です。

  • 実行環境は以下の通りです。

  • Visual Studio 2013

  • OpenCV 3.1

  • OpenCV3のインストールなどはここなどを参考にしてください。

解説のページ

  • パーティクルフィルタの解説のページはこのあたりを参考に

パーティクルフィルタによる物体追跡:このページを参考にプログラムを書きました。
Tutorial/Practice0 MIST Project
6.パーティクルフィルタ

プログラムコード

  • OpenCVを使うためのヘッダファイル
OPENCV.hpp
/***
* Revised 2016/08/07 for OpenCV-3
***/

# pragma once
# include <iostream>
# include <opencv2/opencv.hpp>
# include <opencv2/core/core.hpp>              // (C++用)
# include <opencv2/imgproc/imgproc.hpp>        // (C++用)
# include <opencv2/highgui/highgui.hpp>        // (C++用)
# include <opencv2/ml/ml.hpp>                  // サポートベクタマシン、ブースティングなどの機械学習
# include <opencv2/features2d/features2d.hpp>  // SURF、FASTなどの特徴抽出
# include <opencv2/xfeatures2d.hpp>
# include <opencv2/xfeatures2d/nonfree.hpp>
# include <opencv2/video/background_segm.hpp>  // 前景/背景分離
# include <opencv2/video/tracking.hpp>         // トラッキング
# include <opencv2/objdetect/objdetect.hpp>    // Haar、LBP、HOGなどのオブジェクト検出器
# include <opencv2/calib3d/calib3d.hpp>        // カメラキャリブレーション、ステレオカメラなど
# include <opencv2/flann/flann.hpp>            // 高速最近傍処理(FLANN)など
# include <opencv2/superres/optical_flow.hpp>  //オプティカルフロー
# include <opencv2/tracking/feature.hpp>

# define CV_VERSION_STR CVAUX_STR(CV_MAJOR_VERSION) CVAUX_STR(CV_MINOR_VERSION) CVAUX_STR(CV_SUBMINOR_VERSION)
# ifdef _DEBUG
# define CV_EXT_STR "d.lib"
# else
# define CV_EXT_STR ".lib"
# endif

# define _X64
# undef _X64

# ifdef _X64
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_calib3d"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_core"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_features2d"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_flann"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_highgui"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_imgcodecs"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_imgproc"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_ml"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_objdetect"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_photo"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_shape"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_stitching"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_superres"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_ts"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_video"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_videoio"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x64\\lib\\opencv_videostab"	CV_VERSION_STR	CV_EXT_STR)
# else
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_calib3d"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_core"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_features2d"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_flann"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_highgui"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_imgcodecs"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_imgproc"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_ml"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_objdetect"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_photo"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_shape"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_stitching"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_superres"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_ts"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_video"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_videoio"	CV_VERSION_STR	CV_EXT_STR)
# pragma comment(lib, "C:\\OpenCV3.1.0\\vs2013\\x86\\lib\\opencv_videostab"	CV_VERSION_STR	CV_EXT_STR)
# endif

/***** 画像のピクセルの直接操作 OpenCV-2.x (MAT* ) *****/

// 汎用マクロ
// IMG: IplImage*, TYPE: 型, X,Y: 座標, ID: インデックス
// 型
// IPL_DEPTH_8U: unsigned char
// IPL_DEPTH_16S: short
// IPL_DEPTH_

# define M_VALUE(MAT, TYPE, X, Y, ID) ((TYPE*)((MAT)->data + (MAT)->step*(Y)))[(X)*(MAT)->channels()+(ID)]
// 汎用マクロ
// IMG: IplImage*, TYPE: 型, X,Y: 座標, ID: インデックス
// M_IMG:Mat ,M_X,M_Y:座標,ID:インデックス
// 型
// IPL_DEPTH_8U: unsigned char
// IPL_DEPTH_16S: short
// IPL_DEPTH_
# define I_VALUE(IMG, TYPE, X, Y, ID) ((TYPE*)((IMG)->imageData + (IMG)->widthStep*(Y)))[(X)*(IMG)->nChannels+(ID)]
# define I_VALUE_FOR_MAT(M_IMG, TYPE,M_X,M_Y,ID) (TYPE)M_IMG.data[(M_X) * M_IMG.channels() + (ID) +  M_IMG.step * (M_Y)]	
// よく使う画像用マクロ
// 8ビット1チャンネル画像 (CV_8UC1)
# define MVC(MAT, X, Y) M_VALUE((MAT), unsigned char, X, Y, 0)

// 8ビット3チャンネル画像 (CV_8UC3)
# define MBC(MAT, X, Y) M_VALUE((MAT), unsigned char, X, Y, 0)
# define MGC(MAT, X, Y) M_VALUE((MAT), unsigned char, X, Y, 1)
# define MRC(MAT, X, Y) M_VALUE((MAT), unsigned char, X, Y, 2)

// 16ビット整数1チャンネル画像 (CV_16U) 符号あり16ビット整数(short) 
# define MVS(IMG, X, Y) M_VALUE(IMG, short, X, Y, 0)

// 16ビット3チャンネル画像 (CV_16SC3) 符号あり16ビット整数(short) 
# define MBS(MAT, X, Y) M_VALUE((MAT), short, X, Y, 0)
# define MGS(MAT, X, Y) M_VALUE((MAT), short, X, Y, 1)
# define MRS(MAT, X, Y) M_VALUE((MAT), short, X, Y, 2)

// 32ビット浮動小数点1チャンネル画像 (CV_32FC1)
# define MVF(MAT, X, Y) M_VALUE((MAT), float, X, Y, 0)

// 32ビット浮動小数点3チャンネル画像 (CV_32FC3)
# define MBF(MAT, X, Y) M_VALUE((MAT), float, X, Y, 0)
# define MGF(MAT, X, Y) M_VALUE((MAT), float, X, Y, 1)
# define MRF(MAT, X, Y) M_VALUE((MAT), float, X, Y, 2)

/***** 画像のピクセルの直接操作 OpenCV-1.x (IplImage* ) *****/

// 汎用マクロ
// IMG: IplImage*, TYPE: 型, X,Y: 座標, ID: インデックス
// 型
// IPL_DEPTH_8U: unsigned char
// IPL_DEPTH_16S: short
// IPL_DEPTH_
# define I_VALUE(IMG, TYPE, X, Y, ID) ((TYPE*)((IMG)->imageData + (IMG)->widthStep*(Y)))[(X)*(IMG)->nChannels+(ID)]

// よく使う画像用マクロ
// 8ビット1チャンネル画像 (IPL_DEPTH_8U, 1)
# define IVC(IMG, X, Y) I_VALUE(IMG, unsigned char, X, Y, 0)

// 8ビット3チャンネル画像 (IPL_DEPTH_8U, 3)
# define IBC(IMG, X, Y) I_VALUE(IMG, unsigned char, X, Y, 0)
# define IGC(IMG, X, Y) I_VALUE(IMG, unsigned char, X, Y, 1)
# define IRC(IMG, X, Y) I_VALUE(IMG, unsigned char, X, Y, 2)

// 16ビット整数1チャンネル画像 (IPL_DEPTH_16S, 1) 符号あり16ビット整数(short) 
# define IVS(IMG, X, Y) I_VALUE(IMG, short, X, Y, 0)

// 16ビット3チャンネル画像 (IPL_DEPTH_16S, 3) 符号あり16ビット整数(short) 
# define IBS(IMG, X, Y) I_VALUE(IMG, short, X, Y, 0)
# define IGS(IMG, X, Y) I_VALUE(IMG, short, X, Y, 1)
# define IRS(IMG, X, Y) I_VALUE(IMG, short, X, Y, 2)

// 32ビット浮動小数点1チャンネル画像 (IPL_DEPTH_32F, 1)
# define IVF(IMG, X, Y) I_VALUE(IMG, float, X, Y, 0)

// 32ビット浮動小数点3チャンネル画像 (IPL_DEPTH_32F, 3)
# define IBF(IMG, X, Y) I_VALUE(IMG, float, X, Y, 0)
# define IGF(IMG, X, Y) I_VALUE(IMG, float, X, Y, 1)
# define IRF(IMG, X, Y) I_VALUE(IMG, float, X, Y, 2)

/***** 行列の要素の直接操作 *****/
// 行:ROW, 列: COL
// 32ビット浮動小数点1チャンネル行列 (CV_32FC1)
# define M1F1(MAT, ROW, COL) ((float*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)]

// 32ビット浮動小数点2チャンネル行列 (CV_32FC2)
# define M2F1(MAT, ROW, COL) ((float*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)*2+0]
# define M2F2(MAT, ROW, COL) ((float*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)*2+1] 

// 32ビット浮動小数点3チャンネル行列 (CV_32FC3)
# define M3F1(MAT, ROW, COL) ((float*)(((MAT)->data).ptr + (MAT)->step*(ROW)))[(COL)*3+0]
# define M3F2(MAT, ROW, COL) ((float*)(((MAT)->data).ptr + (MAT)->step*(ROW)))[(COL)*3+1]
# define M3F3(MAT, ROW, COL) ((float*)(((MAT)->data).ptr + (MAT)->step*(ROW)))[(COL)*3+2]

// 64ビット浮動小数点1チャンネル行列 (CV_32FC1)
# define M1D1(MAT, ROW, COL) ((double*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)]

// 64ビット浮動小数点2チャンネル行列 (CV_64FC2)
# define M2D1(MAT, ROW, COL) ((double*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)*2+0]
# define M2D2(MAT, ROW, COL) ((double*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)*2+1] 

// 64ビット浮動小数点3チャンネル行列 (CV_64FC3)
# define M3D1(MAT, ROW, COL) ((double*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)*3+0]
# define M3D2(MAT, ROW, COL) ((double*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)*3+1]
# define M3D3(MAT, ROW, COL) ((double*)((MAT)->data.ptr + (MAT)->step*(ROW)))[(COL)*3+2]
  • パーティクルフィルタのヘッダファイル
Particle.hpp
# pragma once
# include <iostream>
# include <vector>
# include <random>

# include "OPENCV.hpp"

class Particle;       //パーティクルに関するクラス
class ParticleFilter; //パーティクルフィルタ関係のクラス

class Particle{
public:
	//重み
	double weight; // = 1.0;

	//パラメータ
	int height;
	int width;
	int height_speed;
	int width_speed;

	//コンストラクタ
	Particle();
	Particle(int height_point, int width_point,
		 int height_speed_point, int width_speed_point);

	void PrintParameter();
};

class ParticleFilter
{
private:
	int num; //粒子数
	int width; //横
	int height; //縦
	std::vector<int> upper; //最大値
	std::vector<int> lower; //最小値
	std::vector<int> noise; //ノイズ
	std::vector<Particle> particle_vector; //パーティクルの管理 

public:
	ParticleFilter();
	ParticleFilter(int particle_num, int height_point, int width_point,
		std::vector<int> &upper_point, std::vector<int> &lower_point,
		std::vector<int> &noise_point);
	
	Particle Measure(); //重心の計算
	void Predict(); //予測
	void CalcWeight(cv::Mat &input_image); //重みの計算
	void Resampling(); //リサンプリング
	double Likelifood(int x, int y, cv::Mat &input_image); //尤度計算

	std::vector<Particle> GetPaticleVector(); //粒子を返却する
};
  • パーティクルフィルタのコード内容
Particle.cpp
# include "ParticleFilter.hpp"

//初期化
Particle::Particle()
{
	Particle(0, 0, 0, 0);
}

//初期化
Particle::Particle(int height_point, int width_point, int height_speed_point, int width_speed_point)
{
	height = height_point;
	width = width_point;
	height_speed = height_speed_point;
	width_speed = width_speed_point;
}

//パラメータの表示
void Particle::PrintParameter()
{
	std::cout << "width = " << width <<
		", height = " << height << 
		", v = " << width_speed <<
		", u = " << height_speed << "\n";
}

//パーティクルフィルタの初期化
ParticleFilter::ParticleFilter()
{
	//ランダム(画像サイズに変更するべき?)
	int rand_point = rand() * 100 + 1;
	std::vector<int> upper = { rand_point, rand_point, 10, 10 };
	std::vector<int> lower = { 0, 0, -10, -10 };
	std::vector<int> noise = { 30, 30, 10, 10 };
	ParticleFilter(100, rand_point, rand_point, upper, lower, noise);
}

//パーティクルフィルタの初期化
ParticleFilter::ParticleFilter(int particle_num, int height_point, int width_point,
	std::vector<int> &upper_point, std::vector<int> &lower_point,
	std::vector<int> &noise_point)
{
	num = particle_num;
	height = height_point;
	width = width_point;

	upper = upper_point;
	lower = lower_point;
	noise = noise_point;

	//パーティクルの初期化を行う
	for (int i = 0; i < num; ++i)
	{
		//ランダムで初期化する
		int n[4];
		for (int i = 0; i < 4; ++i)
		{
			int x = (int)(((double)rand() / RAND_MAX)*INT_MAX);
			n[i] = x % (upper[i] - lower[i]) + lower[i];
		}
		Particle particle(n[0], n[1], n[2], n[3]);

		//粒子の数だけ重みを初期化する
		particle_vector.push_back(particle);
		particle_vector[i].weight = 1.0 / num;		
	}

}

//Particleの重心を計算
Particle ParticleFilter::Measure()
{
	Particle p = Particle(0, 0, 0, 0);

	//初期化
	double n[4];
	for (int i = 0; i < 4; ++i)
		n[i] = 0.0;

	for (int i = 0; i < particle_vector.size(); ++i)
	{
		n[0] += particle_vector[i].width * particle_vector[i].weight;
		n[1] += particle_vector[i].height * particle_vector[i].weight;
		n[2] += particle_vector[i].width_speed * particle_vector[i].weight;
		n[3] += particle_vector[i].height_speed * particle_vector[i].weight;
	}
	p.width        = (int)n[0];
	p.height       = (int)n[1];
	p.width_speed  = (int)n[2];
	p.height_speed = (int)n[3];

	return p;
}

//物体の位置を予測する
void ParticleFilter::Predict()
{
	for (int i = 0; i < num; ++i)
	{
		int n[4];
		for (int i = 0; i < 4; ++i)
			n[i] = (int)(((double)rand() / RAND_MAX) * INT_MAX) % (noise[i] * 2) - noise[i];
		
		particle_vector[i].width += particle_vector[i].width_speed + n[0];
		particle_vector[i].height += particle_vector[i].height_speed + n[1];
		particle_vector[i].width_speed += n[2];
		particle_vector[i].height_speed += n[3];

		//細かい条件はこちら
		//update state
		if (particle_vector[i].width < lower[0]) particle_vector[i].width = lower[0];
		if (particle_vector[i].height < lower[1]) particle_vector[i].height = lower[1];
		if (particle_vector[i].width_speed < lower[2]) particle_vector[i].width_speed = lower[2];
		if (particle_vector[i].height_speed < lower[3]) particle_vector[i].height_speed = lower[3];

		if (particle_vector[i].width >= upper[0]) particle_vector[i].width = upper[0];
		if (particle_vector[i].height >= upper[1]) particle_vector[i].height = upper[1];
		if (particle_vector[i].width_speed >= upper[2]) particle_vector[i].width_speed = upper[2];
		if (particle_vector[i].height_speed >= upper[3]) particle_vector[i].height_speed = upper[3];
	}
}

//リサンプリング
void ParticleFilter::Resampling()
{
	// accumulate weight
	std::vector<double> sum_weight(num);
	sum_weight[0] = particle_vector[0].weight;
	for (int i = 1; i < num; ++i)
	{
		sum_weight[i] = sum_weight[i - 1] + particle_vector[i].weight;
	}

	std::vector<Particle> pre_particle(particle_vector);
	for (int i = 0; i < num; ++i)
	{
		double weight_threshold = (double)(rand() % 10000) / 10000.0;
		for (int j = 0; j < num; ++j)
		{
			if (weight_threshold > sum_weight[j])
			{
				continue;
			}
			else
			{
				particle_vector[i] = pre_particle[j];
				particle_vector[i].weight = 0.0;
				break;
			}
		}
	}
}

//重みの計算
void ParticleFilter::CalcWeight(cv::Mat &input_image)
{
	double sum_weight = 0.0;

	for (int i = 0; i < particle_vector.size(); ++i)
	{
		int x = particle_vector[i].width;
		int y = particle_vector[i].height;

		//尤度の計算
		if (x < 0 || x > input_image.size().width || y < 0 || y > input_image.size().height)
			particle_vector[i].weight = 0.001;
		else
			particle_vector[i].weight = Likelifood(x, y, input_image);

		sum_weight += particle_vector[i].weight;
	}

	//正規化
	for (int i = 0; i < particle_vector.size(); ++i)
	{
		particle_vector[i].weight /= sum_weight;
	}
}

//粒子ベクトルの返却
std::vector<Particle> ParticleFilter::GetPaticleVector()
{
	return particle_vector;
}

//尤度の計算
//尤度の計算を変更すると色々と使える
//今回は赤色を追跡する
double ParticleFilter::Likelifood(int x, int y, cv::Mat &input_image)
{
	float b, g, r;
	float dist = 0.0, sigma = 50.0;

	b = input_image.data[y * input_image.step + x * input_image.elemSize() + 0];	//B
	g = input_image.data[y * input_image.step + x * input_image.elemSize() + 1];	//G
	r = input_image.data[y * input_image.step + x * input_image.elemSize() + 2];	//R

	dist = sqrt(b * b + g * g + (255.0 - r) * (255.0 - r));

	return 1.0 / (sqrt(2.0 * CV_PI) * sigma) * expf(-dist * dist / (2.0 * sigma * sigma));
}
  • main関数
main.cpp
# include "ParticleFilter.hpp"

using namespace std;

int main(void){

	cv::VideoCapture video;
	video.open(0);

	if (!video.isOpened()){
		cout << "can't open your video" << endl;
	}

	cv::namedWindow("Camera");

	bool start = false;
	
	ParticleFilter *pf = new ParticleFilter();
	while (1){
		cv::Mat frame;
		video >> frame;

		//終了判定の条件
		if (frame.empty()){
			break;
		}

		if (!start)
		{
			std::vector<int> upper = { frame.size().width, frame.size().height, 10, 10 };
			std::vector<int> lower = { 0, 0, -10, -10 };
			std::vector<int> noise = { 30, 30, 10, 10 };

			pf = new ParticleFilter(300, frame.size().height, frame.size().width, upper, lower, noise);
			start = true;
		}

		pf->Resampling();
		pf->Predict();
		pf->CalcWeight(frame);

		Particle p = pf->Measure();
		p.PrintParameter();

		cv::Point pt = cv::Point(p.width, p.height);

		//全部の点を表示
		std::vector<Particle> particle = pf->GetPaticleVector();
		for (int i = 0; i < particle.size(); ++i)
		{
			cv::Point pp = cv::Point(particle[i].width, particle[i].height);
			cv::circle(frame, pp, 1, cv::Scalar(0, 255, 255), -1);
		}

		//中心を赤色で表示
		cv::circle(frame, pt, 3, cv::Scalar(0, 0, 255), -1);


		cv::imshow("Camera", frame);

		char c = (char)cv::waitKey(1);
		
		if (c == 'q')
			break;
	}

}

結果

  • 黄色が粒子全部で、赤色が重心となります。

  • 結果として、何もなければそのあたりをうろうろしています。
    2018-01-10.png

  • 赤いものを持ってくると粒子が集まってきます。
    2018-01-10 (1).png

まとめ

  • 今回は参考した場所とOpenCVのページでRGB系で尤度計算を行っていましたが、距離計算できる系であれば利用できるので、たとえばHSV系などで行えばより照明環境に強い追跡もできるかと思います。
  • 最後にコードをGitHubにも公開しておきます。

参考:
パーティクルフィルタによる物体追跡

7
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?