2017-08-10 19 views
12

Tôi đang cố gắng sử dụng OpenCV để phân đoạn một thanh cong từ nền của nó rồi tìm các đường cong trong đó và tính toán góc giữa mỗi khúc cua.Làm thế nào để phân đoạn thanh cong để tính toán góc?

Phần đầu tiên may mắn là tầm thường với độ tương phản đủ giữa nền trước và nền sau. Một chút xói mòn/giãn nở sẽ chăm sóc phản xạ/điểm nổi bật khi phân đoạn.

Phần thứ hai là nơi tôi không chắc chắn cách tiếp cận.

Tôi có thể dễ dàng lấy đường bao (trên cùng và dưới cùng rất giống nhau, hoặc sẽ làm), nhưng tôi không thể tìm ra cách tách đường bao thành các phần thẳng và thanh uốn để tính Các góc.

Cho đến nay tôi đã thử đơn giản hóa các đường nét, nhưng tôi nhận được quá nhiều hoặc quá ít điểm và cảm thấy khó khăn khi chỉ định đúng cài đặt để giữ các bộ phận thẳng thẳng và phần cong đơn giản.

Dưới đây là hình ảnh đầu vào của tôi (bend.png)

bend.png

Và đây là những gì tôi đã cố gắng cho đến nay:

#!/usr/bin/env python 
import numpy as np 
import cv2 

threshold = 229 
# erosion/dilation kernel 
kernel = np.ones((5,5),np.uint8) 
# contour simplification 
epsilon = 0 

# slider callbacks 
def onThreshold(x): 
    global threshold 
    print "threshold = ",x 
    threshold = x 
def onEpsilon(x): 
    global epsilon 
    epsilon = x * 0.01 
    print "epsilon = ",epsilon 

# make a window to add sliders/preview to 
cv2.namedWindow('processed') 
#make some sliders 
cv2.createTrackbar('threshold','processed',60,255,onThreshold) 
cv2.createTrackbar('epsilon','processed',1,1000,onEpsilon) 
# load image 
img = cv2.imread('bend.png',0) 
# continuously process for quick feedback 
while 1: 
    # exit on ESC key 
    k = cv2.waitKey(1) & 0xFF 
    if k == 27: 
     break 

    # Threshold 
    ret,processed = cv2.threshold(img,threshold,255,0) 
    # Invert 
    processed = (255-processed) 
    # Dilate 
    processed = cv2.dilate(processed,kernel) 
    processed = cv2.erode(processed,kernel) 
    # Canny 
    processed = cv2.Canny(processed,100,200) 

    contours, hierarchy = cv2.findContours(processed,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 
    if len(contours) > 0: 
     approx = cv2.approxPolyDP(contours[0],epsilon,True) 
     # print len(approx) 
     cv2.drawContours(processed, [approx], -1, (255,255,255), 3) 
     demo = img.copy() 
     cv2.drawContours(demo, [approx], -1, (192,0,0), 3) 
    # show result 
    cv2.imshow('processed ',processed) 
    cv2.imshow('demo ',demo) 


# exit 
cv2.destroyAllWindows() 

Đây là những gì tôi đã có cho đến nay, nhưng Tôi không tin rằng đây là phương pháp tốt nhất:

contour finding

simplified contour

Tôi đã cố gắng để con số này ra thị và những gì tôi đã nhắm vào là một cái gì đó dọc theo những dòng:

straight lines and bends segmented

Bởi vì mục tiêu cuối cùng là để tính toán góc giữa các bộ phận cong một cái gì đó như thế này cảm thấy đơn giản hơn:

line fitting

giả định của tôi mà lắp đường dây và tính góc giữa cặp int dòng ersecting có thể làm việc:

angles from line fitting intersections

tôi đã làm một thử nghiệm nhanh bằng cách sử dụng HoughLines OpenCV Python tutorial, nhưng không phụ thuộc vào các thông số thông qua tôi đã không nhận được kết quả tuyệt vời:

#!/usr/bin/env python 
import numpy as np 
import cv2 

threshold = 229 
minLineLength = 30 
maxLineGap = 10 
houghThresh = 15 

# erosion/dilation kernel 
kernel = np.ones((5,5),np.uint8) 

# slider callbacks 
def onMinLineLength(x): 
    global minLineLength 
    minLineLength = x 
    print "minLineLength = ",x 

def onMaxLineGap(x): 
    global maxLineGap 
    maxLineGap = x 
    print "maxLineGap = ",x 

def onHoughThresh(x): 
    global houghThresh 
    houghThresh = x 
    print "houghThresh = ",x 

# make a window to add sliders/preview to 
cv2.namedWindow('processed') 
#make some sliders 
cv2.createTrackbar('minLineLength','processed',1,50,onMinLineLength) 
cv2.createTrackbar('maxLineGap','processed',5,30,onMaxLineGap) 
cv2.createTrackbar('houghThresh','processed',15,50,onHoughThresh) 
# load image 
img = cv2.imread('bend.png',0) 
# continuously process for quick feedback 
while 1: 
    # exit on ESC key 
    k = cv2.waitKey(1) & 0xFF 
    if k == 27: 
     break 

    # Threshold 
    ret,processed = cv2.threshold(img,threshold,255,0) 
    # Invert 
    processed = (255-processed) 
    # Dilate 
    processed = cv2.dilate(processed,kernel) 
    processed = cv2.erode(processed,kernel) 
    # Canny 
    processed = cv2.Canny(processed,100,200) 

    lineBottom = np.zeros(img.shape,np.uint8) 

    contours, hierarchy = cv2.findContours(processed,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE) 
    if len(contours) > 0: 
     cv2.drawContours(lineBottom, contours, 0, (255,255,255), 1) 

    # HoughLinesP 
    houghResult = img.copy() 
    lines = cv2.HoughLinesP(lineBottom,1,np.pi/180,houghThresh,minLineLength,maxLineGap) 
    try: 
     for x in range(0, len(lines)): 
      for x1,y1,x2,y2 in lines[x]: 
       cv2.line(houghResult,(x1,y1),(x2,y2),(0,255,0),2) 
    except Exception as e: 
     print e 

    # show result 
    cv2.imshow('lineBottom',lineBottom) 
    cv2.imshow('houghResult ',houghResult) 


# exit 
cv2.destroyAllWindows() 

HoughLinesP result

Is đây là một cách tiếp cận khả thi? Nếu vậy, cách chính xác để làm phù hợp với dòng trong Python OpenCV là gì?

Nếu không, đó là cách tốt nhất để giải quyết vấn đề này?

Cập nhật Tiếp theo lời khuyên của Miki Tôi đã thử LSD OpenCV 3 và có kết quả đẹp hơn với HoughLinesP nhưng có vẻ như vẫn còn một số điều chỉnh cần thiết, mặc dù nó không giống khác hơn cv2.createLineSegmentDetector không có nhiều lựa chọn để chơi với:

LSD Result

+2

Tôi đã làm một cái gì đó rất giống với approxPolyDP, cuối cùng sáp nhập gần như collinear phân đoạn tiếp theo/đoạn ngắn. – Miki

+1

Một cách tiếp cận khác là sử dụng LSD (máy phát hiện phân đoạn đường) ... Tôi chưa bao giờ sử dụng nó, nhưng đáng để thử – Miki

+0

@Miki nghe có vẻ thú vị. Tôi bắt đầu với approxPolyDP, nhưng không biết phải làm gì với nó tiếp theo. Vì vậy, bạn về cơ bản looped thông qua các dòng và nếu sự khác biệt góc giữa các cặp đường dưới một ngưỡng bạn sáp nhập chúng thành một dòng, phải không? –

Trả lời

1

Có thể thuận tiện khi sử dụng độ cong để tìm đoạn đường. Ở đây example của đường viền tách bằng các điểm cong tối thiểu, có thể tốt hơn để sử dụng các điểm cong tối đa trong trường hợp của bạn. B Bạn có thể chia đường cong thành các phần, sau đó mỗi phần xấp xỉ với phân đoạn đường bằng phương pháp RANSAC.

+0

Điều đó có vẻ rất thú vị, cảm ơn vì điều đó (+1)! Tôi sẽ giới thiệu bản demo nhỏ C++ của tôi và xem nó như thế nào. –

0

Một khi bạn có đường viền, bạn có thể phân tích nó sử dụng một phương pháp giống như một đề xuất trong bài viết này: https://link.springer.com/article/10.1007/s10032-011-0175-3

Về cơ bản, đường viền được theo dõi tính toán độ cong tại mỗi điểm. Sau đó, bạn có thể sử dụng một ngưỡng cong để phân đoạn đường viền thành các phần thẳng và cong.

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