Using Python OpenCV, how would you extract an area of โ€‹โ€‹an image within a specific bounding range of colors?

Given a photo that I have manually drawn with a colored bounding box, I want to copy / crop the content of the image so that the content is contained within the bounding box.

The goal is to detect this bounding rectangle and then use that to tell the script where to copy / trim.

I have experimented with outlines, but I feel like I need additional steps.

Maybe a way:

  • define limited area
  • find the smallest area (the lines of the boxes can be of varying thickness, so I need an inner bounding area - eventually the border will be a multi-colored clipping in the physical world).
  • script creates a mask for this area
  • capture image

There might be a better way; What's the best way to do this? And what OpenCV Python methods would I use?

Based on my current experimental code (I was looking into getting an area from an outline size, but I think I need a better outline code):

import numpy as np
import cv2

image_dir = "/Users/admin/Documents/dir/dir2/"

im = cv2.imread(image_dir+'test_image_bounded.png')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,176,190,43)
#ret,thresh = cv2.threshold(imgray,127,255,0)
contours, hierarchy =         cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

areaArray = []
count = 1

for i, c in enumerate(contours):
    area = cv2.contourArea(c)
    areaArray.append(area)

#first sort the array by area
sorteddata = sorted(zip(areaArray, contours), key=lambda x: x[0], reverse=True)

#find the nth largest contour [n-1][1], in this case 2
largestcontour = sorteddata[0][2]

#draw it
x, y, w, h = cv2.boundingRect(largestcontour)
cv2.drawContours(im, largestcontour, -1, (255, 0, 0), 2)
cv2.rectangle(im, (x, y), (x+w, y+h), (0,255,0), 2)
cv2.imwrite(image_dir+'output.jpg', im)

      

Manually bounded image

edit --------------------------------

I was able to get some pretty good results thanks to color detection, morphology, and second-highest threshold capture

Here's some code:

green_MIN = np.array([45, 25, 25],np.uint8)
green_MAX = np.array([55, 255, 255],np.uint8)

hsv_img = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

frame_threshed = cv2.inRange(hsv_img, green_MIN, green_MAX)

#image = cv2.imread('...') # Load your image in here
# Your code to threshold
#image = cv2.adaptiveThreshold(image, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV, 45, 0)    

# Perform morphology
se = np.ones((20,20), dtype='uint8')
image_close = cv2.morphologyEx(frame_threshed, cv2.MORPH_CLOSE, se)

      

HSV values โ€‹โ€‹- pain; I would like to automate this part. This was helpful for getting value: https://achuwilson.wordpress.com/2012/02/14/hsv-pixel-values-in-opencv/

+3


source to share


1 answer


My quick suggestion would be:

1) Filter by color as the rectangle is green. Green can also exist in the image itself, but this will reduce false positives.

2) Detecting lines that form a rectangle.



This can now be done in a variety of ways. A more general way to do this is to use the Hough transform. I am not aware of an implementation that will directly search for rectangles, although you can implement it as well. The HoughLinesP function will find lines and you can select those that form a rectangle.

However, in your application, you may have fairly strict assumptions that will make this problem much easier. If the bounding box never rotates, you can simply loop over the rows and columns to find the ones that have the most pixels for the color you are looking for. This can be extended to search for adjacent pixels to find line segments, but it may not even be necessary.

0


source







All Articles