Python OpenCV - отфильтровывает контуры, которых нет рядом - PullRequest
0 голосов
/ 17 июня 2020

Я пытаюсь заставить свою программу показывать мне только центр дороги, отфильтровывая остальное. Я начал с определения ширины и длины каждого прямоугольника в центре дороги и фильтрации остальных.

Проблема: некоторые прямоугольники, которые не находятся в центре дороги, все еще видны, поскольку они находятся внутри ширину и длину других прямоугольников, которые находятся в центре дороги.

Моя идея: запустить for-l oop для каждого показанного прямоугольника, который: Использование небольшого радиуса на одном конце прямоугольник, чтобы увидеть, находится ли другой прямоугольник внутри этого радиуса, если да, покажите этот прямоугольник, -> если нет: используйте другой конец прямоугольника с тем же радиусом и посмотрите, находится ли другой прямоугольник внутри этого радиуса, если да, покажите этот прямоугольник , -> если оба эти утверждения ложны: не показывать прямоугольник, который использовался для поиска другого прямоугольника поблизости.

Моя идея состоит в том, чтобы отфильтровать каждый другой найденный прямоугольник, который не является в центре дороги, так как каждый прямоугольник в центре дороги находится близко друг к другу (имеет не менее 1 рек. клубок рядом). В основном каждый прямоугольник, который не находится в центре дороги, имеет большее расстояние до другого прямоугольника, поэтому я думаю, что могу работать с радиусом или расстоянием здесь, но это только моя идея. Теперь у меня закончились идеи, мне нужна помощь, чтобы заставить его работать, поскольку я не только новичок в OpenCV, но и в Python. Я хочу, чтобы этот код работал не только для этой дороги, но и для других дорог, на которых изображение выглядит так же.

Исходное изображение: Это исходное изображение Изображение с оставленными прямоугольниками: Это изображение с оставленными прямоугольниками

ИЗМЕНИТЬ !: Мне сказали, что я могу работать с scipy.spatial.KDTree для поиска соседей.

это мой код:

import cv2
import numpy as np

# Read image

image = cv2.imread('Resources/StreckeUni.png')

# Grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# show image
cv2.imshow('Gray', gray)
cv2.waitKey(0)

# Adjust Contrass and brightness
alpha = 50  # Kontrast (0-100)
beta = 0  # Helligkeit (0-100)
adjusted = cv2.convertScaleAbs(gray, alpha=alpha, beta=beta)

# Bild anzeigen
cv2.imshow('Contrast', adjusted)
cv2.waitKey(0)

#  find Canny Edges
edged = cv2.Canny(adjusted, 30, 200)

# Use Blur
blur = cv2.GaussianBlur(edged, (3, 3), 0)

# find Conturs
contours, hierarchy = cv2.findContours(blur, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

# show img
cv2.imshow('Canny Edges', blur)
cv2.waitKey(0)

# show number of contours
print("Anzahl der Konturen = " + str(len(contours)))

# draw rectangles
for cnt in contours:
    rect = cv2.minAreaRect(cnt)
    box = cv2.boxPoints(rect)
    box = np.int0(box)

    if rect[1][0] > rect[1][1]:
        laenge = rect[1][0]
        breite = rect[1][1]
    else:
        laenge = rect[1][1]
        breite = rect[1][0]

    if 13.9 < laenge < 25.1 and 3.2 < breite < 7.7:
        cv2.drawContours(image, [box], -1, (0, 255, 0), 1)

# show final pic
cv2.imshow('Rectangles', image)
cv2.waitKey(0)
cv2.destroyAllWindows()

Ответы [ 2 ]

0 голосов
/ 24 июня 2020

Я потратил некоторое время, пытаясь использовать обнаруженные вами прямоугольники для центральной линии (со странным шумом других смещенных от центра), чтобы добраться до последовательности вокруг дорожки.

Я начал с небольшой настройки вашего кода чтобы сохранить обнаруженные прямоугольники, чтобы нормализовать их так, чтобы они всегда были шире, чем высота, и сохранить в файл json

Затем я написал код, чтобы взять этот файл json и соединить прямоугольники.

Я подумал об использовании, например, kdtree для поиска ближайших соседей, но это не так просто, потому что есть пробелы, поэтому соединение не всегда с двумя ближайшими соседями. Вместо этого я попытался найти ближайшего соседа в направлении «положительное» в направлении прямоугольника и «отрицательное» - в противоположном направлении.

Три фазы обработки:

Первая фаза - это просто вычислить центр тонких концов - будет использовать их как сегмент линии для параметрических c линейных расчетов пересечения.

Вторая фаза проходит через все сегменты, пытаясь найти наиболее соединенных соседей - здесь используются угол и направление каждого прямоугольника, чтобы рассчитать расстояние по этим углам от сфокусированного прямоугольника до всех других прямоугольников, отклоняя те, которые находятся под слишком крутым углом, и выбирая ближайшие в каждом направлении - я попробовал метри c, рассчитанный из длину пути и угол, выберите минимум для положительного / отрицательного направлений. Сложности с этим заключались в том, что обнаруженные прямоугольники немного дрожали, а некоторые из них параллельны, поэтому здесь и там есть небольшая выдумка, чтобы попытаться устранить неоднозначность (в частности, установлен порог деноминации 30, чтобы заставить это изображение работать, вам может потребоваться настройка это. Если бы изображение было с более высоким разрешением, это, вероятно, было бы проще. Logi c пересечения является наиболее сложной частью. Обнаруженные прямоугольники расположены сверху вниз изображения, и их направление может быть любым, поэтому пересечение имеет Чтобы справиться с этим. Также, когда взаимодействия находятся внутри сегмента линии, который требует особой обработки, потому что не так очевидно, как вычислить длину пути и разницу углов между ними.

Этот поиск ближайших соседей использует грубую силу поиск по всем остальным - он работает достаточно быстро, чтобы не было причин пытаться оптимизировать, сравнивая только с «ближайшими» прямоугольниками.

Поиск положительных / отрицательных соседей будет успешным y мостовидные зазоры - если бы рядом с этими зазорами были прямоугольники шума, которые могли бы вызвать проблемы, но, к счастью, это не так на вашем изображении :-) Моя идея с metri c состояла в том, чтобы попробовать и предпочесть соединения под меньшими углами, чтобы противостоять шум - ваше изображение на самом деле не проявляет этого.

Пример изображения, наложенного со всеми соединениями, - это первое изображение ниже.

Третья фаза, теперь все положительные / отрицательные связи известны: go через последовательность построения. Если один узел имеет положительное или отрицательное соединение с другим, он «соединяется», если этот другой узел имеет обратное положительное или отрицательное соединение. Принятие только взаимных соединений означает, что выбросы отклоняются - они становятся последовательностями из одного прямоугольника. Обратите внимание на то, что соседние прямоугольники могут быть действительными в противоположных направлениях, поэтому, например, положительное соединение с другим узлом может быть действительным как положительное, так и отрицательное соединение от этого узла.

Поскольку начальный узел может (надеюсь, имеет) иметь оба Положительные и отрицательные соединения, я держу стек соединений, чтобы проверить. Положительное соединение начального узла сначала помещается в стек и снимается только после того, как отрицательная сторона не может больше подключаться, затем оно вставляется в начало последовательности - это обрабатывает, где нет подключенного l oop, поэтому последовательность все еще верна.

Затем он показывает вам связанные последовательности :-) См. второе изображение ниже.

Извините, код не совсем доработан / красив, но он работает для этого изображения - мне будет интересно узнать, работает ли оно с другими изображениями дорожек.

Закодировано с использованием Python 3.8.3 и opencv 4.2 в Windows / AMD64

import cv2
import numpy as np
import json
import scipy.spatial
import math

# set to true to produce copious debugging printout while trying to connect
DEBUG = False
# set to true to display image after each iteration of trying to connect
STEP = False
# the image to draw over
TRACK = 'track_ol.png'

def dist(x1,y1,x2,y2):
    return math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
    
# normalise ang to +/-pi
def normalise(ang):
    while ang<-math.pi:
        ang += 2.0*math.pi
    while ang>math.pi:
        ang -= 2.0*math.pi
    return ang

# returns the parametric distance of the intersection of l1 and l2 in terms of l1
def intersect(l1,l2):
    if DEBUG:
        print( f"{l1=}" )
        print( f"{l2=}" )
    x1,y1=l1[0][0],l1[0][1]
    x2,y2=l1[1][0],l1[1][1]
    x3,y3=l2[0][0],l2[0][1]
    x4,y4=l2[1][0],l2[1][1]
    if DEBUG:
        print( f"{x1=} {y1=}" )
        print( f"{x2=} {y2=}" )
        print( f"{x3=} {y3=}" )
        print( f"{x4=} {y4=}" )
    denom = (x1-x2)*(y3-y4)-(y1-y2)*(x3-x4)
    xc1,yc1=(x1+x2)/2.0,(y1+y2)/2.0
    xc2,yc2=(x3+x4)/2.0,(y3+y4)/2.0
    if DEBUG:
        print( f"{denom=}" )
    if abs(denom)<30.0: # this is a bit of a fudge - basically prefer finding parallel lines to slighly divergent ones
        # parallel
        # work out distance between the parallel lines https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line
        dist1 = abs((y2-y1)*x3-(x2-x1)*y3+x2*y1-y2*x1)/math.sqrt(dist(x1,y1,x2,y2))
        if DEBUG:
            print( f"{dist1=}" )
        if dist1>30.0:
            if DEBUG:
                print( f"Parallel rejected dist {dist1=}" )
            return None,None
        # work out the centres of the line joining centres of l1 and l2 - going to use the line joining these centres
        intx,inty = (xc1+xc2)/2.0, (yc1+yc2)/2.0        # and if angle of intersection would be too greate
        pathlength = dist(xc1,yc1,xc2,yc2)
#        t = dist(xc1,yc1,intx,inty)/dist(x1,y1,x2,y2)
#        u = -dist(xc2,yc2,intx,inty)/dist(x1,y1,x2,y2)
        # choose the x or y which is most different
        if abs(y2-y1)>abs(x2-x1):
            t = (inty-y1)/(y2-y1)
        else:
            t = (intx-x1)/(x2-x1)
        if abs(y4-y3)>abs(x4-x3):
            u = (inty-y3)/(y4-y3)
        else:
            u = (intx-x3)/(x4-x3)
        ang1 = math.atan2(y2-y1,x2-x1)
        ang2 = math.atan2(yc2-yc1,xc2-xc1)
        # choose the smaller change
        ang = normalise(ang2-ang1)
        if abs(ang)>0.5*math.pi:
            pathlength = -pathlength
            ang = normalise(math.pi-ang)
            
        if DEBUG:
            print( f"Parallel {xc1=} {yc1=} {xc2=} {yc2=}" )
            print( f"Parallel {intx=} {inty=}" )
            print( f"Parallel {pathlength} {t=} {u=} {ang=} {ang1=} {ang2=}" )
        if abs(ang)>0.5*math.pi:
#            print( f"Rejected ang {ang=}" )
            return None,None
#        if abs(ang) >0.5*math.pi:
#            t = 1.0-t
        if DEBUG:
            print( f"Parallel {pathlength} {t=} {u=} {ang=}" )
        return pathlength,ang
        
    # work out the intersection https://en.wikipedia.org/wiki/Line%E2%80%93line_intersection
    t = ((x1-x3)*(y3-y4)-(y1-y3)*(x3-x4))/denom
    u = -((x1-x2)*(y1-y3)-(y1-y2)*(x1-x3))/denom
    intx,inty = x1+t*(x2-x1),y1+t*(y2-y1)
    pathlength = dist(xc1,yc1,intx,inty)+dist(intx,inty,xc2,yc2)

    if DEBUG:
        print( f"{intx=} {inty=}" )
    # get the raw angle of l1 and l2
    
    # if t is <0, turn ang1 by 180 to point towards the intersection
    ang1 = math.atan2( y2-y1,x2-x1 )
    ang2 = math.atan2( y4-y3,x4-x3 )
    # get the angle of line from centre of l1 to centre of l2
    angc = math.atan2( yc2-yc1,xc2-xc1 )
    # decide if centre l2 is "forwards" (in the direction l1 points) of centre of l1 - used only when there is an intersection within one of them
    # so sign of pathlength can be set correctly
    # MUST do this before normalising ang1 to point to the intersection and ang2 to point away
    if abs(normalise(angc-ang1)) < 0.5*math.pi:
        l1forwards = True
    else:
        l1forwards = False
    if DEBUG:
        print( f"{l1forwards=} {angc=} {ang1=}" )
    # now normalise ang1 to point towards the intersection
    # NOTE if either intersection is within either line, ang1/ang2 normalisation doesn;t matter
    # because the smaller difference angle will be used.
    if t < 0.0:
        ang1 = normalise(ang1+math.pi)
    # we want ang2 going away from the intersection, so it u is positive reverse the angle
    # now normalise ang2 to point away the intersection
    if u > 1.0:
        ang2 = normalise(ang2+math.pi)
    # check for intersection within l1 or l2
    if 0.0 <= t <= 1.0:
        # internal to l1
        if 0.0 <= u <= 1.0:
            # this is internal to both l1 and l2
            raise Exception( "This should never happen because it means the blobs overlap!")
        else:
            # internal only to l1
            # find the smallest angle of intersection
            if abs(normalise(ang2-ang1))<abs(normalise(math.pi-(ang2-ang1))):
                ang = normalise(ang2-ang1)
                if DEBUG:
                    print( "t norev" )
            else:
                ang = normalise(math.pi-(ang2-ang1))
                if DEBUG:
                    print( "t rev" )
            if abs(ang)>0.25*math.pi:
                if DEBUG:
                    print( f"Rejected1 {ang=} {ang1=} {ang2=}" )
                return None,None
            pathlength = pathlength if l1forwards else -pathlength
    else:
        # not internal to l1
        if 0.0 <= u <= 1.0:
            # internal only to l2
            if abs(normalise(ang2-ang1))<abs(normalise(math.pi-(ang2-ang1))):
                ang = normalise(ang2-ang1)
                if DEBUG:
                    print( "u norev" )
            else:
                ang = normalise(math.pi-(ang2-ang1))
                if DEBUG:
                    print( "u-rev" )
            if abs(ang)>0.25*math.pi:
                if DEBUG:
                    print( f"Rejected2 {ang=} {ang1=} {ang2=}" )
                return None,None
            pathlength = pathlength if l1forwards else -pathlength
        else:
            # this is external to both l1 and l2 - use t to decide if forwards or backwards
            ang = normalise(ang2-ang1)
            pathlength = pathlength if t >= 0.0 else -pathlength
        
#    ang = math.atan2(y2-y1,x2-x1)-math.atan2(y4-y3,x4-x3)
    if DEBUG:
        print( f"{pathlength=} {t=} {u=} {ang=} {ang1=} {ang2=}" )
    if abs(ang)>0.5*math.pi:
        if DEBUG:
            print( f"Rejected ang {ang=}" )
        return None,None
    return pathlength,ang
        
#cv2.waitKey(0)
#cv2.destroyAllWindows()

possiblecentres = json.loads(open( "centres.json","r").read() )

# phase 1 - add the x/y coord of each end of the rectangle as the ends of a line segment
for i,candidate in enumerate(possiblecentres):
    candidate.append(0) # usecount    
    xc,yc,dx,dy,angle = candidate[0][0],candidate[0][1],candidate[1][0]/2.0,candidate[1][1]/2.0,candidate[2]*math.pi/180.0
    x1,y1 = xc-dx*math.cos(angle),yc-dx*math.sin(angle)
    x2,y2 = xc+dx*math.cos(angle),yc+dx*math.sin(angle)
    candidate.append(((x1,y1),(x2,y2))) #centre-endpoints

image = cv2.imread(TRACK)

# phase 2 - for each blob, find closest pos/neg blob
for i,candidate in enumerate(possiblecentres):
    posintersect,pospt,posang,len1 = 1e10,None,None,None
    negintersect,negpt,negang,len1 = 1e10,None,None,None
    l1 = candidate[4]
    if DEBUG:
        print( f"\n\n\n===================================\n{i=} {l1=}" )
        print( f"{candidate=}" )
    
    for j,other in enumerate(possiblecentres):
        if i==j:
            continue
        l2 = other[4]
        if DEBUG:
            print( f"\n============\n{j=} {l2=}" )
            print( f"{other=}" )
        
        pathlen,ang = intersect(l1,l2)
        if pathlen is None:
            continue
        metric =pathlen*pathlen*math.exp(abs(ang))
        if metric > 100000000:
            if DEBUG:
                print( f"Rejected metric {metric=}" )
            continue
#        print( f"{pathlen=} {ang=} {metric=}" )
        # find closest intersection in +ve direction
        if pathlen>=0.0 and metric<posintersect:
            posintersect,pospt,posang,len1 = metric,j,ang,pathlen
            if DEBUG:
                print( "POS updated")
        if pathlen<0.0 and metric<negintersect:
            negintersect,negpt,negang,len1 = metric,j,ang,pathlen
            if DEBUG:
                print( "NEG updated")

    if DEBUG:
        print( i,candidate,posintersect,pospt,posang,negintersect,negpt,negang )
    print( f"{i=} {pospt=} {negpt=}" )
#    foundconnections[i] = 0
    possiblecentres[i].append(((posintersect,pospt,posang,len1),(negintersect,negpt,negang,len1)))
#    cv2.line(image,(int(candidate[4][0][0]),int(candidate[4][0][1])),(int(candidate[4][1][0]),int(candidate[4][1][1])),(255,255,255))
    if STEP:
        image = cv2.imread(TRACK)
    thisrect = (candidate[0],candidate[1],candidate[2])
    box = cv2.boxPoints(thisrect)
    box = np.int0(box)
    cv2.drawContours(image, [box], -1, (255, 255, 255), 1)

    if pospt is not None:
        cv2.line(image,(int(candidate[0][0]),int(candidate[0][1])),(int(possiblecentres[pospt][0][0]),int(possiblecentres[pospt][0][1])),(255,0,0))
    if negpt is not None:
        cv2.line(image,(int(candidate[0][0]),int(candidate[0][1])),(int(possiblecentres[negpt][0][0]),int(possiblecentres[negpt][0][1])),(0,255,0))
    if STEP:
        cv2.imshow('Rectangles', image)
        if cv2.waitKey(0)==113:
            break

# finally phase 3 - for each blob's connections, match up with another blob that reverses that connection
# This eliminates odd blobs that aren't recipricolly connected to the things they connect to
sequences = [] # each entry in this list is a sequence of indexes into possiblecentres
todos = list(range(len(possiblecentres)))
stacktochecks = []  # this should never have more than two items on it - and the first one is only removed once the circuit is complete
while True:
    if stacktochecks:
        print( f"{stacktochecks=}" )
        print( f"{sequences[-1]=}" )
        # continued sequence
        startpt = stacktochecks.pop()
        if stacktochecks:
            # we are on the outbound leg - for a fully-connected start point there's a non-empty stack which is the other connection from that starting element
            sequences[-1].append(startpt)
        else:
            # stack is empty so insert new points at the start of this sequence - this ensures the sequence on the list is consecutive even if the outgoing sequence didn't come back here
            sequences[-1].insert(0,startpt)
        print( f"continuing from {startpt=}" )
    else:
        if sequences:
            print( f"FINISHED {sequences[-1]=}" )
        if len(todos)==0:
            break
        # new sequence
        startpt = todos.pop(0)
        sequences.append([startpt])
        print( f"starting from {startpt}" )
    nextpos = possiblecentres[startpt][-1][0][1]
    nextneg = possiblecentres[startpt][-1][1][1]
    print( f"{nextpos=} {nextneg=}" )
    if nextpos is not None:
        if nextpos in todos:
            # hasn't been used yet
            if startpt == possiblecentres[nextpos][-1][0][1]:
                print( f"pos match1 pushing {nextpos}" )
                stacktochecks.append(nextpos)
                todos.remove(nextpos)
            elif startpt == possiblecentres[nextpos][-1][1][1]:
                print( f"pos match2 pushing {nextpos}" )
                stacktochecks.append(nextpos)        
                todos.remove(nextpos)
            else:
                #
                todos.remove(nextpos)
                pass
    #            burp3
        else:
            if nextpos in sequences[-1]:
                # already in sequences, so we closed the loop!
    #            burp1
                pass
            else:
                # not in current sequence and not in todos - that's weird, but end the sequence
                pass
#                burp2
    #            pass
    if nextneg is not None:
        if nextneg in todos:
            # hasn't been used yet
            if startpt == possiblecentres[nextneg][-1][0][1]:
                print( f"neg match1 pushing {nextneg}" )
                stacktochecks.append(nextneg)
                todos.remove(nextneg)
            elif startpt == possiblecentres[nextneg][-1][1][1]:
                print( f"neg match2 pushing {nextneg}" )
                stacktochecks.append(nextneg)        
                todos.remove(nextneg)
            else:
                #
                todos.remove(nextneg)
                pass
    #            burp4
        else:
            if nextneg in sequences[-1]:
                # already in sequences, so we closed the loop!
    #            burp5
                pass
            else:
                # not in current sequence and not in todos - that's weird, but end the sequence
                pass
#                burp6
    #            pass

print( f"{sequences=}")

image = cv2.imread(TRACK)

# now display the sequences, and put circles on the startpoints
for i,seq in enumerate(sequences):
    for j,node in enumerate(seq):
        thisnode = possiblecentres[node]
        thisrect = (thisnode[0],thisnode[1],thisnode[2])
        box = cv2.boxPoints(thisrect)
        box = np.int0(box)
        cv2.drawContours(image, [box], -1, (255, 255, 0), 1)
        thisx,thisy = thisnode[0][0],thisnode[0][1]
        if j == 0:
            cv2.circle(image,(int(thisx),int(thisy)),10,(0,127,127),2)
            firstx,firsty = thisx,thisy
        if j > 0:
            # draw a thick line to previous
            cv2.line(image,(int(lastx),int(lasty)),(int(thisx),int(thisy)),(127,127,127),5)
        if j!=0 and j+1==len(seq):
            # this is the connection back to the start
            cv2.line(image,(int(firstx),int(firsty)),(int(thisx),int(thisy)),(127,127,127),5)
        
        lastx,lasty = thisx,thisy

cv2.imshow('Sequences', image)
cv2.waitKey(0)

Вещи, которые, вероятно, можно было бы улучшить, - это привести в порядок расчет пересечения, например, изменить мою выдумку на просто считайте два отрезка параллельными, используя угол, под которым они находятся, а не значение denom. Теперь есть известный хороший ответ, который вы можете использовать для проверки того, что изменения ничего не ломают - может быть довольно сложно обнаружить аномалии в обнаружении соседей, конечно, непросто на полном изображении, если показаны все соединения, поэтому мне пришлось сделать шаг через обнаружение и сосредоточиться на обнаруженных соединениях для определенного прямоугольника, чтобы понять, почему соединение перескакивает через соседа, чтобы исправить лог c.

Промежуточное изображение после фазы 2, показывающее все соединения - синее соединение - положительный, зеленый - отрицательный. ПРИМЕЧАНИЕ многие соединения накладываются друг на друга, поэтому, особенно между соседними прямоугольниками, вы видите только тот, который нарисован последним.

enter image description here

Resulting image (with a circle over each start point):

введите описание изображения здесь

Вот длинная последовательность дорожки - числа являются индексами в центрах. json массив, прямоугольник 0 находится в самой нижней точке изображения (визуально), который связан с 1 и 18 может быть на один или два пикселя выше.

[18, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 19, 20, 21, 22, 12, 13, 23, 30, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 72, 88, 93, 94, 95, 97, 99, 102, 104, 105, 119, 124, 143, 144, 145, 147, 149, 152, 159, 163, 168, 172, 175, 177, 178, 176, 174, 169, 167, 165, 162, 160, 156, 155, 153, 154, 157, 161, 164, 170, 180, 182, 184, 186, 189, 191, 194, 193, 192, 190, 188, 185, 183, 181, 173, 166, 158, 151, 148, 146, 142, 135, 131, 127, 123, 120, 112, 111, 110, 108, 109, 114, 116, 117, 121, 125, 128, 132, 134, 137, 139, 140, 141, 138, 136, 133, 130, 126, 122, 118, 113, 107, 106, 103, 101, 98, 96, 87, 68, 60, 59, 61, 63, 62, 64, 65, 67, 66, 70, 71, 73, 75, 74, 76, 78, 77, 79, 81, 80, 82, 85, 84, 86, 90, 89, 92, 91, 83, 69, 58, 56, 54, 52, 50, 48, 46, 44, 42, 40, 38, 36, 34, 32, 31, 28, 29, 24, 25, 26, 27, 14, 15, 16, 17]

В следующий раз я настрою автомобильная трасса слотом scalextri c Попробую сфотографировать, посмотрю, работает ли этот код: -)

0 голосов
/ 18 июня 2020

Я публикую как комментарий, потому что точно не знаю, что с этим делать. Я нашел этот фрагмент кода и подумал, что он должен работать с моим:

    def get_laser_points(image):
        """
        Return centers of laser-points found in the given image as list of coordinate-tuples.
        """
        # get the contour areas for the steppers
        mask = cv2.inRange(image, whiteLower, whiteUpper)
        contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        # compute the center of the contour areas
        centroids = []
        for contour in contours:
            m = cv2.moments(contour)
            # avoid division by zero error!
            if m['m00'] != 0:
                cx = int(m['m10'] / m['m00'])
                cy = int(m['m01'] / m['m00'])
                centroids.append((cx, cy))
                # following line manages sorting the found contours from left to right, sorting
                # first tuple value (x coordinate) ascending
                centroids = sorted(centroids)
        return centroids

Теперь, когда у меня есть какой-то центр для каждого контура, что мне делать?

...