ラズパイ4でデジタル時計の「秒」を画像解析する(Python+OpenCV)

「秒」の画像解析状況

 先回の投稿「ラズパイ4で数字を画像認識する(OPEN CV テンプレートマッチング) 」と考え方は同じです。OpenCVのテンプレートマッチング機能を利用して、デジタル目覚し時計の「秒」部を文字列変換するプログラムを作成してみました。
 文字列変換状況の動画を掲載します。

 結果の動画内容は良好と思っています。2文字しか変換していないこともありますが、「秒」の変化に追従しています。
 但し、デジタル時計はもともと薄暗い背景に黒い文字なので、2値化の閾値設定や照明の当て方に少し工夫が必要でした。普通の卓上照明を使いましたが、照らし方によって影が入るなど、単純に明るくすれば良い訳ではないことを理解しました。また、エクセルシートの数字と異なり文字間隔や外枠との隙間が小さいので、検索領域設定や一部の外枠を消去するなどの処理を変更しました。約1時間程度の試行錯誤を経て、動画の様な状態になりました。

テンプレート作成プログラム

 下記の通り、「0」~「9」のテンプレートを作成しました。

 テンプレート作成プログラムです。特定領域の画像を保存してくれます。ファイル保存してくれるだけなので、対象画像を一つづつ処理する必要があります。 

#テンプレート作成
import sys
import cv2
import math
import numpy as np

capture = cv2.VideoCapture(0)

try:
    if capture.isOpened() is False:
        print("カメラを開けませんでした。")
        sys.exit()
    
    X_S0=462
    Y_S0=227
    
    WDT=31
    HGT=56
    
    cntr_top=284
    cntr_lft=10
    
    contours = np.array([[cntr_lft,cntr_top],[cntr_lft,cntr_top+50],[cntr_lft+500,cntr_top+50],[cntr_lft+500,cntr_top]])
   
    while True:
        ret, frame = capture.read()
        #ret, frame = cv2.threshold(frame ,200,255, cv2.THRESH_BINARY)
        gray_frame = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
        ret, gray_frame = cv2.threshold(gray_frame ,40,255, cv2.THRESH_BINARY) 
        cv2.fillPoly(gray_frame,pts=[contours],color=(255,255,255))
        
        if cv2.waitKey(1) & 0xFF==ord('q'):
            break

        img_crop0 = gray_frame[Y_S0:Y_S0+HGT,X_S0:X_S0+WDT]
        
        cv2.imwrite("t_plt0.jpg",img_crop0)     
        cv2.rectangle(gray_frame,(X_S0,Y_S0),(X_S0+WDT,Y_S0+HGT),(0, 0, 0),thickness=1)
        cv2.imshow('frame',gray_frame)
    
    capture.release()
    cv2.destroyAllWindows()      
           

except:    
    print("Error:",sys.exc_info()[0])
    print(sys.exc_info()[1])
    import traceback
    print(traceback.format_tb(sys.exc_info()[2]))
    

 

文字列変換プログラム

 下図の通りUSBカメラで時計を連続的に撮像し、「秒」を文字列変換しています。

 プログラムは下記の通りです。

import sys
import cv2
import numpy as np
import math
import time

try:
    capture=cv2.VideoCapture(0)
    
    if capture.isOpened() is False:
        print("カメラを開けませんでした。")
        sys.exit()

    X_S=[430,460]
    Y_S=[230,229]
    
    WDT=31
    HGT=60
    
    cntr_top1=284
    cntr_lft1=10
    cntr_top2=10
    cntr_lft2=425
    
    cntr01 = np.array([[cntr_lft1,cntr_top1],[cntr_lft1,cntr_top1+50],[cntr_lft1+500,cntr_top1+50],[cntr_lft1+500,cntr_top1]])
    cntr02 = np.array([[cntr_lft2,cntr_top2],[cntr_lft2,cntr_top2+500],[cntr_lft2+5,cntr_top2+500],[cntr_lft2+5,cntr_top2]])
    
    while(True):
        ret,frm_org =capture.read()
        
        ret, frame = cv2.threshold(frm_org ,45,255, cv2.THRESH_BINARY) 
        cv2.fillPoly(frame,pts=[cntr01],color=(255,255,255))
        cv2.fillPoly(frame,pts=[cntr02],color=(255,255,255))
        
        getVal=["*","*"]
        
        for i in range(2):
            T_XS = X_S[i]-3
            T_YS = Y_S[i]-10
            T_XE = T_XS + WDT+6
            T_YE = T_YS + HGT+10
            
            if i==1:
                cv2.rectangle(frame,(T_XS,T_YS),(T_XE,T_YE),(0, 0, 255),thickness=1)
            else:
                cv2.rectangle(frame,(T_XS,T_YS),(T_XE,T_YE),(0, 255, 0),thickness=1)
                
            img_crop = frame[T_YS:T_YE,T_XS:T_XE]
            maxVal_All = 0.4
            num_dsp = -1
            
            #0〜9のテンプレートと照合
            for j in range(10):
                i_tmpl=cv2.imread("tpl"+str(j)+".jpg")
                result= cv2.matchTemplate(img_crop,i_tmpl,cv2.TM_CCOEFF_NORMED)
                mmr=cv2.minMaxLoc(result)
                maxVal=mmr[1]    
                
                if maxVal > maxVal_All:
                    num_dsp = j
                    maxVal_All = maxVal
            
            if num_dsp != -1:
                getVal[i] = str(num_dsp)
        
        print(getVal)
        cv2.putText(frame,getVal[0]+getVal[1],(420,350),cv2.FONT_HERSHEY_SIMPLEX,2,(0,0,255),2,cv2.LINE_AA)
        cv2.imshow('frame',frame)
    
        if cv2.waitKey(1) & 0xFF==ord('q'):
            break

    capture.release()
    cv2.destroyAllWindows()

except:    
    print("Error:",sys.exc_info()[0])
    print(sys.exc_info()[1])
    import traceback
    print(traceback.format_tb(sys.exc_info()[2]))
    

 

 

まとめ

 最初の準備(設定)に少し時間がかかるので、もっと手軽に使えると良いと思っています。