Itsukaraの日記

最新IT技術を勉強・実践中。最近はDeep Learningに注力。

VisualStudioでPowerShell用GUIを作成する方法

PowerShellGUIを使う記事を下記2件書きましたが、PowerShellのプログラムを動かすまでGUIを確認できず不便と思っていました。もしかしたら、VisualStudioを使うと、画面設計ができなかと思ったら、簡単に出来たので報告します。

VisualStudioを使ったGUI設計

  • VisualStudioを立ち上げる。
  • ファイル⇒新規作成⇒プロジェクトを選択。

f:id:Itsukara:20170322232630p:plain

  • WPFアプリケーションを選択。

f:id:Itsukara:20170322232635p:plain

  • 下記ようなGUI設計画面になるので、左のツールボックスから部品を選んで、中央のウィンドウにドラッグして配置しGUIを設計*1

f:id:Itsukara:20170322232640p:plain

自動生成されたXAMLを使いPowerShellプログラム作成

  • 例えば下記のようにGUI部品を配置。

f:id:Itsukara:20170322232649p:plain

  • 画面下部のXAML(文字列)を抜き出してPowerShellのプログラムを作成。
  • ただし、一部の文字列は削除が必要(下記の黄色枠部分)。

f:id:Itsukara:20170322235005p:plain

  • 下記がプログラムの例。「@'」と「'@」で囲まれた部分がXAML
$ErrorActionPreference = "stop"
Set-PSDebug -Strict
Add-Type -AssemblyName PresentationFramework

[xml]$xaml = @'
<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Label x:Name="label01" Content="名前" HorizontalAlignment="Left" Margin="15,26,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="textName" HorizontalAlignment="Left" Height="26" Margin="68,26,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="439"/>
        <Label x:Name="label02" Content="ふりがな" HorizontalAlignment="Left" Margin="15,57,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="textFurigana" HorizontalAlignment="Left" Height="26" Margin="68,57,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="439"/>
        <Label x:Name="label03" Content="性別" HorizontalAlignment="Left" Margin="15,88,0,0" VerticalAlignment="Top"/>
        <StackPanel x:Name="stackGender" HorizontalAlignment="Left" Height="26" Margin="68,88,0,0" VerticalAlignment="Top" Width="129" Orientation="Horizontal">
            <RadioButton x:Name="radioButtonMale" Content="Male" Height="26" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5,5,5,0"/>
            <RadioButton x:Name="radioButtonFemale" Content="Female" Height="26" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="5,5,5,0"/>
        </StackPanel>
        <Label x:Name="label04" Content="国籍" HorizontalAlignment="Left" Margin="15,119,0,0" VerticalAlignment="Top"/>
        <Label x:Name="label05" Content="年齢" HorizontalAlignment="Left" Margin="15,150,0,0" VerticalAlignment="Top"/>
        <TextBox x:Name="textAge" HorizontalAlignment="Left" Height="26" Margin="68,150,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="52"/>
        <ComboBox x:Name="comboBoxCountry" HorizontalAlignment="Left" Height="26" Margin="68,119,0,0" VerticalAlignment="Top" Width="439"/>
        <Button x:Name="buttonRegist" Content="登録" HorizontalAlignment="Left" Height="33" Margin="242,276,0,0" VerticalAlignment="Top" Width="48"/>
        <TextBlock x:Name="textBlock" HorizontalAlignment="Left" Height="90" Margin="15,181,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="492"/>

    </Grid>
</Window>
'@

$reader = New-Object System.Xml.XmlNodeReader $xaml
$frm = [System.Windows.Markup.XamlReader]::Load($reader)

$countries = "U.S.A China Japan Germany France England Russia".split(" ")
$comboBoxCountry = $frm.FindName("comboBoxCountry")
foreach ($country in $countries) {
  [void]$comboBoxCountry.Items.Add($country)
}

$textName = $frm.FindName("textName")
$comboBoxCountry = $frm.FindName("comboBoxCountry")
$textFurigana = $frm.FindName("textFurigana")
$stackGender = $frm.FindName("stackGender")
$textAge = $frm.FindName("textAge")
$textBlock = $frm.FindName("textBlock")

function getChecked($parent) {
    $checked = ""
    foreach ($child in $parent.Children) {
        if ($child.isChecked) {
            $checked += $child.Content
        }
    }
    return $checked
}

function regist {
    $name = $textName.Text
    $furigata = $textFurigana.Text
    $gender = getChecked $stackGender
    $country = $comboBoxCountry.SelectedValue
    $age = $textAge.Text

    $msg = ""
    $msg += "名前:" + $name + "`n" 
    $msg += "ふりがな:" + $furigata + "`n" 
    $msg += "性別:" + $gender + "`n" 
    $msg += "国籍:" + $country + "`n" 
    $msg += "年齢:" + $age + "`n" 

    $textBlock.Text = $msg
}

$buttonRegist =  $frm.FindName("buttonRegist")
$buttonRegist.Add_Click({regist})

$result = $frm.ShowDialog()
  • プログラム実行例。名前等を入力後、「登録」ボタンを押したところ。

f:id:Itsukara:20170322232657p:plain

あとがき

VisualStudioを使うと、PowerShellGUIがとても簡単に設計できるので、ぜひ試してみてください。

おまけ

ListBoxやComboBoxは、PowerShellから簡単に項目を追加できるが、RadioButtonは簡単に追加できない。これはとても不便だが、次のようにプレースホルダを沢山書いておき、必要なものだけ表示するようにPowerShellで制御すれば、ある程度対応できることが分かった。ご参考まで。

  • プログラム例:
$ErrorActionPreference = "stop"
Set-PSDebug -Strict
Add-Type -AssemblyName PresentationFramework

[xml]$xaml = @'
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="xaml test #2"
    Width="170pt" Height="170pt">
  <StackPanel>
    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
      <StackPanel x:Name="country">
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
      </StackPanel>
      <Label Content="  " FontSize="10pt"/>
      <StackPanel x:Name="fruits">
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
        <RadioButton Content="PlaceHolder"></RadioButton>
      </StackPanel>
    </StackPanel>
    <Label x:Name="msg"  Content="  " FontSize="10pt"/>
    <Button x:Name="btn" Content="Push Me"  FontSize="10pt" />
  </StackPanel>
</Window>
'@

$reader = New-Object System.Xml.XmlNodeReader $xaml
$frm = [System.Windows.Markup.XamlReader]::Load($reader)
$country = $frm.FindName("country")
$fruits = $frm.FindName("fruits")
$msg = $frm.FindName("msg")

# 全てのRadioButtonを非表示にする
foreach ($s in $country.Children) {
    $s.Visibility = "Collapsed"
}

# 全てのRadioButtonを非表示にする
foreach ($b in $fruits.Children) {
    $b.Visibility = "Collapsed"
}

# RadioButtonのContentを設定し、表示する
$countryList = "U.S.A China Japan Germany France England Russia".split(" ")
$n = 0
$children = $country.Children
foreach ($c in $countryList) {
    $radioButton = $children[$n]
    $radioButton.Content = $c
    $radioButton.Visibility = "Visible"
    $n += 1
}

# RadioButtonのContentを設定し、表示する
$fruitsList = "Apple Orange Grape".split(" ")
$n = 0
$children = $fruits.Children
foreach ($f in $fruitsList) {
    $radioButton = $children[$n]
    $radioButton.Content = $f
    $radioButton.Visibility = "Visible"
    $n += 1
}

# 選択された項目を返す
function getChecked($parent) {
    $checked = ""
    foreach ($child in $parent.Children) {
        if ($child.isChecked) {
            $checked += $child.Content
        }
    }
    return $checked
}

function clicked {
    $selectedCountry = getChecked $country
    $selectedFruits  = getChecked $fruits
    $msg.content = "Country=" + $selectedCountry + "`n" + "Fruits=" +  $selectedFruits
}

$btn = $frm.FindName("btn")
$btn.Add_Click({clicked})
$result = $frm.ShowDialog()
  • 実行例:

f:id:Itsukara:20170323002422p:plain

*1:それぞれの部品の意味は、別のサイト等で調べてください。

PowerShell+WPFが動かない場合の原因と対策

仕事の関係でPowerShellを使ったので、PowerShellでの勉強内容と作成プログラムを記事に書きましたが、本番で動かず、困ってしまいました。同様の問題で困っている方がいるかもしれないので、解決先を書きます。

問題点

原因と解決方法

まとめ

PowerShellは、スクリプトがネットワークドライブにあるか、どのバージョンか、PowerShellPowerShell ISEか、によって動作が異なるので注意が必要。]

  • 対策:「powershell -sta -ExecutionPolicy Bypass ファイル名」で起動。
  • 別案:「powershell -sta -file ファイル名」で起動(2/18追記)。

PaintsChainerが爆速になっていた

http://itsukara.hateblo.jp/entry/2017/01/29/064926:embed:先週の記事で書いた線画着色(PaintsChanier)の件、久しぶりに最新版をダウンロードして試してみたら、当方の貧弱なGPU RAM(2GB)でも動くようになっており、サイズが500x500位の画像では3秒ぐらいで処理が完了。爆速になっていた。

線画着色最新版が妙に青みがかっている

線画着色の件、最新版(2017/1/31 21:39; 03739fd)を本家github(下記)からダウンロードして試したところ、残念ながら、特に速くなったり、機能が追加されている気はしません。また、残念ながら、色が妙に青みがかっています。

github.com

1/29ダウンロード版で生成した画像

f:id:Itsukara:20170131215053p:plain

1/31 21:39ダウンロード版で生成した画像

f:id:Itsukara:20170131214721p:plain

githubサイトを見ると、OpenCVのインストール方法として、結構面倒な方法へのリンク(下記)が書かれているので、それをやらないとだめなのかと思ったのですが、下記サイトに書かれたテスト用のデモを現在環境で実行したところ、下記サイトに表示される絵が、そのままの色で表示され、何の問題も発生しませんでした。ということは、下記の面倒はインストールをしなくても、"conda install opencv"で十分だったということです。Preferred Networkさん、どうなっているでしょう... (線画着色の件、githubにcommitしている人を見ると、Preferred Networkの人が多数関わっています。Preferred Networkが開発したChainerの宣伝にもなるので、Taizanだけでなく、Preferred Network総がかりで取り組んでいるのだと思います)

  • チェック用プログラムを走らせ、上記サイトのウィンドウに重ねて表示したところ。

f:id:Itsukara:20170131215600j:plain

上記表示結果を基に、本家サイトのIssueで質問予定です。

ちなみに、以前のソースと比べたら、img2imgDataset.pyの旧版と新版で下記のように変わってますが、学習データは旧版のソースコードで学習させていると思いますので、「現在のソースコード」と「旧ソースコードで作成した学習データ」の間での不整合が原因な気がします。
旧版:image2 = cv2.cvtColor(image2, cv2.COLOR_BGR2YUV)
新版:image2 = cv2.cvtColor(image2, cv2.COLOR_RGB2YUV)

本件、githubのissueで議論中です。下記を参照ください。学習データはYUVなので、単に、画像の入出力がRGBかBGRかという問題とのこと。これは、@abbychauさんが解決しました(OpenCVのバージョンを見て自動的に判定できるらしいです)
github.com

線画着色で満員御礼!

当サイトはこれまで平均100PV/日程度のアクセス数だったのですが、昨日と本日は、各1日で1か月分のPVを頂きました。関心を持って頂き、まことにありがとうございます。とても励みになります。
f:id:Itsukara:20170131005452p:plain

ついでに、他の記事も見てくれると更にうれしいです。例えば、OpenAI GymのMontezuma's Revengeで1位になると共に、Deep Mindの論文に書かれていない部屋にも到達した話とか... これがきっかけでOpenAIの本社に招待され、12月にサンフランシスコに行ってきました(費用はOpenAI負担)。
itsukara.hateblo.jp

DeepMindの論文に書かれていない部屋に到達した件は、論文の著者Marc G. Bellemare氏にもお知らせ済で、素直に喜んでくれています(下記youtubeのKorekara Itsukaraのコメントと、Marc G. Bellemare氏のコメント参照)。
Playing Montezuma's Revenge with Intrinsic Motivation - YouTube

OpenAI Gymのスコアは下記参照。1位~3位が当方です。
gym.openai.com

写真から輪郭を抽出し線画着色

ローカルに線画着色できるので、色々試してみました。

今回、写真から輪郭を抽出し、それを基に線画着色してみました。輪郭を抽出するjupyter notebookはgithubにアップしましたので、パラメーターをいろいろ変えて試してみてください。以下では、googleで「美人」で検索した画像から輪郭を抽出し、着色したものです。最後の写真以外、ヒントは無しです。

美人#1

元写真ほど良くないですが、結構きれいな画像になりました。
f:id:Itsukara:20170129223034p:plain

美人#2

元写真は知的で若い女性の写真ですが、おばさんになってしまいました。
f:id:Itsukara:20170129223218p:plain

美人#3

元写真は野性的で若い美人ですが、抽象画になってしまいました。
f:id:Itsukara:20170129223842p:plain

美人#4

元写真と比べ良い線画が撮れませんでしたが、着色したら、それなりになりました。
f:id:Itsukara:20170129224246p:plain

美人#5

細かい線画が撮れ、着色したら、まあまあの出来になりました。
f:id:Itsukara:20170129224540p:plain

建物#1

建物は、輪郭がはっきりしているので、よい線画ができました。ただ、着色したら輪郭があいまいになってしまいました。
f:id:Itsukara:20170129224859p:plain

元の写真は下記です。
http://chihiro015.up.n.seesaa.net/chihiro015/image/IMG_6731.JPG?d=a1

風景#1

森を抜ける階段のようですが、色使いが今一つです。
f:id:Itsukara:20170129225512p:plain

4点ほど緑を加え、会談に灰色を2か所入れました。緑にはなりましたが、下記写真と比べると、今一つですね。
f:id:Itsukara:20170129225725p:plain

元の写真は下記です。
http://travel.tycg.gov.tw/Utility/DisplayImage?id=11271

追記

このように、Webから写真を取ってきて、そこから線画を抽出し、それを基に着色し、着色画像を写真と比較する処理を、自動化して、何百万枚も学習させると、更に凄いものになりそうな気がします。ついでに、線画抽出の部分もDeep Learningで作ると、線画抽出と、線画着色と、一緒に学習できますね。大学や研究機関で豊富なマシンパワーがある方は、ぜひ試してみてください。

DL使った線画自動着色がCPUでも動くようにしました

DL使った線画自動着色の件、下記記事を書いた後で、CPUだけでも動くように修正し、pull requestを出させていただきました。幸い、conflictsは無いようです。

itsukara.hateblo.jp

修正内容ですが、元々CPUで使う場合は"python server.py -g -1"とすれば動くはずなのですが、"cgi_exe.py"で "self.gpu >= 0" か判定して処理を分ける部分が抜けていたので、追加したものです。

ちなみに、トレーニングと異なり判定だけなので、CPUでも十分に速いです。お試しサイトはアクセスが集中して処理が重くなっており着色に1分以上かかるので、お試しサイトの負荷を減らす意味でも、ローカル環境を作って試しましょう!

何よりも、CPUだけでもローカル環境の方がお試しサイトよりもずっと速いです。具体的には、CPUだけも15秒程度で着色が完了します*1。これに対して、お試しサイトはアクセス集中のため1分ぐらい待たされます。

merge前にCPUで試したい方は下記をお使いください。
https://github.com/Itsukara/PaintsChainer.git

GPUメモリ不足時の画面

f:id:Itsukara:20170129073057p:plain

CPUに切替後の画面

f:id:Itsukara:20170129072921p:plain

追記

当初、GPUを使って動くようにするために、下記記事を見てVisual Studioを入れたり、CUDA8.0を入れたりと、1時間以上掛かり、確かにMNISTは10倍くらい速くなったのですが、結局、GPUメモリ不足で一部しか動かず、残念でした。
qiita.com

ちなみに、CPUで動かすだけなら、chainerを"pip install chainer"で入れるだけであり、とても簡単です。(当然ながら、Pythonの事前インストールも必要ですが、これは、Anacondaをインストールして実行するだけなので、これも簡単です。また、opencvも必要ですが、これは"pip install opencv"で大丈夫でした)。

追記2 (Windowsでの簡単なインストール方法)

一応、Windowsでのインストール手順書いておきます。

# (1) Anacondaをインストール(Python 3.5 version)
# ・下記からexeをダウンロードして実行(管理者権限で実行)
#  ・https://www.continuum.io/downloads
# ・DOS窓で"python --version"を実行し、エラーにならないことを確認
#  ・エラーになる場合、"Anaconda Windows インストール方法"でググり、自己対応願います。
# ・parco_opaaiさんが詳細なインストール方法を書かれています。ご参考まで。
#  ・http://qiita.com/parco_opaai/items/5f654237afde9db85beb
#  ・ただし、上記記事のopencv-pythonを使うと色が変になるので要注意。
# (2) 以下を、DOS窓(管理者権限で実行)で実行
> conda upgrade pip
> pip install chainer
> conda install --channel https://conda.anaconda.org/menpo opencv3
# ※ "conda install opencv"ではUbuntuで色が青くなるのNGでした
# (3) paintschainer (CPUで実行可能版)をインストール
# ・下記からzipをダウンロードし解凍(github知らなくてもOK)
#  ・https://github.com/Itsukara/PaintsChainer/archive/master.zip
#  ※本家コードが急速に進化していますので、それを使った方が良さそうです。
#   ・https://github.com/taizan/PaintsChainer/archive/master.zip
# ・解凍してできたフォルダは、下記のように名前を変更
#  ・PaintsChainer-master => PaintsChainer
# ・下記フォルダを作成
#   ・PaintsChainer\cgi-bin\paint_x2_unet\models
# ・下記サイトにある学習済データを上記フォルダにダウンロード
#   ・http://paintschainer.preferred.tech/downloads/
# (4) フォルダPaintsChainerでSHIFTキーを押しながら右クリックし、
#   「コマンドウィンドウをここで開く」でDOS窓を開き、下記を実行
>python server.py -g -1
GPU: -1
start
load model
serving at localhost : 8000
# (4) ブラウザで下記を開く
# ・http://localhost:8000/static/
# ※本家コード使用時は:http://localhost:8000/

追記3 (当サイトの宣伝)

ついでに、他の記事も見てくれると更にうれしいです。例えば、OpenAI GymのMontezuma's Revengeで1位になると共に、Deep Mindの論文に書かれていない部屋にも到達した話とか... これがきっかけでOpenAIの本社に招待され、12月にサンフランシスコに行ってきました(費用はOpenAI負担)。
itsukara.hateblo.jp

  • DeepMindの論文に書かれていない部屋に到達した件は、論文の著者Marc G. Bellemare氏にもお知らせ済で、素直に喜んでくれています(下記youtubeのKorekara Itsukaraのコメントと、Marc G. Bellemare氏のコメント参照)。

Playing Montezuma's Revenge with Intrinsic Motivation - YouTube

  • OpenAI Gymのスコアは下記参照。1位~3位が当方です。

gym.openai.com

  • 下記はMontezuma's Revenge関連の成果をまとめたスライドです。
  • 英語版(最新)

www.slideshare.net

  • 日本語版(少し古い)

www.slideshare.net

*1:CPUはCore i7-4770Kです。なお、大きな画像だと時間が25秒ぐらいに延びますね。通常、Neural Network部分の入力サイズは一定なので処理時間は関わらないはずですが... もしかしたら、Neural Network以外の部分(画像処理とか)で時間が掛かっているのかもしれません。pythonのプロファイルを採ればハッキリすると思います。どなたか試されるてはいかがでしょう。