忍者ブログ

2007/03/04開始。ソフトウェア管理やDelerer SEの作者であるおにぎりくんの試行錯誤の記録です。
2024
前の月へ 10 : 123456789101112131415161718192021222324252627282930 : 12 次の月へ
1  2  3  4  5  6 
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

タイムコードを表示するWebアプリを作りました。
https://heterotactic-locati.000webhostapp.com/timer.html

複数台のカメラで同時に撮影するときに、最初または最後にこのアプリを撮っておくと、映像同士の時刻を合わせやすくなります。 機材がなくてもいい、お手軽な同期アプリとしてご利用ください。

【使い方】
使い方はここにあるとおり、ビデオカメラでWebアプリの画面を撮影することで、映像の時刻をフレーム単位で割り出せるというものです。
カチンコという、いわゆる「アクション!(カンッ)」ってやるやつの代わりに使います。
ちゃんとした撮影機材があれば、専用の機材と線でつないで時刻を同期するのですが、そのような機材は手元になく・・・家庭用ビデオカメラで似たようなことをするためにこのWebアプリを作成しました。複数のカメラで同時に撮影し、あとで編集するようなケースではこれがめちゃめちゃ役に立ちます。

時刻同期の機能は作っていないため、29.7 fpsみたいなことはできません。
代わりではないですが、タイムコードの上にバーを表示しています。これで、画面表示されたタイミングが1frameのなかのどのタイミングだったのかが分かるようになっています。
たとえば30fpsで動かすとき、画面やブラウザはたいてい60fpsなので、同じタイムコードを2回表示することになるわけです。それを撮影したとしても、2回表示したうちのどちらが撮影されたのかまではわかりませんので、複数カメラの映像をつなげるときに若干のズレが起こります。(音がずれるので少し違和感が出ます)
もし印がバーの左側なら表示された値の通り、中央なら0.5frameのあたり、右側なら次のフレームに近いと判断でき、1frame未満も調整できるようになっているわけです。

別の使い方ですが、Clockモードを選ぶと、時計として使えます。

【使ったテクノロジー】
フレームワークはVue.js+Vuerifyを使っています。npmでビルドするのが面倒だったので、CDNから持ってくるだけになっています。思ったよりVuerifyはサイズ小さい。

PR
学生のころは、自分で勉強しながらフリーソフトを作っていました。そのころは、意欲と好奇心で楽しかったのですが、いまはお仕事でシステム開発をしています。チームでの開発、他人からもらった要求で開発する、という違いはあるけれど、技術的にはひとりでやっていたときよりも現代的で、面白みのあるものを扱っています。
あの頃のような意欲はなかったとしても、今は知識と経験があって、また違った面で技術習得したくなる…反面、ちょっと自分にはムリかなと思ってしまうこともある…。

readpro6
https://github.com/LapisCactus/readpro6

readpro6というツールはそういう意味で、いまでもフリーソフトを作りたい気持ちがある、手の届く範囲の技術で、いまの自分の要求を叶えるツールを作ってみたい、そんな気持ちの現れなのかも、と思ったのでした。

「sikulix」というアプリを使うことがあって、ちょっと遊んでいます。 sikulixは、画面に表示されているボタンやリンクを画像認識するソフトウェアです。テスト自動化にも使えます。

sikulixの勉強がてら、便利関数を幾つか作りました。現状の成果ということで、ここに添付して説明したいと思います。

# utility function
import time

# wait and click
# @param picture a string of picture file name or a Pattern instance
# @param time a integer of timeout
# @throws Exception when timeout
def wc(picture, time):
    pic_name = picture
    if isinstance(picture, Pattern):
        pic_name = picture.getFilename()
    print "> wc " + pic_name
    target = exists(picture, time)
    if target:
        click(target)
    else:
        print "> ->wc pic not found:"+pic_name
        raise Exception("wc error. pic not found "+pic_name)

# find and click
# @param picture a string of picture file name or a Pattern instance
# @param time a integer of timeout
def fc(picture, timeout):
    pic_name = picture
    if isinstance(picture, Pattern):
        pic_name = picture.getFilename()
    print "> fc %s %d"%(pic_name, timeout)
    start_time = time.time()
    while(start_time + (timeout/1000.0) > time.time()):
        try:
            icons = findAll(picture)
            sorted_icons = sorted(icons, key=lambda m:m.y)
            print "> ->found:"+pic_name
            target = sorted_icons[0]
            click(target)
            return
        except:
            print "> ->not found... continue:"+pic_name
            continue
    print "> ->not found... timeout!"
    raise Exception("fc timeout")

# wait and keep clicking until the specified picture appears
# @param picture a string of picture file name or a Pattern instance
# @param loc a Location instance specifying a point to click untile picture appears
def wkc(picture, loc):
    while(True):
        if exists(picture):
            print "> wkc end"
            return
        else:
            print "> wkc click (%d, %d)" % (loc.x, loc.y)
            click(loc)

※引数の「画像」について
画像となっている部分は、パターンオブジェクト、画像ファイル名のどちらの型でも受け付けます。Sikulixの関数には、見つけたい画像を画像ファイル名だけでも指定できますが、Patternクラスのインスタンスを作成して類似度(similarity)や、オフセット(targetOffset)を合わせて指定することができます。そのため、作成した便利関数では、ファイル名、Patternオブジェクトのどちらも受け付けるようにしました。

wc関数

指定された画像が表示されるまで、画像認識を続けます。見つけたら、見つかった部分をクリックします。
最初の3行はログ出力のための画像ファイル名の取得を行っています。
5行目のexists関数呼び出しで、画像認識を行います。戻り値はMatchオブジェクトで、見つからなかった場合はNoneが得られます。見つかった場合は、Matchオブジェクトをクリック対象とします。見つからなかった場合は、エラーを出力して例外を発生させます。
exists関数の代わりにwait関数を使っても良かったのですが、独自のログを出力して分かりやすくしたかったため、exists関数を使用しています。

fc関数

指定された画像が表示されるまで、画像認識を続けます。複数見つかった場合、一番上にあるものをクリックします。wc関数を発展させたものです。
最初の3行は同じく、ログ出力のための画像ファイル名の取得を行っています。
5行目では、タイムアウトを計算するために、現在時刻を取得しています。次の行で、タイムアウトの判定を行っています。(time.time関数では、秒単位で時刻を返すため、timeout引数を1000で割っています)
8行目では画像認識にて見つかったすべてのMatchオブジェクトを返すfindAll関数を呼び出しています。得られた結果を、次の行でソートしています。ソートに使うキーの指定は、key=lambda m:m.yであり、Matchオブジェクトの属性"y"でソートされることになります。
ソートされたMatchオブジェクトのリストのうち、先頭のオブジェクトを取り出してクリック対象としています。クリック後は、関数を抜けます。画像認識で見つからなかった場合は、findAll関数にて例外が発生します。ログを出力して、whileの中をループします。
whileのループが終わるのは、タイムアウトしたときになりますので、ログを出力して、例外を発生させます。

wkc関数

指定された画像が表示されるまで、画像認識とクリックを続けます。クリックする場所は引数で指定します。画像が見つかっても、その場所はクリックしません。
1行目から無限ループになっています。ループの終了条件は、2行目の「画像が見つかったら」です。
画像が見つからない場合は、5行目のelse節に入ります。引数で指定された位置(Locationオブジェクト)をクリックします。

JavaFXについて学習中です。
まとまった資料がほしいので、こちらにメモを残したいと思います…。

JavaFXアプリケーションについて

1.アプリケーションの構成とクラス
JavaFXは、Javaでアプレットや画面をもったアプリケーションを作成するためのフレームワークである。画面を表すクラス(Stage)やコントロールを表すクラス(Control)、コントロールのレイアウトを管理するクラス(XxxPane)、見た目をカスタマイズするクラス(Xxxxx)を組み合わせつつ、アプリケーション(Application)を作成する。

1.1.アプリケーション(Application)
JavaFxアプリケーションは、Applicationクラスが中心となる。(エントリポイントは通常のmainメソッドだが、通常ここではApplication.launch()メソッドを呼び出して、フレームワークに制御を委ねる。mainメソッドがなければ、launchが呼ばれたとされる・・・?暗黙の実装があるのかもしれない。)
Applicationクラスは、以下の3つのメソッドをオーバーライドする。(ライフサイクルメソッドとして、適切なタイミングで呼び出される)
initメソッド:JavaFxの初期化を行う前に呼び出される。ロジックなど、JavaFxに関係のない部分の初期化を行うことができる)
startメソッド:JavaFxの初期化後に呼び出される。画面の構築などを行うことができる。
stopメソッド:アプリケーションが終了(Platform.exit()による)する前に呼び出される。JavaFxが破棄されたあとに呼ばれるため、ロジックの終了処理を行う場所となる。

1.2.ステージ(Stage)
画面クラス。
Stageは一つのScene(https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/Scene.html)を持つ(setSceneメソッドを用いる)。Sceneはシーングラフ全体を管理するためのオブジェクトであり、ドラッグ・アンド・ドロップやサイズの取得などをサポートする。シーングラフは、図形やUIコントロールを階層にしたものである。GroupクラスやRegionクラス、レイアウト関連のクラス(XxxPane)は子要素を持つことができる(これらはParentクラスのサブクラスである)。他のUIコントロールや図形は、子要素を持たない。これらが複雑に構成され、または動的に変更されるとき、表示も更新される。
ここでクラスの関連を整理しておく。
[Stage] 1-->1 [Scene] 1-->1 [Node] <-extends,has- [Parent]

1.2.1.プロパティ(Property)
Java Beanで使われているプロパティの仕組み(java.beanにあります)をベースに、拡張を加えたプロパティの仕組みがJavaFXでは使われています。
プロパティは、通常のフィールド(属性)を、一定のルールにもとづいて定義するようになっています。
ルール1:getter/setterを持つ。名前はgetXxx/setXxx。
ルール2:プロパティオブジェクトを返すメソッドを持つ。名前はxxxProperty。
プロパティオブジェクトは、プリミティブのラッパーになっていて、以下の機能を持ちます。
・変更監視(リスナーを登録して、変更時になにかしら処理できる)
・バインディング(プロパティ同士の関連を表現できる。例えば、常にAとBの和となるようなCを作れる。位置関係や金額の総和などの関係をオブジェクトとして表現できる。)(UIコントロールのプロパティ同士を連動させられる。ユーザーが入力すればプロパティも更新され、その変更をバインドした別のプロパティに反映させられる。)
バインディングオブジェクト(?)には、変更監視のリスナー登録に加えて、値が変更されたInvalidationListenerを登録できる。Bindingクラスのサブクラスを作れば、オリジナルの関係性を作ることができる。

1.3.コントロール
Scene上に配置するNodeについて。
Nodeには図形やUIコントロール、コンテナがある。
図形:四角や丸といった図形
UIコントロール:ボタンやテキストフィールド、ラベルなど。ユーザーに情報を提示したり、操作を提供したりする。
コンテナ:他のNodeを包含する。レイアウト機能を持つ(Groupは何もレイアウトを行わない)

UIコントロール
https://docs.oracle.com/javase/jp/8/javafx/user-interface-tutorial/ui_components.htm#JFXUI101
コンテナ(レイアウト)
http://www.oracle.com/pls/topic/lookup?ctx=javase80&id=JFXLY

1.4.FXML
(FXMLLoaderクラスで読み込める。コントローラクラスをセットすると、FXMLのイベント(?)を受け取ることができる)
(FXMLからイベントをセットするには、コントロールにonActionといった属性を記述する。これで、fx:controlで指定されたクラスのメソッドと紐付く)
http://krr.blog.shinobi.jp/javafx/fxml%E3%82%92%E5%88%A9%E7%94%A8%E3%81%99%E3%82%8B%EF%BC%88%EF%BC%91%EF%BC%89%E5%9F%BA%E6%9C%AC%E7%9A%84%E3%81%AA%E4%BD%BF%E3%81%84%E6%96%B9

1.5.スタイルシート
https://docs.oracle.com/javase/jp/8/javafx/user-interface-tutorial/css_tutorial.htm#JFXUI733


1.6.ダイアログ(カスタムダイアログ)
メッセージダイアログは、Alertクラスが使える。選択ボックスやテキスト入力が必要な場合は、それぞれChoiceDialog, TextInputDialogを使える。
カスタムダイアログのためには、Stageクラスに独自のコントロールを並べたものを設定する必要がある。


2.スレッドモデル
Swingやその他のGUIフレームワーク同様、シングルスレッドモデルである。JavaFx関連の操作を行う場合は、アプリケーションスレッドと呼ばれる専用のスレッド上で行う必要がある。
(きっと、このスレッドを止めると画面の描画が進まなくなる。アプリケーションスレッドではファイルの読み書きやネットワーク通信を行わないこと。)

3.標準的なアプリケーションの例(公式チュートリアル)



------

javadoc link

* Application
https://docs.oracle.com/javase/jp/8/javafx/api/javafx/application/Application.html
* Stage
https://docs.oracle.com/javase/jp/8/javafx/api/javafx/stage/Stage.html
* Scene
https://docs.oracle.com/javase/jp/8/javafx/api/javafx/scene/Scene.html
* Group
* Text

* FXMLLoader
https://docs.oracle.com/javase/jp/8/javafx/api/javafx/fxml/FXMLLoader.html

document link

* Overview
https://docs.oracle.com/javase/jp/8/javafx/get-started-tutorial/jfx-overview.htm
* Properties
https://docs.oracle.com/javase/jp/8/javafx/properties-binding-tutorial/binding.htm
http://itpro.nikkeibp.co.jp/article/COLUMN/20121219/445461/?P=2
* Scene Graph
https://docs.oracle.com/javase/jp/8/javafx/scene-graph-tutorial/scenegraph.htm#JFXSG107
* UI Controls, Layouts, CSS
https://docs.oracle.com/javase/jp/8/javafx/user-interface-tutorial/ui_components.htm#JFXUI101
* Containers
* Screen Transition http://javafx-trick.appspot.com/article/110001/110009/80051.html
* Dialogs http://krr.blog.shinobi.jp/javafx/javafx%20%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%83%BB%E3%83%80%E3%82%A4%E3%82%A2%E3%83%AD%E3%82%B0
* Samples http://www.oracle.com/technetwork/java/javase/overview/javafx-samples-2158687.html
私のWindows7 では、休止モードから復帰したときに音がならなくなることがあります。
そんなときはWindows Audio Endpoint Builderサービスを再起動するのですが、頻繁に発生するのでいちいち再起動するのが面倒です。そこでバッチファイルをこさえてみました。

@echo off

net session > nul 2>&1
if %ERRORLEVEL% == 0 (
    echo administrative privileges! restart audio service
    net stop audiosrv
    net stop audioendpointbuilder
    net start audioendpointbuilder
    net start audiosrv
) else (
    echo not administrative privileges... restart.
    powershell -command start-process "%0" -verb runas
)
簡単な内容説明:
最初にnet sessionを実行することで、管理者権限があるかどうか、確認しています。
管理者権限があれば、所望の処理を実施しています。
ない場合は、powershell経由でバッチファイル自身を起動しています。このときに管理者権限を要求しており、UACのダイアログが出ます。

この手法は、「バッチファイルを常に管理者権限で実行したい」ときに使えそうです。

参考:
http://okwave.jp/qa/q8634495.html
http://qiita.com/skkzsh/items/5e03bb7792629927acfa
スポンサード・リンク
フリーソフト指向::開発日記 by LapisCactus
忍者ブログ | [PR]

今日の聖書
自己紹介
名前:
LapisCactus (おにぎりくん)
Twitter:
Mail:
onigirikun_hsp@hotmail.com
自己紹介:
ふつうのしすてむえんじにあ。
趣味で「ソフトウェア管理」や
「TextView」を作っています。
仕事でもコンピュータを触っているのに
趣味も同じという。
健康に悪いですね。
カレンダー
10 2024/11 12
S M T W T F S
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
ブログ内検索
最新CM
[03/03 kusakari]
[11/12 おにぎりくん]
[11/08 れい]
アクセス解析