我创建了一个类,尝试从任意数量的图像创建一个平均图像(逐个传递)。
此过程将在其自己的线程中运行,而其他线程读入图像,进行处理,并将输出传递给此平均对象。
不幸的是,每个附加图像的平均图像变得更亮,更亮。 我怀疑我的平均功能有错误,但我一直无法找到它。
编辑:我错过了" curImg / curCount"等式的一部分。通过此校正,图像现在变暗。我的平均成绩并不高。
编辑2:我看到我被投了票。我有什么办法可以改善这个问题吗?
class AverageImage {
private Vector<Mat> average = new Vector<>();
private int count = 0;
public void add(Mat img) {
count++;
Vector<Mat> splitImg = new Vector<>();
Mat convertedImg = img.clone();
convertedImg.convertTo(convertedImg, CvType.CV_32FC1);
Core.split(img.clone(), splitImg);
if (average.isEmpty()) {
average = splitImg;
} else {
// prevAverage * (prevCount/curCount) + curImg/curCount
for (int i = 0; i < average.size(); i++) {
Core.multiply(average.get(i), new Scalar((count - 1) / ((double) count)), average.get(i));
Mat temp = new Mat();
Core.divide(count, splitImg.get(i), temp);
Core.add(average.get(i), temp, average.get(i));
}
}
}
public Mat getAverage() {
Mat convertedAverage = new Mat();
Core.merge(average, convertedAverage);
convertedAverage.convertTo(convertedAverage.clone(), CvType.CV_8UC3);
return convertedAverage;
}
}
答案 0 :(得分:2)
次要评论:您的代码中根本没有使用[Firebird]
Description = Firebird ODBC Driver
Driver = /usr/lib/libOdbcFb.so
Threading = 1
FileUsage = 1
CPTimeout =
CPReuse =
。你可以删除它。
您对所谓cumulative mean的确定是正确的。但是,真正搞乱你的部分是convertedImg
声明:
divide
By consulting the OpenCV documentation,当你调用第一个元素是标量的变体时,正在进行的操作是:
Core.divide(count, splitImg.get(i), temp);
dst(I) = saturate(scale / src(I))
用于分成输出。因此,当您实际应该scale
时,您正在做的是count / splitImg.get(i)
。考虑到这一点,splitImg.get(i) / count
不支持拍摄图像并除以系数。但是,解决方法是使用divide
与Core.multiply
的倒数:
count
您需要做的就是将Core.multiply(splitImg.get(i), new Scalar(1.0 / count), temp);
语句更改为上面的语句,它应该可以解决。
Core.divide
为了验证这是正确的,这是我在LaTeX中为此写的数学。给定 // prevAverage * (prevCount/curCount) + curImg/curCount
for (int i = 0; i < average.size(); i++) {
Core.multiply(average.get(i), new Scalar((count - 1) / ((double) count)), average.get(i));
Mat temp = new Mat();
// Core.divide(count, splitImg.get(i), temp);
Core.multiply(splitImg.get(i), new Scalar(1.0 / count), temp);
Core.add(average.get(i), temp, average.get(i));
}
值的信号,我们称之为N
,我们可以用等式的第一行计算均值。 x
表示信号x_i
的i th 值。如果我们在平均值中增加一个附加项,那么第二行及以后就会发生这种情况。如果您计算出数学,我们会验证您的代码中的等式是否正确......但您只需更正x
语句:
第二个等式中最左边的术语是循环中第一行代码中的最正确的术语:
Core.divide
最后,为了计算这个等式的第二项,我们做了:
Core.multiply(average.get(i), new Scalar((count - 1) / ((double) count)), average.get(i));
答案 1 :(得分:1)
对于数值稳定性,最好只存储累积的和图像,并在需要平均值时除以当前的N.
请注意不要溢出。