Python openCV ile ışık takibi

Merhabalar bir şirkette staj yapııyorum ve geliştirmem için verilen projeye şu şekilde başladım, amacım telefon flaşı veya bir ışığı yakalayıp center point ’ in koordinatlarını yazdırmak, aşağıdaki gibi bir başlangıç yaptım ve geliştirme konusunda fikirlerinizi almak istiyorum. Yardımcı olursanız sevinirim.
iki de problemim var. birincisi tek detect yapıyorum ve daha parlak bir şey örneğin gün ışığı olduğunda orayı alıyor sadece ben tüm parlak noktaları yakalamak istiyorum, ikincisi center koordinatını almak istiyorum.

import cv2
cap = cv2.VideoCapture(0)
while True:
    _, frame = cap.read()

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (9, 9), 0)

    (minVal, maxVal, minLoc, maxLoc) = cv2.minMaxLoc(blur)

    hi, threshold = cv2.threshold(blur, maxVal - 20, 230, cv2.THRESH_BINARY)
    thr = threshold.copy()

    cv2.resize(thr, (300, 300))
    edged = cv2.Canny(threshold, 50, 150)
    lightcontours, hierarchy = cv2.findContours(edged, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

    circles = cv2.HoughCircles(threshold, cv2.HOUGH_GRADIENT, 1.0, 20,
                               param1=10,
                               param2=15,
                               minRadius=20,
                               maxRadius=100, )
    if len(lightcontours) and circles is not None:
        maxcontour = max(lightcontours, key=cv2.contourArea)
        if cv2.contourArea(maxcontour):
            (x, final_y), radius = cv2.minEnclosingCircle(maxcontour)
            cv2.circle(frame, (int(x), int(final_y)), int(radius), (0, 255, 0), 4)
            cv2.rectangle(frame, (int(x) - 5, int(final_y) - 5), (int(x) + 5, int(final_y) + 5), (0, 128, 255), -1)
    cv2.imshow('light', thr)
    cv2.imshow('frame', frame)
    key = cv2.waitKey(5) & 0xFF
    if key == ord('q'):
        break
cap.release()
cv2.destroyAllWindows()

Bunun için threshold yaparken kullandığın maxVal - 20 değeri yerine maxVal - 1 yazabilirsin.

Merkez noktayı zaten bulmuşsun.

x ve final_y senin merkez noktalarının koordinatları.

Yazdığın programa gelecek olursak ışık yayılırken kamerada tamamen daire şekil oluşturmaz. Bu yüzden HoughCircle tekniği ile kamerada daire oluşturmayan ışık görüntüsünü program tamamıyla doğru şekilde algılayamaz.

Doğru şekilde daireleri algıyamadığı için burada kullandığın koşulda da daire bulunmadığı her kare için herhangi bir değer dönderemeyecek. Eğer sadece;

şu şekilde kullanırsan her karede ışık kaynağı hakkında daha detaylı çalışabilirsin.

Kullandığın teknik tuhaf bir teknik. Bu program ile sadece beyaz veye açık renkli parlak ışıkları algılayabilirsin. Aynı karede farklı renkte ışık kaynakları olursa doğru sonucu vermez. Eğer ışık kaynağı dairesel değil de görüntüde farklı geometrik şeklin görüntüsünü verirse (örneğin ışıklı kare bir levha) HoughCircle ile daire aradığından asla ışık kaynağını bulamaz. Eğer daire aramadan en büyük kontür değerine sahip nesneyi alırsa bu kez de onu kaplayan en küçük cember içerisinde gösterilir ve yanlış gösterim olur.

Işık kaynağını yakalamak için yetersiz bir program olduğunu düşünüyorum. Başlangıcını değiştirmeni öneririm.

1 Beğeni

Öncelikle gecikme için özür dilerim, yanıtınızı görmemişim, aslında şuan bayağı ilerledim projede pyqt ile destekledim modbus server ile yayın yapıyorum ve söylediğiniz konularda halâ problem yaşıyorum, söylediğiniz gibi tekniğimin yanlış olduğunun farkına vardım, ışık kaynağını kare vermeye başladılar ve ışık kaynağını bulamıyorum, hangi tekniği kullanmam gerekir veya nasıl iyileştirme yapabilirim, yardımcı olursanız çok sevinirim.

import sys
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import cv2
from pyModbusTCP.server import ModbusServer, DataBank
from time import sleep

server = ModbusServer("192.168.1.11", 502, no_block=True)
server.start()
state = [0]
yy1 = 50
yy2 = 400
circle_y = 0
circle_x = 0
radius_1 = 0
class MainWindow(QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.VBL = QVBoxLayout()

        self.FeedLabel = QLabel()
        self.VBL.addWidget(self.FeedLabel)

        self.CancelBTN = QPushButton("Cancel")
        self.CancelBTN.clicked.connect(self.CancelFeed)
        self.VBL.addWidget(self.CancelBTN)


        self.up1 = QPushButton("Up 1")
        self.up1.clicked.connect(self.Up1Feed)
        self.VBL.addWidget(self.up1)

        self.dwn1 = QPushButton("Down 1")
        self.dwn1.clicked.connect(self.Dwn1Feed)
        self.VBL.addWidget(self.dwn1)

        self.up2 = QPushButton("Up 2")
        self.up2.clicked.connect(self.Up2Feed)
        self.VBL.addWidget(self.up2)

        self.dwn2 = QPushButton("Down 2")
        self.dwn2.clicked.connect(self.Dwn2Feed)
        self.VBL.addWidget(self.dwn2)


        self.Worker1 = Worker1()

        self.Worker1.start()
        self.Worker1.ImageUpdate.connect(self.ImageUpdateSlot)
        self.setLayout(self.VBL)

    def ImageUpdateSlot(self, Image):
        self.FeedLabel.setPixmap(QPixmap.fromImage(Image))

    def CancelFeed(self):
        self.Worker1.stop()

    def Up1Feed(self):
        global yy1
        yy1 -= 10

    def Dwn1Feed(self):
        global yy1
        yy1 += 10

    def Up2Feed(self):
        global yy2
        yy2 -= 10

    def Dwn2Feed(self):
        global yy2
        yy2 += 10

class Worker1(QThread):
    ImageUpdate = pyqtSignal(QImage)
    def run(self):
        global yy1
        global yy2
        self.ThreadActive = True
        cap = cv2.VideoCapture('rtsp://admin:@192.168.1.48/1')
        while self.ThreadActive:
            _, frame = cap.read()
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            blur = cv2.GaussianBlur(gray, (11, 11), 0)

            (minVal, maxVal, minLoc, maxLoc) = cv2.minMaxLoc(blur)

            hi, threshold = cv2.threshold(blur, maxVal-5, 255, cv2.THRESH_BINARY)
            thr = threshold.copy()

            cv2.resize(thr, (300, 300))
            edged = cv2.Canny(threshold, 50, 150)
            lightcontours, hierarchy = cv2.findContours(edged, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

            circles = cv2.HoughCircles(threshold, cv2.HOUGH_GRADIENT, 1.0, 20,
                                       param1=10,
                                       param2=15,
                                       minRadius=5,
                                       maxRadius=200, )
            if len(lightcontours) and circles is not None:
                maxcontour = max(lightcontours, key=cv2.contourArea)
                if cv2.contourArea(maxcontour):
                    global circle_y
                    global circle_x
                    global radius_1
                    (x, final_y), radius = cv2.minEnclosingCircle(maxcontour)
                    circle_y = final_y
                    circle_x = x
                    radius_1 = radius
                    cv2.circle(frame, (int(x), int(final_y)), int(radius), (0, 255, 0), 4)
                    cv2.rectangle(frame, (int(x) - 5, int(final_y) - 5), (int(x) + 5, int(final_y) + 5), (0, 128, 255),
                                  -1)
                    cv2.putText(frame, "{},{}".format(int(x), int(final_y)), (20, 40), cv2.FONT_HERSHEY_COMPLEX, 1,
                                (0, 0, 255), 2, cv2.LINE_4,)
                    cv2.putText(frame, "%{}".format(self.PercentCalculate()), (400, 40), cv2.FONT_HERSHEY_COMPLEX, 1, (255, 0, 0), 2, cv2.LINE_4)
                    a = int(circle_x + radius)
                    b = int(circle_x - radius)
                    c = int(circle_y - radius)
                    cv2.line(frame, (a, c), (b, c), (0, 0, 255), 2)

            cv2.line(frame, (0, yy1), (640, yy1), (0, 0, 255), 2)
            cv2.line(frame, (0, yy2), (640, yy2), (0, 0, 255), 2)

            DataBank.set_words(0, [int(self.PercentCalculate())])
            DataBank.set_words(1, [int(yy1)])
            DataBank.set_words(2, [int(yy2)])

            Image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            ConvertToQtFormat = QImage(Image.data, Image.shape[1], Image.shape[0], QImage.Format_RGB888)
            Pic = ConvertToQtFormat.scaled(640, 480, Qt.KeepAspectRatio)
            self.ImageUpdate.emit(Pic)

    def PercentCalculate(self):
        fark = yy2 - yy1
        cizgi_uzakligi = yy2 - circle_y+(radius_1)
        percent = 100*cizgi_uzakligi/fark
        return percent

    def stop(self):
        server.stop()
        self.ThreadActive = False
        self.quit()


if __name__ == "__main__":
    App = QApplication(sys.argv)
    Root = MainWindow()
    Root.show()
    sys.exit(App.exec())

Kendi haar cascade’ini oluştarabilirsin. Önce kendi örneklerinle/verilerinle sınıflandırıcıyı eğitir sonra nesneyi tespit edebilirsin. Haar cascade oluştururken kullanacağın verileri senin hazırlamanı ve verilere threshhold uygulayıp eğitime dahil etmeni öneririm. Bu sayede karşılaştırma yapacağın kısımda da elindeki görüntüye threshhold uygularsan daha doğru sonuç vereceğine inanıyorum. Eğer haar cascade oluşturmak istemiyorsan veya proje yönetecileri buna izin vermiyorsa doğru sonuca ulaşmak için zorlanmaya devam edeceksin.
Eğer zorlanmaya mecbursan doğru sonuca ulaşman için engelleri yok etmeni öneririm. Yani eğer arka plan engel oluşturuyorsa engel oluşturmayan bir ortam seçmelisin, eğer ışık kaynağı kare ise görüntüde kare/dörtgen arayan fonksiyonu kullanmalısın, farklı renkli ışık kaynakları kullanılıyorsa her biri için ayrı ayrı karşılaştırma yapmalısın ve test aşamasında da bunlara özen göstermelisin ki hata vermesin. Kesinlikle kaliteli bir program olmayacak ama proje yöneticilerinin isteğini karşılıyorsa kabul göreceklerdir.

3 Beğeni

Yorum ve tavsiyeleriniz için çok teşekkür ederim, kendi haar cascade’imi oluşturmayı deneyebilirim, söylediğiniz gibi çok mantıklı ve iyi sonuç verebilir ama haar cascade oluşturma konusunda çok bilgili değilim kendimi o konuda geliştirmem gerekiyor.