【问题标题】:Python Image Processing - How to remove certain contour and blend the value with surrounding pixels?Python图像处理 - 如何删除某些轮廓并将值与周围像素混合?
【发布时间】:2020-05-02 19:40:41
【问题描述】:

我正在做一个带有深度图像的项目。但是我的深度相机存在噪音和像素读取失败的问题。有一些点和轮廓(尤其是边缘)的值为零。如何忽略这个零值并将其与周围的值混合? 我已经尝试过dilation 和erosion(变形图像处理),但我仍然无法获得正确的组合。它确实消除了一些噪音,但我只需要在所有点上去掉零

图片示例:

零值是最深的蓝色(我正在使用颜色图)

为了说明我想要做什么,请参考这张糟糕的油漆图:

我想去除黑点(例如黑色值是 0 或某个值),并将其与周围混合。 是的,我可以使用np.where 或类似功能来定位该地点,但我不知道如何混合它。也许要应用过滤器?我需要在流中执行此操作,因此我需要一个相当快的过程,也许 10-20 fps 就可以了。提前谢谢!

更新:

除了inpaint之外还有其他方法吗?我已经寻找了各种修复,但我不需要像修复那样复杂。我只需要将它与简单的线条、曲线或形状和一维混合。我认为inpaint是一种矫枉过正。此外,我需要它们足够快以用于 10-20 fps 甚至更好的视频流。

【问题讨论】:

  • 看看修复算法。 OpenCV 实现了一些。
  • Skimage中也有修复算法。
  • @GeorgeProfenza 第一次听到这个词,我会试试的
  • @fmw42 谢谢,我会和opencv修复比较一下

标签: python opencv image-processing computer-vision


【解决方案1】:

这是在 Python/OpenCV 中执行此操作的一种方法。

使用中值过滤来填补空洞。

  • 读取输入
  • 转换为灰色
  • 制作蒙版的阈值(斑点为黑色)
  • 反转蒙版(斑点为白色)
  • 从倒置蒙版中找到最大的点轮廓周长,并将该值的一半用作中值过滤器大小
  • 对图像应用中值滤波
  • 将掩码应用于输入
  • 对中值滤波图像应用反向掩码
  • 将两者相加形成结果
  • 保存结果

输入:

import cv2
import numpy as np
import math

# read image
img = cv2.imread('spots.png')

# convert to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# threshold 
mask = cv2.threshold(gray,0,255,cv2.THRESH_BINARY)[1]

# erode mask to make black regions slightly larger
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
mask = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel)


# make mask 3 channel
mask = cv2.merge([mask,mask,mask])

# invert mask
mask_inv = 255 - mask

# get area of largest contour
contours = cv2.findContours(mask_inv[:,:,0], cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours = contours[0] if len(contours) == 2 else contours[1]
perimeter_max = 0
for c in contours:
    perimeter = cv2.arcLength(c, True)
    if perimeter > perimeter_max:
        perimeter_max = perimeter

# approx radius from largest area
radius = int(perimeter_max/2) + 1
if radius % 2 == 0:
    radius = radius + 1
print(radius)

# median filter input image
median = cv2.medianBlur(img, radius)

# apply mask to image
img_masked = cv2.bitwise_and(img, mask)

# apply inverse mask to median
median_masked = cv2.bitwise_and(median, mask_inv)

# add together
result = cv2.add(img_masked,median_masked)

# save results
cv2.imwrite('spots_mask.png', mask)
cv2.imwrite('spots_mask_inv.png', mask_inv)
cv2.imwrite('spots_median.png', median)
cv2.imwrite('spots_masked.png', img_masked)
cv2.imwrite('spots_median_masked.png', median_masked)
cv2.imwrite('spots_removed.png', result)

cv2.imshow('mask', mask)
cv2.imshow('mask_inv', mask_inv )
cv2.imshow('median', median)
cv2.imshow('img_masked', img_masked)
cv2.imshow('median_masked', median_masked)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()


阈值图像作为掩码:

反转掩码:

中值过滤图像:

蒙面图片:

蒙面中值滤波图像:

结果:

【讨论】:

  • 聪明。比修复快得多。
【解决方案2】:

也许使用 NaN 调整的高斯滤波器足够好且足够快?当您将零点/黑点视为 NaN 时,this 方法也适用于较大的黑色区域。

# import modules
import matplotlib.pyplot as plt
import numpy as np
import skimage
import skimage.filters

# set seed
np.random.seed(42)

# create dummy image
# (smooth for more realisitc appearance)
size = 50
img = np.random.rand(size, size)
img = skimage.filters.gaussian(img, sigma=5)

# create dummy missing/NaN spots
mask = np.random.rand(size, size) < 0.02
img[mask] = np.nan

# define and apply NaN-adjusted Gaussian filter
# (https://stackoverflow.com/a/36307291/5350621)
def nangaussian(U, sigma=1, truncate=4.0):
    V = U.copy()
    V[np.isnan(U)] = 0
    VV = skimage.filters.gaussian(V, sigma=sigma, truncate=truncate)
    W = 0*U.copy()+1
    W[np.isnan(U)] = 0
    WW = skimage.filters.gaussian(W, sigma=sigma, truncate=truncate)
    return VV/WW
smooth = nangaussian(img, sigma=1, truncate=4.0)

# do not smooth full image but only copy smoothed NaN spots
fill = img.copy()
fill[mask] = smooth[mask]

# plot results
vmin, vmax = np.nanmin(img), np.nanmax(img)
aspect = 'auto'
plt.subplot(121)
plt.title('original image (white = NaN)')
plt.imshow(img, aspect=aspect, vmin=vmin, vmax=vmax)
plt.axis('off')
plt.subplot(122)
plt.title('filled image')
plt.imshow(fill, aspect=aspect, vmin=vmin, vmax=vmax)
plt.axis('off')

【讨论】:

    猜你喜欢
    • 2010-10-23
    • 1970-01-01
    • 2011-12-30
    • 2021-09-08
    • 1970-01-01
    • 2016-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多