Python 检测具有模糊边缘和不同背景的卡的边缘
这是我的测试照片 我正在努力寻找卡片的边缘。但是,正如您所看到的,边缘有些模糊 为了找到边缘,我首先增强了图像的对比度,希望模糊边缘不会那么模糊,更容易找到: 然后我用高斯模糊来平滑它(我试着去除高斯模糊,但是边缘检测器在背景+卡片中发现了很多细节) 然后我将canny与“动态阈值”结合使用,得到以下结果: 正如你所看到的,我发现了卡片的任何边缘(除了左边的,因为背景很暗,所以很容易找到)。是否有一种稳健的(我不想“过度拟合”这幅图像)方法来发现直线模糊边缘 我在这里找到了一些建议: ,但没有一个产生令人满意的边缘 完整代码:Python 检测具有模糊边缘和不同背景的卡的边缘,python,opencv,computer-vision,Python,Opencv,Computer Vision,这是我的测试照片 我正在努力寻找卡片的边缘。但是,正如您所看到的,边缘有些模糊 为了找到边缘,我首先增强了图像的对比度,希望模糊边缘不会那么模糊,更容易找到: 然后我用高斯模糊来平滑它(我试着去除高斯模糊,但是边缘检测器在背景+卡片中发现了很多细节) 然后我将canny与“动态阈值”结合使用,得到以下结果: 正如你所看到的,我发现了卡片的任何边缘(除了左边的,因为背景很暗,所以很容易找到)。是否有一种稳健的(我不想“过度拟合”这幅图像)方法来发现直线模糊边缘 我在这里找到了一些建议: ,但没有
def auto_canny(image, sigma=0.5):
v = np.median(image)
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
return cv2.Canny(image, lower, upper)
def add_contrast(img, contrast_level=8):
lab = cv2.cvtColor(img, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab)
clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(contrast_level, contrast_level))
cl = clahe.apply(l)
limg = cv2.merge((cl, a, b))
final = cv2.cvtColor(limg, cv2.COLOR_LAB2BGR)
return final
# ------------------------------------------ #
# FIND EDGES
# ------------------------------------------ #
img = add_contrast(img=img, contrast_level=8)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0)
edges = auto_canny(image=blur_gray)
# Show images for testing
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
您可以通过使用
cv2.floodFill
填充部分背景来改进解决方案
在找到边之前增强对比度是一个不错的主意,但它似乎会创建一些瑕疵,使得查找边更加困难
下面是一个代码示例:
import numpy as np
import cv2
def auto_canny(image, sigma=0.5):
v = np.median(image)
lower = int(max(0, (1.0 - sigma) * v))
upper = int(min(255, (1.0 + sigma) * v))
return cv2.Canny(image, lower, upper)
img = cv2.imread('card.png')
h, w = img.shape[0], img.shape[1]
# Seed points for floodFill (use few points at each corner for improving robustness)
seedPoints = ((5, 5), (w-5, 5), (5, h-5), (w-5, h-5),
(w//2, 5), (w//2, h-5), (5, h//2), (w-5, h//2),
(w//4, 5), (w//4, h-5), (5, h//4), (w-5, h//4),
(w*3//4, 5), (w*3//4, h-5), (5, h*3//4), (w-5, h*3//4))
# Fill parts of the background with black color
for seed in seedPoints:
cv2.floodFill(img, None, seedPoint=seed, newVal=(0, 0, 0), loDiff=(2, 2, 2), upDiff=(2, 2, 2))
# ------------------------------------------ #
# FIND EDGES
# ------------------------------------------ #
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.imshow("gray", gray)
kernel_size = 5
blur_gray = cv2.GaussianBlur(gray, (kernel_size, kernel_size), 0)
# Second, process edge detection use Canny.
edges = auto_canny(image=blur_gray)
# Show images for testing
cv2.imshow('edges', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:我知道这不是一个完整的解决方案,但我希望它能帮助 这也不是一个完整的解决方案,但是如果红色部分有问题,您可以首先使用函数修复这些部分。然后,您可以应用其余的方法来查找卡片边缘
# create an inpainting mask with "red-enough" pixels
mask = cv2.inRange(img_src_rgb, np.array([200,0,0]), np.array([255,50,50]))
# enlarge the mask to cover the borders
kernel = np.ones((3,3),np.uint8)
mask = cv2.dilate(mask,kernel,iterations = 1)
# inpaint the red parts using Navier-Stokes based approach
img_dst = cv2.inpaint(img_src, mask,50,cv2.INPAINT_NS)
cv2.imshow("no_red", img_dst)
生成的图像如下所示
编辑:现在我们知道了您的问题,下面是一个完整的解决方案
修复后,可以应用Hough变换来查找图像中的强直线
gray = cv2.cvtColor(img_dst, cv2.COLOR_RGB2GRAY)
edges = auto_canny(gray) # your auto_canny function, WITHOUT blur
lines = cv2.HoughLines(edges, 1, np.pi/90, 50)
for line in lines:
rho,theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 10000*(-b))
y1 = int(y0 + 10000*(a))
x2 = int(x0 - 10000*(-b))
y2 = int(y0 - 10000*(a))
cv2.line(img_dst,(x1,y1),(x2,y2),(0,255,0),1)
cv2.imwrite('linesDetected.jpg', img_dst)
同样,结果行如下所示
一步很难找到ID的底部。您可以将阈值放宽到canny并对返回的边进行后处理,或者编写自己的边检测方法。在某种程度上,检测上边缘和左边缘应该更容易。你真正需要的是左上角和左下角来查找倾斜和缩放。测试图像是否用红色编辑了信息?或者你是在发布图片之前手动添加的?@eldesgraciado我在发布图片之前手动添加了红色(尽管我在这张图片上运行了算法)。这是个好主意!然而,这不是我的问题。我希望找到一种检测模糊边缘的方法在您的示例中,模糊边缘主要由红色区域边界控制,因此我建议将此解决方案作为预处理步骤。您应该纠正您的问题,指出原始图像中没有红色部分,并根据原始图像生成一个示例输出,以便我们提供帮助。@AlexGoft,请参阅上面的完整答案。谢谢您的回答,并对由此带来的不便表示歉意。你能详细解释一下为什么使用canny而不使用模糊吗?你实际上需要边和角,高斯模糊会使它们平滑,所以你也会丢失卡片的边。如果需要一些边缘感知平滑,可以尝试双边过滤器。此外,增加对比度会引入新的边,这些边对噪波的贡献大于对搜索的边的贡献。在这种情况下,您应该利用数据中的假设:卡片边缘是直线。点只是沿着图像的周长均匀分布(我应该使用循环)。