cv::EM
알고리즘을 사용하여 이미지 스트림에 대한 가우스 혼합 모델 분류를 수행합니다. 그러나 EM::prediction
방법을 사용하여 픽셀을 다른 모델로 분류하는 동안 너무 느리고 한 개의 600x800 이미지에 약 3 초를 사용합니다. 반면에 OpenCV에서 제공하는 MOG background subtractor
은이 부분을 매우 빠르게 수행하며 약 30ms 만 사용합니다. 그래서 perform 메서드를 사용하여 EM::prediction
부분을 대체하기로 결정했습니다. 그러나, 나는 그것을 어떻게 바꿀 지 모른다.OpenCV : 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;
}
}
}
}
:
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);
}
}
내가 EM prediction
은 "cvbgfg_gaussmix.cpp"에서 발견 된 일부 코드는 다음과 같다 이 부분 코드를 어떻게 내 코드에서 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
과 관련이 있으며 다른 값으로 변경했을 수도 있지만 차이는 없습니다. 그래서 나는 그것이 오류없이 컴파일 되어도 틀린 방식으로 사용했다고 믿습니다.
답변 해 주셔서 대단히 감사합니다. 나는 당신이 말한 것처럼 변형을 사용하여 그것을 한 다음 각 표본 대신 전체 표본을 사용했습니다. 그러나 그 결과는 큰 차이를 만들어 내지 못합니다. –
OpenCV를 최적화하여 컴파일 했습니까? 이제는 모든 것을 다시 쓸 필요없이 할 수있는 가장 좋은 방법은 당신의 제안을 위해 – remi
을 parellelize하는 것입니다. opencv에서 제공 한 배경 빼기가 왜 그렇게 빨리 작동하는지 궁금합니다. 이렇게 빨리 할 수있는 방법이 있어야한다고 생각합니다. 그래서 나는이 질문을했습니다. parellelize를 제외하고 나는이 "process8uC3"함수를 내 자신의 코드로 변경할 수 있다면 달성 할 수 있다고 생각한다. 그렇게 생각하지 않아? –