Python3實現燈光檢測

實際情況

目前無論基於電信號還是光信號的通信,都無法避免的有一定概率會發生“丟包‘’,這是因爲光或者電信號傳輸都依賴“媒介”,而"媒介"的實際狀態我們無法把控。比如CAN總線通信,是在一對導線上傳遞的差分電壓信號。2.4G的無線,是在空間上傳遞的電磁波信號。而"媒介"的狀態,比如CAN通信導線上的特徵阻抗或許我們認爲還能控制,但是導線周圍的電磁環境呢?2.4G無線傳輸就更不必說了,空間上的一堵牆,一塊鐵板,就能明顯的影響無線傳輸。
擺在我們面前的,就是我們如何證明我們的通信,是穩定的呢?
你的想法或許是這樣:我們需要將每一次通信的“發起端”發起的時間和"結束端"接收的時間都記錄下來,一一對應即可。這種想法沒有問題,我們可以將發起端設備和結束端設備將記錄時間的Log都統一輸出到一個地方做記錄統計,但是這種方法成本比較高。所以我們可以針對具體的產品,去做這個測試。
我手上的設備,通信的發起端設備可以通過通信的協議控制結束端設備上燈的亮滅,於是我們寫一個測試程序,讓發起端設備按一定次數控制終端亮滅(舉個例子一萬次),我們則根據接收端實際亮滅的的次數來判斷通信的丟包率。而這種測試方式,需要一個能實現燈光檢測的圖像識別軟件(判斷燈亮滅的狀態)。用Python3來利用筆記本上的攝像頭來實現起來代碼不超過150行。

Python3代碼

找個帶有攝像頭的筆記本,安裝PyCharm,你可以理解它爲Python的IDE。爲了實現光電的圖像識別,我們需要導入CV2以及numpy兩個Package。打開當前的工程的設置,點開Project Interpreter,點擊右側的加號,增加這兩個庫。
在這裏插入圖片描述
代碼將攝像頭捕捉的圖像輸出到一個窗口上,我們重寫窗口有鼠標點下的事件函數,記錄當前鼠標的座標信息。
我們在捕捉到圖像的時候,如果有記錄的座標信息,則在座標周圍畫一個黑色圓圈,表示我們監控這個圓圈內的燈的亮滅。然後我們這個圓圈內部的RGB值的信息來判斷是否亮燈,並輸出記錄爲.CSV文件,具體代碼如下。(代碼寫的C風格比較重,如果熟悉Python的人應該能寫的更短更好看)

import cv2
import time
import numpy
from numpy import *
import datetime
import numpy as np

CirclLightNumber=12

MousClickNumber=0
MousClickTable=numpy.zeros(shape=(CirclLightNumber,2)) #第一個參數爲點的

LightState=[0,0,0,0,0,0,0,0,0,0,0,0]

LightUpNumber=[0,0,0,0,0,0,0,0,0,0,0,0]
LightDownNumber=[0,0,0,0,0,0,0,0,0,0,0,0]
AverageLight=[0,0,0,0,0,0,0,0,0,0,0,0]

ALightUpNumber=0
ALightDownNumber=0
ALightState=0
ALightArrSta=[[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0],[0,0,0]]
ALightUpN=0
ALightDownN=0

WhLoopIndex=0

def on_EVENT_LBUTTONDOWN(event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        global MousClickNumber
        MousClickTable[MousClickNumber] =[y, x]
        MousClickNumber=MousClickNumber+1
        if MousClickNumber>(CirclLightNumber-1):#循環頭
            MousClickNumber=0

cap = cv2.VideoCapture(0)

cv2.namedWindow("image")
cv2.setMouseCallback("image", on_EVENT_LBUTTONDOWN)

time_creat = datetime.datetime.now().strftime('%H%M%S.csv')

fout = open(time_creat,encoding='utf8',mode='w')

content = "%s,%s,%s\n" % ("Index","State", "Time,")
fout.write(content)


while(1):
    # get a frame and show
    ret, frame = cap.read()
    WhLoopIndex=WhLoopIndex+1
    if WhLoopIndex >2:
        WhLoopIndex=0

    for index  in range(MousClickNumber):
        kin=int(MousClickTable[index][0])
        lin=int(MousClickTable[index][1])
        '''
        xy = "%d,%d,%d" % (frame[kin, lin, 0], frame[kin,lin , 1], frame[kin, lin, 2])
        cv2.putText(frame, xy, (lin, kin), cv2.FONT_HERSHEY_PLAIN,
                    1.0, (0, 0, 0), thickness=1)
        '''
        #獲取採樣點周圍5個點的亮度值
        xy = "%d|" % (index)
        AverageLight[0]=(int(frame[kin, lin, 0])+int(frame[kin, lin, 1])+int(frame[kin, lin, 2]))/3
        AverageLight[1]= (int(frame[(kin+1), lin, 0]) + int(frame[(kin+1), lin, 1]) + int(frame[(kin+1), lin, 2])) / 3
        AverageLight[2]= (int(frame[(kin), (lin+1), 0]) + int(frame[(kin), (lin+1), 1]) + int(frame[(kin), (lin+1), 2])) / 3
        AverageLight[3]= (int(frame[(kin-1), lin, 0]) + int(frame[(kin-1), lin, 1]) + int(frame[(kin-1), lin, 2])) / 3
        AverageLight[4] = (int(frame[(kin), (lin-1), 0]) +int(frame[(kin), (lin-1), 1]) + int(frame[(kin), (lin-1), 2])) / 3

        ALightUpNumber=0;
        ALightDownNumber=0;
        ALightUpN=0;
        ALightDownN=0;

        #5個點中 >220爲燈亮 <=則爲燈滅
        for indexIn in range(5):
            if AverageLight[indexIn] >  220:
                ALightUpNumber=ALightUpNumber+1
            else:
                ALightDownNumber=ALightDownNumber+1
        #燈亮的次數爲3~5,則記錄此次循環的狀態爲燈亮
        if ALightUpNumber>2:
            ALightArrSta[index][WhLoopIndex]=250
        else:
            ALightArrSta[index][WhLoopIndex]=150

        # 針對這個LightBow,3個歷史記錄的點中 >220爲燈亮 <=則爲燈滅
        for indexIn in range(3):
            if ALightArrSta[index][indexIn] > 220:
                ALightUpN =ALightUpN+1
            else:
                ALightDownN = ALightDownN + 1

        # 在歷史中,有兩次即爲燈亮
        if ALightUpN>1:
            ALightState=250
        else:
            ALightState=150

        if ALightState>220 and LightState[index]==0:#檢測到燈亮
            #xyz = "%d,%d,%d" % (frame[kin, lin, 0], frame[kin, lin, 1], frame[kin, lin, 2])
            #print(xyz)
            LightState[index]=1
            time_now = datetime.datetime.now().strftime('%H:%M:%S.%f')
            print("%d,%d,%s" % (index,1,time_now))
            content = "%d,%d,%s\n" % (index, 1, time_now)
            fout.write(content)
            LightUpNumber[index]=LightUpNumber[index]+1
        if ALightState <220 and LightState[index] == 1:#檢測到燈滅
            #xyz = "%d,%d,%d" % (frame[kin, lin, 0], frame[kin, lin, 1], frame[kin, lin, 2])
            #print(xyz)
            LightState[index] = 0
            time_now = datetime.datetime.now().strftime('%H:%M:%S.%f')
            #print("%d,%d,%s" % (index,0,time_now))
            content="%d,%d,%s\n" % (index, 0, time_now)
            fout.write(content)
            LightDownNumber[index] = LightDownNumber[index] + 1
            #print(LightDownNumber[index] )
        cv2.circle(frame, (lin, kin), 10, (50, 50, 50), thickness=2)
        cv2.putText(frame, xy, (lin,(kin-10)), cv2.FONT_HERSHEY_PLAIN,
                          1.0, (0, 0, 0), thickness=2)


    cv2.imshow("image", frame)
    #h, w, _ = frame.shape  # 返回height,width,以及通道數,不用所以省略掉
    #print('行數%d,列數%d' % (h, w))

    time.sleep(0.1)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
fout.close()

fout = open("Result"+time_creat,encoding='utf8',mode='w')
#fout.seek(15,0)
fout.write("Index,LightUpUmber,LightDownUmber\n")
for index  in range(MousClickNumber):
    ReContent = "%d,%d,%d\n" % ((index),LightUpNumber[index], LightDownNumber[index])
    fout.write(ReContent)
fout.close()
cv2.destroyAllWindows()

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章