使用opencv进行图像减法

4
我想要对两张图片进行减法运算,但问题在于cvSub()函数会饱和。我的目标是:
1)将原始图片转换为灰度图像。
2)使用灰度图像(值从0到255)。
3)相减得到图像(值从-255到255)-> 由于使用cvSub()会出现重新缩放的问题。
4)通过乘以0.5并加上128来重新缩放。
我考虑将8位灰度图像转换为16位,但结果变得更糟糕了,代码变得很长,最终也没有成功。

丑陋的解决方案就是循环遍历图像,并逐个像素地自己完成。这基本上只是用C++将您的问题翻译一下(甚至可能更短)。 - mb14
2个回答

5
使用openCV,您可以执行以下操作:
  • 按0.5倍因子缩放源图像(1和2)。两个图像现在都在范围[0..127]内
  • 将图像1移位128。它现在在范围[128..255]内
  • 从图像1中减去图像2
这样,不需要进行范围转换,结果完全缩放为8位。对于前两个操作,请使用cvConvertScale。类似于以下代码:
//...
cvConvertScale(src1, tmp1, 0.5, 128);
cvConvertScale(src2, tmp2, 0.5, 0);
cvSub(tmp1, tmp2, dst);

编辑:

针对您关于信息(精度)丢失的评论,您是正确的,但在使用整数运算进行除法时总会出现这种情况。而在您的情况下,缩放只是这样做的。简单地将所有位向右移动一位即可。因此,最后一位信息将被丢失。

另一方面,应用操作的顺序也很重要。通过除以2,每个像素都会引入一个舍入(或截断)误差为0.5。如果在减去它们之前同时缩放输入图像,则舍入误差会累加到1.0。这在结果图像中表现为一些像素与您使用初始和亚历山大方法得到的结果相比偏差了1个单位。但这是不扩展图像到16位或浮点数的更简单解决方案的权衡。

请看以下示例:

实数:
(200 - 101) / 2 = 99 / 2 = 49.5

亚历山大的解决方案(整数运算):
(200 - 101) / 2 = 99 /2 = 49

我的解决方案(整数运算):
(200 / 2) - (101 / 2) = 100 - 50 = 50


1
感谢这个简单的解决方案!!! 它起作用了!先进行缩放再减去图片是很好的想法。 - supergranu
唯一的问题是会丢失信息。在这种情况下最好选择 Alexander Rafferty 的版本。 - supergranu
你能告诉我你认为你失去了哪些信息吗?你是指精度吗? - Frank Bollack
1
我认为这是一张8位图像。如果我乘以0.5,我只能使用128个值来存储图像的信息。256个值被减少到了128个。我将失去原始图像的分辨率。- 如果我的想法有误,请告诉我。 - supergranu

1

你需要将8位转换为16位。 然后对第一张图像加上255,再从中减去第二张图像。 然后除以2并转换回8位。

告诉我这个怎么样,应该可以工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接