Python图像处理-如何删除特定轮廓并将值与周围像素混合?
我正在做一个深度图像的项目。但我的深度相机存在噪音和像素读取失败的问题。有些点和轮廓(尤其是边)的值为零。如何忽略此零值并将其与周围的值混合? 我尝试了Python图像处理-如何删除特定轮廓并将值与周围像素混合?,python,opencv,image-processing,computer-vision,Python,Opencv,Image Processing,Computer Vision,我正在做一个深度图像的项目。但我的深度相机存在噪音和像素读取失败的问题。有些点和轮廓(尤其是边)的值为零。如何忽略此零值并将其与周围的值混合? 我尝试了膨胀和侵蚀(变形图像处理),但仍然无法得到正确的组合。它确实消除了一些噪声,但我只需要在所有点上去掉零 图像示例: 零值是最深的蓝色(我使用的是colormap) 为了说明我想做什么,请参考这张拙劣的绘画图: 我想去除黑点(例如,黑点值为0或某个值),并将其与周围环境混合。 是的,我可以使用np.where或类似的函数来定位该点,但我不知道如
膨胀
和侵蚀
(变形图像处理),但仍然无法得到正确的组合。它确实消除了一些噪声,但我只需要在所有点上去掉零
图像示例:
零值是最深的蓝色(我使用的是colormap)
为了说明我想做什么,请参考这张拙劣的绘画图:
我想去除黑点(例如,黑点值为0或某个值),并将其与周围环境混合。
是的,我可以使用np.where
或类似的函数来定位该点,但我不知道如何混合它。也许需要一个过滤器?我需要在一个流中这样做,所以我需要一个相当快的过程,也许10-20 fps就可以了。提前谢谢你
更新:
除了修复,还有别的方法吗?我已经找过各种各样的修补,但我不需要像雕刻那样复杂。我只需要将它与简单的直线、曲线或形状和1D混合。我认为修复是一种过分的做法。此外,我需要它们足够快,可以用于10-20 fps的视频流,甚至更好。两种情况下的图像修复都太慢,这是一个已知的问题。
我不认为不深入研究算法就可以加快速度
如果您真的对“传统”(即没有深入学习)修复算法感兴趣,并准备实施一种修复算法,我强烈建议您看看。该算法在视觉上的表现与双谐波方法相当或优于双谐波方法,并且,一旦正确地转换为代码,即使对于大型图像,也可以非常快地执行
事实上,双谐波修复的实现在性能上远远不是最优的。当前版本非常简单,因为它是以nD输入支持为主要目标编写的
实施的可能改进包括但不限于:
如果您正在寻找一种“足够快和好”的修复方法,请查看GitHub上众多的修复解决方案。也许使用NaN调整高斯滤波器是足够快和好的?当你把零点/黑点看作是NANS时,方法也适用于较大的黑色区域。
#导入模块
将matplotlib.pyplot作为plt导入
将numpy作为np导入
进口撇渣
导入撇渣过滤器
#播种
np.随机种子(42)
#创建虚拟图像
#(光滑,外观更逼真)
尺寸=50
img=np.random.rand(大小,大小)
img=撇除.过滤器.高斯(img,sigma=5)
#创建虚拟缺失点/NaN点
掩码=np.rand.rand(大小,大小)<0.02
img[mask]=np.nan
#定义并应用调整后的高斯滤波器
# (https://stackoverflow.com/a/36307291/5350621)
def(U,sigma=1,truncate=4.0):
V=U.copy()
V[np.isnan(U)]=0
VV=撇除.过滤器.高斯(V,sigma=sigma,truncate=truncate)
W=0*U.复制()+1
W[np.isnan(U)]=0
WW=skimage.filters.gaussian(W,sigma=sigma,truncate=truncate)
返回VV/WW
平滑=高斯(img,sigma=1,截断=4.0)
#不平滑整个图像,但仅复制平滑的点
fill=img.copy()
填充[遮罩]=平滑[遮罩]
#绘图结果
vmin,vmax=np.nanmin(img),np.nanmax(img)
方面='auto'
小地块(121)
plt.title('原始图像(白色=NaN)')
plt.imshow(img,aspect=aspect,vmin=vmin,vmax=vmax)
打印轴(“关闭”)
小地块(122)
打印标题(“填充图像”)
plt.imshow(fill,aspect=aspect,vmin=vmin,vmax=vmax)
打印轴(“关闭”)
在Python/OpenCV中有一种方法可以做到这一点
使用中值滤波填充孔。
- 读取输入
- 变灰
- 制作遮罩的阈值(斑点为黑色)
- 反转遮罩(斑点为白色)
- 从反转遮罩中找到最大的光斑轮廓周长,并使用该值的一半作为中值滤波器大小
- 对图像应用中值滤波
- 将掩码应用于输入
- 将反转遮罩应用于中值滤波图像
- 将两者相加,形成结果
- 保存结果
阈值图像作为遮罩: 反向遮罩: 中值滤波图像: 遮罩图像: 遮罩中值滤波图像: 结果:
看看修复算法。OpenCV实现了一些。在Skimage中也有修复算法。@GeorgeProfenza第一次听到这个术语,我会试试it@fmw42谢谢你,我会把它和opencv修补软件进行比较。谢谢你的推荐,我会试试的!除了修补,还有别的办法吗?我已经找过各种各样的修补,但我不需要像雕刻那样复杂。我只需要将它与简单的直线、曲线或形状和1D混合。我认为修复是一种过分的做法。此外,我需要他们足够快,可以用于视频流10-20 fps,甚至更好。聪明。比修补快得多。
# 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')
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()