使用 OpenCV 减去置换掩码

Posted

技术标签:

【中文标题】使用 OpenCV 减去置换掩码【英文标题】:Subtract displaced mask using OpenCV 【发布时间】:2012-03-20 17:26:21 【问题描述】:

我想做:

masked = image - mask

但我想“取代”mask。即垂直和水平移动它(只要它与image的交集不为空,这将是有效的)。

我有一些手工编码的程序集(它使用 MMX 指令),它嵌入在 C++ 程序中,但是在进行垂直位移时它不稳定,所以我想改用 OpenCV。是否可以仅调用一个 OpenCV 函数来执行此操作?

性能至关重要;使用 OpenCV,时间至少应该和汇编代码在一个数量级。

编辑:这是一个例子

image(中框,看那家伙头骨的对比):

mask(第一帧,无对比):

image - mask,没有位移。请注意对比路径是如何增强的,但由于患者移动了一点,我们可以看到一些颅骨轮廓,这些轮廓是用于诊断目的的视觉噪声。

image - mask蒙版向下移动了大约 5 个像素。为了尝试补偿患者运动引入的噪音,我们稍微“移位”了遮罩,以便去除轮廓并更好地查看对比度路径(亮度和对比度进行了调整,这就是它看起来有点暗的原因)。

编辑 2:关于算法,我设法解决了它的问题。它不再崩溃,但缺点是它现在处理所有图像像素(它应该只处理那些需要减去的像素)。无论如何,如何修复旧代码不是我的问题;我的问题是,如何使用 OpenCV 进行此处理?稍后我会发布一些分析结果。

【问题讨论】:

您能否用更多项目更新您的答案: 1. 带有“移位”几个掩码的示例输入图像(即,给定输入的预期输出)。 2. 可能是您正在做的示例代码或伪代码。 3. 你的置换算法目前在给定的图像尺寸和硬件上运行的速度有多快。 这不是related to this thread,是吗? @karlphillip:不,那个线程正在谈论不同的效果,这似乎比我的更复杂,顺便说一句。看我的例子。 @mevatron:完成。稍后我会发布一些分析结果。 +1 有趣的图片。 【参考方案1】:

我知道这是在 Python 中,所以不是你想要的,但是将它翻译成 C++ 应该非常简单。它将两个图像裁剪为匹配的大小(几乎所有操作都需要),由图像之间的位移及其相对大小决定。这个方法应该很快,因为cv.GetSubRect 不会复制任何东西,所以它只需要cv.AbsDiff 函数(如果你有一个实际的差异掩码,你可以使用cv.Sub,它应该会更快)。此代码还将处理任何方向的位移,并且蒙版和图像可以是任何大小(蒙版可以大于图像)。指定位移必须有重叠。可以单独查看图像之间的差异,也可以“就地”查看差异。

一个很好的图表来说明发生了什么。前两个方块是示例imagemask。接下来的三个方块显示“掩码”的水平位移为 -30、0 和 30 像素,最后一个方块的位移为 20、20。

import cv

image = cv.LoadImageM("image.png")
mask = cv.LoadImageM("mask.png")

image = cv.LoadImageM("image2.png")
mask = cv.LoadImageM("small_mask.png")

image_width, image_height = cv.GetSize(image)
mask_width, mask_height = cv.GetSize(mask)
#displacements here:
horiz_disp = 20
vert_disp = 20

image_horiz = mask_horiz = image_vert = mask_vert = 0

if vert_disp < 0:
    mask_vert = abs(vert_disp)
    sub_height = min(mask_height + vert_disp, image_height)
else:
    sub_height = min(mask_height, image_height - vert_disp)
    image_vert = vert_disp

if horiz_disp < 0:
    mask_horiz = abs(horiz_disp)
    sub_width = min(mask_width + horiz_disp, image_width)
else:
    sub_width = min(mask_width, image_width - horiz_disp)
    image_horiz = horiz_disp

#cv.GetSubRect returns a rectangular part of an image, without copying any data. - fast.
mask_sub = cv.GetSubRect(mask, (mask_horiz, mask_vert, sub_width, sub_height))
image_sub = cv.GetSubRect(image, (image_horiz, image_vert, sub_width, sub_height))

#Subtracts the mask overlap region from the image overlap region, puts it in image_sub
cv.AbsDiff(image_sub, mask_sub, image_sub)

# Shows diff only:
cv.ShowImage('image_sub', image_sub)
# Shows image with diff section
cv.ShowImage('image', image)

cv.WaitKey(0)

【讨论】:

看起来不错。当我有空闲时间时,我会根据我的传统手工算法对此进行分析并发布结果。 @dario_ramos - 刚刚更新以允许在任何方向上位移(+漂亮的图片)。而且..cool,期待听到关于分析的消息:)

以上是关于使用 OpenCV 减去置换掩码的主要内容,如果未能解决你的问题,请参考以下文章

Opencv检测边界和ROI掩码

opencv如何制作圆形的掩码

使用 OpenCV 从轮廓中获取掩码

在 Python 中使用 Opencv 从图像中减去背景

opencv(emgu)中的模板匹配usink掩码

在 OpenCV、Java 中从 Mat 中减去 double