tutorial_3

文書の過去の版を表示しています。


第3章 スターターコード【中級編 ライン判定(通過判定)】

この章では、

  • エリア検知からラインをまたいだ検知への応用
  • WEB UIを利用することで画像から座標情報をペイントツールで目視で読み取って転記するという面倒な作業の廃止
  • カメラ画像座標から見取り図画像座標への切り替え

がテーマとなります。
WEBUIについてはカスタマイズ対象としませんが、興味がある人が調べられるように簡単に説明します。

WEB UIを利用した時の解析プログラム

import sys
import os
import json
import math
from datetime import datetime, timedelta, timezone
import csv
import glob
import numpy as np

def intersect(p1, p2, p3, p4):
    tc1 = (p1[0] - p2[0]) * (p3[1] - p1[1]) + (p1[1] - p2[1]) * (p1[0] - p3[0])
    tc2 = (p1[0] - p2[0]) * (p4[1] - p1[1]) + (p1[1] - p2[1]) * (p1[0] - p4[0])
    td1 = (p3[0] - p4[0]) * (p1[1] - p3[1]) + (p3[1] - p4[1]) * (p3[0] - p1[0])
    td2 = (p3[0] - p4[0]) * (p2[1] - p3[1]) + (p3[1] - p4[1]) * (p3[0] - p2[0])
    return tc1*tc2<0 and td1*td2<0

if __name__ == '__main__':
    
    dirpath = 'data'
    line_def_file = os.environ['HOME']+'/drawui/sketchlines.json'
    
    JST = timezone(timedelta(hours=+9), 'JST')
    print(sys.argv[1]+"を集計しています・・")
    file_list = sorted(glob.glob('./'+dirpath+'/'+sys.argv[1]+'/raw_'+sys.argv[1]+'*.json'))
    print("対象ファイル一覧")
    for filename in file_list:
        print(filename)
    
    json_open = open(line_def_file, 'r')
    result_json_file = open('result_sketchlines_'+sys.argv[1]+'.json', 'w')
    linedef = json.load(json_open)
    resultarr = {}
    for lineidx, line in enumerate(linedef['lines']):
        linename='lineID'+str(lineidx)
        print(linename)
        resultarr[linename]={}
        
    print("集計・・")
    for lineidx, line in enumerate(linedef['lines']):
        linename='lineID'+str(lineidx)
        print(linename)
        polygon = []
        print(line)
        for point in line['points']:
            polygon.append([point['x'],point['y']])

        for filename in file_list:
            print(linename+"_"+filename)
            if os.path.getsize(filename) == 0:
                continue
                
            raw_json_open = open(filename, 'r')
            raw_json = json.load(raw_json_open)
            
            for frame in raw_json:
                jptime = datetime.fromtimestamp(frame['frame_time'],JST)
                people = frame['objects']
                for person in people:
                    
                    #print(linename+'_'+person['tracking_id']+'_'+str(judgenum))
                    personpos = [person["floor"]["x"],person["floor"]["y"]]
                    if person['tracking_id'] in resultarr[linename]:
                        if intersect(personpos,resultarr[linename][person['tracking_id']]['prev_pos'],polygon[0],polygon[1]):
                            resultarr[linename][person['tracking_id']]['passing_judge'] = True
                            resultarr[linename][person['tracking_id']]['passing_time'] = jptime.isoformat()
                        resultarr[linename][person['tracking_id']]['end_time'] = frame['frame_time']
                        resultarr[linename][person['tracking_id']]['end_time_jp'] = jptime.isoformat()
                    else:
                        resultarr[linename][person['tracking_id']]={'line':linename,'start_time_jp':jptime.isoformat(),'end_time_jp':jptime.isoformat(),'start_time':frame['frame_time'],'end_time':frame['frame_time'],'stream_id':frame['stream_id'],'passing_judge':False,'passing_time':0,'prev_pos':personpos}

    json.dump(resultarr,result_json_file)
    
    for linename, records in resultarr.items():
        print(linename)
        f = open("sketchlines_"+sys.argv[1]+"_"+linename+".csv", 'w', encoding='utf-8', newline='')
        write = csv.writer(f)
        write.writerow(["stream_id","linename","tracking_id","start_time_jp","end_time_jp","passing_judge","passing_time"])
        for tracking_id, record in records.items():
            write.writerow([record['stream_id'],linename,tracking_id,record['start_time_jp'],record['end_time_jp'],record['passing_judge'],record['passing_time']])
        
        f.close()      
二章で作成したプログラムからの改変となっているので、基本的な構造は同じになります。

線情報はUIから都度更新される下記のものを参照しています

{
    "lines": [
        {
            "points": [
                {"x": 131, "y": 134}, 
                {"x": 260, "y": 128}
            ]
        }, 
        {
            "points": [
                {"x": 59, "y": 226}, 
                {"x": 130, "y": 100}
            ]
        }
    ]
}

WEB UIを使う前に、まず前章と同じように座標値を手で調べる前提でラインを通過した時の検知を作りましょう 通過については下記のように例えば一つ前の11秒00のフレームと現在の11秒10のフレームとの人物位置をそれぞれA(p1)、B(p2)、検知線の開始・終了位置C(p3)、D(p4)の線が交差しているかどうかを判定することになります。

これらについては一つまとまった判定になるため、下記のように4点与えてあげれば通過・非通過を1,0で応答してくれる関数を別途定義します。

def intersect(p1, p2, p3, p4):
    tc1 = (p1[0] - p2[0]) * (p3[1] - p1[1]) + (p1[1] - p2[1]) * (p1[0] - p3[0])
    tc2 = (p1[0] - p2[0]) * (p4[1] - p1[1]) + (p1[1] - p2[1]) * (p1[0] - p4[0])
    td1 = (p3[0] - p4[0]) * (p1[1] - p3[1]) + (p3[1] - p4[1]) * (p3[0] - p1[0])
    td2 = (p3[0] - p4[0]) * (p2[1] - p3[1]) + (p3[1] - p4[1]) * (p3[0] - p2[0])
    return tc1*tc2<0 and td1*td2<0

また、前章のエリア判定から変わっているポイントとして

  • ライン判定になっているので関連する変数をすべて変更
  • 1つ前の座標を結果配列で保持(prev_pos項目)しておいて、簡単にintersect関数に引き渡せるようにしている
  • 通過時間を記録する
  • CSVに出力する内容を変更

となっています。
これらを反映したプログラムがこちらです。

import sys
import os
import json
import math
from datetime import datetime, timedelta, timezone
import csv
import glob
import numpy as np

def intersect(p1, p2, p3, p4):
    tc1 = (p1[0] - p2[0]) * (p3[1] - p1[1]) + (p1[1] - p2[1]) * (p1[0] - p3[0])
    tc2 = (p1[0] - p2[0]) * (p4[1] - p1[1]) + (p1[1] - p2[1]) * (p1[0] - p4[0])
    td1 = (p3[0] - p4[0]) * (p1[1] - p3[1]) + (p3[1] - p4[1]) * (p3[0] - p1[0])
    td2 = (p3[0] - p4[0]) * (p2[1] - p3[1]) + (p3[1] - p4[1]) * (p3[0] - p2[0])
    return tc1*tc2<0 and td1*td2<0

if __name__ == '__main__':
    
    dirpath = 'data'
    duration = 5
    line_def_file = '03lines.json'
    
    JST = timezone(timedelta(hours=+9), 'JST')
    print(sys.argv[1]+"を集計しています・・")
    file_list = sorted(glob.glob('./'+dirpath+'/'+sys.argv[1]+'/raw_'+sys.argv[1]+'*.json'))
    print("対象ファイル一覧")
    for filename in file_list:
        print(filename)
    
    json_open = open(line_def_file, 'r')
    result_json_file = open('result_'+line_def_file[:len(line_def_file)-5]+'_'+sys.argv[1]+'.json', 'w')
    linedef = json.load(json_open)
    resultarr = {}
    for lineidx, line in enumerate(linedef['lines']):
        linename='lineID'+str(lineidx)
        print(linename)
        resultarr[linename]={}
        
    print("集計・・")
    for lineidx, line in enumerate(linedef['lines']):
        linename='lineID'+str(lineidx)
        print(linename)
        polygon = []
        print(line)
        for point in line['points']:
            polygon.append([point['x'],point['y']])

        for filename in file_list:
            print(linename+"_"+filename)
            if os.path.getsize(filename) == 0:
                continue
                
            raw_json_open = open(filename, 'r')
            raw_json = json.load(raw_json_open)
            
            for frame in raw_json:
                jptime = datetime.fromtimestamp(frame['frame_time'],JST)
                people = frame['objects']
                for person in people:
                    
                    #print(linename+'_'+person['tracking_id']+'_'+str(judgenum))
                    personpos = [(person["x0"]+person["x1"])/2,person["y1"]]
                    if person['tracking_id'] in resultarr[linename]:
                        if intersect(personpos,resultarr[linename][person['tracking_id']]['prev_pos'],polygon[0],polygon[1]):
                            resultarr[linename][person['tracking_id']]['passing_judge'] = True
                            resultarr[linename][person['tracking_id']]['passing_time'] = jptime.isoformat()
                        resultarr[linename][person['tracking_id']]['end_time'] = frame['frame_time']
                        resultarr[linename][person['tracking_id']]['end_time_jp'] = jptime.isoformat()
                    else:
                        resultarr[linename][person['tracking_id']]={'line':linename,'start_time_jp':jptime.isoformat(),'end_time_jp':jptime.isoformat(),'start_time':frame['frame_time'],'end_time':frame['frame_time'],'stream_id':frame['stream_id'],'passing_judge':False,'passing_time':0,'prev_pos':personpos}

    json.dump(resultarr,result_json_file)
    
    for linename, records in resultarr.items():
        print(linename)
        f = open(line_def_file[:len(line_def_file)-5]+"_"+sys.argv[1]+"_"+linename+".csv", 'w', encoding='utf-8', newline='')
        write = csv.writer(f)
        write.writerow(["stream_id","linename","tracking_id","start_time_jp","end_time_jp","passing_judge","passing_time"])
        for tracking_id, record in records.items():
            write.writerow([record['stream_id'],linename,tracking_id,record['start_time_jp'],record['end_time_jp'],record['passing_judge'],record['passing_time']])
        
        f.close()    

さて、前項でライン判定まではできるようになったので、WEBUIを利用してみましょう 今まではtutorialフォルダのみで作業していましたが、次は

cd ~/drawui

でフォルダを切り替えましょう ここではフロントエンド(WEB画面で表示される部分のプログラム)とバックエンド(フロントエンドのプログラムから指示されてデータを保存したり出力したりする部分のプログラム)両方を兼ね備えており、

./start.sh

を押してしばらく待てば http://解析端末のIP/ などの画面にアクセスすることができます。 ===== 第四項 Reactについて ===== ===== 第五項 WEBサーバーの構築 ===== ===== 第六項 APIサーバーの構築 ===== ===== 第七項 スターターコードの完成 ===== ===== 第八項 エリア検知のUI連携 ===== ===== 第九項 カメラ座標から見取り図座標への切り替え =====

  • tutorial_3.1641270871.txt.gz
  • 最終更新: 2022/01/04 13:34
  • by satoshi