【问题标题】:Removing background color from image opencv python从图像opencv python中删除背景颜色
【发布时间】:2020-06-03 18:15:52
【问题描述】:

我有许多样本图像,其背景颜色无法控制。其中一些具有黑色背景。其中一些具有白色背景。其中一些有绿色背景等。

我想删除给定图像的这些背景颜色,其中图像中的对象只是一个样本。我尝试了这段代码,但它没有像我预期的那样工作。

def get_holes(image, thresh):
        gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

        im_bw = cv2.threshold(gray, thresh, 255, cv2.THRESH_BINARY)[1]
        im_bw_inv = cv2.bitwise_not(im_bw)

        _, contour, _ = cv2.findContours(im_bw_inv, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE)
        for cnt in contour:
            cv2.drawContours(im_bw_inv, [cnt], 0, 255, -1)

        nt = cv2.bitwise_not(im_bw)
        im_bw_inv = cv2.bitwise_or(im_bw_inv, nt)
        return im_bw_inv


    def remove_background(image, thresh, scale_factor=.25, kernel_range=range(1, 15), border=None):
        border = border or kernel_range[-1]

        holes = get_holes(image, thresh)
        small = cv2.resize(holes, None, fx=scale_factor, fy=scale_factor)
        bordered = cv2.copyMakeBorder(small, border, border, border, border, cv2.BORDER_CONSTANT)

        for i in kernel_range:
            kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2*i+1, 2*i+1))
            bordered = cv2.morphologyEx(bordered, cv2.MORPH_CLOSE, kernel)

        unbordered = bordered[border: -border, border: -border]
        mask = cv2.resize(unbordered, (image.shape[1], image.shape[0]))
        fg = cv2.bitwise_and(image, image, mask=mask)
        return fg

file = your_file_location
img = cv2.imread(file)
nb_img = dm.remove_background(img, 255)

这些是一些示例图像

我可以给你一些建议吗?

【问题讨论】:

    标签: python image opencv image-processing computer-vision


    【解决方案1】:

    这是一种简单的方法,假设每张图像只有一个样本。

    1. Kmeans 颜色量化。 我们加载图像,然后执行 Kmeans 颜色量化,将图像分割成指定的颜色簇。例如clusters=4,图像将被标记为四种颜色。

    2. 获取二值图像。转换为灰度、高斯模糊、自适应阈值。

    3. 在遮罩上绘制最大的封闭圆。查找轮廓,使用轮廓区域过滤对最大轮廓进行排序,然后使用cv2.minEnclosingCircle在遮罩上绘制最大的封闭圆。

    4. 按位与。由于我们已经隔离了要提取的所需部分,因此我们只需按位与掩码和输入图像


    输入图像->Kmeans->二进制图像

    检测到最大包围圈-> Mask ->Result

    这是第二张图片的输出

    输入图像->Kmeans->二进制图像

    检测到最大包围圈-> Mask ->Result

    代码

    import cv2
    import numpy as np
    
    # Kmeans color segmentation
    def kmeans_color_quantization(image, clusters=8, rounds=1):
        h, w = image.shape[:2]
        samples = np.zeros([h*w,3], dtype=np.float32)
        count = 0
    
        for x in range(h):
            for y in range(w):
                samples[count] = image[x][y]
                count += 1
    
        compactness, labels, centers = cv2.kmeans(samples,
                clusters, 
                None,
                (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10000, 0.0001), 
                rounds, 
                cv2.KMEANS_RANDOM_CENTERS)
    
        centers = np.uint8(centers)
        res = centers[labels.flatten()]
        return res.reshape((image.shape))
    
    # Load image and perform kmeans
    image = cv2.imread('2.jpg')
    original = image.copy()
    kmeans = kmeans_color_quantization(image, clusters=4)
    
    # Convert to grayscale, Gaussian blur, adaptive threshold
    gray = cv2.cvtColor(kmeans, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (3,3), 0)
    thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,21,2)
    
    # Draw largest enclosing circle onto a mask
    mask = np.zeros(original.shape[:2], dtype=np.uint8)
    cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    cnts = sorted(cnts, key=cv2.contourArea, reverse=True)
    for c in cnts:
        ((x, y), r) = cv2.minEnclosingCircle(c)
        cv2.circle(image, (int(x), int(y)), int(r), (36, 255, 12), 2)
        cv2.circle(mask, (int(x), int(y)), int(r), 255, -1)
        break
    
    # Bitwise-and for result
    result = cv2.bitwise_and(original, original, mask=mask)
    result[mask==0] = (255,255,255)
    
    cv2.imshow('thresh', thresh)
    cv2.imshow('result', result)
    cv2.imshow('mask', mask)
    cv2.imshow('kmeans', kmeans)
    cv2.imshow('image', image)
    cv2.waitKey()
    

    【讨论】:

    • 如果我的标本不是圆形而是椭圆形怎么办。我认为我应该将 cv2.minEncloseingCircle(c) 行修改为其他内容。我可以给你一些建议吗?
    • 你可以试试cv2.fitEllipse
    • 如果它不是一个完美的圆形而是椭圆形,您可以尝试另一种方法,而不是使用一些圆形/椭圆拟合函数获取蒙版,您可以简单地使用 cv2.findContours 找到轮廓,然后绘制最大的轮廓cv2.drawContours 戴在面具上。它应该适用于任何方向
    猜你喜欢
    • 2020-12-05
    • 2014-02-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 1970-01-01
    • 2010-11-02
    相关资源
    最近更新 更多