如何从图像中裁剪或删除白色背景

时间:2018-01-23 06:23:42

标签: python opencv python-imaging-library scikit-image

我正在尝试使用OpenCV和Python比较图像。

考虑这些图片:

Image  900 x 726

Image 900 x 675

两者都有一双相同的鞋子,设置为白色背景。唯一的区别是第一个背景比第二个背景更高。

我想知道如何以编程方式裁剪两者的白色背景,以便我只留下一双鞋。

我必须补充一点,我手动裁剪背景是不可能的。

4 个答案:

答案 0 :(得分:10)

您在评论中要求:The shoes are on a white background. I would like to completely get rid of the border; as in be left with a rectangular box with either a white or a transparent background, having the length and width of the shoes in the picture.

然后我采取裁剪目标区域的步骤:

  
      
  1. 转换为灰色和阈值
  2.   
  3. 变形去除噪音
  4.   
  5. 查找最大面积轮廓
  6.   
  7. 裁剪并保存
  8.   
#!/usr/bin/python3
# Created by Silencer @ Stackoverflow 
# 2018.01.23 14:41:42 CST
# 2018.01.23 18:17:42 CST
import cv2
import numpy as np

## (1) Convert to gray, and threshold
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
th, threshed = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)

## (2) Morph-op to remove noise
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
morphed = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, kernel)

## (3) Find the max-area contour
cnts = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
cnt = sorted(cnts, key=cv2.contourArea)[-1]

## (4) Crop and save it
x,y,w,h = cv2.boundingRect(cnt)
dst = img[y:y+h, x:x+w]
cv2.imwrite("001.png", dst)

结果:

答案 1 :(得分:1)

国王的solution效果很好。就我而言,我也有CMYK图像。裁切它们时,输出不正确(鲜艳的色彩)。而且看来OpenCV不支持CMYK。因此,我需要一种将CMYK图像转换为RGB,然后使用OpenCV打开它的方法。这是我的处理方式:

import cv2
import numpy

from PIL import Image
from PIL import ImageCms

# force opening truncated/corrupt image files
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

img = "shoes.jpg"

img = Image.open(img)
if img.mode == "CMYK":
    # color profiles can be found at C:\Program Files (x86)\Common Files\Adobe\Color\Profiles\Recommended
    img = ImageCms.profileToProfile(img, "USWebCoatedSWOP.icc", "sRGB_Color_Space_Profile.icm", outputMode="RGB")
# PIL image -> OpenCV image; see https://stackoverflow.com/q/14134892/2202732
img = cv2.cvtColor(numpy.array(img), cv2.COLOR_RGB2BGR)

## (1) Convert to gray, and threshold
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
th, threshed = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)

## (2) Morph-op to remove noise
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))
morphed = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, kernel)

## (3) Find the max-area contour
cnts = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]
cnt = sorted(cnts, key=cv2.contourArea)[-1]

## (4) Crop and save it
x,y,w,h = cv2.boundingRect(cnt)
dst = img[y:y+h, x:x+w]

# add border/padding around the cropped image
# dst = cv2.copyMakeBorder(dst, 10, 10, 10, 10, cv2.BORDER_CONSTANT, value=[255,255,255])

cv2.imshow("image", dst)
cv2.waitKey(0)
cv2.destroyAllWindows()

# create/write to file
# cv2.imwrite("001.png", dst)

答案 2 :(得分:0)

This链接对我来说非常适用于类似的问题,尽管它使用了PIL。请注意,它会产生一个矩形图像,由顶部/右侧/底部/最左侧的非白色像素限定。在您的情况下,它应该提供相同大小的相同图像。

我猜测代码可以很容易地适应OpenCV函数。

答案 3 :(得分:0)

我在github上发现了这个。

https://imagemagick.org/script/download.php

import pgmagick

def remove_background(image, background=None):
    """Returns a copy of `image` that only contains the parts that is distinct
       from the background. If background is None, returns parts that are
       distinct from white."""
    if background is None:
        background = pgmagick.Image(image.size(), 'white')
    elif isinstance(background, pgmagick.Image):
        blob = pgmagick.Blob()
        background.write(blob)
        background = pgmagick.Image(blob, image.size())
    else:
        background = pgmagick.Image(image.size(), background)
    background.composite(image, 0, 0, pgmagick.CompositeOperator.DifferenceCompositeOp)
    background.threshold(25)
    blob = pgmagick.Blob()
    image.write(blob)
    image = pgmagick.Image(blob, image.size())
    image.composite(background, 0, 0, pgmagick.CompositeOperator.CopyOpacityCompositeOp)
    return image