如何从图像中删除背景

How to remove the background from an image

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

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

概念

在这种情况下,微调您用来扩大和侵蚀从图像中检测到的精巧边缘的内核非常有用。这是一个示例,其中膨胀内核为 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()

如果为您提供了所需的完美样本,您可以尝试使用 SIFT 或 SURF 算法。我以 'intact' 数据集中的一个为例。 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) 

您可以使用Rembg(删除图片背景的工具)。即使使用 pre-trained 权重,这也能很好地工作。我尝试了测试图像,这是我使用 Rembg 的结果

您可以使用 pip 下载 Rembg

pip install rembg

删除单个文件的背景

rembg i path/to/input.png path/to/output.png

删除文件夹中所有图像的背景

rembg p path/to/input path/to/output