У меня есть код, который обнаруживает ЛАЗЕРНЫЙ свет, но я испытываю проблемы при разных условиях освещения. Поэтому я думаю, что смогу решить эту проблему, если добавлю код, который проверяет, является ли этот свет кругом.

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

Я надеюсь, что вы поможете мне с моим кодом.

Вот мой код:

import cv2
import numpy as np

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) convert from bgr to hsv color space

    lower = np.array([0,0,255]) #range of laser light
    upper = np.array([255, 255, 255])

    mask = cv2.inRange(hsv, lower, upper) 
    maskcopy = mask.copy()

    circles = cv2.HoughCircles(maskcopy, cv2.HOUGH_GRADIENT, 1, 500,
                      param1 = 20, param2 = 10,
                      minRadius = 1, maxRadius = 3)
    _,cont,_ = cv2.findContours(maskcopy, cv2.RETR_LIST,
                            cv2.CHAIN_APPROX_SIMPLE)
    if circles is not None:
        circles = np.round(circles[0,:]).astype('int')

        for(x,y,r) in circles:
            cv2.circle(frame, (x,y), r, (0,255,0),4)

    cv2.imshow('mask', mask)
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

Снимок экрана:

enter image description here

0
jomsamago 8 Июн 2018 в 13:38
Используйте HoughCircle из docs.opencv.org/3.1.0/da/d53 /tutorial_py_houghcircles.html
 – 
Akhilesh
8 Июн 2018 в 13:49
Если бы я использовал это, где я должен был бы поместить это в свой код? Потому что какое-то время это было в моем коде. @ Ахилеш
 – 
jomsamago
8 Июн 2018 в 13:51
После maskcopy = mask.copy() вы можете взять копию maskcopy и применить houghcircle этой копии.
 – 
Akhilesh
8 Июн 2018 в 13:58
Я отредактировал свой код там, но я не уверен в значениях параметров. Не возражаете, если вы проверите? :( @ Ахилеш
 – 
jomsamago
8 Июн 2018 в 14:09
Используйте cv :: findContours. Проверьте для каждого контура, содержит ли minEnclosingCircle меньше некоторого относительного количества нулевых пикселей.
 – 
Micka
8 Июн 2018 в 16:43

2 ответа

Однажды я пробовал нечто подобное, и лучшим решением для меня было:

(Я сохранил ваше изображение на свой жесткий диск и сделал образец кода)

import cv2
import math

img = cv2.imread('laser.jpg')
gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(gray_image,100,255,cv2.THRESH_BINARY)
im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
area = sorted(contours, key=cv2.contourArea, reverse=True)
contour = area[0]
(x,y),radius = cv2.minEnclosingCircle(contour)
radius = int(radius)
area = cv2.contourArea(contour)
circ = 4*area/(math.pi*(radius*2)**2)
cv2.drawContours(img, [contour], 0, (0,255,0), 2)
cv2.imshow('img', img)
print(circ)

Итак, идея состоит в том, чтобы найти ваш контур с помощью cv2.findContours (лазерной точки) и окружности, чтобы вы могли получить радиус, затем получить площадь с помощью cv2.contourArea вашего контура и проверить его округлость с помощью формулы circ = 4*area/(math.pi*(radius*2)**2). Идеальный цитрус вернет результат 1. Чем больше он переходит в 0, тем меньше "круговой" ваш контур (на рисунках ниже). Надеюсь, это поможет!

enter image description here

enter image description here

Поэтому ваш код должен быть примерно таким, и он не будет возвращать ошибку (попробовал, и он работает)

import cv2
import numpy as np
import math

cap = cv2.VideoCapture(0)

while True:
    try:
        ret, frame = cap.read()
        hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV) #convert from bgr to hsv color space

        lower = np.array([0,0,255]) #range of laser light
        upper = np.array([255, 255, 255])

        mask = cv2.inRange(hsv, lower, upper) 

        im2, contours, hierarchy = cv2.findContours(mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
        area = sorted(contours, key=cv2.contourArea, reverse=True)
        contour = area[0]
        (x,y),radius = cv2.minEnclosingCircle(contour)
        radius = int(radius)
        area = cv2.contourArea(contour)
        circ = 4*area/(math.pi*(radius*2)**2)
        print(circ)
    except:
        pass

    cv2.imshow('mask', mask)
    cv2.imshow('frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
1
kavko 8 Июн 2018 в 18:14
Я пробовал применить его на видео, но получил массу ошибок :(
 – 
jomsamago
8 Июн 2018 в 17:51
Но я понял.
 – 
jomsamago
8 Июн 2018 в 17:57
Я попробовал, и это сработало ... Я отредактировал и разместил свой код, реализованный в вашем
 – 
kavko
8 Июн 2018 в 18:15
Ничего себе, сэр, я думаю, это может быть решение, которое я искал. БОЛЬШОЕ СПАСИБО!
 – 
jomsamago
8 Июн 2018 в 18:24
Рад, что смог помочь. Ваше здоровье!
 – 
kavko
8 Июн 2018 в 18:26

Я придумал решение с другим подходом.

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

Вот код:

white = np.where(mask>250) # you can also make it == 255
white = np.asarray(white)
minx = min(white[0])
maxx = max(white[0])
miny = min(white[1])
maxy = max(white[1])
radius = int((maxx-minx)/2)
cx = minx + radius
cy = miny + radius
black = mask.copy()
black[:,:]=0
cv2.circle(black, (cy,cx), radius, (255,255,255),-1)
diff = cv2.bitwise_xor(black, mask)
diffPercentage = len(diff>0)/diff.size
print (diffPercentage)

Затем вы должны придумать, какой процентный порог является для вас «одинаковым».

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

import cv2
import numpy as np

cap = cv2.VideoCapture(0)

while True:
    ret, frame = cap.read()
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

    lower = np.array([0,0,255]) #range of laser light
    upper = np.array([255, 255, 255])

    mask = cv2.inRange(hsv, lower, upper) 
    white = np.where(mask>250) # you can also make it == 255
    white = np.asarray(white)
    minx = min(white[0])
    maxx = max(white[0])
    miny = min(white[1])
    maxy = max(white[1])
    radius = int((maxx-minx)/2)
    cx = minx + radius
    cy = miny + radius
    black = mask.copy()
    black[:,:]=0
    cv2.circle(black, (cy,cx), radius, (255,255,255),-1)
    diff = cv2.bitwise_xor(black, mask)
    diffPercentage = len(diff>0)/diff.size
    print (diffPercentage)

    cv2.imshow('mask', mask)
    cvw.imshow('diff', diff)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()
0
Fred Guth 9 Июн 2018 в 21:56
Применимо ли это к видео, сэр? И где я это размещу?
 – 
jomsamago
8 Июн 2018 в 16:26
Да, видео - это просто последовательность изображений. Буду редактировать с видео частью.
 – 
Fred Guth
8 Июн 2018 в 16:35
Спасибо, сэр, но я получаю эту ошибку: "white = np.where (mask [:,:, 0]> 250) # вы также можете сделать это == 255 IndexError: слишком много индексов для массива"
 – 
jomsamago
8 Июн 2018 в 17:07
Я поменял код. попробуй сейчас. Что действительно важно, так это понять идею. Это просто потому, что я не тестировал ваш код с преобразованием hsl и функцией inRange. У меня нет примера вашего ввода, чтобы проверить это.
 – 
Fred Guth
8 Июн 2018 в 20:11
Я все еще получаю сообщение об ошибке «IndexError: слишком много индексов для массива» в white = np.where (mask [:,; 0]> 250)
 – 
jomsamago
9 Июн 2018 в 07:18