2016-05-12 11 views
5

minAreaRect trong OpenCV trả về một hình chữ nhật xoay. Làm thế nào để cắt phần này của hình ảnh bên trong hình chữ nhật?Hình chữ nhật cắt được trả về bởi minAreaRect OpenCV [Python]

boxPoints trả về tọa độ của các điểm góc của hình chữ nhật xoay để người ta có thể truy cập pixel bằng cách lặp qua các điểm bên trong hộp, nhưng có cách nào nhanh hơn để cắt bằng Python không?

EDIT

Xem code trong câu trả lời của tôi dưới đây.

+0

Bạn có thể: 1) tạo mặt nạ cho rect rect (dễ dàng đủ với 'fillConvexPoly' hoặc' drawContours (... CV_FILLED) '). 2) Đen khởi tạo một ma trận có cùng kích thước với bản gốc. 3) Chỉ sao chép nội dung của mặt nạ trong ảnh mới ('new_image.setTo (old_image, mask)'), 4) Cắt ảnh mới trên hộp giới hạn của hình chữ nhật xoay – Miki

Trả lời

1

Bạn chưa cung cấp mã mẫu, vì vậy tôi cũng không trả lời mã nào. Bạn có thể tiến hành như sau:

  1. Từ các góc của hình chữ nhật, xác định góc quay alpha theo trục ngang.
  2. Xoay hình ảnh theo hình chữ nhật để hình chữ nhật được cắt song song với đường viền hình ảnh. Hãy chắc chắn rằng hình ảnh tạm thời là lớn hơn về kích thước sao cho không có thông tin bị mất (cf: Rotate image without cropping OpenCV)
  3. Cắt hình ảnh sử dụng cắt NumPy (cf: How to crop an image in OpenCV using Python)
  4. Xoay hình ảnh trở lại bởi -alpha.
+1

Để có hình ảnh lớn, điều này không quá đắt? –

+0

Tôi đoán là các hàm tích hợp sẽ luôn nhanh hơn so với thực hiện một vòng lặp lồng nhau trên pixel.Nhưng cách duy nhất để tìm ra điều này là để đo lường nó, nó chỉ là một dòng fey của mã như mô tả ở trên. – tfv

+0

Nếu tôi có rất nhiều cảnh thì có thể nó sẽ hiển thị. Tôi sẽ viết mã và liên hệ lại với bạn sau khi thử. –

8

Đây là mã để thực hiện tác vụ trên. Để tăng tốc quá trình, thay vì trước tiên xoay toàn bộ hình ảnh và cắt xén, một phần của hình ảnh có hình chữ nhật xoay được cắt đầu tiên, sau đó xoay và cắt lại để cung cấp kết quả cuối cùng.

# Let cnt be the contour and img be the input 

rect = cv2.minAreaRect(cnt) 
box = cv2.boxPoints(rect) 
box = np.int0(box) 

W = rect[1][0] 
H = rect[1][1] 

Xs = [i[0] for i in box] 
Ys = [i[1] for i in box] 
x1 = min(Xs) 
x2 = max(Xs) 
y1 = min(Ys) 
y2 = max(Ys) 

angle = rect[2] 
if angle < -45: 
    angle += 90 

# Center of rectangle in source image 
center = ((x1+x2)/2,(y1+y2)/2) 
# Size of the upright rectangle bounding the rotated rectangle 
size = (x2-x1, y2-y1) 
M = cv2.getRotationMatrix2D((size[0]/2, size[1]/2), angle, 1.0) 
# Cropped upright rectangle 
cropped = cv2.getRectSubPix(img, size, center) 
cropped = cv2.warpAffine(cropped, M, size) 
croppedW = H if H > W else W 
croppedH = H if H < W else W 
# Final cropped & rotated rectangle 
croppedRotated = cv2.getRectSubPix(cropped, (int(croppedW),int(croppedH)), (size[0]/2, size[1]/2)) 
+0

Tôi đã thử mã này nhưng không cung cấp cho tôi ROI. Bất kỳ cải tiến nào kể từ đó? –

+0

Nó không cung cấp cho bạn khu vực phù hợp. – epinal

+0

hoạt động hoàn hảo cho tôi, cảm ơn. – razzak

8

đây một chức năng nào công việc này:

import cv2 
import numpy as np 

def crop_minAreaRect(img, rect): 

    # rotate img 
    angle = rect[2] 
    rows,cols = img.shape[0], img.shape[1] 
    M = cv2.getRotationMatrix2D((cols/2,rows/2),angle,1) 
    img_rot = cv2.warpAffine(img,M,(cols,rows)) 

    # rotate bounding box 
    rect0 = (rect[0], rect[1], 0.0) 
    box = cv2.boxPoints(rect) 
    pts = np.int0(cv2.transform(np.array([box]), M))[0]  
    pts[pts < 0] = 0 

    # crop 
    img_crop = img_rot[pts[1][1]:pts[0][1], 
         pts[1][0]:pts[2][0]] 

    return img_crop 

đây một cách sử dụng ví dụ

# generate image 
img = np.zeros((1000, 1000), dtype=np.uint8) 
img = cv2.line(img,(400,400),(511,511),1,120) 
img = cv2.line(img,(300,300),(700,500),1,120) 

# find contours/rectangle 
_,contours,_ = cv2.findContours(img, 1, 1) 
rect = cv2.minAreaRect(contours[0]) 

# crop 
img_croped = crop_minAreaRect(img, rect) 

# show 
import matplotlib.pylab as plt 
plt.figure() 
plt.subplot(1,2,1) 
plt.imshow(img) 
plt.subplot(1,2,2) 
plt.imshow(img_croped) 
plt.show() 

này là sản phẩm

original and croped image

+0

Đó chính xác là những gì tôi muốn và chức năng này hoàn toàn rõ ràng! Tuy nhiên tôi đã không thể làm cho nó hoạt động với hình ảnh này. https://i.imgur.com/4E8ILuI.jpg Nó kết thúc lên xoay hơi sai và các cạnh cắt. Bạn có sẵn sàng để xem nó? – Hatshepsut

+0

Nó không cung cấp cho bạn khu vực phù hợp. – epinal

+0

Làm việc cho tôi tốt, tôi tìm kiếm rất nhiều và đây là câu trả lời tốt nhất cho tôi – Txeif

1

@AbdulF atir đã được vào một giải pháp tốt nhưng như các ý kiến ​​đã nêu (@ Randika @epinal) nó đã không được khá làm việc cho tôi, hoặc vì vậy tôi sửa đổi nó một chút và nó có vẻ là làm việc cho trường hợp của tôi. đây là hình ảnh tôi đang sử dụng. mask_of_image

im, contours, hierarchy = cv2.findContours(open_mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 
print("num of contours: {}".format(len(contours))) 


mult = 1.2 # I wanted to show an area slightly larger than my min rectangle set this to one if you don't 
img_box = cv2.cvtColor(img.copy(), cv2.COLOR_GRAY2BGR) 
for cnt in contours: 
    rect = cv2.minAreaRect(cnt) 
    box = cv2.boxPoints(rect) 
    box = np.int0(box) 
    cv2.drawContours(img_box, [box], 0, (0,255,0), 2) # this was mostly for debugging you may omit 

    W = rect[1][0] 
    H = rect[1][1] 

    Xs = [i[0] for i in box] 
    Ys = [i[1] for i in box] 
    x1 = min(Xs) 
    x2 = max(Xs) 
    y1 = min(Ys) 
    y2 = max(Ys) 

    rotated = False 
    angle = rect[2] 

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

    center = (int((x1+x2)/2), int((y1+y2)/2)) 
    size = (int(mult*(x2-x1)),int(mult*(y2-y1))) 
    cv2.circle(img_box, center, 10, (0,255,0), -1) #again this was mostly for debugging purposes 

    M = cv2.getRotationMatrix2D((size[0]/2, size[1]/2), angle, 1.0) 

    cropped = cv2.getRectSubPix(img_box, size, center)  
    cropped = cv2.warpAffine(cropped, M, size) 

    croppedW = W if not rotated else H 
    croppedH = H if not rotated else W 

    croppedRotated = cv2.getRectSubPix(cropped, (int(croppedW*mult), int(croppedH*mult)), (size[0]/2, size[1]/2)) 

    plt.imshow(croppedRotated) 
    plt.show() 

plt.imshow(img_box) 
plt.show() 

này nên sản xuất một loạt các hình ảnh như thế này: isolated contour 1isolated contour 2isolated contour 3

Và nó cũng sẽ cung cấp một hình ảnh kết quả như thế này: results

Các vấn đề liên quan