使用 numpy 和/或 cv2 在深度图中查找最暗区域

Posted

技术标签:

【中文标题】使用 numpy 和/或 cv2 在深度图中查找最暗区域【英文标题】:Finding the darkest region in a depth map using numpy and/or cv2 【发布时间】:2021-05-02 00:25:19 【问题描述】:

我试图在从视频生成的一系列深度图图像中始终如一地找到最暗的区域。深度图是使用 PyTorch 实现生成的 here

他们的示例运行脚本会生成与输入相同大小的预测,其中每个像素都是一个浮点值,最高/最亮的值是最接近的。使用 ConvNets 进行标准深度估计。

然后将深度预测归一化如下,以制作 png 以供查看

bits = 2
depth_min = prediction.min() 
depth_max = prediction.max()

max_val = (2**(8*bits))-1

out = max_val * (prediction - depth_min) / (depth_max - depth_min)

我正在尝试识别视频中每张图像中最暗的区域,并假设该区域具有最大的“开放空间”。

我尝试了几种方法:

cv2模板匹配

使用cv2模板匹配和minMaxLoc我创建了一个np.zeros(100,100)的模板,然后应用类似于docs的模板

img2 = out.copy().astype("uint8")
template = np.zeros((100, 100)).astype("uint8")
w, h = template.shape[::-1]

res = cv2.matchTemplate(img2,template,cv2.TM_SQDIFF)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = min_loc
bottom_right = (top_left[0] + w, top_left[1] + h)

val = out.max()
cv2.rectangle(out,top_left, bottom_right, int(val) , 2)

如您所见,这种实现与许多误报非常不一致

np.argmin

使用np.argmin(out, axis=1) 生成许多索引。我取前两个,在那些坐标处写上MIN这个词

text = "MIN"
textsize = cv2.getTextSize(text, font, 1, 2)[0] 
textX, textY = np.argmin(prediction, axis=1)[:2]
cv2.putText(out, text, (textX, textY), font, 1, (int(917*max_val), int(917*max_val), int(917*max_val)), 2)

这不太不一致,但仍然缺乏

np.argwhere

使用np.argwhere(prediction == np.min(preditcion),然后在坐标上写下MIN这个词。我以为这会给我图像上最暗的像素,但事实并非如此

我也想过用 50x50 的核进行卷积运算,然后取最小值的区域作为最暗区域

我的问题是为什么会有不一致和误报。我该如何解决?直觉上,这似乎是一件非常简单的事情。

更新 感谢汉斯的想法。请关注this link下载png格式的输出深度。

【问题讨论】:

不可思议的视频,预计会有一些跳跃恐慌。 ;-) 你有没有调试过一些你得到不一致结果的帧?另外,您能否提供一些框架或视频,以便人们可以玩耍?照原样,我认为回答您的问题将是猜测。 @HansHirse谢谢你的想法!我用指向谷歌驱动器文件夹的链接更新了问题。 【参考方案1】:

最小值不是一个点,而是一个更大的区域。 argmin 找到该区域的第一个 x 和 y(左上角):

如果最小值多次出现,则索引 对应于第一次出现的被返回。

你需要的是这个最小区域的中心。您可以使用moments 找到它。有时您有多个最小区域,例如frame107.png。在这种情况下,我们通过找到面积最大的轮廓来取最大的轮廓。

我们仍然有一些跳跃标记,因为有时你有一个最小的区域,例如在frame25.png。因此我们使用最小面积阈值min_area,即我们不使用绝对最小区域,而是使用所有区域中大于或等于该阈值的最小值的区域。

import numpy as np
import cv2
import glob

min_area = 500

for file in glob.glob("*.png"):
    img = cv2.imread(file, cv2.IMREAD_GRAYSCALE)
    for i in range(img.min(), 255):
        if np.count_nonzero(img==i) >= min_area:
            b = np.where(img==i, 1, 0).astype(np.uint8)
            break
    contours,_ = cv2.findContours(b, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    max_contour = max(contours, key=cv2.contourArea)
    m = cv2.moments(max_contour)
    x = int(m["m10"] / m["m00"])
    y = int(m["m01"] / m["m00"])
    out = cv2.circle(img, (x,y), 10, 255, 2 )
    cv2.imwrite(file,out)

frame107 具有图像为0 的五个区域,以增强的伽马显示:

frame25 具有非常小的最小区域(红色箭头),我们采用第五大最小区域(白色圆圈):

结果(对于min_area=500)在某些地方仍然有点跳动,但是如果您进一步增加min_area,对于具有非常急剧下降(因此每个值很小)暗区的帧,您将得到错误的结果.或许可以用时间轴(帧数)过滤掉最暗区域的位置在3帧内来回跳动的帧。

【讨论】:

非常感谢!很好的答案,我能够遵循它并让它工作。非常感谢您解释详细信息

以上是关于使用 numpy 和/或 cv2 在深度图中查找最暗区域的主要内容,如果未能解决你的问题,请参考以下文章

在图中查找所有可能的路径

将CV2 numpy数组转换为QImage时如何配置颜色?

使用 cv2 VideoWriter 编写 numpy 数组

算法之深度和广度优先搜索算法

python 安装 cv2 和 numpy

常见搜索算法:深度优先和广度优先搜索