灵感来源于我之前写的一篇博客:图像处理:基于cv2.inpaint()图像修补。
这种方式可以有效的去除白色的噪点,这里我们需要一张噪点的图像,你可以用下面的代码随机生成一张噪点图片:
import cv2
import numpy as np
# import pyzjr
def addnoisy(image, n=2000):
"""
:param image: 原始图像
:param n: 添加椒盐的次数,默认为10000
:return: 返回被椒盐处理后的图像
"""
result = image.copy()
w, h = image.shape[:2]
for i in range(n):
x = np.random.randint(0, w)
y = np.random.randint(0, h)
if np.random.randint(0, 1) == 0:
result[x, y] = 255
return result
img = cv2.imread("crack.jpg")
result = addnoisy(img)
cv2.imwrite("crack.png",result)
原图crack.jpg:
噪点图crack.png:
然后我们就可以用下面的代码进行处理了。
import cv2
import numpy as np
from skimage.feature import blob_log
import matplotlib.pyplot as plt
image = cv2.imread(r"D:\PythonProject\net\High_tower\crack.png")
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
min_sigma = 1 # 斑点最小尺寸
max_sigma = 50 # 斑点最大尺寸
threshold = 0.1 # 斑点阈值,用于控制检测的灵敏度
blobs = blob_log(gray_image, min_sigma=min_sigma, max_sigma=max_sigma, threshold=threshold)
height, width = image.shape[:2]
black_image = np.zeros((height, width), dtype=np.uint8)
for blob in blobs:
y, x, sigma = blob
radius = int(sigma * np.sqrt(2)) # 半径是标准差乘以sqrt(2)
cv2.circle(black_image, (int(x), int(y)), radius, (255,255,255), -1)
dst = cv2.inpaint(image, black_image, 10, cv2.INPAINT_TELEA)
cv2.imwrite("filled_blobs.png", black_image)
cv2.imwrite("dst.png", dst)
这里先是使用blob_log函数从灰度图像中检测斑点,并将检测到的斑点存储在blobs中。根据图像的高度和宽度,创建一个与输入图像相同尺寸的全黑图像,用于标记检测到的斑点。
使用for循环遍历检测到的每个斑点,然后在全黑图像上绘制一个白色的圆圈来标记斑点的位置和大小。
使用图像修复技术,将标记了斑点的全黑图像balck_image与原始图像image相结合,生成修复后的图像dst。
这里保存了两张图,一张是mask,一张是处理后的图片。
检测到的mask:
处理后的图片:
原先的图片受到了噪点的污染,在处理后的效果很不错了,这里你可以选择调参优化,或者再加一个参数小的滤波处理。
这种方法的原理是检测白色噪点位置,生成对应的掩模图,然后使用修补函数,用附近的像素点替代掉噪点,比起滤波处理会让图像变得模糊,使用这种方式让图像更加的平滑。
如果是其他颜色的污染,你可以参照本文开头给的那篇博客,里面有详细的介绍。
当然,这种方法有些缺陷,它在某些特定的场景下,表现效果很好。