class CuiController(): u"""Cuiコントローラークラス.""" def __init__(self, settei): u"""初期設定.""" self.settei = settei self.video = None self.playlist = None self.playnumber = None self.playfile = None self.pause = True # コマンドライン引数取得 args = docopt(__doc__, version="1.0beta") self.settei.load_cui_settings(args) if self.settei.settings["webcam"]: # カメラ入力 print("Input from webcam...") self.set_webcam_cli() ok = True while (ok): try: ok = self.play_cli() except KeyboardInterrupt: print("\nKeyboardInterrupt!!!\n") self.video.close_video() sys.exit() else: # ビデオ入力 playdir = self.settei.settings["playdir"] if Path(playdir).exists(): self.playlist = self.get_playlist(playdir) if len(self.playlist) > 0: # プレイリストのビデオに対してチェック for playfile in self.playlist: self.set_video_cli(playfile) ok = True while (ok): ok = self.play_cli() else: print("Nothing playlist.") else: print("playdir does not exist.") sys.exit() def set_video_cli(self, playfile): u"""ビデオの初期設定.""" print(playfile) tmppath = self.settei.settings["outdir"] + playfile.replace( self.settei.settings["playdir"], "") recursive_outdir = str(Path(tmppath).parent) self.playfile = playfile self.video = Video(playfile, recursive_outdir) self.video.set_bounding(self.settei.settings["bounding"]) self.video.set_detecttype(self.settei.settings["detecttype"]) self.video.set_verbose(self.settei.settings["verbose"]) top = self.settei.settings["detectionTop"] bottom = self.settei.settings["detectionBottom"] left = self.settei.settings["detectionLeft"] right = self.settei.settings["detectionRight"] #順番大事 self.video.set_imgscale(self.settei.settings["imgscale"]) self.video.set_detectionarea(top, bottom, left, right) def set_webcam_cli(self): u"""カメラの初期設定.""" outdir = self.settei.settings["outdir"] playfile = self.playfile = self.settei.settings["device"] self.video = Video(playfile, outdir, webcam=True) if self.video.check_webcam() is True: self.video.set_bounding(self.settei.settings["bounding"]) self.video.set_detecttype(self.settei.settings["detecttype"]) self.video.set_verbose(self.settei.settings["verbose"]) top = self.settei.settings["detectionTop"] bottom = self.settei.settings["detectionBottom"] left = self.settei.settings["detectionLeft"] right = self.settei.settings["detectionRight"] #順番大事 self.video.set_imgscale(self.settei.settings["imgscale"]) self.video.set_detectionarea(top, bottom, left, right) else: print("No connected with WebCam !") sys.exit() def play_cli(self): u"""再生&検知.""" # 1フレーム処理 ret, skip = self.video.process_nextframe() if ret is True: # ビデオ終わりでなければビデオ&jpg書き出しチェック&実行 if not skip: if self.settei.settings["writejpg"]: self.video.writeout_jpg() if self.settei.settings["writevideo"]: self.video.writeout_video() # if self.settei.settings["webcam"]: # self.video.writeout_webcam() else: # ビデオ終わりなら書き込み終了&結果出力&検知グラフ&データ出力 self.video.close_video() return ret def fild_all_files(self, directory): u"""ビデオリスト取得のための関数.""" for root, dirs, files in os.walk(directory): yield root for file in files: yield os.path.join(root, file) def get_playlist(self, playdir): u"""ディレクトリ内のビデオのリストを取得.""" playlist = [] for file in self.fild_all_files(playdir): ext = splitext(basename(file))[1][1:].lower() # ピリオドを抜いた拡張子 if ext in self.settei.settings and self.settei.settings[ext]: playlist.append(file.replace('/', os.sep)) return playlist
class MainController(): u"""処理クラス.""" def __init__(self, settei, main_view): u"""初期設定.""" self.settei = settei self.main_view = main_view self._timer = QtCore.QTimer() self._timer.timeout.connect(self.play) self.video = None self.playlist = None self.playnumber = None self.playfile = None self.pause = True self.mouseselectmode = False u"""設定の読み込み.""" inidir = find_exedir() setting_file = Path(inidir) / "settings.json" self.load_settings(setting_file) # GUIのアクション設定(設定読み込みの後に実行) self.set_actions() def set_actions(self): u"""アクションの設定.""" self.main_view.actionOpen_Folder.triggered.connect(self.set_playdir) self.main_view.folderButton.clicked.connect(self.set_playdir) self.main_view.actionWebCam.triggered.connect(self.get_webcam) self.main_view.actionSave_Settings.triggered.connect( self.save_settings) self.main_view.actionLoad_Settings.triggered.connect(self.get_settings) self.main_view.outdirButton.clicked.connect(self.set_outdir) self.main_view.playButton.clicked.connect(self.control_video) self.main_view.nextframeButton.clicked.connect(self.step_nextframe) self.main_view.nextvideoButton.clicked.connect(self.step_nextvideo) self.main_view.previousvideoButton.clicked.connect( self.step_previousvideo) self.main_view.trackSlider.valueChanged.connect(self.changed_slider) self.main_view.trackSlider.sliderPressed.connect(self.pressed_slider) self.main_view.trackSlider.sliderReleased.connect(self.moved_slider) self.main_view.speedSlider.valueChanged.connect(self.set_speed) self.main_view.treeView.doubleClicked.connect( self.select_playfile_treeview) self.main_view.writevideo_checkBox.stateChanged.connect( self.set_writevideo) self.main_view.writejpg_checkBox.stateChanged.connect( self.set_writejpg) self.main_view.bounding_checkBox.stateChanged.connect( self.set_bounding) self.main_view.crop_checkBox.stateChanged.connect(self.set_crop) self.main_view.display_checkBox.stateChanged.connect(self.set_display) self.main_view.verbose_checkBox.stateChanged.connect(self.set_verbose) self.main_view.detectA_radioButton.clicked.connect(self.set_detectA) self.main_view.detectB_radioButton.clicked.connect(self.set_detectB) self.main_view.detectC_radioButton.clicked.connect(self.set_detectC) self.main_view.avi_checkBox.stateChanged.connect(self.set_inputformat) self.main_view.mov_checkBox.stateChanged.connect(self.set_inputformat) self.main_view.mpg_checkBox.stateChanged.connect(self.set_inputformat) self.main_view.mp4_checkBox.stateChanged.connect(self.set_inputformat) self.main_view.wmv_checkBox.stateChanged.connect(self.set_inputformat) self.main_view.flv_checkBox.stateChanged.connect(self.set_inputformat) self.main_view.mts_checkBox.stateChanged.connect(self.set_inputformat) self.main_view.m2ts_checkBox.stateChanged.connect(self.set_inputformat) self.main_view.resetArea_Button.clicked.connect(self.reset_detectarea) self.main_view.detectionTop_Edit.editingFinished.connect( self.check_detectionarea) self.main_view.detectionBottom_Edit.editingFinished.connect( self.check_detectionarea) self.main_view.detectionLeft_Edit.editingFinished.connect( self.check_detectionarea) self.main_view.detectionRight_Edit.editingFinished.connect( self.check_detectionarea) self.main_view.detectionArea_Button.clicked.connect( self.active_mouseselect) self.main_view.videoFrame.mousePressEvent = self.set_area_by_mouse self.main_view.videoFrame.mouseReleaseEvent = self.set_area_by_mouse self.main_view.videoFrame.mouseMoveEvent = self.set_area_by_mouse self.main_view.imgscale_comboBox.currentIndexChanged.connect( self.set_imgscale) self.main_view.clearlog_pushButton.clicked.connect(self.clear_log) def play(self, singlestep=False): u"""再生&表示&検知処理.(タイマーからループで呼び出される).""" # 1フレーム処理 ret, skip = self.video.process_nextframe() if ret is True: curpos = self.video.get_position() self.main_view.set_track_position(curpos) # ビデオ終わりでなければビデオ&jpg書き出しチェック&画面表示 if not skip: if self.settei.settings["writejpg"]: self.video.writeout_jpg() if self.settei.settings["writevideo"]: self.video.writeout_video() # if self.settei.settings["webcam"]: # self.video.writeout_webcam() if self.settei.settings["display"]: RGBframe = self.video.get_RGBframe() self.main_view.set_frame(RGBframe) else: # ビデオ終わりなら書き込み終了 self.video.close_video() # 次のファイルを確認&変更 if len(self.playlist) > self.playnumber + 1: # ファイル残っていたら次のビデオを再生 self.playnumber = self.playnumber + 1 filename = self.playlist[self.playnumber] self.set_video(filename) if not singlestep: self.control_video("START") else: # ファイル残っていなかったら停止 self.control_video("STOP") def control_video(self, action): u"""ビデオ再生 or 停止処理.""" if self.video is not None: if action == "START": # 再生させる self.pause = False self.main_view.set_play_label("STOP") self.main_view.set_format_checkbox(False) self.main_view.set_stepvideo_button(False) self.main_view.set_treeview(False) self.main_view.set_settingframe(False) self.video.set_detecttype(self.settei.settings["detecttype"]) self._timer.start() elif action == "STOP": # 停止させる self.pause = True self._timer.stop() self.video.close_video() # ビデオも一旦書き出し self.main_view.set_play_label("START") self.main_view.set_settingframe(True) if not self.settei.settings["webcam"]: self.main_view.set_format_checkbox(True) self.main_view.set_stepvideo_button(True) self.main_view.set_treeview(True) elif self.pause: # 停止していたら再生させる self.pause = False self.main_view.set_play_label("STOP") self.main_view.set_format_checkbox(False) self.main_view.set_stepvideo_button(False) self.main_view.set_treeview(False) self.main_view.set_settingframe(False) self.video.set_detecttype(self.settei.settings["detecttype"]) self._timer.start() else: # 再生していたら停止させる self.pause = True self._timer.stop() self.video.close_video() # ビデオも一旦書き出し self.main_view.set_play_label("START") self.main_view.set_settingframe(True) if not self.settei.settings["webcam"]: self.main_view.set_format_checkbox(True) self.main_view.set_stepvideo_button(True) self.main_view.set_treeview(True) def step_nextframe(self): u"""コマ送り再生.""" #self.control_video("STOP") if self.video is not None: if self.video.bs is None: self.video.set_detecttype(self.settei.settings["detecttype"]) self.play(singlestep=True) def step_previousvideo(self): u"""前のビデオに切り替え.""" if len(self.playlist) > 0: if self.playnumber > 0 and self.video.curpos == 0: self.playnumber = self.playnumber - 1 # playnumberが0の場合と再生途中の場合は、同じビデオを初期設定する。 filename = self.playlist[self.playnumber] self.set_video(filename) def step_nextvideo(self): u"""次のビデオに切り替え.""" if len(self.playlist) > self.playnumber + 1: self.playnumber = self.playnumber + 1 filename = self.playlist[self.playnumber] self.set_video(filename) def changed_slider(self, pos): u"""トラックバー変更でラベル変更.""" fps = self.video.get_fps() self.main_view.change_tracklabel(fps) def pressed_slider(self): u"""トラックバー移動でビデオ停止.""" self.control_video("STOP") def moved_slider(self): u"""トラックバーの移動終了.""" pos = self.main_view.get_slider_position() self.video.set_position(pos) self.refresh_view() def set_outdir(self): u"""出力フォルダを設定.""" outdir = self.main_view.get_outdir() if outdir: self.settei.settings["outdir"] = outdir self.main_view.set_outdir(outdir) if self.video: if self.settei.settings["webcam"]: self.video.set_outdir(outdir) else: outdir = self.settei.settings["outdir"] playdir = self.settei.settings["playdir"] playfile = self.playfile recursive_outdir = self.get_recursive_outdir( outdir, playdir, playfile) self.video.set_outdir(recursive_outdir) def select_playfile_treeview(self, index): u"""ツリービューから選択されたファイルを再生ビデオに設定.""" playfile = self.main_view.get_filename_treeview(index) if Path(playfile).exists(): # directoryなら何もしない playnumber = self.playlist.index(playfile) self.playnumber = playnumber self.playfile = playfile self.set_video(playfile) def set_playdir(self): u"""プレイフォルダを設定.""" self.control_video("STOP") playdir = self.main_view.get_playdir() if playdir: self.settei.settings["webcam"] = False self.settei.settings["playdir"] = playdir self.main_view.set_playdir(playdir) self.set_inputformat() def set_inputformat(self): u"""入力ビデオフォーマットのフィルタリング設定.プレイリストも更新.""" self.main_view.set_inputformat() self.set_playlist() def set_playlist(self): u"""再生リストの設定.""" playdir = self.settei.settings["playdir"] self.playlist = self.main_view.get_playlist(playdir) if len(self.playlist) == 0: self.video = None self.main_view.set_nothing_playlist() else: self.playnumber = 0 playfile = self.playlist[self.playnumber] self.playfile = playfile self.set_video(playfile) def get_recursive_outdir(self, outdir, playdir, playfile): u"""playfileのフォルダ構成を考慮したビデオ&画像出力フォルダ.""" tmppath = Path(outdir) / playfile.replace(playdir, "").lstrip( '\\' ) # playdirがG:\とかだとバックスラッシュが取れるためos.sep追加。取れない場合のために左のバックスラッシュを一旦とる。 recursive_outdir = str(tmppath.parent) return recursive_outdir def set_video(self, playfile): u"""再生ビデオを変更&初期設定.""" if self.settei.settings["verbose"]: print(playfile) self.video = None outdir = self.settei.settings["outdir"] playdir = self.settei.settings["playdir"] recursive_outdir = self.get_recursive_outdir(outdir, playdir, playfile) logfunc = self.main_view.write_log self.video = Video(playfile, recursive_outdir, logfunc) self.video.set_bounding(self.settei.settings["bounding"]) self.video.set_verbose(self.settei.settings["verbose"]) self.video.set_detecttype(self.settei.settings["detecttype"]) framecount = self.video.get_framecount() fps = self.video.get_fps() self.main_view.set_video_view(playfile, framecount, fps) top = self.settei.settings["detectionTop"] bottom = self.settei.settings["detectionBottom"] left = self.settei.settings["detectionLeft"] right = self.settei.settings["detectionRight"] self.set_detectionarea(top, bottom, left, right) self.set_imgscale() self.set_speed() def reset_detectarea(self): u"""検知範囲リセット.""" if self.video is not None: height, width = self.video.get_size() top = 0 bottom = height left = 0 right = width self.set_detectionarea(top, bottom, left, right) def refresh_view(self): u"""表示を更新する.""" if self.settei.settings["display"]: bounding = self.settei.settings["bounding"] currentframe = self.video.get_currentframe(bounding) self.main_view.set_frame(currentframe) else: self.main_view.clear_display() def set_detectionarea(self, top, bottom, left, right): u"""検知範囲のビデオへの設定.""" height, width = self.video.get_size() self.main_view.set_detectionarea(top, bottom, left, right, height) self.settei.settings["detectionTop"] = top self.settei.settings["detectionBottom"] = bottom self.settei.settings["detectionLeft"] = left self.settei.settings["detectionRight"] = right self.video.set_detectionarea(top, bottom, left, right) self.refresh_view() def check_detectionarea(self): u"""検知エリアの確認.""" top, bottom, left, right = self.main_view.get_detectionarea() # 逆の場合は、入れ替える。 if bottom - top < 0: tmp = top top = bottom bottom = tmp if right - left < 0: tmp = right right = left left = tmp # 左右、上下が同じ値ならもとに戻す if bottom - top == 0 or right - left == 0: top = self.settei.settings["detectionTop"] bottom = self.settei.settings["detectionBottom"] left = self.settei.settings["detectionLeft"] right = self.settei.settings["detectionRight"] self.set_detectionarea(top, bottom, left, right) def get_webcam(self): u"""カメラデバイスの取得.""" device, ok = self.main_view.get_device() if ok: self.set_webcam(device) def set_webcam(self, device): u"""webcamの設定.""" self.settei.settings["webcam"] = True self.settei.settings["device"] = device self.video = None outdir = self.settei.settings["outdir"] playfile = self.playfile = device logfunc = self.main_view.write_log self.video = Video(playfile, outdir, logfunc, webcam=True) # webcamが接続されていれば初期設定 if self.video.check_webcam() is True: self.video.set_bounding(self.settei.settings["bounding"]) self.video.set_verbose(self.settei.settings["verbose"]) self.video.set_detecttype(self.settei.settings["detecttype"]) self.main_view.set_webcam_view() top = self.settei.settings["detectionTop"] bottom = self.settei.settings["detectionBottom"] left = self.settei.settings["detectionLeft"] right = self.settei.settings["detectionRight"] self.set_detectionarea(top, bottom, left, right) self.set_imgscale() self.set_speed() self.control_video("START") else: self.main_view.set_webcam_view(webcam=False) def get_settings(self): u"""設定の読み込み.""" setting_file = self.main_view.get_loadfile() if setting_file: self.load_settings(setting_file) def load_settings(self, setting_file): u"""設定の保存.""" self.settei.load_settings(setting_file) self.main_view.set_settings(self.settei) top, bottom, left, right = self.main_view.get_detectionarea() if self.settei.settings["webcam"]: device = self.settei.settings["device"] self.set_webcam(device) else: self.set_inputformat() def save_settings(self): u"""設定の保存.""" setting_file = self.main_view.get_savefile() if setting_file: self.settei.save_settings(setting_file) def set_speed(self): u"""タイマーのインターバルを設定.""" if self.settei.settings["webcam"]: interval = 0 else: speedvalue = self.main_view.get_speed() # speed: 0~2 の値 0はできるだけ速く.2は通常の2倍の時間遅い speed = -speedvalue / 50.0 + 2 self.settei.settings["speedSlider"] = speedvalue interval = 0 if self.video is not None: interval = 1000 * speed / self.video.get_fps() self._timer.setInterval(interval) def set_bounding(self): u"""領域表示設定.""" bounding = self.main_view.get_bounding() self.settei.settings["bounding"] = bounding if self.video is not None: self.video.set_bounding(bounding) self.refresh_view() def set_crop(self): u"""領域表示設定.""" crop = self.main_view.get_crop() self.settei.settings["crop"] = crop if self.video is not None: self.video.set_crop(crop) self.refresh_view() def set_writevideo(self): u"""ビデオを書き出すか設定.""" writevideo = self.main_view.get_writevideo() self.settei.settings["writevideo"] = writevideo def set_writejpg(self): u"""jpgを書き出すか設定.""" writejpg = self.main_view.get_writejpg() self.settei.settings["writejpg"] = writejpg def set_display(self): u"""画面表示設定.""" display = self.main_view.get_display() self.settei.settings["display"] = display if display is False: self.main_view.clear_display() else: self.refresh_view() def set_verbose(self): u"""ログ出力を設定.""" verbose = self.main_view.get_verbose() self.settei.settings["verbose"] = verbose if self.video is not None: self.video.set_verbose(verbose) def set_imgscale(self): u"""画像スケールを設定.""" imgscale = self.main_view.get_imgscale() old_imgscale = self.settei.settings["imgscale"] self.settei.settings["imgscale"] = imgscale if self.video is not None: self.video.set_imgscale(imgscale) height, width = self.video.get_size() self.main_view.set_imgsize_label(width, height) top, bottom, left, right = self.main_view.get_detectionarea() aspect = imgscale / old_imgscale self.set_detectionarea(int(top * aspect), int(bottom * aspect), int(left * aspect), int(right * aspect)) def set_detectA(self, enabled): u"""表示画像を設定.""" self.settei.settings["detecttype"] = "detectA" if self.video is not None: self.video.set_detecttype("detectA") def set_detectB(self, enabled): u"""表示画像を設定.""" self.settei.settings["detecttype"] = "detectB" if self.video is not None: self.video.set_detecttype("detectB") def set_detectC(self, enabled): u"""表示画像を設定.""" self.settei.settings["detecttype"] = "detectC" if self.video is not None: self.video.set_detecttype("detectC") def set_area_by_mouse(self, event): u"""検出範囲or背景分類範囲をマウスで選択.""" if self.video: if self.mouseselectmode: if (event.type() != QtCore.QEvent.MouseButtonRelease): self.main_view.select_detectionarea_by_mouse(event) elif (event.type() == QtCore.QEvent.MouseButtonRelease): height, width = self.video.get_size() self.main_view.set_detectionarea_by_mouse(event, height) self.check_detectionarea() self.mouseselectmode = False def active_mouseselect(self): u"""検知範囲のマウス選択を有効化.""" self.mouseselectmode = True self.main_view.set_mouseselect(False) def clear_log(self): u"""ログを消去.""" self.main_view.clear_log()