使用 numpy 和/或 cv2 在深度图中找到最暗的区域 cv2 模板匹配np.argminnp.argwhere

问题描述

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

生成

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

然后将深度预测归一化如下以制作 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)

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

enter image description here

  • 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),(int(917*max_val),int(917*max_val),int(917*max_val)),2)

np.argmin with a hack

这不那么不一致,但仍然缺乏

  • np.argwhere

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

enter image description here

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

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

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

解决方法

最小值不是一个点,而是一个更大的区域。 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 显示为增强伽玛: enter image description here

frame25 具有非常小的最小区域(红色箭头),我们取第五大最小区域(白色圆圈): enter image description here

结果(对于 min_area=500)在某些地方仍然有点不稳定,但是如果进一步增加 min_area,对于下降非常陡峭(因此每个值)暗区。也许你可以用时间轴(帧数)来过滤掉最暗区域位置在3帧内来回跳跃的帧。

output for min_area=500