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:
- Convert to gray, and threshold
- Morph-op to remove noise
- Find the max-area contour
- 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.