ラベル PowerShell の投稿を表示しています。 すべての投稿を表示
ラベル PowerShell の投稿を表示しています。 すべての投稿を表示

PowerShellでCD-ROMドライブを開閉する

| 2011年11月6日日曜日

ドライブを開けることは知っていたけど、閉めることもできるんじゃないかと調べてみたらどうやらできるようだ。
⇒ http://thepowershellguy.com/blogs/posh/archive/2008/08/04/powershell.aspx

紹介されていたのは開閉どちらにでも使えるものだったけど、自分としては開ける、閉めるは別コマンドの方がよかったので分けてみた。
コードが重複しているけど、分けた方が使いやすいと思ったので。

--- Open-CDDrive.ps1 ---
  1. $winnm = Add-Type -memberDefinition @ 
  2.   [DllImport("winmm.dll", CharSet = CharSet.Ansi)]  
  3.   public static extern int mciSendStringA(  
  4.   string lpstrCommand,  
  5.   string lpstrReturnString,  
  6.   int uReturnLength,  
  7.   IntPtr hwndCallback);  
  8. "@  -ErrorAction 'SilentlyContinue' -passthru -name mciSendString  
  9.   
  10. $winnm::mciSendStringA("set cdaudio door open" ,$null ,0 ,0)  
--- Closed-CDDrive.ps1 ---
  1. $winnm = Add-Type -memberDefinition @ 
  2.   [DllImport("winmm.dll", CharSet = CharSet.Ansi)]  
  3.   public static extern int mciSendStringA(  
  4.   string lpstrCommand,  
  5.   string lpstrReturnString,  
  6.   int uReturnLength,  
  7.   IntPtr hwndCallback);  
  8. "@  -ErrorAction 'SilentlyContinue' -passthru -name mciSendString  
  9.   
  10. $winnm::mciSendStringA("set cdaudio door closed" ,$null ,0 ,0)  


Windows7のPowerShellでDVDドライブからのディスク取り出し

| 2011年7月18日月曜日

Windows7を使い始めて、リムーバブルディスクの取り出しをやってみると動かなかったので修正。

前のようにWScript.Shellを使って

> $shell = New-Object -ComObject WScript.Shell
> $Shell.Application.NameSpace(17).ParseName('D:\').InvokeVerb("取り出し(&J)")

っとやろうとしたけどShellの下にApplication.NameSpaceってのがないらしく呼び出せなかった。
そこで調べてみるとWMPlayerの機能を呼び出しても取り出しができそうだったので、そっちでやってみた。

> $wmp = New-Object -ComObject WMPlayer.OCX.7
> $wmp.cdromCollection.Item(0).Eject()

自分の場合はドライブが1つしかないので試せないけど、複数ドライブなら”Item(0)”の部分を変えればいけると思う。

PowerShellで作成したフォルダに直ぐに移動(ただのメモ)

| 2010年12月1日水曜日
フォルダを作成するとき、直ぐにそのフォルダに移動して作業をしたいことが多いと思う。

でも、フォルダが多い場所で作成すると、目的のフォルダに移動するのはなかなか時間がかかる。
特に日本語のフォルダに移動するときは、Tabを連打したり、フォルダ名の一部を入力、またはペースとして補完するなど、わりと面倒くさい。

そんな時、作成したフォルダに直ぐに移動するには、PowerShellでは以下のようにすればよい。

> mkdir "適当なフォルダ名" | cd $_

mkdirをすると、DirectoryInfoオブジェクトが返ってくるのでそれをパイプして移動する。

※単純だけど、なんとなく忘れてしまいそうなTipsなのでメモ

Pingの結果をPowerShellっぽく取得してみる

| 2010年11月30日火曜日
PowerShellからPing打つことはもちろんできるが、バッチファイルの中で利用すると結果が一々コンソールに出力されてちょっと邪魔な時がある。

バッチファイルの中で知りたいのは、そのIPのマシンが生きているかどうかなので、結果は「True」か「False」で十分だ。

そこで、Pingの結果をラップしてPowerShellで扱いやすいようにしてみる。

■使い方
> Get-PingResult www.google.com #成功時
Value Reply
----- -----
True {www.l.google.com [66.249.89.104]に ping を送...

> $a = Get-PingResult www.google.com #変数に入れてみる
> $a.Reply
www.l.google.com [66.249.89.104]に ping を送信しています 32 バイトのデータ:
66.249.89.104 からの応答: バイト数 =32 時間 =19ms TTL=57
66.249.89.104 からの応答: バイト数 =32 時間 =21ms TTL=57
66.249.89.104 からの応答: バイト数 =32 時間 =19ms TTL=57
66.249.89.104 からの応答: バイト数 =32 時間 =20ms TTL=57
66.249.89.104 の ping 統計:
パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
最小 = 19ms、最大 = 21ms、平均 = 19ms

> Get-PingResult www.google.coma #失敗時
Value Reply
----- -----
False ping 要求ではホスト www.google.coma が見つかり...

  1. function Get-PingResult([String]$IP) {
  2.  $reply = C:\Windows\System32\PING.EXE $IP
  3.  #余分な空白行を削除する
  4.  $reply = $reply | % { if ($_ -ne "") { $_ }}
  5.  #上手くいったかどうかは結果の行数で判断する
  6.  $success = 9
  7.  $result = New-Object psobject
  8.  if ($reply.Length -eq $success) {
  9.   $result | Add-Member -MemberType NoteProperty -Name "Value" -Value $true
  10.  } else {
  11.   $result | Add-Member -MemberType NoteProperty -Name "Value" -Value $false
  12.  }
  13.  $result | Add-Member -MemberType NoteProperty -Name "Reply" -Value $reply
  14.  return $result
  15. }

PowerShellで文字列をバイトで区切って切り出す

|
メールの本文を生成する場合などに、きれいにフォーマットするためスペースなどで埋めたり、文字数でカットして成形したい時がある。
ただ、PowerShellだと、半角の「ABCD」というのと、全角の「ABCD」はおなじ4文字としてカウントされる。
そこでVBのLeftBのようにバイト数で切り取ってみる。

■使い方
> Get-SubStringBytes "ABCD" 2 2 #半角文字を2バイト目から2バイト切り取る
CD
> Get-SubStringBytes "ABCD" 2 2 #全角文字を・・・(略)
  1. function Get-SubStringBytes([String]$Text, [int]$StartIndex = 0, [int]$Length = 0) {
  2. $enc = [System.Text.Encoding]::Default
  3. $bytes = $enc.GetBytes($Text)
  4. return $enc.GetString($bytes, $StartIndex, $Length)
  5. }

PowerShellでユーザー一覧に利用可能か無効を付けて出力する

|
Windowsのサーバー管理をしていると、突然に利用しているユーザーの一覧を提出するように求められることがある。

そんな時、慌ててGUIの管理ツールからユーザー一覧をCSV形式やなんかでエクスポートすると、削除せずに無効にしているユーザーまで出力されてしまい、そのユーザーが現在利用可能かどうかなどの状態情報は出力されないので後で指摘されることがある。

そこで、現在利用可能か無効かの情報も一緒にユーザー一覧に付けて出力してみる。

> Get-WmiObject Win32_UserAccount | Select-Object -Property Status, Name, FullName, Description

Status    Name      FullName  Description
------    ----       --------   -----------
Degraded   Administrator         コンピュータ/ドメイン...
Degraded  Guest               コンピュータ/ドメイン...
OK      ユーザー名

利用可能なユーザーは「Status」が「OK」になっている。

PowerShellでディスクトップのキャプチャを撮る

| 2010年10月19日火曜日
わざわざキャプチャを撮るのにPowerShellを使っても仕方がないから、あまり使う機会はないかもしれない。
普通にPrintScreenキー押してMSBitmapに張り付ければいいからね。

ただ、サーバー管理なんかをしている人だと、サーバー側で現在のサーバー自身のディスクトップをキャプチャして、定期的にメールしてくるってのは、わりといいのではないかと思って作成してみた。

下のコードはコマンドを打つと、カレントフォルダに「out.jpg」ファイルができる感じです。

--- PrintScreen-Desktop.ps1 ---
  1. param([string]$outImage = "out.jpg")
  2. $b = New-Object System.Drawing.Bitmap([System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Width, [System.Windows.Forms.Screen]::PrimaryScreen.Bounds.Height)
  3. $g = [System.Drawing.Graphics]::FromImage($b)
  4. $g.CopyFromScreen((New-Object System.Drawing.Point(0, 0)),(New-Object System.Drawing.Point(0, 0)), $b.Size)
  5. $g.Dispose()
  6. $b.Save((Join-Path $PWD $outImage))

PowerShellで「du」コマンド その3

| 2010年10月7日木曜日
【その2】の「du」だと、フルパスが長すぎるとうまく取得できない場合があるのでWSHの力を借りる。

やっていることは、カレントフォルダ内のフォルダを対象に、右クリックのプロパティで取得できるサイズをとっているだけ。

GetFolderのSizeを取っているだけなのであっさりと書けるのがよい。

速度も【その2】の時より早い。
簡単に計測したのでは、【13倍】の速さだった。

$fs = New-Object -ComObject Scripting.FileSystemObject
ls | % {
if ($_.PSIsContainer) {
$name = $_.name
$size = ($fs.GetFolder($_)).size / 1MB
Write-Host $name " : " $size.ToString("0.00") "MB"
}
}

PowerShellで「ユーザーは次回ログオン時にパスワードの変更が必要」を有効化するには

| 2010年6月18日金曜日
サーバー管理をしていてリストにあるユーザー全員の「ユーザーは次回ログオン時にパスワードの変更が必要」を有効化しないといけなくなったので調べてみた。

手順としては、まずユーザー情報を取ってくる。
そのあと、有効化フラグである「1」を指定して反映させる。

PS> $username = ユーザーID
PS> $query "WinNT://./" + $username + ",user"
PS> $user = [ADSI]($query)
PS> $user.PasswordExpired = 1
PS> $user.SetInfo()

自分が実際にやった時には、CSVに書かれたユーザーIDをImport-CSVして一気に処理させたけどね;-)

PowerShellでダミーファイルを作る

|
別にPowerShellでなくても普通にCMDでダミーファイルを作る時も同じだけど、

PS> fsutil.exe file createnew 1MBのダミーファイル 1048576
ファイル C:\Windows\system32\1MBのダミーファイル が作成されました

っとすると、1MBのファイルを作る事が出来る。

それをPowerShellでやると何が嬉しいかと言うと、引数に「1048576」じゃなくて「1MB」と指定しても作れるところだ。

PowerShellでは、

PS> fsutil.exe file createnew 1MBのダミーファイル (1MB)
ファイル C:\Windows\system32\1MBのダミーファイル が作成されました

っとすれば、作ることができる。これで、「100MB」でも「1GB」でも簡単に作れそうだ。

ただ、「1MB」を括弧で囲んで「 (1MB) 」としないと、下のようにヘルプが表示されてしまう。
「1MB」が展開されずに「1MB」と文字列で渡されてしまうからだろう。

PS> fsutil.exe file createnew 1MBのダミーファイル 1MB
使用法 : fsutil file createnew <ファイル名> <長さ>
例 : fsutil file createnew C:\testfile.txt 1000

※ちなみに、Vistaだと管理者権限でPowerShellを起動しないと作れない。

PowerShellでLinuxの「du」コマンド その2

| 2010年6月8日火曜日
 フォルダ容量を取得するくらいなら、PowerShellのコマンドレットだけでできるような気がしてたけど、実際にできたのでメモ。
っというか、前にブログを書いた時点で気付けたと思うんだけどね。まだまだだな俺。

binフォルダ以下の容量を取得ところ、「Sum」が合計
> Get-ChildItem -Path .\bin -Force -Recurse | Measure-Object -Property Length -Sum

Count : 13391
Average :
Sum : 1243746959
Maximum :
Minimum :
Property : Length

これだと、わかりにくいので、MBにする。
> Get-ChildItem -Path .\bin -Force -Recurse | Measure-Object -Property Length -Sum | ForEach-Object { $_.Sum / 1MB }
1186.12953090668

MBでもわかりにくかったのでGBで、
> Get-ChildItem -Path .\bin -Force -Recurse | Measure-Object -Property Length -Sum | ForEach-Object { $_.Sum / 1GB }
1.15832962002605

PowerShellでMACアドレスからメーカーを調べる

| 2010年6月1日火曜日
PowerShellでMACアドレスからメーカー(ベンダー)を調べてみる。

まずは、MACアドレスを取得する。
MACアドレスの取り方はいろいろあるけど、ここでは、「nbtstat」コマンドを利用することにした。
まぁ一行であっさり書きたかっただけだけど。

--- Get-MACAddress.ps1 ---
  1. param([string]$ip)
  2. nbtstat -A $ip | ForEach-Object { if ( $_ -match "MAC") { $_ -replace " ","" -replace "MACアドレス=","" } }

次に、取得したMACアドレスからメーカーを調べる。
メーカーを調べるサイトは、ここを利用させてもらう。

--- Find-MacAddressFromVendorName.ps1 ---
  1. param([string]$macaddress)
  2. [void]([Reflection.Assembly]::LoadWithPartialName("System.Web"))
  3. $macaddress = [Web.HttpUtility]::UrlEncode($macaddress)
  4. $webReq = [Net.HttpWebRequest]::Create("http://www.coffer.com/mac_find/?string=$macaddress")
  5. $webReq.Method = "GET"
  6. $webReq.UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.0.3705; .NET CLR 1.1.4322)"
  7. $webRes = $webReq.GetResponse()
  8. $sr = New-Object IO.StreamReader($webRes.GetResponseStream(), $webRes.ContentEncoding)
  9. $content = $sr.ReadToEnd()
  10. $sr.Close()
  11. $webRes.Close()
  12. $content = $content.Split("`n")
  13. $result = $content | ForEach-Object {
  14. if ($_ -match "table2" -and $_ -match "td") {
  15. $_ -replace "<.*?>","" -replace "`t","" }
  16. }
  17. $obj = New-Object PSObject
  18. $obj | Add-Member NoteProperty MacAddress $macaddress
  19. $obj | Add-Member NoteProperty Vendor $result[1]
  20. $obj
利用方法は、パスを通したところにスプリクトを保存しておいて、

> Find-MacAddressFromVendorName ( Get-MACAddress 192.168.0.1)

MacAddress            Vendor
----------                ------
XX-XX-XX-XX-XX-XX       XXX

っといった感じ。

PowerShellでLinuxの「du」コマンド

| 2010年5月22日土曜日
作ろうと思ったら、もう作っている人がいたので、メモ。

PowerShellからLucene.netを使ってみる

| 2009年11月17日火曜日
@ITのこの記事を見て使ってみたくなったのでさわってみた。
お試しなので単純にできるように、テキストファイル限定で中身を全文検索してファイル名を返すようにしようと思う。

まずは、DLLをダウンロードしてくる。場所は記事に書かれているところから飛べるのでそこから落としてくる。
落としてくるのは、Lucene.Netと記事の筆者が作成された日本語用のDLLがあるのでそちらも落としてる。

記事ではLucene.Net.Analysys.Ja.JapaneseAnalyereを使用しているけど、TokenStreamメソッドを使おうとすると下の例外が出て使えなかった。

"2" 個の引数を指定して "TokenStream" を呼び出し中に例外が発生しました: "保護されているメモリに読み取りまたは書き込み操作を行おうとしました。他のメモリが壊れていることが考えられます。"
発生場所 行:1 文字:37
+ $tokenStream = $analyzer.TokenStream <<<< ("",$stringReader)
+ CategoryInfo : NotSpecified: (:) []、MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodTargetInvocation

できればJapaneseAnalyereを使って見たかったがしかたがない。今回はLuceneで全文検索をすることが目的なので、代わりにLucene.Net.Analysis.CJK.CJKAnalyzerの方を使う。
今度時間のある時に調べてみよう。N-gramより形態素解析の方が面白そうだからね。

Lucene.netを試してる時に、PowerShellからDLLのインナークラスの使い方がわからなかった。
「Lucene.Net.Documents.Field.Store.YES」と「Lucene.Net.Documents.Field.Index.TOKENIZED」は、ソースをみる限りでは、Lucene.Net.Documents.Fieldクラスのインナークラスみたいだけど、.(ドット)でつないだのではアクセスできなかった。
例外を出してその内容からわかった使い方は以下

[Lucene.Net.Documents.Field+Store]::YES
[Lucene.Net.Documents.Field+Index]::TOKENIZED

+(プラス)ってなんだ??
よくわからんが、インナークラスを使う時は+(プラス)でつなげるようだ。
一応、小さいインナークラスのDLLを作って試したけど、どうやらそうらしい。
しかし、これはildasmでDLLをみてもぱっと見わかんないな。
まぁDLLを読み込んだあとならPowerShellのTab補完が効くか効かないかで判断できるけど…in Actionに載ってたかなぁ…?

自分の試したサンプル下に貼っておく。
サンプルを実行するのに必要なDLLは下の二つなので、適当なフォルダにコピーしておく。

・Lucene.Net.dll
・Lucene.Net.Analysis.CJK.dll

そのフォルダに移動してから、サンプルをコピー&ペーストしてPowerShellに読み込ませる。
(たぶん、単純にコピーすると行番号までついてくるのでメモ帳にでも貼って番号を削除してからコピーして貼り付ければいい)

使い方は、

インデックスフォルダとインデックスファイルのベースの作成する。
> Create-LuceneIndex -IndexPath C:\LuceneIndex

インデックスファイルに指定したファイルを追加する。インデックスに追加されるのは、ファイル名(フルパス)とテキストファイルの中身。
追加するファイルを渡す引数の型は「System.IO.FileInfo」なので、「ls」の結果を変数に詰めて渡すか。フルパスを書く必要がある。
> Add-LuceneDocument -IndexPath C:\LuceneIndex -file c:\hoge\foo.txt

検索する。ファイルのフルパスが返ってくる。
> Find-LuceneDocument -IndexPath C:\LuceneIndex -word foo

インデックスを削除する。
> Remove-LuceneDocument -IndexPath C:\LuceneIndex -file c:\hoge\foo.txt

他にも追加と削除を組み合わせて更新用の関数なんかもあれば便利だと思う。
このサンプルのままで日本語も検索できるから、あと実際の業務で使おうと思ったら、クローラとOffice系のファイルの読み込みが必要かな。
Office系のファイルの読み込みならAdd-LuceneDocument関数内の

$contents = Get-Content $file

の部分を変更して、xDoc2txtなどを使う必要があると思う。
まぁPowerShellならクローラは簡単だと思うし、拡張子を見て$contentに入れる中身を変えるのも難しくないだろう。

ちょっと長いけど、サンプル↓
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd Lucene.Net.dll))
  2. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd Lucene.Net.Analysis.CJK.dll))
  3. # 元となるインデックスを作成する
  4. function Create-LuceneIndex([string]$indexPath) {
  5. # インデックスが存在した場合はフォルダを削除して作り直す
  6. if (Test-Path $indexPath) {
  7. if ([Lucene.Net.Index.IndexReader]::IndexExists($indexPath)) {
  8. [void][System.IO.Directory]::Delete($indexPath, $true)
  9. [void][System.IO.Directory]::CreateDirectory($indexPath)
  10. }
  11. }
  12. $indexWriter = New-Object Lucene.Net.Index.IndexWriter($indexPath, ( New-Object Lucene.Net.Analysis.CJK.CJKAnalyzer ), $true)
  13. $indexWriter.Close()
  14. }
  15. # インデックスにファイルを追加する
  16. function Add-LuceneDocument([string]$indexPath, [System.IO.FileInfo]$file) {
  17. # Documentオブジェクトの作成
  18. $document = New-Object Lucene.Net.Documents.Document
  19. # Fieldオブジェクトの作成
  20. $fileName = $file.FullName
  21. $contents = Get-Content $file
  22. $fieldFileName = New-Object Lucene.Net.Documents.Field("filename", $fileName, [Lucene.Net.Documents.Field+Store]::YES, [Lucene.Net.Documents.Field+Index]::TOKENIZED)
  23. $fieldContents = New-Object Lucene.Net.Documents.Field("contents", $contents, [Lucene.Net.Documents.Field+Store]::YES, [Lucene.Net.Documents.Field+Index]::TOKENIZED)
  24. # Documentオブジェクトにフィールドを追加
  25. $document.Add($fieldFileName)
  26. $document.Add($fieldContents)
  27. $indexWriter = New-Object Lucene.Net.Index.IndexWriter($indexPath, ( New-Object Lucene.Net.Analysis.CJK.CJKAnalyzer ), $false)
  28. # インデックスにDocumentオブジェクトを追加
  29. $indexWriter.AddDocument($document)
  30. # インデックスを最適化する
  31. $indexWriter.Optimize()
  32. $indexWriter.Close()
  33. }
  34. # インデックスからファイルを削除する
  35. function Remove-LuceneDocument([string]$indexPath, [System.IO.FileInfo]$file) {
  36. # アナライザの準備
  37. $analyzer = New-Object Lucene.Net.Analysis.CJK.CJKAnalyzer
  38. # ファイル名を対象にクエリを作成
  39. $queryPsr = New-Object Lucene.Net.QueryParsers.QueryParser("filename", $analyzer)
  40. $word = $file.Name
  41. $query = $queryPsr.Parse($word)
  42. # インデックスからヒットするものを探す
  43. $searcher = New-Object Lucene.Net.Search.IndexSearcher($indexPath)
  44. $hits = $searcher.Search($query)
  45. $target = $file.FullName
  46. # ヒットしたものをインデックスから削除する
  47. $indexReader = [Lucene.Net.Index.indexReader]::Open($indexPath)
  48. for ($i = 0; $i -lt $hits.Length(); $i++) {
  49. $doc = $hits.Doc($i)
  50. # ファイルのフルパスと一致するものだけを削除する
  51. if ($doc.Get("filename") -eq $target) {
  52. $indexReader.DeleteDocument($hits.Id($i))
  53. }
  54. }
  55. $indexReader.Close()
  56. }
  57. # インデックスから検索する
  58. function Find-LuceneDocument([string]$indexPath, [string]$word) {
  59. # アナライザの準備
  60. $analyzer = New-Object Lucene.Net.Analysis.CJK.CJKAnalyzer
  61. # ファイルの中身を対象にクエリを作成
  62. $queryPsr = New-Object Lucene.Net.QueryParsers.QueryParser("contents", $analyzer)
  63. $query = $queryPsr.Parse($word)
  64. # インデックスからヒットするものを探す
  65. $searcher = New-Object Lucene.Net.Search.IndexSearcher($indexPath)
  66. $hits = $searcher.Search($query)
  67. # Lucene.Net.Documents.Documentの配列を作成してヒットしたものを詰める
  68. [Lucene.Net.Documents.Document[]]$docments = New-Object Lucene.Net.Documents.Document[]($hits.Length())
  69. for ($i = 0; $i -lt $hits.Length(); $i++) {
  70. $docments[$i] = $hits.Doc($i)
  71. }
  72. return ($docments | % { $_.Get("filename") })
  73. }

PowerShellで動画の輪郭検出をしてみる

| 2009年11月14日土曜日
OpenCVSharpを使用してWebカメラから動画をキャプチャーしながら輪郭検出をしてみる。
静止画と同じではつまらないので、円の中の4点を赤色にして、その4点の座標を緑の字でウィンドウ上に表示させてみる。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. $camera = [OpenCvSharp.CvCapture]::FromCamera(0)
  3. $window = New-Object OpenCvSharp.CvWindow("SampleCapture")
  4. $threshold = 128 # 白色か黒色かのしきい値
  5. $smooth = 5 # 値が大きいほどぼかしが強い
  6. $font = New-Object OpenCvSharp.CvFont([OpenCvSharp.FontFace]::HersheyComplex, 0.7, 0.7)
  7. $point1 = New-Object OpenCvSharp.CvPoint(10,20)
  8. $point25 = New-Object OpenCvSharp.CvPoint(10,45)
  9. $point50 = New-Object OpenCvSharp.CvPoint(10,70)
  10. $point75 = New-Object OpenCvSharp.CvPoint(10,95)
  11. $colorString = [OpenCvSharp.CvColor]::Green
  12. $colorPoint = [OpenCvSharp.CvColor]::Red
  13. $colorLine = [OpenCvSharp.CvColor]::Blue
  14. $size = New-Object OpenCvSharp.CvSize(15, 15)
  15. # この値が大きいほど輪郭が狭まる
  16. $tremCriteria = New-Object OpenCvSharp.CvTermCriteria(300)
  17. $alpha = [System.Single]0.45
  18. $beta = [System.Single]0.35
  19. $gamma = [System.Single]0.2
  20. $srcSize = New-Object OpenCvSharp.CvSize($camera.FrameWidth, $camera.FrameHeight)
  21. $srcIplImage = New-Object OpenCvSharp.IplImage( $srcSize, [OpenCvSharp.BitDepth]::U8, 1)
  22. $dstIplImage = New-Object OpenCvSharp.IplImage( $srcSize, [OpenCvSharp.BitDepth]::U8, 1)
  23. # ポイントを配列で初期化 全部ゼロで初期化される
  24. [OpenCvSharp.CvPoint[]]$contour = New-Object OpenCvSharp.CvPoint[](100)
  25. # ウィンドウの中心点を取得
  26. $center = New-Object OpenCvSharp.CvPoint(($srcSize.Width / 2), ($srcSize.Height / 2))
  27. while ( [OpenCvSharp.CvWindow]::WaitKey(10) -lt 0 ) {
  28. $iplImage = $camera.QueryFrame()
  29. # 中心点を元にポイントの初期値を設定
  30. for ($i = 0; $i -lt $contour.Length; $i++) {
  31. $x = [int]($center.X * [System.Math]::Cos(2 * [System.Math]::PI * $i / $contour.Length) + $center.X)
  32. $y = [int]($center.Y * [System.Math]::Sin(2 * [System.Math]::PI * $i / $contour.Length) + $center.Y)
  33. $p = New-Object OpenCvSharp.CvPoint($x, $y)
  34. $contour.Set($i, $p)
  35. }
  36. # グレースケールに変換
  37. [OpenCvSharp.Cv]::CvtColor($iplImage, $srcIplImage, [OpenCvSharp.ColorConversion]::BgraToGray)
  38. # ぼかす
  39. $srcIplImage.Smooth($srcIplImage, [OpenCvSharp.SmoothType]::Blur, $smooth)
  40. # 二値化
  41. $srcIplImage.Threshold($dstIplImage, $threshold, 255, [OpenCvSharp.ThresholdType]::Binary)
  42. # 領域検知
  43. $dstIplImage.SnakeImage($contour, $alpha, $beta, $gamma, $size, $tremCriteria, $true)
  44. # 領域中の4点の座標を取得
  45. $str1 = [String]::Format("1 : (x = {0}, y = {1})", $contour.Get(1).X, $contour.Get(1).Y)
  46. $str25 = [String]::Format("25 : (x = {0}, y = {1})", $contour.Get(25).X, $contour.Get(25).Y)
  47. $str50 = [String]::Format("50 : (x = {0}, y = {1})", $contour.Get(50).X, $contour.Get(50).Y)
  48. $str75 = [String]::Format("75 : (x = {0}, y = {1})", $contour.Get(75).X, $contour.Get(75).Y)
  49. # ポイントを線で結んで描写
  50. for ($i = 0; $i -lt ($contour.Length - 1); $i++) {
  51. # 選んだ4点だけ 赤 それ以外は 青
  52. if ($i -eq 1 -or $i -eq 25 -or $i -eq 50 -or $i -eq 75) {
  53. $iplImage.Line($contour[$i], $contour[($i + 1)], $colorPoint, 6)
  54. } else {
  55. $iplImage.Line($contour[$i], $contour[($i + 1)], $colorLine, 3)
  56. }
  57. }
  58. # 最初の点と最後の点を結ぶ
  59. $iplImage.Line($contour[($contour.Length -1)], $contour[0], $colorLine, 3)
  60. # 座標をウィンドウに描写
  61. $iplImage.PutText($str1, $point1, $font, $colorString)
  62. $iplImage.PutText($str25, $point25, $font, $colorString)
  63. $iplImage.PutText($str50, $point50, $font, $colorString)
  64. $iplImage.PutText($str75, $point75, $font, $colorString)
  65. $window.Image = $iplImage
  66. # 連続でループするとCPUをたくさん喰うので3秒間をあける
  67. Start-Sleep 3
  68. }
  69. $iplImage.Dispose()
  70. $srcIplImage.Dispose()
  71. $dstIplImage.Dispose()
  72. $window.Dispose()
  73. $camera.Dispose()

PowerShellで静止画の輪郭検出をしてみる

|
OpenCVSharpを使用して画像の中の輪郭?色の境界?を検出する。
処理のイメージは、画像の中心からいっぱいに一つの丸を描いて輪郭が出てくるまで徐々に狭めていく。
どれくらいまで敏感に輪郭に反応するかは、

$tremCriteria = New-Object OpenCvSharp.CvTermCriteria(270)

の値を大きくすれば、よりはっきりと囲まれる。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. # グレースケールで読み込む
  3. $srcIplImage = [OpenCvSharp.Cv]::LoadImage((Join-Path $pwd "src.jpg"), [OpenCvSharp.LoadMode]::GrayScale)
  4. $dstIplImage = New-Object OpenCvSharp.IplImage($srcIplImage.Size, [OpenCvSharp.BitDepth]::U8, 3)
  5. [OpenCvSharp.CvPoint[]]$contour = New-Object OpenCvSharp.CvPoint[] 100
  6. # 中心点
  7. $center = New-Object OpenCvSharp.CvPoint(($srcIplImage.Width / 2), ($srcIplImage.Height / 2))
  8. # 全体をかこむ丸を作る
  9. for ($i = 0; $i -lt $contour.Length; $i++) {
  10. $contour[$i] = New-Object OpenCvSharp.CvPoint([int]($center.X * [System.Math]::Cos(2 * [System.Math]::PI * $i / $contour.Length) + $center.X), [int]($center.Y * [System.Math]::Sin(2 * [System.Math]::PI * $i / $contour.Length) + $center.Y))
  11. }
  12. $size = New-Object OpenCvSharp.CvSize(15, 15)
  13. $tremCriteria = New-Object OpenCvSharp.CvTermCriteria(270)
  14. $alpha = [System.Single]0.45
  15. $beta = [System.Single]0.35
  16. $gamma = [System.Single]0.2
  17. # 輪郭を検出
  18. $srcIplImage.SnakeImage($contour, $alpha, $beta, $gamma, $size, $tremCriteria, $true)
  19. [OpenCvSharp.Cv]::CvtColor($srcIplImage, $dstIplImage, [OpenCvSharp.ColorConversion]::GrayToRgb)
  20. # 赤で輪郭を描く
  21. $color = [OpenCvSharp.CvColor]::Red
  22. for ($i = 0; $i -lt ($contour.Length - 1); $i++) {
  23. $dstIplImage.Line($contour[$i], $contour[($i + 1)], $color, 2)
  24. }
  25. $dstIplImage.Line($contour[($contour.Length -1)], $contour[0], $color, 2)
  26. $dstIplImage.SaveImage((Join-Path $pwd "dst.jpg"))
  27. $srcIplImage.Dispose()
  28. $dstIplImage.Dispose()

PowerShellで動画の差分をとってみる

| 2009年11月13日金曜日
OpenCVSharpを使用してWebカメラからキャプチャーして、差分を動画で表示する。

処理は、静止画の時とほぼ同じ。
一応より差分を分かりやすくするためにぼかしを入れている。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. # カメラの情報を取得
  3. $camera = [OpenCvSharp.CvCapture]::FromCamera(0)
  4. $window = New-Object OpenCvSharp.CvWindow("SampleCapture")
  5. while ( [OpenCvSharp.CvWindow]::WaitKey(10) -lt 0 ) {
  6. $iplImage = $camera.QueryFrame()
  7. $srcIplImage = New-Object OpenCvSharp.IplImage( $iplImage.Size, [OpenCvSharp.BitDepth]::U8, 1)
  8. # グレースケールに変換
  9. [OpenCvSharp.Cv]::CvtColor($iplImage,$srcIplImage, [OpenCvSharp.ColorConversion]::BgraToGray)
  10. $dstIplImage1 = New-Object OpenCvSharp.IplImage( $srcIplImage.Size, [OpenCvSharp.BitDepth]::U8, 1)
  11. # ぼかし
  12. $srcIplImage.Smooth($srcIplImage, [OpenCvSharp.SmoothType]::Blur, 5)
  13. # 白黒に変換
  14. $srcIplImage.Threshold($dstIplImage1, 128, 255, [OpenCvSharp.ThresholdType]::Binary)
  15. # 差分出力先
  16. $dstIplImage2 = New-Object OpenCvSharp.IplImage($dstIplImage1.Size, $dstIplImage1.Depth, $dstIplImage1.NChannels)
  17. if ($tempIplImage -ne $null) {
  18. # 差分をとる
  19. [OpenCvSharp.Cv]::AbsDiff($dstIplImage1, $tempIplImage, $dstIplImage2)
  20. # 差分を表示する
  21. $window.Image = $dstIplImage2
  22. }
  23. # 今回の元データをTempに入れる
  24. $tempIplImage = $dstIplImage1
  25. }
  26. $iplImage.Dispose()
  27. $srcIplImage.Dispose()
  28. $dstIplImage1.Dispose()
  29. $dstIplImage2.Dispose()
  30. $tempIplImage.Dispose()
  31. $window.Dispose()
  32. $camera.Dispose()

PowerShellで静止画の差分をとる

|
OpenCVSharpを使用して二つの画像から差分をとって保存してみる。

同じ背景の画像を撮影して、一回目に撮ったものと二回目に撮ったものの差分をとる。
差分画像は、違う部分に色が付いていて、まったく同じ部分は黒で表示される。
ただ、それをそのまま見てもわかりにくかったので、二極化して白黒にした。
白黒にすると差分の部分だけが白くなるので見た目にわかりやすい。

ここでは、差分処理がどう動くのかを知りたかったので、差分画像を保存してから、それを読み込んで白黒にしてみた。
そのまま保存した画像と比較して見るとわかりやすいと思う。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. # 背景画像
  3. $srcIplImage1 = [OpenCvSharp.Cv]::LoadImage((Join-Path $pwd "a.jpg"))
  4. # 背景の前に何か写した画像
  5. $srcIplImage2 = [OpenCvSharp.Cv]::LoadImage((Join-Path $pwd "b.jpg"))
  6. # 差分出力先
  7. $dstIplImage1 = New-Object OpenCvSharp.IplImage($srcIplImage1.Size, $srcIplImage1.Depth, $srcIplImage1.NChannels)
  8. # 差分をとる
  9. [OpenCvSharp.Cv]::AbsDiff($srcIplImage1, $srcIplImage2, $dstIplImage1)
  10. # 差分の画像を保存 変わらなかったところは黒
  11. $dstIplImage1.SaveImage((Join-Path $pwd "c.jpg"))
  12. $srcIplImage1.Dispose()
  13. $srcIplImage2.Dispose()
  14. $dstIplImage1.Dispose()
  15. # 2極化して白黒にした方がわかりやすい
  16. # 差分の部分だけが白くなる
  17. $srcIplImage3 = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "c.jpg"), [OpenCvSharp.LoadMode]::GrayScale)
  18. $dstIplImage2 = New-Object OpenCvSharp.IplImage( $srcIplImage3.Size, $srcIplImage3.Depth, 1)
  19. $srcIplImage3.Threshold($dstIplImage2, 128, 255, [OpenCvSharp.ThresholdType]::Binary)
  20. $dstIplImage2.SaveImage((Join-Path $pwd "d.jpg"))
  21. $srcIplImage3.Dispose()
  22. $dstIplImage2.Dispose()

PowerShellでタスクトレイアイコンにバルーンウィンドウを表示してみる

| 2009年11月11日水曜日
PowerShellでタスクトレイアイコンにバルーンウィンドウを表示させる。
あんまり使うことはないかもしれないけど、PowerShell 2.0からはバックグラウンドで処理を実行できるようになったので、それの終了を知らせるのには役に立つかもしれない。

下のコードを「Show-BalloonTip.ps1」という名前でパスの通ったところにおいて

> Show-BalloonTip -title ジョブ -body 処理が終了しました。 -toolTipIcon Info

っと実行する。ToolTipIconは「Info」「Warning「Error「None」の4つのアイコン(なにも表示されないのも含めて)を表示させることができる。

表示時間を1ミリ秒にしているけど、うちの環境では1ミリ秒でも長いこと表示されっぱなしになってた(笑)

-- Show-BalloonTip.ps1 --
  1. param([int]$timeout = 1, [string]$tilte = "件名", [string]$body = "本文", [string]$toolTipIcon = "Info")
  2. [Void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
  3. $notifyIcon = New-Object System.Windows.Forms.NotifyIcon
  4. # PowerShell.exeからアイコンを抽出する System.Drawing.Icon型
  5. $powerShellExe = "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe"
  6. $icon = [System.Drawing.Icon]::ExtractAssociatedIcon($powerShellExe)
  7. $notifyIcon.Icon = $icon
  8. $notifyIcon.Visible = $true
  9. # 引数は、 表示時間(ミリ秒) 件名 本文 件名の前のアイコン(System.Windows.Forms.ToolTipIcon列挙体)
  10. $notifyIcon.ShowBalloonTip($timeout, $tilte, $body, $toolTipIcon)

PowerShellでHTMLファイルから画像のURLを取り出す

| 2009年11月7日土曜日
ワンライナーでできるのは便利。
なんとなく、もっと短くできそうな気がするけど、今の俺ではこの長さ。

正規表現の部分を変えれば、「zip」だけを返したりも出来る。ここでは、JPEG、GIF、PNG、BMPをマッチさせている。
抜きたかったHTMLでしかテストしてないから、上手くいかないサイトもあるかも。
  1. Get-Content foo.html | % { if ( $_ -match "http://.*\.(jpg|jpeg|gif|png|bmp)") { $Matches.Values | % { $_.Split("`"") | % { if ($_ -match "\.(jpg|jpeg|gif|png|bmp)") { return $_ }}}}}
ついでに、某大きな掲示板用
本文に”ttp://~~~/~~~”が普通なので、最初にばっさりHTMLのタグを消してしまってから処理している。
  1. (Get-Content foo.html) -replace "<.*?>","" | % { if ( $_ -match "ttp://.*\.(jpg|jpeg|gif|png|bmp)") { $Matches.values | % { $_.Split() | % { if ($_ -match "\.(jpg|jpeg|gif|png|bmp)") { return $_.Replace("ttp://","http://") }}}}}