Hướng dẫn minarearect opencv python - minareect opencv python

Thật không may, câu trả lời của Oliver Wilken đã không dẫn đến hình ảnh được hiển thị.Có lẽ vì một phiên bản OpenCV khác nhau?Ở đây phiên bản được thông qua của tôi thêm một số tính năng:

  • mở rộng quy mô và đệm của trực tràng, tức là để có được các bộ phận bên ngoài trực tràng ban đầu
  • góc của hình ảnh kết quả có thể được cấu hình theo trực tràng, tức là góc 0 hoặc 90 [deg] sẽ trả về trực tràng theo chiều ngang hoặc theo chiều dọc
  • Trả về ma trận dịch để xoay những thứ khác, ví dụ:điểm, dòng, ...
  • Chức năng của người trợ giúp cho lập chỉ mục mảng Numpy và OpenCV và thao tác trực tràng

Mã số

import cv2
import numpy as np


def img_rectangle_cut(img, rect=None, angle=None):
    """Translate an image, defined by a rectangle. The image is cropped to the size of the rectangle
    and the cropped image can be rotated.
    The rect must be of the from (tuple(center_xy), tuple(width_xy), angle).
    The angle are in degrees.
    PARAMETER
    ---------
    img: ndarray
    rect: tuple, optional
        define the region of interest. If None, it takes the whole picture
    angle: float, optional
        angle of the output image in respect to the rectangle.
        I.e. angle=0 will return an image where the rectangle is parallel to the image array axes
        If None, no rotation is applied.
    RETURNS
    -------
    img_return: ndarray
    rect_return: tuple
        the rectangle in the returned image
    t_matrix: ndarray
        the translation matrix
    """
    if rect is None:
        if angle is None:
            angle = 0
        rect = (tuple(np.array(img.shape) * .5), img.shape, 0)
    box = cv2.boxPoints(rect)

    rect_target = rect_rotate(rect, angle=angle)
    pts_target = cv2.boxPoints(rect_target)

    # get max dimensions
    size_target = np.int0(np.ceil(np.max(pts_target, axis=0) - np.min(pts_target, axis=0)))

    # translation matrix
    t_matrix = cv2.getAffineTransform(box[:3].astype(np.float32),
                                      pts_target[:3].astype(np.float32))

    # cv2 needs the image transposed
    img_target = cv2.warpAffine(cv2.transpose(img), t_matrix, tuple(size_target))

    # undo transpose
    img_target = cv2.transpose(img_target)
    return img_target, rect_target, t_matrix


def reshape_cv(x, axis=-1):
    """openCV and numpy have a different array indexing (row, cols) vs (cols, rows), compensate it here."""
    if axis < 0:
        axis = len(x.shape) + axis
    return np.array(x).astype(np.float32)[(*[slice(None)] * axis, slice(None, None, -1))]

def connect(x):
    """Connect data for a polar or closed loop plot, i.e. np.append(x, [x[0]], axis=0)."""
    if isinstance(x, np.ma.MaskedArray):
        return np.ma.append(x, [x[0]], axis=0)
    else:
        return np.append(x, [x[0]], axis=0)


def transform_np(x, t_matrix):
    """Apply a transform on a openCV indexed array and return a numpy indexed array."""
    return transform_cv2np(reshape_cv(x), t_matrix)


def transform_cv2np(x, t_matrix):
    """Apply a transform on a numpy indexed array and return a numpy indexed array."""
    return reshape_cv(cv2.transform(np.array([x]).astype(np.float32), t_matrix)[0])


def rect_scale_pad(rect, scale=1., pad=40.):
    """Scale and/or pad a rectangle."""
    return (rect[0],
            tuple((np.array(rect[1]) + pad) * scale),
            rect[2])


def rect_rotate(rect, angle=None):
    """Rotate a rectangle by an angle in respect to it's center.
    The rect must be of the from (tuple(center_xy), tuple(width_xy), angle).
    The angle is in degrees.
    """
    if angle is None:
        angle = rect[2]
    rad = np.deg2rad(np.abs(angle))
    rot_matrix_2d = np.array([[np.cos(rad), np.sin(rad)],
                              [np.sin(rad), np.cos(rad)]])

    # cal. center of rectangle
    center = np.sum(np.array(rect[1]).reshape(1, -1) * rot_matrix_2d, axis=-1) * .5
    center = np.abs(center)

    return tuple(center), rect[1], angle

Example:

# Generate Image
img = np.zeros((1200, 660), dtype=np.uint8)

# Draw some lines and gen. points
x_0 = np.array([150,600])
x_1 = np.int0(x_0 + np.array((100, 100)))
x_2 = np.int0(x_0 + np.array((100, -100))*2.5)
img = cv2.line(img,tuple(x_0),tuple(x_1),1,120)
img = cv2.line(img,tuple(x_0),tuple(x_2),1,120)
points = np.array([x_0, x_1, x_2])

# Get Box
rect = cv2.minAreaRect(np.argwhere(img))

# Apply transformation
rect_scale = rect_scale_pad(rect, scale = 1., pad = 40.)
img_return, rect_target, t_matrix = img_rectangle_cut(
    img, 
    rect_scale, 
    angle=0,
    angle_normalize=True  # True <-> angel=0 vertical; angel=90 horizontal
   )

# PLOT
fig, ax = plt.subplots(ncols=2, figsize=(10,5))
ax = ax.flatten()
ax[0].imshow(img)

box_i = reshape_cv(cv2.boxPoints(rect))
ax[0].plot(*connect(box_i).T, 'o-', color='gray', alpha=.75, label='Original Box')
box_i = reshape_cv(cv2.boxPoints(rect_scale))
ax[0].plot(*connect(box_i).T, 'o-', color='green', alpha=.75, label='Scaled Box')
ax[0].plot(*points.T, 'o', label='Points')


ax[1].imshow(img_return)
box_i = transform_cv2np(cv2.boxPoints(rect), t_matrix)
ax[1].plot(*connect(box_i).T, 'o-', color='gray', alpha=.75, label='Original Box')

point_t = transform_np(points, t_matrix)
ax[1].plot(*point_t.T, 'o', label='Points')

ax[0].set_title('Original')
ax[1].set_title('Translated')

for axi in ax:
    axi.legend(loc=1)
    
plt.tight_layout()

Hướng dẫn minarearect opencv python - minareect opencv python