crop and center to square formed by points with OpenCV python

1

I was wanting to make a cut of a square formed by points and then center that cut on an image with opencv in python, I have a problem generating a square around the place where I have the most points. This is the original picture:

And this is what I get when I want to enclose the part with the most points inside a rectangle:

The rectangle looks like this because there are scattered pixels. This is the code I am using:

import numpy as np
import cv2

img = cv2.imread('123456__.png')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

ret,thresh = cv2.threshold(imgray,64,255,0)

kernel = np.ones((2,2),np.uint8)
img_e = cv2.dilate(thresh,kernel,iterations = 1)
imgbw, contours, hierarchy = 
cv2.findContours(img_e,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
margin_distance = 25
def get_min_max_values(cs, im_y, im_x):
 min_y = im_y - margin_distance
 min_x = im_x - margin_distance
 max_y = margin_distance
 max_x = margin_distance
 for lvl1 in cs:
     for lvl2 in lvl1:
         x, y = lvl2[0]
         # x = im_x - x
         # y = im_y - y
         max_y = max(y, max_y) if y + margin_distance < im_y else max_y
         max_x = max(x, max_x) if x + margin_distance < im_x else max_x
         min_y = min(y, min_y) if y > margin_distance else min_y
         min_x = min(x, min_x) if x > margin_distance else min_x
  return ((min_y, min_x), (min_y, max_x), (max_y, min_x), (max_y, max_x))

  new_rect = get_min_max_values(contours, len(img), len(img[0]))
  new_rect = list(map(lambda x: list(x)[::-1], list(new_rect)))
  rect = cv2.minAreaRect(np.int0(new_rect))
  box = cv2.boxPoints(rect)
  box = np.int0(box)

  img_out = cv2.drawContours(img, [box], -1, (0,0,255), 5) # -1 = wszystkie kontury
  img_out = cv2.drawContours(img, contours, -1, (0,255,0), 3)

  cv2.imwrite("outssss.png", 

Thank you very much in advance for the help!

    
asked by Rodrigo Baccaro 19.09.2018 в 22:23
source

1 answer

1

I think that, at least for the example you propose, it is much simpler to increase the dilation to completely fill in the gaps and then stay with the contour of greater area. You can do this simply by increasing the size of the kernel based on the expected scatter of the "points" of your rectangle:

import numpy as np
import cv2



def crop_min_rect(img, countour):
    rect = cv2.minAreaRect(countour)
    box = cv2.boxPoints(rect)
    box = np.int0(box)

    w, h = (int(n) for n in  rect[1])
    xs, ys = zip(*box)
    x1, y1 = min(xs), min(ys)
    x2, y2 = max(xs), max(ys)
    center = int((x1 + x2) / 2), int((y1 + y2) / 2)
    size = int((x2 - x1)), int((y2 - y1))

    rotated = False
    angle = rect[2]

    if angle < -45:
        angle += 90
        rotated = True

    rot_m = cv2.getRotationMatrix2D((size[0] / 2, size[1] / 2), angle, 1.0)
    cropped = cv2.warpAffine(cv2.getRectSubPix(img, size, center), rot_m, size)

    cw = w if not rotated else h
    ch = h if not rotated else w

    img_crop = cv2.getRectSubPix(cropped, (cw, ch), (size[0] / 2, size[1] / 2))
    im_draw  = cv2.drawContours(img, [box], -1, (0, 0, 255), 5)
    return im_draw, img_crop



KERNEL_SIZE = 20

img = cv2.imread('123456__.png')
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(imgray, 64, 255, 0)

kernel = np.ones((KERNEL_SIZE, KERNEL_SIZE), np.uint8)
img_e = cv2.dilate(thresh, kernel, iterations=1)
_, contours, _ = cv2.findContours(img_e, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

max_countour = max(contours, key = cv2.contourArea)

cont_img, crop_img = crop_min_rect(img, max_countour)

cv2.imwrite("countour.png", cont_img)
cv2.imwrite("cropped.png", crop_img)

countour.png

cropped.png

    
answered by 22.09.2018 / 06:13
source