racemic
racemic

Reputation: 123

How to use OpenCV to crop an image based on a certain criteria?

I would like to crop the images like the one below using python's OpenCV library. The area of interest is inside the squiggly lines on the top and bottom, and the lines on the side. The problem is that every image is slightly different. This means that I need some automated way of cropping for the area of interest. I guess the top and the sides would be easy since you could just crop it by 10 pixels or so. But how can I crop out the bottom half of the image where the line is not straight? I have included this example image. The image that follows highlights in pink the area of the image that I am interested in keeping.

enter image description here

enter image description here

Upvotes: 1

Views: 2085

Answers (1)

fmw42
fmw42

Reputation: 53081

Here is one way using Python/OpenCV.

  • Read input
  • Get center point (assume it is inside the desired region)
  • Convert image to grayscale
  • Floodfill the gray image and set background to black
  • Get the largest contour and its bounding box
  • Draw the largest contour as filled on black background as mask
  • Apply the mask to the input image
  • Crop the masked input image

Input:

enter image description here

import cv2
import numpy as np

# load image and get dimensions
img = cv2.imread("odd_region.png")
hh, ww, cc = img.shape

# compute center of image (as integer)
wc = ww//2
hc = hh//2

# create grayscale copy of input as basis of mask
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# create zeros mask 2 pixels larger in each dimension
zeros = np.zeros([hh + 2, ww + 2], np.uint8)

# do floodfill at center of image as seed point
ffimg = cv2.floodFill(gray, zeros, (wc,hc), (255), (0), (0), flags=8)[1]

# set rest of ffimg to black
ffimg[ffimg!=255] = 0

# get contours, find largest and its bounding box 
contours = cv2.findContours(ffimg, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
contours = contours[0] if len(contours) == 2 else contours[1]
area_thresh = 0
for cntr in contours:
    area = cv2.contourArea(cntr)
    if area > area_thresh:
        area = area_thresh
        outer_contour = cntr
        x,y,w,h = cv2.boundingRect(outer_contour)

# draw the filled contour on a black image
mask = np.full([hh,ww,cc], (0,0,0), np.uint8)
cv2.drawContours(mask,[outer_contour],0,(255,255,255),thickness=cv2.FILLED)

# mask the input
masked_img = img.copy()
masked_img[mask == 0] = 0
#masked_img[mask != 0] = img[mask != 0]

# crop the bounding box region of the masked img
result = masked_img[y:y+h, x:x+w]

# draw the contour outline on a copy of result
result_outline = result.copy()
cv2.drawContours(result_outline,[outer_contour],0,(0,0,255),thickness=1,offset=(-x,-y))


# display it
cv2.imshow("img", img)
cv2.imshow("ffimg", ffimg)
cv2.imshow("mask", mask)
cv2.imshow("masked_img", masked_img)
cv2.imshow("result", result)
cv2.imshow("result_outline", result_outline)
cv2.waitKey(0)
cv2.destroyAllWindows()

# write result to disk
cv2.imwrite("odd_region_cropped.png", result)
cv2.imwrite("odd_region_cropped_outline.png", result_outline)


Result: enter image description here

Result With Contour Drawn: enter image description here

Upvotes: 1

Related Questions