How to crop or remove white background from an image How to crop or remove white background from an image python python

How to crop or remove white background from an image


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 CSTimport cv2import numpy as np## (1) Convert to gray, and thresholdgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)th, threshed = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)## (2) Morph-op to remove noisekernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))morphed = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, kernel)## (3) Find the max-area contourcnts = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]cnt = sorted(cnts, key=cv2.contourArea)[-1]## (4) Crop and save itx,y,w,h = cv2.boundingRect(cnt)dst = img[y:y+h, x:x+w]cv2.imwrite("001.png", dst)

Result:


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 cv2import numpyfrom PIL import Imagefrom PIL import ImageCms# force opening truncated/corrupt image filesfrom PIL import ImageFileImageFile.LOAD_TRUNCATED_IMAGES = Trueimg = "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/2202732img = cv2.cvtColor(numpy.array(img), cv2.COLOR_RGB2BGR)## (1) Convert to gray, and thresholdgray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)th, threshed = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)## (2) Morph-op to remove noisekernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11,11))morphed = cv2.morphologyEx(threshed, cv2.MORPH_CLOSE, kernel)## (3) Find the max-area contourcnts = cv2.findContours(morphed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)[-2]cnt = sorted(cnts, key=cv2.contourArea)[-1]## (4) Crop and save itx,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)


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.