How to crop or remove white background from an image

后端 未结 4 811
隐瞒了意图╮
隐瞒了意图╮ 2020-12-08 17:04

I am trying to compare images using OpenCV and Python.

Consider these images:




Both feature an identical pair of shoes, se

相关标签:
4条回答
  • 2020-12-08 17:41

    This link worked perfectly for me for a similar problem, although it uses PIL. Note that it will result in a rectangular image, bounded by the top/right/bottom/left-most pixels that are not white. In your case, it should give identical images with the same size.

    I am guessing the code could be easily adapted to work with OpenCV functions only.

    0 讨论(0)
  • 2020-12-08 17:43

    I found this on 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
    
    0 讨论(0)
  • 2020-12-08 17:51

    Kinght's solution works well. In my case, I also have CMYK images. When I crop them, I get incorrect (vivid colors) output. And it seems OpenCV doesn't support CMYK. So I needed a way to convert CMYK images to RGB, and then open it with OpenCV. This is how I handled it:

    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)
    
    0 讨论(0)
  • 2020-12-08 18:04

    You requirement in the comment: 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.

    Then my steps to crop the target regions:

    1. Convert to gray, and threshold
    2. Morph-op to remove noise
    3. Find the max-area contour
    4. Crop and save it
    #!/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)
    

    Result:

    0 讨论(0)
提交回复
热议问题