アルゴリズムを使用cv::EM
して、画像ストリームのガウス混合モデル分類を行っています。ただし、方法を使用してピクセルをさまざまなモデルに分類している間EM::prediction
、遅すぎることがわかりました。一方、MOG background subtractor
OpenCV が提供する は、この部分を非常に高速に実行し、約 30 ミリ秒しか使用しません。そのため、その perform メソッドを使用してEM::prediction
パーツを交換することにしました。ただし、変更方法がわかりません。
その部分まで使用しているコードprediction
は次のとおりです。
cv::Mat floatSource;
source.convertTo ( floatSource, CV_32F );
cv::Mat samples ( source.rows * source.cols, 3, CV_32FC1 );
int idx = 0;
for ( int y = 0; y < source.rows; y ++ )
{
cv::Vec3f* row = floatSource.ptr <cv::Vec3f> (y);
for ( int x = 0; x < source.cols; x ++ )
{
samples.at<cv::Vec3f> ( idx++, 0 ) = row[x];
}
}
cv::EMParams params(2); // num of mixture we use is 2 here
cv::ExpectationMaximization em ( samples, cv::Mat(), params );
cv::Mat means = em.getMeans();
cv::Mat weight = em.getWeights();
const int fgId = weights.at<float>(0) > weights.at<flaot>(1) ? 0:1;
idx = 0;
for ( int y = 0; y < source.rows; y ++ )
{
for ( int x = 0; x < source.cols; x ++ )
{
const int result = cvRound ( em.predict ( samples.row ( idx++ ), NULL );
}
}
「cvbgfg_gaussmix.cpp」から見つけた部分コードEM prediction
は次のようなものです。
static void process8uC3 ( BackgroundSubtractorMOG& obj, const Mat& image, Mat& fgmask, double learningRate )
{
int x, y, k, k1, rows = image.rows, cols = image.cols;
float alpha = (float)learningRate, T = (float)obj.backgroundRatio, vT = (float)obj.varThreshold;
int K = obj.nmixtures;
const float w0 = (float)CV_BGFG_MOG_WEIGHT_INIT;
const float sk0 = (float)(CV_BGFG_MOG_WEIGHT_INIT/CV_BGFG_MOG_SIGMA_INIT);
const float var0 = (float) (CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT);
for ( y = 0; y < rows; y ++ )
{
const uchar* src = image.ptr<uchar>(y);
uchar* dst = fgmask.ptr<uchar>(y);
MixData<Vec3f>* mptr = (MixData<Vec3f>*)obj.bgmodel.ptr(y);
for ( x = 0; x < cols; x++, mptr += K )
{
float wsum = 0, dw = 0;
Vec3f pix ( src [x*3], src[x*3+1], src[x*3+2]);
for ( k = 0; k < K; k ++ )
{
float w = mptr[k].weight;
Vec3f mu = mptr[k].mean[0];
Vec3f var = mptr[k].var[0];
Vec3f diff = pix - mu;
float d2 = diff.dot(diff);
if ( d2 < vT * (var[0] +var[1] + var[2] )
{
dw = alpha * ( 1.f - w );
mptr[k].weight = w + dw;
mptr[k].mean = mu + alpha * diff;
var = Vec3f ( max ( var[0] + alpha * ( diff[0] * diff[1] - var[0] ), FLT_EPSILON),
max ( var[1] + alpha * ( diff[1]*diff[1] - var[1] ), FLT_EPSILON,
max ( var[2] + alpha * ( diff[2]*diff[2] - var[2] ), FLT_EPSILON ));
mptr[k].var = var;
mptr[k].sortKey = w/sqrt ( var[0] + var[1] + var[2] );
for ( k1 = k-1; k1 >= 0; k1-- )
{
if ( mptr[k1].sortKey > mptr[k1+1].sortKey)
break;
std::swap ( mptr[k1],mptr[k1+1]);
}
break;
}
wsum += w;
}
dst[x] = (uchar) (-(wsum >= T ));
wsum += dw;
if ( k == K )
{
wsum += w0 - mptr[K-1].weight;
mptr[k-1].weight = w0;
mptr[K-1].mean = pix;
mptr[K-1].var = Vec3f ( var0, var0, var0 );
mptr[K-1].sortKey = sk0;
}
else
for ( ; k < K; k ++ )
wsum += mptr[k].weight;
dw = 1.f/wsum;
for ( k = 0; k < K; k ++ )
{
mptr[k].weight *= dw;
mptr[k].sortKey *= dw;
}
}
}
}
この部分的なコードを変更して、最初のコードで使用できるようにするにはどうすればよいem.predict
ですか? 前もって感謝します。
アップデート
process8uC3
コードで関数を使用するために、次のように自分で行いました。
cv::Mat fgImg ( 600, 800, CV_8UC3 );
cv::Mat bgImg ( 600, 800, CV_8UC3 );
double learningRate = 0.001;
int x, y, k, k1;
int rows = sourceMat.rows; //source opencv matrix
int cols = sourceMat.cols; //source opencv matrix
float alpha = (float) learningRate;
float T = 2.0;
float vT = 0.30;
int K = 3;
const float w0 = (float) CV_BGFG_MOG_WEIGTH_INIT;
const float sk0 = (float) (CV_BGFG_MOG_WEIGHT_INIT/CV_BGFG_MOG_SIGMA_INIT);
const float var0 = (float) (CV_BGFG_MOG_SIGMA_INIT*CV_BGFG_MOG_SIGMA_INIT);
const float minVar = FLT_EPSILON;
for ( y = 0; y < rows; y ++ )
{
const char* src = source.ptr < uchar > ( y );
uchar* dst = fgImg.ptr < uchar > ( y );
uchar* tmp = bgImg.ptr ( y );
MixData<cv::Vec3f>* mptr = (MixData<cv::Vec3f>*)tmp;
for ( x = 0; x < cols; x ++, mptr += K )
{
float w = mptr[k].weight;
cv::Vec3f mu = mpptr[k].mean[0];
cv::Vec3f var = mptr[k].var[0];
cv::Vec3f diff = pix - mu;
float d2 = diff.dot ( diff );
if ( d2 < vT * ( var[0] + var[1] + var[2] ) )
{
dw = alpha * ( 1.f - w );
mptr[k].weight = w + dw;
mptr[k].mean = mu + alpha * diff;
var = cv::Vec3f ( max ( var[0] + alpha*(diff[0]*diff[0]-var[0]),minVar),
max ( var[1]+ alpha*(diff[1]*diff[1]-var[1]),minVar),
max ( var[2] + alpha*(diff[2]*diff[2]-var[2]),minVar) );
mptr[k].var = var;
mptr[k].sortKey = w/sqrt ( var[0] + var[1] + var[2] );
for ( k1 = k-1; k1 >= 0; k1 -- )
{
if ( mptr[k1].sortKey > mptr[k1+1].sortKey )
break;
std::swap ( mptr[k1], mptr[k1+1] );
}
break;
}
wsum += w;
}
dst[x] = (uchar) (-(wsum >= T ));
wsum += dw;
if ( k == K )
{
wsum += w0 - mptr[k-1].weight;
mptr[k-1].weight = w0;
mptr[k-1].mean = pix;
mptr[k-1].var = cv::Vec3f ( var0, var0, var0 );
mptr[k-1].sortKey = sk0;
}
else
for ( ; k < K; k ++ )
{
mptr[k].weight *= dw;
mptr[k].sortKey *= dw;
}
}
}
}
エラーなくコンパイルされましたが、結果は完全に固まりました。T
値とに関連するものではないかと思いvT
ますが、他のいくつかの値でそれらを変更しましたが、違いはありませんでした。だから私はそれがエラーなしでコンパイルされたとしても、私はそれを間違った方法で使用したと信じています。