【问题标题】:How do I remove background from an image like this?如何从这样的图像中删除背景?
【发布时间】:2022-01-02 12:49:51
【问题描述】:

我想去除背景,并绘制图像中显示的框的轮廓(有multiple such images具有相似的背景)。我在 OpenCV 中尝试了多种方法,但是我无法确定可以帮助删除此图像背景的功能组合。尝试过的一些方法是:

  • 边缘检测 - 由于背景本身有自己的边缘,因此单独使用边缘检测(例如 Canny 和 Sobel)似乎没有给出好的结果。
  • 通道过滤/阈值 - 背景和前景都具有相似的白色,因此我无法找到正确的阈值来过滤前景。
  • 轮廓检测 - 由于背景本身有很多轮廓,只使用最大的轮廓区域,通常用于背景去除,也不起作用。

我愿意接受计算机视觉或深度学习(Python)中的工具来解决这个特定问题。

【问题讨论】:

  • 深度学习。没有什么可以做的。 -- 我假设盒子下面的东西是传送带并且它会移动。不要在你的描述中含糊其辞。 你应该说我刚才说的话,没有提示。 -- 显示多个示例或视频以获得更好的建议
  • 降低相机怎么样?
  • @ChristophRackwitz 添加了另一个示例。这是公共数据集的一部分 - 我无权访问相机或传送带设置。您能否介绍一下可以使用哪些特定的深度学习工具/框架?
  • 如果它是公共数据集的一部分,请提供指向它的链接。如果您希望人们为您提供帮助,那么让他们轻松一点通常是个好主意。谢谢。
  • 好吧 Ann Zen 的回答是一个非常好的解决方案,我只想提一下......外面还有一种特殊的算法类可以解决你的问题:背景减法方法(opencv 包括一些基本的算法)我用 quit awesome 库取得了最好的结果:github.com/andrewssobral/bgslibrary

标签: python opencv computer-vision


【解决方案1】:

概念

在这种情况下,微调您用来扩张和侵蚀从图像中检测到的精巧边缘的内核非常有用。下面是一个例子,膨胀核是np.ones((4, 2)),腐蚀核是np.ones((13, 7))

代码

import cv2
import numpy as np

def process(img):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    img_blur = cv2.GaussianBlur(img_gray, (3, 3), 2)
    img_canny = cv2.Canny(img_blur, 50, 9)
    img_dilate = cv2.dilate(img_canny, np.ones((4, 2)), iterations=11)
    img_erode = cv2.erode(img_dilate, np.ones((13, 7)), iterations=4)
    return cv2.bitwise_not(img_erode)

def get_contours(img):
    contours, _ = cv2.findContours(process(img), cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    cnt = max(contours, key=cv2.contourArea)
    cv2.drawContours(img, [cv2.convexHull(cnt)], -1, (0, 0, 255), 2)

img = cv2.imread("image2.png")
get_contours(img)
cv2.imshow("result", img)

cv2.waitKey(0)
cv2.destroyAllWindows()

输出

提供的两个图像的输出:

图片1:

图 2:

注意事项

请注意,处理后的图像 (二进制)cv2.bitwise_not(img_erode) 处反转。观察两个图像的处理版本(由上面定义的process() 函数返回),反转:

处理后的图像 1:

处理后的图像 2:

工具

最后,如果你碰巧有其他图像上面的程序不能正常工作,你可以使用OpenCV Trackbars通过下面的程序来调整传递给方法的值:

import cv2
import numpy as np

def process(img, b_k, b_s, c_t1, c_t2, k1, k2, k3, k4, iter1, iter2):
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    b_k = b_k // 2 * 2 + 1
    img_blur = cv2.GaussianBlur(img_gray, (b_k, b_k), b_s)
    img_canny = cv2.Canny(img_blur, c_t1, c_t2)
    img_dilate = cv2.dilate(img_canny, np.ones((k1, k2)), iterations=iter1)
    img_erode = cv2.erode(img_dilate, np.ones((k3, k4)), iterations=iter2)
    return cv2.bitwise_not(img_erode)

d = {"Blur Kernel": (3, 50),
     "Blur Sigma": (2, 30),
     "Canny Threshold 1": (50, 500),
     "Canny Threshold 2": (9, 500),
     "Dilate Kernel1": (4, 50),
     "Dilate Kernel2": (2, 50),
     "Erode Kernel1": (13, 50),
     "Erode Kernel2": (7, 50),
     "Dilate Iterations": (11, 40),
     "Erode Iterations": (4, 40)}

cv2.namedWindow("Track Bars")
for i in d:
    cv2.createTrackbar(i, "Track Bars", *d[i], id)

img = cv2.imread("image1.png")

while True:
    img_copy = img.copy()
    processed = process(img, *(cv2.getTrackbarPos(i, "Track Bars") for i in d))
    contours, _ = cv2.findContours(processed, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
    if contours:
        cnt = max(contours, key=cv2.contourArea)
        cv2.drawContours(img_copy, [cv2.convexHull(cnt)], -1, (0, 0, 255), 2)
    cv2.imshow("result", img_copy)
    
    if cv2.waitKey(1) & 0xFF == ord("q"):
        break

cv2.waitKey(0)
cv2.destroyAllWindows()

【讨论】:

    【解决方案2】:

    如果您获得了所需的完美样本,您可以尝试使用 SIFT 或 SURF 算法。我以“完整”数据集中的一个为例。 SIFT 算法将尝试将样本中的特征与实际图像进行匹配。 从那里,您可以清理匹配项并找到一个单应性(RANSAC 在这种情况下效果最好)来找到轮廓。

    测试图片: 参考图像(从测试中截取): 结果(可以跳过灰度转换):

    我在这里展示的代码是指在 Colab 中执行,您可以使用自定义参数进行更多调整。

    import cv2 
    import numpy as np
    from google.colab.patches import cv2_imshow
    
    img = cv2.imread("reference_1.png", cv2.IMREAD_GRAYSCALE) 
    frame = cv2.imread("top.png", cv2.IMREAD_GRAYSCALE)
    
    # if SIFT_create() gives problems, try downgrading opencv with
    # pip uninstall opencv-python
    # pip install opencv-contrib-python==3.4.2.17
    sift = cv2.xfeatures2d.SIFT_create() 
    kp_image, desc_image = sift.detectAndCompute(img, None) 
    kp_frame, desc_frame = sift.detectAndCompute(frame, None) 
    
    index_params = dict(algorithm=0, trees=5) 
    search_params = dict() 
    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.knnMatch(desc_image, desc_frame, k=2)
    
    # clean the matches
    good_points=[] 
    for m, n in matches: 
        if(m.distance < 0.6 * n.distance): 
            good_points.append(m)
    
    query_pts = np.float32([kp_image[m.queryIdx].pt for m in good_points]).reshape(-1, 1, 2) 
    train_pts = np.float32([kp_frame[m.trainIdx].pt for m in good_points]).reshape(-1, 1, 2)
    
    # find homography to find mask
    matrix, mask = cv2.findHomography(query_pts, train_pts, cv2.RANSAC, 5.0) 
    matches_mask = mask.ravel().tolist()
    h,w = img.shape
    pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
    dst = cv2.perspectiveTransform(pts, matrix)
    homography = cv2.polylines(frame, [np.int32(dst)], True, (255, 0, 0), 3) 
    
    cv2_imshow(homography) 
    

    【讨论】:

      猜你喜欢
      • 2015-06-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-18
      • 1970-01-01
      • 2021-05-23
      • 2020-12-11
      • 1970-01-01
      • 2019-03-13
      相关资源
      最近更新 更多