Nisse Karlsson
Nisse Karlsson

Reputation: 139

How to auto crop the white part of this picture that is inside the grey?

I want to crop out the white part inside the grey and save it as a new picture for thousands of pictures. Can this be done by PIL or opencv? If so how? A picture can look like this:

enter image description here

I know the PIL lib has n crop, but how do I make the script auto find the white part inside the grey? The white part sometimes has other images within it and sometimes text in it, also. So the white part is not always blank white or only a black frame as in the example.

Upvotes: 2

Views: 1807

Answers (2)

fmw42
fmw42

Reputation: 53089

If you are willing to use ImageMagick, that can be done in one line of code using its -trim function twice, once for each of the two gray regions -- dark and light. The trim function looks for nearly constant regions in the background and removes them. The -fuzz XX% is the percent variation in gray colors in each region to consider as the same color.

Imagemagick is already installed with most Linux distributions and it is available also for Windows and Mac OSX.

Input:

enter image description here

convert 0.png -fuzz 30% -trim +repage -trim +repage 0_trim.png


enter image description here

In fact, you can process a whole folder of images, using ImageMagick mogrify rather than convert.

Create a new directory to hold the output
Change directory to the one containing your images
mogrify -path path_to/new_directory -fuzz 30% -trim +repage -trim +repage *


You can also use Python Wand, which is based upon ImageMagick. See trim at http://docs.wand-py.org/en/latest/wand/image.html. Here is the Wand code:

#!/bin/python3.7

from wand.image import Image

with Image(filename='0.png') as img:
    img.trim(fuzz=0.3*img.quantum_range)
    img.save(filename='0_wand_trim.png')


You can also make a subprocess call from Python to ImageMagick, if you want to do it that way.

#!/opt/local/bin/python3.7

import subprocess

cmd = 'convert 0.png -fuzz 30% -trim +repage -trim +repage 0_trim.png'
subprocess.check_output(cmd, shell=True, universal_newlines=True)


You may need to provide the path to convert, if it is not in your PATH environment variable.

Upvotes: 1

nathancy
nathancy

Reputation: 46590

Here's the main idea:

  • Convert image to grayscale and blur image
  • Perform canny edge detection
  • Find contours of image and find area of each contour
  • Filter for maximum contour area and crop for ROI section

Canny edge detection

Now we iterate through each contour and filter for the largest contour which is highlighted in green.

Crop the ROI from the bounding box coordinates

import numpy as np
import cv2

original_image = cv2.imread("1.png")
image = original_image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
canny = cv2.Canny(blurred, 120, 255, 1)

# Find contours in the image
cnts = cv2.findContours(canny.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

# Obtain area for each contour
contour_sizes = [(cv2.contourArea(contour), contour) for contour in cnts]

# Find maximum contour and crop for ROI section
if len(contour_sizes) > 0:
    largest_contour = max(contour_sizes, key=lambda x: x[0])[1]
    x,y,w,h = cv2.boundingRect(largest_contour)
    cv2.rectangle(image, (x, y), (x + w, y + h), (36,255,12), 2)
    ROI = original_image[y:y+h, x:x+w]
    cv2.imshow("ROI", ROI) 

cv2.imshow("canny", canny) 
cv2.imshow("detected", image) 
cv2.waitKey(0)

Upvotes: 0

Related Questions