Python OpenCV: получение точки ax / y с наклоном и другой координатой - PullRequest
0 голосов
/ 08 января 2020

Я пытаюсь нарисовать прямую линию, представляющую путь линейного движущегося объекта. Я работаю на склоне, получая первую точку (oX,oY) и вторую точку (x3, y3) и выполняя ((y3-oY)/(x3-oX)). У меня сейчас есть точка (x3, y3) и уклон. В зависимости от того, где проходит линия, например, если она пересекает левую, правую, верхнюю или нижнюю границу, я получаю другую точку, основанную на высоте и длине окна (640 пикселей, 480 пикселей). Поэтому, если линия пересекает левую сторону, значение x равно 0, и все, что мне нужно сделать, это найти значение y. Как я могу сделать это со всеми 4 сторонами? Мой код ниже, и в настоящее время dr aws строка в порядке, но не останавливается сверху или снизу. например, значение y не равно 0 или 480. Причина, по которой мне нужно, чтобы линия остановилась на краю окна, состоит в том, чтобы нарисовать идентичную линию с перевернутым наклоном, чтобы представить, должен ли линейный объект отскочить. Спасибо!

import cv2
import numpy as np
import math

lower_red = np.array([-10,160,160])
upper_red = np.array([10,255,255])

oX, oY = 0,0

cap = cv2.VideoCapture(0)
if not cap.isOpened():
    print("Cannot open camera")
    exit()
while(1):
    ret, frame = cap.read()
    if not ret:
        print("Can't receive frame (stream end?). Exiting ...")
        break

    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower_red, upper_red)
    #ret, thresh = cv2.threshold(mask, 80, 255, cv2.THRESH_BINARY)
    contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    if len(contours) != 0:
        c = max(contours, key = cv2.contourArea)
        x1, y1, w, h = cv2.boundingRect(c)
        x2, y2 = x1 + w, y1 + h
        cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)
        x3, y3 = round((x1+x2)/2), round((y1+y2)/2)
        cv2.circle(frame, (x3,y3), 4, (255,0,0), 2)
        #print(x3, y3)

        def slope(oX,oY,x3,y3):
        ###finding slope
            if x3!=oX:
                return((y3-oY)/(x3-oX))
            else:
                return 'NA'

        slope(oX,oY,x3,y3)

    def drawLine(frame,oX,oY,x3,y3):
        m=slope(oX,oY,x3,y3)
        h,w=frame.shape[:2]
        if m!='NA':
            ### here we are essentially extending the line to x=0 and x=width
            ### and calculating the y associated with it
            ##starting point
            px=0
            py=-(oX-0)*m+oY
            ##ending point
            qx=w
            qy=-(x3-w)*m+y3
        else:
        ### if slope is zero, draw a line with x=x1 and y=0 and y=height
            px,py=oX,0
            qx,qy=oX,h

        if x3 < oX and y3 < oY:
            qx, qy = oX, oY
            cv2.line(frame, (int(px), int(py)), (int(qx), int(qy)), (0, 255, 0), 2)
        elif x3 < oX and y3 > oY:
            qx, qy = oX, oY
            cv2.line(frame, (int(px), int(py)), (int(qx), int(qy)), (0, 255, 0), 2)
        elif x3 > oX and y3 < oY:
            px, py = oX, oY
            cv2.line(frame, (int(px), int(py)), (int(qx), int(qy)), (0, 255, 0), 2)
        elif x3 > oX and y3 > oY:
            px, py = oX, oY
            cv2.line(frame, (int(px), int(py)),(int(qx), int(qy)), (0, 255, 0), 2)
        #print(int(px),int(py), int(qx), int(qy))


    drawLine(frame,oX,oY,x3,y3)
    oX, oY = x3, y3
    cv2.imshow('frame', frame)
    cv2.imshow('mask', mask)


    if cv2.waitKey(1) == ord('q'):
        break
# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

1 Ответ

0 голосов
/ 08 января 2020

Я не знаю cv2, но код ниже вернет конечные точки на контуре прямоугольника, который пересекает его. Он чистый python нет numpy, поэтому работает на одной коробке / строке за раз Если линия не пересекает поле, возвращается список нулевой длины.

from math import isclose

def grad_and_inter( x0, y0, x1, y1 ):
    """ Return gradient and intercept in y = gradient * x + intercept
        for a line through (x0,y0) and (x1, y1) """
    try:
        grad = (y1-y0) / (x1-x0)
        return grad, y0 - grad * x0  # gradient & intercept
    except ZeroDivisionError:
        return float('Inf'), x0      # if vertical Inf and x

def frame_intersect( xlo, ylo, xhi, yhi, grad, inter ):
    """ Return the 2 points on the bounding box (xlo, ylo), (xhi, yhi)
        where a line (y = grad * x + inter) intercepts the box. """

    if grad == 0.0:    # y = inter for all x 
        return [ (xlo, inter), (xhi, inter) ]

    if grad == float('Inf'):  # x = inter for all y
        return [(inter, ylo), (inter, yhi) ]

    def y_func( x ):
        y = grad * x + inter
        if (y < ylo) or (y > yhi):
            return None   # Return None if outside the bounds
        return ( x, y )  # Return x and the calculated y

    def x_func( y ):
        x = (y - inter) / grad
        if (x < xlo) or (x>xhi):
            return None   # Return None if outside the bounds
        return ( x, y )  # Return calculated x and y

    func = [ x_func, x_func, y_func, y_func ] # Iterate through the 4 funcs
    param = [ ylo, yhi, xlo, xhi ]            # with the 4 parameters.

    res = []
    first_x = float('Inf')  # first_x must be a float for isclose below.
    for f, p in zip(func, param):
        coords  = f(p)
        if coords is None:
            continue
        if not isclose(first_x, coords[0]):  
            # If the x in coord is the same as the first x don't append it.
            # If one (or both) coords are a corner they'll be repeated.
            res.append(coords)
            if len(res)>1:
                break  # Once two coords found break.
            first_x = coords[0]

    return res

def constant_frame( xlo, ylo, xhi, yhi ):
    """ Returns a function that uses a constant bounding box. """

    def user_func( x0, y0, x1, y1 ):
        return frame_intersect( xlo, ylo, xhi, yhi, *grad_and_inter( x0, y0, x1, y1 ) )

    return user_func

do_640x480 = constant_frame( 0., 0., 640., 480. )

print( 247., 50., 247., 10., do_640x480( 247., 50., 247., 10. ) ) # Vertical
print( 123., 50., 456., 50. , do_640x480( 123., 50., 456., 50. ) ) # Horizontal
print( 10., 50., 450, 450., do_640x480( 10., 50., 450, 450.) )
print( 10., 5., 630, 300., do_640x480( 10., 5., 630, 300.) )
print( 10., 300., 530, 5., do_640x480( 10., 300., 530, 5.) )
print( 10., 5., 500, 400., do_640x480( 10., 5., 500, 400.) )
print( 10., 10.,500, 300., do_640x480( 10., 10., 500, 300.) )


# 247.0 50.0 247.0 10.0 [(247.0, 0.0), (247.0, 480.0)]
#  50.0 456.0 50.0 [(0.0, 50.0), (640.0, 50.0)]
#  50.0 450 450.0 [(483.00000000000006, 480.0), (0.0, 40.90909090909091)]
#  5.0 630 300.0 [(0.0, 0.24193548387096797), (640.0, 304.758064516129)]
#  300.0 530 5.0 [(538.8135593220339, 0.0), (0.0, 305.6730769230769)]
#  5.0 500 400.0 [(3.79746835443038, 0.0), (599.2405063291139, 480.0)]
#  10.0 500 300.0 [(0.0, 4.081632653061225), (640.0, 382.85714285714283)

Возможно, это не то, что вам нужно, но, надеюсь, указывает в правильном направлении.

...