使用OpenCV从图像序列中获取中间图像

时间:2015-05-03 14:07:22

标签: java android opencv image-processing matrix

我有一系列图像,我想要计算中间图像(以移除移动元素)。直观地,对循环进行硬编码以遍历所有像素将具有总运行时间以及相当大的存储器使用。有没有办法在OpenCV中轻松完成此操作? (我对平均不感兴趣,我需要做一个中位数)。我正在为Android编写此文件(使用OpenCV4Android),因此显然计算能力有限。

2 个答案:

答案 0 :(得分:3)

据我所知,没有OpenCV函数可以从图像序列中创建中值图像。几年前我需要相同的功能,我必须自己实现。它相对较慢,因为对于每个像素,您需要从多个图像中提取相关像素(低效的内存访问)并计算中值(也是一个耗时的过程)。

提高效率的可能方法是:

  • 无需计算所有图像的中位数。小部分图像就足够了。
  • 您可以找到更有效的算法来查找某些小组的中位数。例如,我使用的算法可以有效地找到九个值组的中位数。

答案 1 :(得分:0)

如果平均值没问题:

Mat result(CV_64FC3, listImages[0].size());
for(int i = 0; i < listImages.size(); i++) {
    result += listImages[i];
}
result /= listImages.size();
result.convertTo(result, CV_8UC3);

修改

这个快速伪中位数应该成为诀窍:

// Following algorithm will retain the pixel which is the closest to the mean
// Computing Mean
Mat tmpResult = Mat.zeros(listImages[0].size(), CV_64FC3);
for(int i = 0; i < listImages.size(); i++) {
    tmpResult += listImages[i];
}
tmpResult /= listImages.size();
tmpResult.convertTo(tmpResult, CV_8UC3);
// We will now, for each pixel retain the closest to the mean
// Initializing result with the first image
Mat result(listImages[0].clone());
Mat diff1, diff2, minDiff;
for(int i = 1; i < listImages.size(); i++) {
    // Computing diff between mean/newImage and mean/lastResult
    absdiff(tmpResult, listImages[i], diff1);
    absdiff(tmpResult, result, diff2);
    // If a pixel of the new image is closer to the mean, it replaces the old one
    min(diff1, diff2, minDiff);
    // Get the old pixels that are still ok
    result = result & ~(minDiff - diff2);
    // Get the new pixels
    result += listImages[i] & (minDiff - diff2);
}

然而,经典的应该也很快。它是O(nb ^ 2 * w * h),其中nb是图像的数量,w,h是它们的宽度,高度。以上是O(nb * w * h),对Mats有更多操作。

经典代码(几乎所有计算都将以原生方式进行):

Mat tmp;
// We will sorting pixels where the first mat will get the lowest pixels and the last one, the highest
for(int i = 0; i < listImages.size(); i++) {
    for(int j = i + 1; j < listImages.size(); j++) {
        listImages[i].copyTo(tmp);
        min(listImages[i], listImages[j], listImages[i]);
        max(listImages[j], tmp, listImages[j]);
    }
}
// We get the median
Mat result = listImages[listImages.size() / 2];