差分
このページの2つのバージョン間の差分を表示します。
| 両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン | ||
| tutorial_3 [2022/01/04 14:02] – satoshi | tutorial_3 [2022/01/05 10:49] (現在) – [第四項 Reactについて] satoshi | ||
|---|---|---|---|
| 行 1: | 行 1: | ||
| - | ====== 第3章 スターターコード【中級編 ライン判定(通過判定)】 ====== | + | ====== 第3章 ライン判定(WEBUIを使った通過判定)【中級編】 ====== |
| この章では、\\ | この章では、\\ | ||
| * エリア検知からラインをまたいだ検知への応用 | * エリア検知からラインをまたいだ検知への応用 | ||
| 行 265: | 行 265: | ||
| 等から学び始めることがよいでしょう。\\ | 等から学び始めることがよいでしょう。\\ | ||
| - | ただし今回はReact自体が分からなくても、どのプログラムファイルをどういじれば何が変わるかという点だけでピンポイントで解説していこうと思いますので、本チュートリアルを進めるうえではReactの学習は必須ではありません。\\ | + | ただし今回はReact自体が分からなくても、どのプログラムファイルをどういじれば何が変わるかという点だけでピンポイントで上級編の一環として解説していこうと思いますので、本チュートリアルを進めるうえではReactの学習は必須ではありません。\\ |
| ===== 第五項 WEBサーバーの解説===== | ===== 第五項 WEBサーバーの解説===== | ||
| WEBサーバーについては今回FlaskというPythonで簡単にWEBサーバーを構築できる仕組みを採用します。\\ | WEBサーバーについては今回FlaskというPythonで簡単にWEBサーバーを構築できる仕組みを採用します。\\ | ||
| 行 298: | 行 299: | ||
| がその設定になり、トップページと、何もないページにアクセスした場合強制的にトップページを表示するという設定となります。Reactを使う上ではこういうものだと思ってもらえれば大丈夫です。\\ | がその設定になり、トップページと、何もないページにアクセスした場合強制的にトップページを表示するという設定となります。Reactを使う上ではこういうものだと思ってもらえれば大丈夫です。\\ | ||
| - | なお、このFlaskでのWEBページ公開方法は開発用となっており、インターネットで大量にアクセスしてくるような大規模な本番用WEBページには非推奨です。ですが、SCORER Edge上で少数の人間がアクセスしてくる分には全く問題ありません。\\ | + | なお、このFlaskでのWEBページ公開方法は開発用となっており、インターネットで大量にアクセスしてくるような大規模な本番用WEBページには非推奨です。\\ |
| + | 昔から有名なApacheや最近はNginxなどのWEBサーバーがよく使われています。\\ | ||
| + | ですが、SCORER Edge上で少数の人間がアクセスしてくる分には全く問題ありません。\\ | ||
| ===== 第六項 APIサーバーの解説 ===== | ===== 第六項 APIサーバーの解説 ===== | ||
| + | 描画画面でエリアや線分を設定したあと、そのデータを保存したり、ページ表示時に読み込んだりする部分のプログラム(API)についての解説ですが、今回は特殊な方法を使っているため、WEBサーバー公開と同じserver.py内で処理が行われています。 | ||
| + | <sxh Python; | ||
| + | import os | ||
| + | import sys | ||
| + | |||
| + | from flask import Flask, json, jsonify, request, render_template | ||
| + | |||
| + | |||
| + | |||
| + | app = Flask(__name__, | ||
| + | |||
| + | def get_file(filename): | ||
| + | print(f' | ||
| + | try: | ||
| + | with open( f' | ||
| + | file = json.load(infile) | ||
| + | except Exception: | ||
| + | return jsonify(reason=' | ||
| + | else: | ||
| + | return file | ||
| + | |||
| + | def save_file(filename, | ||
| + | try: | ||
| + | with open(f' | ||
| + | json.dump(data, | ||
| + | except Exception: | ||
| + | return ( | ||
| + | jsonify(reason=' | ||
| + | 500 | ||
| + | ) | ||
| + | |||
| + | return data, 200 | ||
| + | |||
| + | @app.route("/" | ||
| + | def index(): | ||
| + | return render_template(" | ||
| + | @app.errorhandler(404) | ||
| + | def not_found(e): | ||
| + | return render_template(" | ||
| + | |||
| + | @app.route('/ | ||
| + | def camareas(): | ||
| + | if request.method == ' | ||
| + | return get_file(' | ||
| + | elif request.method == ' | ||
| + | return save_file(' | ||
| + | else: | ||
| + | return {' | ||
| + | |||
| + | @app.route('/ | ||
| + | def sketchareas(): | ||
| + | if request.method == ' | ||
| + | return get_file(' | ||
| + | elif request.method == ' | ||
| + | return save_file(' | ||
| + | else: | ||
| + | return {' | ||
| + | |||
| + | @app.route('/ | ||
| + | def camlines(): | ||
| + | if request.method == ' | ||
| + | return get_file(' | ||
| + | elif request.method == ' | ||
| + | return save_file(' | ||
| + | else: | ||
| + | return {' | ||
| + | |||
| + | @app.route('/ | ||
| + | def sketchlines(): | ||
| + | if request.method == ' | ||
| + | return get_file(' | ||
| + | elif request.method == ' | ||
| + | return save_file(' | ||
| + | else: | ||
| + | return {' | ||
| + | | ||
| + | if __name__ == ' | ||
| + | app.run(host=' | ||
| + | |||
| + | </ | ||
| + | 10-30行目が読み出しや保存に関するコード\\ | ||
| + | 39-73行目はどのURLにアクセスして来たらどういう動き(どのファイルを保存・読み出しするか)かを定義しています。\\ | ||
| + | |||
| ===== 第七項 スターターコードの完成 ===== | ===== 第七項 スターターコードの完成 ===== | ||
| + | |||
| + | 第四項のコードからの変更として、\\ | ||
| + | * 保存ファイルの読み出し先を変更する | ||
| + | ということを行います。\\ | ||
| + | <sxh Python; | ||
| + | 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, | ||
| + | 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< | ||
| + | |||
| + | if __name__ == ' | ||
| + | | ||
| + | dirpath = ' | ||
| + | line_def_file = os.environ[' | ||
| + | | ||
| + | JST = timezone(timedelta(hours=+9), | ||
| + | print(sys.argv[1]+" | ||
| + | file_list = sorted(glob.glob(' | ||
| + | print(" | ||
| + | for filename in file_list: | ||
| + | print(filename) | ||
| + | | ||
| + | json_open = open(line_def_file, | ||
| + | result_json_file = open(' | ||
| + | linedef = json.load(json_open) | ||
| + | resultarr = {} | ||
| + | for lineidx, line in enumerate(linedef[' | ||
| + | linename=' | ||
| + | print(linename) | ||
| + | resultarr[linename]={} | ||
| + | | ||
| + | print(" | ||
| + | for lineidx, line in enumerate(linedef[' | ||
| + | linename=' | ||
| + | print(linename) | ||
| + | polygon = [] | ||
| + | print(line) | ||
| + | for point in line[' | ||
| + | polygon.append([point[' | ||
| + | |||
| + | for filename in file_list: | ||
| + | print(linename+" | ||
| + | if os.path.getsize(filename) == 0: | ||
| + | continue | ||
| + | | ||
| + | raw_json_open = open(filename, | ||
| + | raw_json = json.load(raw_json_open) | ||
| + | | ||
| + | for frame in raw_json: | ||
| + | jptime = datetime.fromtimestamp(frame[' | ||
| + | people = frame[' | ||
| + | for person in people: | ||
| + | | ||
| + | # | ||
| + | personpos = [(person[" | ||
| + | if person[' | ||
| + | if intersect(personpos, | ||
| + | resultarr[linename][person[' | ||
| + | resultarr[linename][person[' | ||
| + | resultarr[linename][person[' | ||
| + | resultarr[linename][person[' | ||
| + | else: | ||
| + | resultarr[linename][person[' | ||
| + | |||
| + | json.dump(resultarr, | ||
| + | | ||
| + | for linename, records in resultarr.items(): | ||
| + | print(linename) | ||
| + | f = open(" | ||
| + | write = csv.writer(f) | ||
| + | write.writerow([" | ||
| + | for tracking_id, | ||
| + | write.writerow([record[' | ||
| + | | ||
| + | f.close() | ||
| + | </ | ||
| + | 実際変更するところは20行目のみで、ファイルの参照先をtutorial内ではなく隣のdrawuiフォルダのcamlines.jsonに切り替えています。\\ | ||
| + | |||
| + | さて、これでカメラ座標系の設定としては洗練されたものになりましたが、そのまま見取り図座標での設定ができるようにコードを変更していきましょう。\\ | ||
| + | <sxh Python; | ||
| + | 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, | ||
| + | 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< | ||
| + | |||
| + | if __name__ == ' | ||
| + | | ||
| + | dirpath = ' | ||
| + | line_def_file = os.environ[' | ||
| + | | ||
| + | JST = timezone(timedelta(hours=+9), | ||
| + | print(sys.argv[1]+" | ||
| + | file_list = sorted(glob.glob(' | ||
| + | print(" | ||
| + | for filename in file_list: | ||
| + | print(filename) | ||
| + | | ||
| + | json_open = open(line_def_file, | ||
| + | result_json_file = open(' | ||
| + | linedef = json.load(json_open) | ||
| + | resultarr = {} | ||
| + | for lineidx, line in enumerate(linedef[' | ||
| + | linename=' | ||
| + | print(linename) | ||
| + | resultarr[linename]={} | ||
| + | | ||
| + | print(" | ||
| + | for lineidx, line in enumerate(linedef[' | ||
| + | linename=' | ||
| + | print(linename) | ||
| + | polygon = [] | ||
| + | print(line) | ||
| + | for point in line[' | ||
| + | polygon.append([point[' | ||
| + | |||
| + | for filename in file_list: | ||
| + | print(linename+" | ||
| + | if os.path.getsize(filename) == 0: | ||
| + | continue | ||
| + | | ||
| + | raw_json_open = open(filename, | ||
| + | raw_json = json.load(raw_json_open) | ||
| + | | ||
| + | for frame in raw_json: | ||
| + | jptime = datetime.fromtimestamp(frame[' | ||
| + | people = frame[' | ||
| + | for person in people: | ||
| + | | ||
| + | # | ||
| + | personpos = [person[" | ||
| + | if person[' | ||
| + | if intersect(personpos, | ||
| + | resultarr[linename][person[' | ||
| + | resultarr[linename][person[' | ||
| + | resultarr[linename][person[' | ||
| + | resultarr[linename][person[' | ||
| + | else: | ||
| + | resultarr[linename][person[' | ||
| + | |||
| + | json.dump(resultarr, | ||
| + | | ||
| + | for linename, records in resultarr.items(): | ||
| + | print(linename) | ||
| + | f = open(" | ||
| + | write = csv.writer(f) | ||
| + | write.writerow([" | ||
| + | for tracking_id, | ||
| + | write.writerow([record[' | ||
| + | | ||
| + | f.close() | ||
| + | </ | ||
| + | 20行目参照JSONファイルの変更と61行目人物の座標を座標を見取り図上のものを利用するだけの変更するだけにとどまりました。\\ | ||
| + | これでスターターコードは完成です。\\ | ||
| + | |||
| + | |||
| ===== 第八項 エリア検知のUI連携 ===== | ===== 第八項 エリア検知のUI連携 ===== | ||
| - | ===== 第九項 カメラ座標から見取り図座標への切り替え | + | ついでにエリア検知もUIで設定できるようにしましょう。変更箇所の解説はあまりいらないかと思いますので、結果プログラムを見てください。 |
| + | <sxh Python; | ||
| + | import sys | ||
| + | import os | ||
| + | import json | ||
| + | import cv2 | ||
| + | import math | ||
| + | from datetime import datetime, timedelta, timezone | ||
| + | import csv | ||
| + | import glob | ||
| + | import numpy as np | ||
| + | |||
| + | if __name__ | ||
| + | |||
| + | dirpath | ||
| + | duration | ||
| + | area_def_file | ||
| + | |||
| + | JST = timezone(timedelta(hours=+9), | ||
| + | print(sys.argv[1]+" | ||
| + | file_list = sorted(glob.glob(' | ||
| + | print(" | ||
| + | for filename in file_list: | ||
| + | print(filename) | ||
| + | |||
| + | json_open = open(area_def_file, | ||
| + | result_json_file = open(' | ||
| + | areadef = json.load(json_open) | ||
| + | resultarr = {} | ||
| + | for areaidx, area in enumerate(areadef[' | ||
| + | areaname=' | ||
| + | print(areaname) | ||
| + | resultarr[areaname]={} | ||
| + | print(" | ||
| + | for areaidx, area in enumerate(areadef[' | ||
| + | areaname=' | ||
| + | print(areaname) | ||
| + | polygon = [] | ||
| + | for point in area[' | ||
| + | polygon.append([point[' | ||
| + | |||
| + | contour = np.array(polygon) | ||
| + | print(contour) | ||
| + | |||
| + | for filename in file_list: | ||
| + | print(areaname+" | ||
| + | if os.path.getsize(filename) == 0: | ||
| + | continue | ||
| + | |||
| + | raw_json_open = open(filename, | ||
| + | raw_json = json.load(raw_json_open) | ||
| + | |||
| + | for frame in raw_json: | ||
| + | jptime = datetime.fromtimestamp(frame[' | ||
| + | people = frame[' | ||
| + | for person in people: | ||
| + | |||
| + | # | ||
| + | personpos = [person[" | ||
| + | test = cv2.pointPolygonTest(contour, | ||
| + | if test> | ||
| + | if person[' | ||
| + | resultarr[areaname][person[' | ||
| + | resultarr[areaname][person[' | ||
| + | resultarr[areaname][person[' | ||
| + | if resultarr[areaname][person[' | ||
| + | resultarr[areaname][person[' | ||
| + | else: | ||
| + | resultarr[areaname][person[' | ||
| + | |||
| + | json.dump(resultarr, | ||
| + | |||
| + | for areaname, records in resultarr.items(): | ||
| + | print(areaname) | ||
| + | f = open(" | ||
| + | write = csv.writer(f) | ||
| + | write.writerow([" | ||
| + | for tracking_id, | ||
| + | write.writerow([record[' | ||
| + | |||
| + | f.close() | ||
| + | </ | ||