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)

wgetの使い方メモ

| 2009年11月7日土曜日
テキストファイルに一行毎に書かれたURLで同じフォルダ内にないファイルを三秒間隔をあけてダウンロードする。

> wget -nc -nv -w 3 -t 1 -i list.txt

たまにうまくいかない時があったので、PowerShellを使って一個づつダウンロードする場合。

> cat list.txt | % { wget $_ }

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

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

正規表現の部分を変えれば、「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://") }}}}}

PowerShellで画像の色をカウントする

| 2009年11月6日金曜日
OpenCVSharpを使用して画像の白、黒、赤、青、緑、黄色、マゼンタ、シアン、その他の色に該当する色を数えてみる。
下のコードには、その色に該当するかについて、あそびをまったく入れていないのでほとんどが、その他の色になってしまう。
けど、今回は、白黒画像をカウントする事が目的で、白と黒だけちゃんと取れればよかっただけなのでこれで良しとする。
今度、ある程度まともな条件で取得できるようにしよう。
あと、この方法だとかなり遅いので、なにか別な取得方法がないかについても調べておこう。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. $iplImage = [OpenCvSharp.Cv]::LoadImage((Join-Path $pwd "foo.jpg"))
  3. for ($x = 0; $x -lt $iplImage.Width; $x++) {
  4. for ($y = 0; $y -lt $iplImage.Height; $y++) {
  5. # CvColor型にキャスト
  6. $cvColor = [OpenCvSharp.CvColor]$iplImage.Get2D($y, $x)
  7. $count++
  8. switch ($cvColor) {
  9. {$_ -eq [OpenCvSharp.CvColor]::White} {
  10. $white++
  11. break
  12. }
  13. {$_ -eq [OpenCvSharp.CvColor]::Black} {
  14. $black++
  15. break
  16. }
  17. {$_ -eq [OpenCvSharp.CvColor]::Red} {
  18. $red++
  19. break
  20. }
  21. {$_ -eq [OpenCvSharp.CvColor]::Blue} {
  22. $blue++
  23. break
  24. }
  25. {$_ -eq [OpenCvSharp.CvColor]::Green} {
  26. $green++
  27. break
  28. }
  29. {$_ -eq [OpenCvSharp.CvColor]::Yellow} {
  30. $yellow++
  31. break
  32. }
  33. {$_ -eq [OpenCvSharp.CvColor]::Magenta} {
  34. $magenta++
  35. break
  36. }
  37. {$_ -eq [OpenCvSharp.CvColor]::Cyan} {
  38. $cyan++
  39. break
  40. }
  41. default {
  42. $other++
  43. }
  44. }
  45. }
  46. }
  47. Write-Host White = ($white / $count).ToString("00.0%")
  48. Write-Host Black = ($black / $count).ToString("00.0%")
  49. Write-Host Red = ($red / $count).ToString("00.0%")
  50. Write-Host Blue = ($blue / $count).ToString("00.0%")
  51. Write-Host Green = ($green / $count).ToString("00.0%")
  52. Write-Host Yellow = ($yellow / $count).ToString("00.0%")
  53. Write-Host Magenta = ($magenta / $count).ToString("00.0%")
  54. Write-Host Cyan = ($cyan / $count).ToString("00.0%")
  55. Write-Host Other = ($other / $count).ToString("00.0%")
  56. $iplImage.Dispose()

PowerShellで動画を白黒でキャプチャー

| 2009年10月31日土曜日
OpenCVSharpを使用して、動画を白黒でキャプチャーする。
グレースケールの時と同じで、読み込む→グレースケールに変換→白黒に変換の順に行う。
最後に変換したものをウィンドウに表示させる。
  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. $threshold = 128 # 白色か黒色かのしきい値
  6. while ( [OpenCvSharp.CvWindow]::WaitKey(10) -lt 0 ) {
  7. $iplImage = $camera.QueryFrame()
  8. $srcIplImage = New-Object OpenCvSharp.IplImage( $iplImage.Size, [OpenCvSharp.BitDepth]::U8, 1)
  9. # グレースケールに変換
  10. [OpenCvSharp.Cv]::CvtColor($iplImage,$srcIplImage, [OpenCvSharp.ColorConversion]::BgraToGray)
  11. $dstIplImage = New-Object OpenCvSharp.IplImage( $srcIplImage.Size, [OpenCvSharp.BitDepth]::U8, 1)
  12. # 白黒に変換
  13. $srcIplImage.Threshold($dstIplImage, $threshold, 255, [OpenCvSharp.ThresholdType]::Binary)
  14. $window.Image = $dstIplImage
  15. }
  16. $iplImage.Dispose()
  17. $srcIplImage.Dispose()
  18. $dstIplImage.Dispose()
  19. $window.Dispose()
  20. $camera.Dispose()

PowerShellで動画をグレースケールでキャプチャー

|
OpenCVSharpを使用して、動画をグレースケールでキャプチャーする。
静止画をグレースケールにするのと同じ方法で、一度、IplImage型で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. $srcIplImage = $camera.QueryFrame()
  7. $dstIplImage = New-Object OpenCvSharp.IplImage( $srcIplImage.Size, [OpenCvSharp.BitDepth]::U8, 1)
  8. # グレースケールに変換
  9. [OpenCvSharp.Cv]::CvtColor($srcIplImage,$dstIplImage, [OpenCvSharp.ColorConversion]::BgraToGray)
  10. $window.Image = $dstIplImage
  11. }
  12. $srcIplImage.Dispose()
  13. $dstIplImage.Dispose()
  14. $window.Dispose()
  15. $camera.Dispose()

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

| 2009年10月29日木曜日
OpenCvSharpを使用して、Webカメラでキャプチャーしながら顔検出をしてみる。
基本的には静止画の時と同じで、その部分のコードを動画のキャプチャーに埋め込んだだけ。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. #顔を検出するためにHaar分類器のカスケードを用いる
  3. $color = [OpenCvSharp.CvColor]::Red
  4. $scale = 1.04;
  5. $scaleFactor = 1.139;
  6. $minNeighbors = 2;
  7. $camera = [OpenCvSharp.CvCapture]::FromCamera(0)
  8. $window = New-Object OpenCvSharp.CvWindow("SampleCapture")
  9. $srcWidth = $camera.FrameWidth
  10. $srcHeight = $camera.FrameHeight
  11. $srcSize = New-Object OpenCvSharp.CvSize([int]$srcWidth, [int]$srcHeight)
  12. $srcIplImage = New-Object OpenCvSharp.IplImage( $srcSize, [OpenCvSharp.BitDepth]::U8, 1)
  13. $dstWidth = $camera.FrameWidth / $scale
  14. $dstHeight = $camera.FrameHeight / $scale
  15. $dstSize = New-Object OpenCvSharp.CvSize([int]$dstWidth, [int]$dstHeight)
  16. $dstIplImage = New-Object OpenCvSharp.IplImage( $dstSize, [OpenCvSharp.BitDepth]::U8, 1)
  17. while ( [OpenCvSharp.CvWindow]::WaitKey(10) -lt 0 ) {
  18. $iplImage = $camera.QueryFrame()
  19. #顔検出用の画像の生成
  20. [OpenCvSharp.Cv]::CvtColor($iplImage,$srcIplImage, [OpenCvSharp.ColorConversion]::BgraToGray)
  21. [OpenCvSharp.Cv]::Resize($srcIplImage, $dstIplImage, [OpenCvSharp.Interpolation]::Linear)
  22. [OpenCvSharp.Cv]::EqualizeHist($dstIplImage,$dstIplImage)
  23. $cascade = [OpenCvSharp.CvHaarClassifierCascade]::FromFile((Join-Path $pwd "haarcascade_frontalface_alt.xml"))
  24. $storage = New-Object OpenCvSharp.CvMemStorage
  25. $storage.Clear()
  26. # 顔の検出
  27. $faces = [OpenCvSharp.Cv]::HaarDetectObjects($dstIplImage, $cascade, $storage, $scaleFactor, $minNeighbors, 0, (New-Object OpenCvSharp.CvSize(30, 30)));
  28. Write-Host $faces.Total
  29. # 検出された全ての顔位置に四角い枠を描画する
  30. for ($i = 0; $i -lt $faces.Total; $i++) {
  31. $r = $faces[$i].Rect
  32. $pt1 = New-Object OpenCvSharp.CvPoint($r.x, $r.y)
  33. $pt2 = new-object OpenCvSharp.CvPoint(($r.x + $r.Width),($r.y + $r.Height ))
  34. $iplImage.Rectangle($pt1, $pt2, $color, 3, 8, 0)
  35. }
  36. # 丸で囲む
  37. # for ($i = 0; $i -lt $faces.Total; $i++) {
  38. # $r = $faces[$i].Rect
  39. # $X = [OpenCvSharp.Cv]::Round(($r.X + $r.Width * 0.5) * $Scale)
  40. # $Y = [OpenCvSharp.Cv]::Round(($r.Y + $r.Height * 0.5) * $Scale)
  41. # $center = New-Object OpenCvSharp.CvPoint($X, $Y)
  42. # $radius = [OpenCvSharp.Cv]::Round(($r.Width + $r.Height) * 0.25 * $Scale)
  43. # $iplImage.Circle($center, $radius, $color, 3, [OpenCvSharp.LineType]::AntiAlias, 0)
  44. # }
  45. # ウィンドウに表示
  46. $window.Image = $iplImage
  47. }
  48. $srcIplImage.Dispose()
  49. $dstIplImage.Dispose()
  50. $iplImage.Dispose()
  51. $window.Dispose()
  52. $camera.Dispose()

PowerShellで画像のRGBを調べてみる

| 2009年10月27日火曜日
OpenCVSharpを使用して画像のRGBを調べてみる。
下のコードは読み込んだ画像の1ピクセル?づつのRGB情報を順番に出力していくもの。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. $iplImage = [OpenCvSharp.Cv]::LoadImage((Join-Path $pwd "foo1.jpg"))
  3. for ($x = 0; $x -lt $iplImage.Width; $x++) {
  4. for ($y = 0; $y -lt $iplImage.Height; $y++) {
  5. $cvColor = [OpenCvSharp.CvColor]$iplImage.Get2D($y, $x)
  6. $line = [String]::Format("x = {0:000}, y = {1:000} : R = {2:000}, G = {3:000}, B = {4:000}", $x, $y, $cvColor.R, $cvColor.G, $cvColor.B)
  7. Write-Host $line
  8. }
  9. }
  10. $iplImage.Dispose()

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

| 2009年10月26日月曜日
OpenCvSharpを使用して、画像から顔を検出してみる。
顔があったらその周りを赤色の四角い枠で囲む。

顔検出には数千枚の画像ファイルから機械学習を行って、人間の顔とは?ってのを修めたデータが必要らしい…
でも、それをやるには時間がかかりすぎるので、Sampleに入っている学習済みのデータ「haarcascade_frontalface_alt.xml」を使用させてもらう。

利用させてもらっておいてどうかとは思うが、試したデータでは今一だった。
どうも余計なものまで顔と認識して検出してくる。もちろん、顔も検出してくれるからいいんだけどね。

いつものDLLと「haarcascade_frontalface_alt.xml」を同じフォルダーにコピーして、検出した元画像を「foo.jpg」として下のコードを実行する。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. # 元データ
  3. $iplImage = [OpenCvSharp.Cv]::LoadImage((Join-Path $pwd "foo.jpg"))
  4. $color = [OpenCvSharp.CvColor]::Red
  5. $scale = 1.04;
  6. $scaleFactor = 1.139;
  7. $minNeighbors = 2;
  8. $srcWidth = $iplImage.Width
  9. $srcHeight = $iplImage.Height
  10. $srcSize = New-Object OpenCvSharp.CvSize([int]$srcWidth, [int]$srcHeight)
  11. $srcIplImage = New-Object OpenCvSharp.IplImage( $srcSize, [OpenCvSharp.BitDepth]::U8, 1)
  12. $dstWidth = $iplImage.Width / $scale
  13. $dstHeight = $iplImage.Height / $scale
  14. $dstSize = New-Object OpenCvSharp.CvSize([int]$dstWidth, [int]$dstHeight)
  15. $dst1IplImage = New-Object OpenCvSharp.IplImage( $dstSize, [OpenCvSharp.BitDepth]::U8, 1)
  16. # 顔検出用の画像の生成
  17. [OpenCvSharp.Cv]::CvtColor($iplImage,$srcIplImage, [OpenCvSharp.ColorConversion]::BgraToGray)
  18. [OpenCvSharp.Cv]::Resize($srcIplImage, $dst1IplImage, [OpenCvSharp.Interpolation]::Linear)
  19. [OpenCvSharp.Cv]::EqualizeHist($dst1IplImage,$dst1IplImage)
  20. $cascade = [OpenCvSharp.CvHaarClassifierCascade]::FromFile((Join-Path $pwd "haarcascade_frontalface_alt.xml"))
  21. $storage = New-Object OpenCvSharp.CvMemStorage
  22. $storage.Clear()
  23. # 顔の検出
  24. $faces = [OpenCvSharp.Cv]::HaarDetectObjects($dst1IplImage, $cascade, $storage, $scaleFactor, $minNeighbors, 0, (New-Object OpenCvSharp.CvSize(30, 30)));
  25. # 検出された全ての顔位置に四角い枠で囲む
  26. for ($i = 0; $i -lt $faces.Total; $i++) {
  27. $r = $faces[$i].Rect
  28. $pt1 = New-Object OpenCvSharp.CvPoint($r.x, $r.y)
  29. $pt2 = new-object OpenCvSharp.CvPoint(($r.x + $r.Width),($r.y + $r.Height ))
  30. $iplImage.Rectangle($pt1, $pt2, $color, 3, 8, 0)
  31. }
  32. # 丸で囲いたい場合はこっち
  33. #for ($i = 0; $i -lt $faces.Total; $i++) {
  34. # $r = $faces[$i].Rect
  35. # $X = [OpenCvSharp.Cv]::Round(($r.X + $r.Width * 0.5) * $Scale)
  36. # $Y = [OpenCvSharp.Cv]::Round(($r.Y + $r.Height * 0.5) * $Scale)
  37. # $center = New-Object OpenCvSharp.CvPoint($X, $Y)
  38. # $radius = [OpenCvSharp.Cv]::Round(($r.Width + $r.Height) * 0.25 * $Scale)
  39. # $iplImage.Circle($center, $radius, $color, 3, [OpenCvSharp.LineType]::AntiAlias, 0)
  40. #}
  41. # 赤枠で囲ったデータを保存する
  42. $iplImage.SaveImage((Join-Path $pwd "bar.jpg"))
  43. $iplImage.Dispose()
  44. $srcIplImage.Dispose()
  45. $dst1IplImage.Dispose()

PowerShellで画像を白黒に変換する

| 2009年10月19日月曜日
OpenCVSharpを使って画像を白黒(2値化)する。
最初にグレースケールにしておいて、しきい値以下だったら白色、以上だったら黒色の二色の画像にする。
少しぼかした方が、白い部分と黒い部分が分かれるのでいいかもしれない。
ぼかさないと、ノイズが多い感じになる。
サンプルはぼかし無しで、ぼかしの部分はコメントアウトしてある。
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. # グレースケールで読み込む
  3. $srcIplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg"), [OpenCvSharp.LoadMode]::GrayScale)
  4. # ソース画像と同じサイズのグレースケールで初期化する
  5. $dstIplImage = New-Object OpenCvSharp.IplImage( $srcIplImage.Size, [OpenCvSharp.BitDepth]::U8, 1)
  6. # 画像をすこしぼかすした方がいいかも
  7. #$smooth = 5
  8. #$srcIplImage.Smooth($srcIplImage, [OpenCvSharp.SmoothType]::Gaussian, $smooth)
  9. $threshold = 128 # 白色か黒色かのしきい値
  10. $srcIplImage.Threshold($dstIplImage, $threshold, 255, [OpenCvSharp.ThresholdType]::Binary)
  11. $dstIplImage.SaveImage((Join-Path $pwd "bar.jpg"))
  12. $srcIplImage.Dispose()
  13. $dstIplImage.Dispose()

PowerShellで画像をグレースケールに変換する

| 2009年10月18日日曜日
OpenCVSharpを使って画像をグレースケールにする。
グレースケールにする方法は下記の二つ。

①画像を読み込む時にグレースケールで読み込む方法。
②OpenCvSharp.IplImageオブジェクトを減色する方法。

①の方法だと一度ファイルに保存する必要があるので、Webカメラでキャプチャーしながらの解析には向かない。その時は、②を使えばいい。

まずは、①のコード
  1. [void][System.Reflection.Assembly]::LoadFrom((Join-Path $pwd OpenCvSharp.dll))
  2. #グレースケールで読み込む
  3. $iplImage = [OpenCvSharp.Cv]::LoadImage((Join-Path $pwd "foo.jpg"), [OpenCvSharp.LoadMode]::GrayScale)
  4. $iplImage.SaveImage((Join-Path $pwd "bar.jpg"))
  5. $iplImage.Dispose()
続いて、②のコード
  1. [void][System.Reflection.Assembly]::LoadFrom(( Join-Path $pwd OpenCvSharp.dll))
  2. #グレースケールに変換
  3. $srcIplImage = [OpenCvSharp.Cv]::LoadImage((Join-Path $pwd "foo.jpg"))
  4. $dstIplImage = New-Object OpenCvSharp.IplImage( $srcIplImage.Size, [OpenCvSharp.BitDepth]::U8, 1)
  5. [OpenCvSharp.Cv]::CvtColor($srcIplImage,$dstIplImage, [OpenCvSharp.ColorConversion]::BgraToGray)
  6. $dstIplImage.SaveImage((Join-Path $pwd "bar.jpg"))
  7. $srcIplImage.Dispose()
  8. $dstIplImage.Dispose()

PowerShellで画像をぼかす

| 2009年10月17日土曜日
OpenCVSharpを使って画像をぼかす(平滑化する)。
たぶん、一部だけぼかすこともできるとは思うけど、やり方がわからないので、まずは全体をぼかす。

ぼかし方は五種類、OpenCvSharp.SmoothTypeで定義されている。

・ BlurNoScale
・ Blur
・ Gaussian
・ Median
・ Bilateral

そのうちの一つ「Bilateral」は例がでて使えなかった。

以下、コード
  1. [void][System.Reflection.Assembly]::LoadFrom( ( Join-Path $pwd OpenCvSharp.dll) )
  2. $smooth = 5 # ぼかし率?値が大きいほどぼかしが強い
  3. # 強い光を当てたみたいな画像になった
  4. $iplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg"))
  5. $iplImage.Smooth($iplImage, [OpenCvSharp.SmoothType]::BlurNoScale, $smooth)
  6. $iplImage.SaveImage((Join-Path $pwd "BlurNoScale.jpg"))
  7. $iplImage.Dispose()
  8. # 全体的にぼゃ~って感じ
  9. $iplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg"))
  10. $iplImage.Smooth($iplImage, [OpenCvSharp.SmoothType]::Blur, $smooth)
  11. $iplImage.SaveImage((Join-Path $pwd "Blur.jpg"))
  12. $iplImage.Dispose()
  13. # 全体的にぼゃっとしてるけどBlurよりははっきり
  14. $iplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg"))
  15. $iplImage.Smooth($iplImage, [OpenCvSharp.SmoothType]::Gaussian, $smooth)
  16. $iplImage.SaveImage((Join-Path $pwd "Gaussian.jpg"))
  17. $iplImage.Dispose()
  18. # 油絵みたい
  19. $iplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg"))
  20. $iplImage.Smooth($iplImage, [OpenCvSharp.SmoothType]::Median, $smooth)
  21. $iplImage.SaveImage((Join-Path $pwd "Median.jpg"))
  22. $iplImage.Dispose()
  23. #ぼかし方(平滑化)をBilateralにすると例外が発生してうまくいかない
  24. #$iplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg"))
  25. #$iplImage.Smooth($iplImage, [OpenCvSharp.SmoothType]::Bilateral, $smooth)
  26. #$iplImage.SaveImage((Join-Path $pwd "Bilateral.jpg"))
  27. #$iplImage.Dispose()

PowerShellで画像を回転させる

|
OpenCVSharpを使って画像を回転したり反転したりしてみる。

OpenCvSharp.Cv.Flip()メソッドを使って、X軸かY軸か両軸で画像を反転させれる。

以下、コード
  1. [void][System.Reflection.Assembly]::LoadFrom( ( Join-Path $pwd OpenCvSharp.dll) )
  2. #画像を左右を入れ替える
  3. $iplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg") )
  4. [OpenCvSharp.Cv]::Flip($iplImage, $iplImage, [OpenCvSharp.FlipMode]::Y )
  5. $iplImage.SaveImage((Join-Path $pwd "bar1.jpg"))
  6. $iplImage.Dispose()
  7. #画像を180度回転させる
  8. $iplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg") )
  9. [OpenCvSharp.Cv]::Flip($iplImage, $iplImage, [OpenCvSharp.FlipMode]::XY )
  10. $iplImage.SaveImage((Join-Path $pwd "bar2.jpg"))
  11. $iplImage.Dispose()
  12. #画像を左右を入れ替えて180度回転させる
  13. $iplImage = [OpenCvSharp.Cv]::LoadImage( (Join-Path $pwd "foo.jpg") )
  14. [OpenCvSharp.Cv]::Flip($iplImage, $iplImage, [OpenCvSharp.FlipMode]::X )
  15. $iplImage.SaveImage((Join-Path $pwd "bar3.jpg"))
  16. $iplImage.Dispose()