<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>橋本商会 &#187; C#</title>
	<atom:link href="http://shokai.org/blog/archives/tag/csharp/feed" rel="self" type="application/rss+xml" />
	<link>http://shokai.org/blog</link>
	<description>なんか作ったりした記録を忘れないうちに書くblog</description>
	<lastBuildDate>Sun, 20 May 2012 10:50:20 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<atom:link rel="hub" href="http://pubsubhubbub.appspot.com/" />
			<item>
		<title>C++/CLIで動かしているOpenCVのCvImageをC#.NETのBitmapオブジェクトにして読み込む</title>
		<link>http://shokai.org/blog/archives/4499</link>
		<comments>http://shokai.org/blog/archives/4499#comments</comments>
		<pubDate>Fri, 24 Apr 2009 20:45:36 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[CLI]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[DLL]]></category>
		<category><![CDATA[OpenCV]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=4499</guid>
		<description><![CDATA[橋本商会: Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC# Formアプリから使う の続き。 FormアプリからOpenCVのHighGUIを別ウィンドウで開いていたが、Bitmapオブジェク [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://shokai.org/blog/archives/4477">橋本商会: Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC# Formアプリから使う</a> の続き。<br />
FormアプリからOpenCVのHighGUIを別ウィンドウで開いていたが、Bitmapオブジェクトにキャストする事で.NETアプリのPictureBoxなどに読み込む事が出来る。<br />
これにより画像処理だけ高速にC++で行い、アプリケーションのUIやネットワーク部分はC#.NETで実装するといういいとこどりが出来る。<br />
<br />
<br />
■出来た物<br />
FormにLoadImageボタンとPictureBoxを追加。<br />
LoadButtonを押すとShadowCamera.dllから呼び出しているOpenCV側のCvImageが変換されてBitmapになって出てくる関数を作った。<br />
<a href="http://www.flickr.com/photos/shokai/3470686133/" title="C++/OpenCVのCvImageを.NETのBitmapに変換できた by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3609/3470686133_47f62356e6.jpg" width="500" height="337" alt="C++/OpenCVのCvImageを.NETのBitmapに変換できた" /></a><br />
<br />
今回作っているShadowCameraは背景を蓄積させて統計を取り、差分で人物の影だけを抜き出すライブラリなので、毎フレーム計算し続ける必要がある。runCapture()の最後でwhileループさせて実現している。<br />
なので、1つBitmapオブジェクトを用意しておき、whileループの最後で処理結果を毎回保存しておいてそれをC#側から適当なタイミングで読みに行く実装にした。<br />
DLLであるC++/OpenCV側のループを毎フレーム回し続けながら、それをブロックする事なくC# Formアプリ側から取得できる。<br />
<br />
<br />
例によって<a href="http://shokai.org/projects/opencv-study/">OpenCV勉強用mercurialリポジトリ</a>の<a href="http://shokai.org/projects/opencv-study/index.cgi/rev/c9320e90f1be">changes19としてcommit</a>してある。<br />
<br />
<br />
なお、VisualStudioはC#はutf8なのにC++はshift_jisで保存されてしまい、utf8にするとビルドできなくなってしまうのでリポジトリビューアでは文字化けしてしまっている。悲しい。<br />
文字化けしている部分には大したこと書いてないので無視していいし、必要ならリポジトリの左側からzipでダウンロードできる。<br />
<br />
<br />
ちなみに今回の方法は、<a href="http://shokai.org/blog/archives/829">3年以上前の開発合宿</a>の記事に匿名様が<br />
コメントで教えてくれたSharperCVのCvImage型をSystem.Drawing.Bitmap型に変換する方法が書かれていてそれを元にした。<br />
やはりできなかった事とかも書いてみるものだなと思った。もちろん助けをアテにしちゃいけないが<br />
<br />
<br />
■ShadowCamera.dll側の変更<br />
C++プロジェクトのShadowCameraに、System.Drawingへの参照を追加する。Bitmapクラスを使うため。<br />
<a href="http://www.flickr.com/photos/shokai/3471041179/" title="C++/OpenCVのCvImageを.NETのBitmapに変換できた by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3643/3471041179_3d3645598e.jpg" width="296" height="369" alt="C++/OpenCVのCvImageを.NETのBitmapに変換できた" /></a><br />
<br />
<br />
「新しい参照の追加」ボタンを押す<br />
<a href="http://www.flickr.com/photos/shokai/3471043787/" title="C++/OpenCVのCvImageを.NETのBitmapに変換できた by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3325/3471043787_974c803312_o.png" width="856" height="479" alt="C++/OpenCVのCvImageを.NETのBitmapに変換できた" /></a><br />
<br />
<br />
.NETタブの下の方にスクロールしていって、System.Drawing を追加する。<br />
<a href="http://www.flickr.com/photos/shokai/3471045215/" title="C++/OpenCVのCvImageを.NETのBitmapに変換できた by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3546/3471045215_b29fff723b_o.png" width="553" height="347" alt="C++/OpenCVのCvImageを.NETのBitmapに変換できた" /></a><br />
<br />
<br />
ShadowCamera.hにコードを書き加える<br />
<br />
<a href="http://shokai.org/projects/opencv-study/index.cgi/file/c9320e90f1be/ShadowCamera/ShadowCamera.h">OpenCV Study: c9320e90f1be ShadowCamera/ShadowCamera.h</a><br />
DLLへの参照を追加して<br />
<pre class="prettyprint">using namespace System::Drawing;</pre>
<br />
<br />
勝手に書き換えられたら嫌なので、privateでグローバル変数 shadow を作っておく<br />
<pre class="prettyprint">private:<br />
&nbsp;&nbsp;&nbsp;&nbsp;System::Drawing::Bitmap^&nbsp;shadow;</pre>
<br />
<br />
DLL利用側のためのアクセサを用意する<br />
<pre class="prettyprint">public:<br />
&nbsp;&nbsp;&nbsp;&nbsp;System::Drawing::Bitmap^&nbsp;ShadowImage(void){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;this-&gt;shadow;<br />
&nbsp;&nbsp;&nbsp;&nbsp;}</pre>
これでDLL内のshadowというBitmapオブジェクトを、DLL外から読み出す事が出来るようになった。<br />
いまいち ^ や ~ などをつけるルールを把握しきれていないけど、他のC++/CLIアプリがそうやっていたので先人の作法に倣うことにする。<br />
<br />
<br />
あとはrunCapture()の最後のwhileループ内で、毎回作られるimgResultというIplImage(CvImage互換)オブジェクトをdynamic_castしてshadowに保存する。<br />
<pre class="prettyprint">this-&gt;shadow&nbsp;=&nbsp;dynamic_cast&lt;System::Drawing::Bitmap^&gt;<br />
&nbsp;&nbsp;&nbsp;&nbsp;(gcnew&nbsp;System::Drawing::Bitmap(w,h,w*3,&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;System::Drawing::Imaging::PixelFormat::Format24bppRgb,<br />
&nbsp;&nbsp;&nbsp;&nbsp;static_cast&lt;System::IntPtr&gt;(imgResult-&gt;imageDataOrigin)));</pre>
長いので変換部分のみ抜粋。<a href="http://shokai.org/projects/opencv-study/index.cgi/file/c9320e90f1be/ShadowCamera/ShadowCamera.h">ShadowCamera.h</a>の85～125行目がwhileループです<br />
<br />
dynamic_castやstatic_castの違いは<a href="http://www.s34.co.jp/cpptechdoc/article/newcast/">C++の新しいキャスト</a>が参考になった。<br />
オブジェクトの代入のためのcastは.NETの上で動いているからdynamic_castで、unmanaged領域と行き来するSystem::IntPtrと*char間のcastはstatic_castになるという理解でいいのかな？<br />
<br />
<br />
<br />
■ShadowCamera.dllを使うC# Formアプリ側の変更<br />
ボタン（buttonLoadImage）と画像を表示するためのPictureBox（pictureBoxResult）を配置。<br />
PictureBoxはSizeModeをStretchImageにしておくと自動リサイズされて便利。<br />
<a href="http://www.flickr.com/photos/shokai/3471068855/" title="C++/OpenCVのCvImageを.NETのBitmapに変換できた by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3301/3471068855_0530ffed82_o.png" width="460" height="515" alt="C++/OpenCVのCvImageを.NETのBitmapに変換できた" /></a><br />
<br />
<br />
で、ボタン押下イベントで<br />
<pre class="prettyprint">pictureBoxResult.Image&nbsp;=&nbsp;cam.ShadowImage();</pre>
BitmapをPictureBoxのImageプロパティに突っ込むだけで表示できる。楽ちんだ<br />
<a href="http://www.flickr.com/photos/shokai/3470686133/" title="C++/OpenCVのCvImageを.NETのBitmapに変換できた by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3609/3470686133_47f62356e6.jpg" width="500" height="337" alt="C++/OpenCVのCvImageを.NETのBitmapに変換できた" /></a><br />
<br />
終わり。<br />
<br />
ボタンじゃなくてThreadなどで適当にsleepを入れながら読み込み続ければふつうに影カメラになる。<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/4499/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC# Formアプリから使う</title>
		<link>http://shokai.org/blog/archives/4477</link>
		<comments>http://shokai.org/blog/archives/4477#comments</comments>
		<pubDate>Fri, 24 Apr 2009 12:11:15 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[CLI]]></category>
		<category><![CDATA[cpp]]></category>
		<category><![CDATA[DLL]]></category>
		<category><![CDATA[OpenCV]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[VS2008]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=4477</guid>
		<description><![CDATA[重い画像処理をC++の画像処理ライブラリであるOpenCVでやって、ネットワーク処理は慣れ親しんだC#.NETでやりたい。 そこで、色々試行錯誤した結果、C#からは「処理し終わった画像を表示してくれるカメラ」に見えるよう [...]]]></description>
			<content:encoded><![CDATA[<p>
重い画像処理をC++の画像処理ライブラリであるOpenCVでやって、ネットワーク処理は慣れ親しんだC#.NETでやりたい。<br />
そこで、色々試行錯誤した結果、C#からは「処理し終わった画像を表示してくれるカメラ」に見えるような、OpenCVの処理部分を含んだDLLをC++/CLIで作ることにした。<br />
（OpenCVそのものについてと開発環境構築は<a href="http://shokai.org/blog/archives/4141">橋本商会 ? OpenCVをはじめた</a>に書いた）<br />
<br />
<br />
他にも連動のさせかたは<a href="http://www.cs.ru.ac.za/research/groups/SharperCV/">SharperCV</a>というC#ラッパーを使うとか、<a href="http://cv.nextfoods.jp/index.php?opencv%2Fsample%2Fstreaming">SocketでOpenCVで処理した結果の画像だけ送る</a>とか色々とやり方はあるけど、<br />
前者は2003年でプロジェクトが止まっていてcvPow等の配列関連の関数が無く、後者は俺のMicrosoft SDKのWinUser.hの6373行目あたりから文字化けしていてWinSocketが使えなかったりしたのでDLLを作るやり方に落ち着いた。<br />
<br />
<br />
この方法のメリットは、まず納得のいくOpenCVの処理をC++単体のプロジェクトでいつもどおり書いて、それをほぼコピペすればDLLができてしまうところ。<br />
ShaperCVを使う場合は全て関数を照らし合わせてC#で書き直さなければならないので面倒。<br />
Socketを使う方はよく知らない。<br />
<br />
<br />
DLLの作り方はかせいさんとこが参考になった。CLIを使う場合と使わない場合が解説されている。（今回は楽する為にCLIを使う）<br />
<ul>
<li><a href="http://d.hatena.ne.jp/kasei_san/20070511/p1">DLLの概要と実装方法。 &#8211; かせいさんとこ</a></li>
<li><a href="http://d.hatena.ne.jp/pota_dahon/20080305">C#からC++のDLLを利用する方法 &#8211; pota_dahonの日記</a></li>
</ul>
<br />
<br />
■今回つくるもの<br />
<a href="http://shokai.org/projects/opencv-study/">mercurialリポジトリ</a>をアップロードした。左のバーからzipでダウンロードするか、<br />
</p>
<blockquote><p>hg clone http://shokai.org/projects/opencv-study/ opencv-study</p></blockquote>
<p>
してリポジトリを複製してください。<br />
<br />
<ul>
<li><a href="http://shokai.org/projects/opencv-study/index.cgi/file/7537970cfc6b/ShadowCamera">OpenCV Study: 7537970cfc6b /ShadowCamera/</a> : 影カメラライブラリ</li>
<li><a href="http://shokai.org/projects/opencv-study/index.cgi/file/7537970cfc6b/ShadowCameraSample">OpenCV Study: 7537970cfc6b /ShadowCameraSample/</a> : 影カメラライブラリを使うFormアプリケーション</li>
</ul>
の2つを作ります。<br />
影カメラライブラリの方は、<a href="http://shokai.org/projects/opencv-study/index.cgi/file/7537970cfc6b/BgSubAvg/bgsubAvg.cpp">OpenCV Study: 7537970cfc6b BgSubAvg/bgsubAvg.cpp</a>をDLL化したもので、cvRunningAvgを使って背景統計を取って背景差分して人型の影を作るもの → <a href="http://d.hatena.ne.jp/shokai/20090212/1234440251">cvRunningAvgを使って背景統計を取り背景差分する &#8211; 橋本詳解</a><br />
<br />
<br />
完成図はこれ。C#で作ったFormアプリで、ボタンを押すとDLLに書いてあるOpenCVの処理が起動してウィンドウが開き画像処理結果が表示/毎フレーム更新される。<br />
<a href="http://www.flickr.com/photos/shokai/3470022957/" title="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3499/3470022957_55c118a20c.jpg" width="500" height="249" alt="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う" /></a><br />
<br />
<br />
<br />
■C++でDLLを作る<br />
まず空のソリューションを作る。<br />
ソリューション名を右クリックして新しいプロジェクト追加<br />
<a href="http://www.flickr.com/photos/shokai/3470811574/" title="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3507/3470811574_e25fa193ee.jpg" width="454" height="404" alt="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う" /></a><br />
<br />
<br />
VC++のクラスライブラリを作成する。名前はShadowCameraにした<br />
<a href="http://www.flickr.com/photos/shokai/3469998341/" title="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3506/3469998341_e92f96d625_o.png" width="796" height="408" alt="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う" /></a><br />
<br />
<br />
できたShadowCameraプロジェクトを右クリックしてプロパティを編集<br />
<a href="http://www.flickr.com/photos/shokai/3470815346/" title="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3035/3470815346_32fd943140.jpg" width="319" height="180" alt="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う" /></a><br />
<br />
<br />
OpenCV用のライブラリを読み込む。<br />
すべての構成->入力->追加の依存ファイル に<br />
</p>
<blockquote><p>$(NoInherit) highgui.lib cxts.lib cv.lib cxcore.lib ml.lib cvaux.lib cvhaartraining.lib</p></blockquote>
<p>
を書く <br />
<a href="http://www.flickr.com/photos/shokai/3470817812/" title="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3595/3470817812_ea25865e46_o.png" width="856" height="479" alt="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う" /></a><br />
<br />
<a href="http://shokai.org/projects/opencv-study/index.cgi/file/7537970cfc6b/ShadowCamera/ShadowCamera.h">ShadowCamera.h</a>のClass名をCameraに変更、さらにint runCapture()関数を書く。<br />
この関数の中にOpenCVのmain()を全部突っ込んでしまえばそのまま動く。今回は<a href="http://shokai.org/projects/opencv-study/index.cgi/file/7537970cfc6b/BgSubAvg/bgsubAvg.cpp">bgsubAvg.cpp</a>のmain()をコピペしたけど<a href="http://shokai.org/projects/opencv-study/index.cgi/file/7537970cfc6b/">他にも赤色重心追跡や肌色検出、単純なカメラ入力など色々作った</a>ので好きなものをコピペしてよい。<br />
OpenCV関連のヘッダを#includeで読み込むのを忘れずに。<br />
（試しにint asdf()という単に数値を返すだけの関数も作っておいた。これがC#から呼べればちゃんとDLLとして読み込めているはず）<br />
<br />
<a href="http://shokai.org/projects/opencv-study/index.cgi/file/7537970cfc6b/ShadowCamera/ShadowCamera.h">OpenCV Study: 7537970cfc6b ShadowCamera/ShadowCamera.h</a><br />
</p>
<blockquote><p>
//&nbsp;ShadowCamera.h<br />
#include&nbsp;&lt;cv.h&gt;<br />
#include&nbsp;&lt;highgui.h&gt;<br />
#include&nbsp;&lt;ctype.h&gt;<br />
#include&nbsp;&lt;stdio.h&gt;<br />
<br />
#pragma&nbsp;once<br />
<br />
using&nbsp;namespace&nbsp;System;<br />
<br />
namespace&nbsp;ShadowCamera&nbsp;{<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;ref&nbsp;class&nbsp;Camera<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;TODO:&nbsp;このクラスの、ユーザーのメソッドをここに追加してください。<br />
&nbsp;&nbsp;&nbsp;&nbsp;public:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;asdf(void){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;15;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;public:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;runCapture(void){<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;bool&nbsp;isStop&nbsp;=&nbsp;false;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;int&nbsp;INIT_TIME&nbsp;=&nbsp;50;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;double&nbsp;BG_RATIO&nbsp;=&nbsp;0.02;&nbsp;//&nbsp;背景領域更新レート<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;double&nbsp;OBJ_RATIO&nbsp;=&nbsp;0.005;&nbsp;//&nbsp;物体領域更新レート<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;double&nbsp;Zeta&nbsp;=&nbsp;10.0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*img&nbsp;=&nbsp;NULL;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CvCapture&nbsp;*capture&nbsp;=&nbsp;NULL;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;capture&nbsp;=&nbsp;cvCreateCameraCapture(0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//capture&nbsp;=&nbsp;cvCaptureFromAVI(&quot;test.avi&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(capture&nbsp;==&nbsp;NULL){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;capture&nbsp;device&nbsp;not&nbsp;found!!&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;-1;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img&nbsp;=&nbsp;cvQueryFrame(capture);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;w&nbsp;=&nbsp;img-&gt;width;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;h&nbsp;=&nbsp;img-&gt;height;<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*imgAverage&nbsp;=&nbsp;cvCreateImage(cvSize(w,&nbsp;h),&nbsp;IPL_DEPTH_32F,&nbsp;3);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*imgSgm&nbsp;=&nbsp;cvCreateImage(cvSize(w,&nbsp;h),&nbsp;IPL_DEPTH_32F,&nbsp;3);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*imgTmp&nbsp;=&nbsp;cvCreateImage(cvSize(w,&nbsp;h),&nbsp;IPL_DEPTH_32F,&nbsp;3);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*img_lower&nbsp;=&nbsp;cvCreateImage(cvSize(w,&nbsp;h),&nbsp;IPL_DEPTH_32F,&nbsp;3);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*img_upper&nbsp;=&nbsp;cvCreateImage(cvSize(w,&nbsp;h),&nbsp;IPL_DEPTH_32F,&nbsp;3);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*imgSilhouette&nbsp;=&nbsp;cvCreateImage(cvSize(w,&nbsp;h),&nbsp;IPL_DEPTH_8U,&nbsp;1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*imgSilhouetteInv&nbsp;=&nbsp;cvCreateImage(cvSize(w,&nbsp;h),&nbsp;IPL_DEPTH_8U,&nbsp;1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IplImage&nbsp;*imgResult&nbsp;=&nbsp;cvCreateImage(cvSize(w,&nbsp;h),&nbsp;IPL_DEPTH_8U,&nbsp;3);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;背景初期化中&#8230;&yen;n&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvSetZero(imgAverage);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;INIT_TIME;&nbsp;i++){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img&nbsp;=&nbsp;cvQueryFrame(capture);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvAcc(img,&nbsp;imgAverage);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;輝度平均&nbsp;%d/%d&yen;n&quot;,&nbsp;i,&nbsp;INIT_TIME);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvConvertScale(imgAverage,&nbsp;imgAverage,&nbsp;1.0&nbsp;/&nbsp;INIT_TIME);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvSetZero(imgSgm);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;INIT_TIME;&nbsp;i++){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img&nbsp;=&nbsp;cvQueryFrame(capture);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvConvert(img,&nbsp;imgTmp);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvSub(imgTmp,&nbsp;imgAverage,&nbsp;imgTmp);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvPow(imgTmp,&nbsp;imgTmp,&nbsp;2.0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvConvertScale(imgTmp,&nbsp;imgTmp,&nbsp;2.0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvPow(imgTmp,&nbsp;imgTmp,&nbsp;0.5);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvAcc(imgTmp,&nbsp;imgSgm);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;輝度振幅&nbsp;%d/%d&yen;n&quot;,&nbsp;i,&nbsp;INIT_TIME);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvConvertScale(imgSgm,&nbsp;imgSgm,&nbsp;1.0&nbsp;/&nbsp;INIT_TIME);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf(&quot;背景初期化完了&yen;n&quot;);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;winNameCapture[]&nbsp;=&nbsp;&quot;Capture&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;char&nbsp;winNameSilhouette[]&nbsp;=&nbsp;&quot;Silhouette&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvNamedWindow(winNameCapture,&nbsp;0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvNamedWindow(winNameSilhouette,&nbsp;0);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(1){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(!isStop){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;img&nbsp;=&nbsp;cvQueryFrame(capture);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(img&nbsp;==&nbsp;NULL)&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvConvert(img,&nbsp;imgTmp);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;輝度範囲<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvSub(imgAverage,&nbsp;imgSgm,&nbsp;img_lower);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvSubS(img_lower,&nbsp;cvScalarAll(Zeta),&nbsp;img_lower);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvAdd(imgAverage,&nbsp;imgSgm,&nbsp;img_upper);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvAddS(img_upper,&nbsp;cvScalarAll(Zeta),&nbsp;img_upper);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvInRange(imgTmp,&nbsp;img_lower,&nbsp;img_upper,&nbsp;imgSilhouette);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;輝度振幅<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvSub(imgTmp,&nbsp;imgAverage,&nbsp;imgTmp);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvPow(imgTmp,&nbsp;imgTmp,&nbsp;2.0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvConvertScale(imgTmp,&nbsp;imgTmp,&nbsp;2.0);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvPow(imgTmp,&nbsp;imgTmp,&nbsp;0.5);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;背景領域を更新<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvRunningAvg(img,&nbsp;imgAverage,&nbsp;BG_RATIO,&nbsp;imgSilhouette);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvRunningAvg(imgTmp,&nbsp;imgSgm,&nbsp;BG_RATIO,&nbsp;imgSilhouette);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;物体領域を更新<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvNot(imgSilhouette,&nbsp;imgSilhouetteInv);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvRunningAvg(imgTmp,&nbsp;imgSgm,&nbsp;OBJ_RATIO,&nbsp;imgSilhouetteInv);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvErode(imgSilhouette,&nbsp;imgSilhouette,&nbsp;NULL,&nbsp;1);&nbsp;//&nbsp;収縮<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvDilate(imgSilhouette,&nbsp;imgSilhouette,&nbsp;NULL,&nbsp;2);&nbsp;//&nbsp;膨張<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvErode(imgSilhouette,&nbsp;imgSilhouette,&nbsp;NULL,&nbsp;1);&nbsp;//&nbsp;収縮<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvMerge(imgSilhouette,&nbsp;imgSilhouette,&nbsp;imgSilhouette,&nbsp;NULL,&nbsp;imgResult);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvShowImage(winNameCapture,&nbsp;img);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvShowImage(winNameSilhouette,&nbsp;imgResult);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;waitKey&nbsp;=&nbsp;cvWaitKey(33);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(waitKey&nbsp;==&nbsp;&#8217;q')&nbsp;break;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(waitKey&nbsp;==&nbsp;&#8217;&nbsp;&#8217;){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;isStop&nbsp;=&nbsp;!isStop;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if(isStop)&nbsp;printf(&quot;stop&yen;n&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else&nbsp;printf(&quot;start&yen;n&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvReleaseCapture(&amp;capture);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvDestroyWindow(winNameCapture);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cvDestroyWindow(winNameSilhouette);<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;};<br />
}<br />
</p></blockquote>
<p>
<br />
<br />
■C#でFormアプリを作る<br />
新しいプロジェクトを作る。<br />
ソリューションエクスプローラで[参照設定]→[プロジェクト参照]でShadowCameraを参照。<br />
<a href="http://www.flickr.com/photos/shokai/3470892320/" title="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3497/3470892320_427521cbab.jpg" width="246" height="236" alt="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う" /></a><br />
なお、同一Solution内ならプロジェクト参照が便利だけど、<br />
ReleaseにShadowCamera.dllができているのでそれを他の人に配布して、[ファイルを参照]してもらってdllから呼び出してもらっても同じ機能が使えます<br />
<br />
<br />
ボタンを1つ置く。buttonStartという名前にして、ダブルクリックしてクリックイベントの雛形を作る<br />
<a href="http://www.flickr.com/photos/shokai/3470835562/" title="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3553/3470835562_906e5d2262.jpg" width="464" height="494" alt="Cで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う" /></a><br />
<br />
<br />
<br />
ShadowCameraを読み込んで<br />
</p>
<blockquote><p>using ShadowCamera;</p></blockquote>
<p>
<br />
新しいCameraクラスのインスタンスを作って、startButtonイベント内でさっき作ったrunCapture関数を呼ぶようにする<br />
<a href="http://shokai.org/projects/opencv-study/index.cgi/file/7537970cfc6b/ShadowCameraSample/ShadowCameraForm.cs#l1">OpenCV Study: 7537970cfc6b ShadowCameraSample/ShadowCameraForm.cs</a><br />
</p>
<blockquote><p>
using&nbsp;System;<br />
using&nbsp;System.Collections.Generic;<br />
using&nbsp;System.ComponentModel;<br />
using&nbsp;System.Data;<br />
using&nbsp;System.Drawing;<br />
using&nbsp;System.Linq;<br />
using&nbsp;System.Text;<br />
using&nbsp;System.Windows.Forms;<br />
using&nbsp;ShadowCamera;<br />
<br />
namespace&nbsp;ShadowCameraSample<br />
{<br />
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;partial&nbsp;class&nbsp;ShadowCameraForm&nbsp;:&nbsp;Form<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;Camera&nbsp;cam;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;ShadowCameraForm()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;InitializeComponent();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cam&nbsp;=&nbsp;new&nbsp;Camera();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private&nbsp;void&nbsp;buttonStart_Click(object&nbsp;sender,&nbsp;EventArgs&nbsp;e)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cam.runCapture();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
</p></blockquote>
<p>
<br />
<br />
ShadowCameraSampleを（右クリックして）スタートアッププロジェクトに設定し、<br />
ビルドするとShadowCameraFormが起動する。ボタンを押すとしばらくカメラを読み込んで、数秒後にOpenCVのHighGUIのウィンドウが起動するはず。<br />
<a href="http://www.flickr.com/photos/shokai/3470022957/" title="Ｃで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3499/3470022957_55c118a20c.jpg" width="500" height="249" alt="Ｃで書いたOpenCVのコードをC++/CLIで.NET用DLLにしてC#から使う" /></a><br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/4477/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>C# &#8211; UDP/IPでチャットアプリ</title>
		<link>http://shokai.org/blog/archives/4193</link>
		<comments>http://shokai.org/blog/archives/4193#comments</comments>
		<pubDate>Wed, 11 Feb 2009 15:34:19 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[UDP]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=4193</guid>
		<description><![CDATA[ちょっとUDPを使ってアプリを作る用事があるので、まずは.NETのSystem.Net.Sockets.UdpClientクラスでシンプルなテキストチャットを作ってみた。相手のIPアドレスとポートを指定してメッセージ（文 [...]]]></description>
			<content:encoded><![CDATA[<p>
ちょっとUDPを使ってアプリを作る用事があるので、まずは.NETのSystem.Net.Sockets.UdpClientクラスでシンプルなテキストチャットを作ってみた。相手のIPアドレスとポートを指定してメッセージ（文字列）を送り、受信側はポートを開けてさえいればメッセージが読める。<br />
<a href="http://dobon.net/vb/dotnet/internet/udpclient.html">UDPによりデータの送受信を行う: .NET Tips: C#, VB.NET, Visual Studio</a>を参考にした。<br />
<br />
<br />
学部の頃にインターネット概論という授業で、<br />
<ul>
<li>コンジェスチョンコントロールがない</li>
<li>フローコントロールがない</li>
</ul>
とか習って、「ふーん」という感じだったけど。セッションを張らずに送信できて、受信するかは受信側の自由なんだな。<br />
<br />
<br />
■ソースコード<br />
<a href="http://bitbucket.org/shokai/c-udp-sample/src/1ed2ea1cc0d7/UDPClientSample/">shokai / C# UDP Sample / source — bitbucket.org</a><br />
(VisualStudio2008pro C#で作成)<br />
<br />
<br />
別ホスト（VMWare上のUbuntuでmonoで実行）とも通信できた<br />
<a href="http://www.flickr.com/photos/shokai/3267151562/" title="UDPの勉強 by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3399/3267151562_847535d9d6_o.png" width="603" height="610" alt="UDPの勉強" /></a><br />
<br />
<br />
<br />
■UdpClientの使い方<br />
まず必要な物読み込んで<br />
</p>
<blockquote><p>
using&nbsp;System.Net;<br />
using&nbsp;System.Net.Sockets;<br />
</p></blockquote>
<p>
<br />
UdpClientオブジェクトを作ってportを開く。<br />
</p>
<blockquote><p>
UdpClient&nbsp;client&nbsp;=&nbsp;new&nbsp;UdpClient(6000);&nbsp;//&nbsp;受信port<br />
client.DontFragment&nbsp;=&nbsp;true;<br />
client.EnableBroadcast&nbsp;=&nbsp;true;<br />
</p></blockquote>
<p>
これですでに受信できるようになっている。<br />
<br />
<br />
相手のIPアドレスかホスト名とportを指定して、UTF8エンコードで送信<br />
</p>
<blockquote><p>
Encoding&nbsp;encoding&nbsp;=&nbsp;Encoding.UTF8;<br />
byte[]&nbsp;sendBytes&nbsp;=&nbsp;encoding.GetBytes(&quot;送信する文字列&quot;);<br />
client.Send(sendBytes,&nbsp;sendBytes.Length,&nbsp;&quot;192.168.0.15&quot;,&nbsp;6000);<br />
</p></blockquote>
<p>
<br />
<br />
受信バッファから読み出すと、文字列と受信元IPとportがわかる。<br />
</p>
<blockquote><p>
if&nbsp;(client.Available&nbsp;&gt;&nbsp;0)<br />
{<br />
&nbsp;&nbsp;byte[]&nbsp;recvByte&nbsp;=&nbsp;client.Receive(ref&nbsp;remoteEP);<br />
&nbsp;&nbsp;Console.WriteLine(&quot;receive:&nbsp;&quot;&nbsp;+&nbsp;encoding.GetString(recvByte)&nbsp;+<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&quot;&nbsp;(form&quot;&nbsp;+&nbsp;remoteEP.Address&nbsp;+&nbsp;&quot;:&quot;&nbsp;+&nbsp;remoteEP.Port+&quot;)&quot;);<br />
}<br />
</p></blockquote>
<p>
<br />
<br />
最後にUdpClientを閉じるのを忘れないように<br />
</p>
<blockquote><p>
client.Close();<br />
</p></blockquote>
<p>
<br />
チャットアプリの実際の処理は<a href="http://bitbucket.org/shokai/c-udp-sample/src/1ed2ea1cc0d7/UDPClientSample/UDPClientSampleForm.cs">UDPClientSampleForm.cs</a>に全部書いてある。受信を別スレッドにしてある。</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/4193/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C#でWord2007のOCR機能を使う</title>
		<link>http://shokai.org/blog/archives/4162</link>
		<comments>http://shokai.org/blog/archives/4162#comments</comments>
		<pubDate>Sun, 08 Feb 2009 17:35:40 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[OCR]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=4162</guid>
		<description><![CDATA[wordのOCR機能がCOM APIから使えるとの事だったので試した。 まちみのな::C#で文字認識を行うとCodeProject: OCR with Microsoft? Office. Free source cod [...]]]></description>
			<content:encoded><![CDATA[<p>
wordのOCR機能がCOM APIから使えるとの事だったので試した。<br />
<br />
<a href="http://tmp.junkbox.info/e48.html">まちみのな::C#で文字認識を行う</a>と<a href="http://www.codeproject.com/KB/office/modi.aspx">CodeProject: OCR with Microsoft? Office. Free source code and programming help</a>を参考にした、というかほぼそのままで、UIを付けただけ。<br />
<br />
日本語OCRは商用の物しか見つからなくて、<a href="http://www.moongift.jp/2007/11/xelo_reader_zero/">クセロReader</a>に入ってるとかどうやってか<a href="http://appsv.ocrgrid.org/nhocr/index-j.html">自分で作ってる</a>人もいるけど、高嶺の花だった。英語はオープンソースプロジェクトがいくつかあるのになあ・・・<br />
<br />
<br />
できたもの。<br />
画像をドラッグアンドドロップするとOCR発動、文字を読み取る。この画質の写真でも相当間違える。<br />
<a href="http://www.flickr.com/photos/shokai/3255725751/" title="word2007のOCR機能をC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3362/3255725751_8d421ce2af_o.png" width="393" height="395" alt="word2007のOCR機能をC#から使う" /></a><br />
<br />
<br />
<br />
■作ったサンプル<br />
<a href="http://bitbucket.org/shokai/ocr-c-sample/">shokai / OCR C# Sample / overview — bitbucket.org</a> (VS2008 C#.NET用)<br />
右上のDownloadからzipでもダウンロードできます<br />
wordについてるDocument Image Writerがインストールされているマシンなら動くと思う。<br />
<br />
<br />
<br />
<br />
<br />
■Microsoft Office Document Image Writerのセットアップ<br />
Word2007には入っていたのでCDからインストールしなおした。普通にインストールするとチェックが外れててインストールされない。<br />
<a href="http://www.flickr.com/photos/shokai/3255572709/" title="word2007 by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3444/3255572709_719c7b9dd9.jpg" width="500" height="422" alt="word2007" /></a><br />
<br />
<span id="more-4162"></span><br />
<br />
VisualStudioのプロジェクトの「参照の追加」で「Microsoft Office Document Imaging 12.0 Type Library」があるので読み込むと使える<br />
2007で12.0なので、昔のwordにも入っていそう<br />
<a href="http://www.flickr.com/photos/shokai/3255605797/" title="word2007のOCR機能 by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3533/3255605797_115e65584c.jpg" width="500" height="279" alt="word2007のOCR機能" /></a><br />
<br />
<br />
<br />
■使う<br />
<br />
参照の追加ができていればこれだけでOCRが動いて、テキストが読み取れる。<br />
<a href="http://bitbucket.org/shokai/ocr-c-sample/src/a48c1593dac9/OcrSample/OcrSampleForm.cs">OcrSampleForm.cs</a><br />
</p>
<blockquote><p>
MODI.Document&nbsp;doc&nbsp;=&nbsp;new&nbsp;MODI.Document();<br />
doc.Create(filename);&nbsp;//&nbsp;ファイル名を指定<br />
doc.OCR(MODI.MiLANGUAGES.miLANG_JAPANESE,&nbsp;false,&nbsp;false);&nbsp;//&nbsp;日本語指定<br />
foreach&nbsp;(MODI.Image&nbsp;img&nbsp;in&nbsp;doc.Images)&nbsp;//&nbsp;複数ページあるファイルを順に読む<br />
{<br />
&nbsp;&nbsp;MODI.Layout&nbsp;layout&nbsp;=&nbsp;img.Layout;<br />
&nbsp;&nbsp;textBoxResult.Text&nbsp;=&nbsp;layout.Text;&nbsp;//&nbsp;テキストボックスに表示<br />
}<br />
</p></blockquote>
<p>
フォント名も取れるらしい。<br />
<br />
<br />
font名が取れるという事はwindowsにインストールされているfontに依存しているのかな？<br />
たくさんインストールしてあれば認識率が上がるかも。<br />
Monoでは動かせなかった。ole32.dllでエラーが出るが、同じディレクトリに置いたりしても駄目だった。サーバーで動かせれば夢が広がるだが<br />
<br />
<br />
<br />
■色々な画像を読み込ませる<br />
スクリーンショットはよく読める。<br />
<a href="http://www.flickr.com/photos/shokai/3255740983/" title="ocr by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3488/3255740983_12b1fe8d22_o.png" width="291" height="430" alt="ocr" /></a><br />
<br />
<br />
印刷物の縦書きが自動認識された<br />
<a href="http://www.flickr.com/photos/shokai/3256633878/" title="縦書きが自動認識されてた by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3097/3256633878_a59d87f19a_o.png" width="264" height="441" alt="縦書きが自動認識されてた" /></a><br />
<br />
<br />
まずまず<br />
<a href="http://www.flickr.com/photos/shokai/3256564190/" title="word2007のOCR機能をC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3494/3256564190_15332ee4f3.jpg" width="500" height="305" alt="word2007のOCR機能をC#から使う" /></a><br />
<br />
<br />
まあまあ<br />
<a href="http://www.flickr.com/photos/shokai/3255729635/" title="word2007のOCR機能をC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3390/3255729635_d7438f5cbf.jpg" width="393" height="395" alt="word2007のOCR機能をC#から使う" /></a><br />
<br />
<br />
全然駄目<br />
<a href="http://www.flickr.com/photos/shokai/3255723257/" title="word2007のOCR機能をC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3467/3255723257_6fda746554.jpg" width="420" height="394" alt="word2007のOCR機能をC#から使う" /></a><br />
<br />
<br />
切り抜いても駄目<br />
<a href="http://www.flickr.com/photos/shokai/3256554840/" title="word2007のOCR機能をC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3478/3256554840_9cf3ff8b89.jpg" width="420" height="394" alt="word2007のOCR機能をC#から使う" /></a><br />
<br />
<br />
softbankだけ認識した<br />
<a href="http://www.flickr.com/photos/shokai/3255722409/" title="word2007のOCR機能をC#から使う by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3416/3255722409_995903dde6.jpg" width="420" height="394" alt="word2007のOCR機能をC#から使う" /></a><br />
<br />
<br />
これを使ってwebcam頭に付けて町中歩き回って、認識した文字をtwitterにpostしまくる、とかはうまくいかないと思う。<br />
fontが合致しないと認識しないみたいなので、看板のfontが全部手に入ったらできるかも。<br />
<br />
この精度でも検索ワード代わりにはなりそうなので、手持ちの写真のExifに全部OCRでテキストデータを付けるとかしようかな。<br />
Flickrでやってもいいけどタグは完全一致だから検索用には向いてない。自前でDB作るとか。<br />
<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/4162/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>C#.NETでコンソールアプリを作るためのConsoleLib.NET</title>
		<link>http://shokai.org/blog/archives/2352</link>
		<comments>http://shokai.org/blog/archives/2352#comments</comments>
		<pubDate>Thu, 11 Dec 2008 04:32:45 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=2352</guid>
		<description><![CDATA[Monoでコンソールアプリケーションを作るときにargsの扱いが手間だったので作った。今のところ機能はそれだけ。dllとして書き出しているのでVB.NETやC++.NETでも使える。 shokai / ConsoleLi [...]]]></description>
			<content:encoded><![CDATA[<p>
Monoでコンソールアプリケーションを作るときにargsの扱いが手間だったので作った。今のところ機能はそれだけ。dllとして書き出しているのでVB.NETやC++.NETでも使える。<br />
<br />
<a href="http://www.bitbucket.org/shokai/consolelibnet/">shokai / ConsoleLib.NET / overview — bitbucket.org</a><br />
右上からzipでダウンロードできる。mercurialを使っている人は<br />
</p>
<blockquote><p>hg clone http://bitbucket.org/shokai/consolelibnet/ ./consolelibnet</p></blockquote>
<p>
<br />
<br />
<a href="http://www.bitbucket.org/shokai/consolelibnet/src/d127eb789a4b/ConsoleLibSample/Program.cs">使用例(ConsoleLibSample.exeのコード)</a><br />
argsをハイフンなし、ハイフンつきなどを分けてくれる。<br />
<br />
<br />
動かしてみる。ためしに引数を渡すと<br />
</p>
<blockquote><p>./ConsoleLibSample.exe post -m &#8220;hello world&#8221; -o out.txt -l -s</p></blockquote>
<p>
こういう風に分割してくれる。<br />
</p>
<blockquote><p>First: post<br />
Switches: l s <br />
Params: <br />
 m=hello world<br />
 output=out.txt<br />
ARGS: post,-m,hello world,-o,out.txt,-l,-s,</p></blockquote>
<p>
<br />
<a href="http://www.bitbucket.org/shokai/consolelibnet/src/d127eb789a4b/ConsoleLibSample/Program.cs">使用例のコード</a>を見ればわかるが、ParamsParserに渡せば分解してくれる。<br />
<br />
<span id="more-2352"></span><br />
<br />
<ul>
	<li>一番最初の引数。postとか、メソッド名的に使うであろうもの<br />
 → ParamsParser.Firstでアクセスできる。一番最初がハイフンで始まる時はnullを返す。</li>
	<li>-m &#8220;hello world&#8221;や-o out.txtの様にhashとして使うであろうもの<br />
 → ParamsParser.ParamsプロパティとしてDictionary(.NETのHash)でアクセスできる。<br />
ParamsParser.Params["m"]で&#8221;hello world&#8221;が取り出せる。</li>
	<li>-l、-sなどハイフンありの次にハイフン無しの引数が来ない物<br />
 → スイッチ。ParamsParser.Switchesとして、Listでアクセスできる。ParamsParser.hasSwitch(&#8220;s&#8221;)でtrue/falseで返ってくる。</li>
</ul>
<br />
頭のハイフンは何個付けても全て取り除かれる。<br />
</p>
<blockquote><p>./ConsoleLibSample.exe post -s -l -o out.txt -m &#8220;hello world&#8221;</p></blockquote>
<p>
のように順番が変わっていても、全て同じように扱える。<br />
<br />
-o out.txtとしたのに出力で<br />
output=out.txtとなっているのは、Bindを使っているから。<br />
</p>
<blockquote><p>pp.Bind(&#8220;output&#8221;, &#8220;o&#8221;);</p></blockquote>
<p>
これで、-outputでも-oでも、pp.Params["output"]としてアクセスできる。引数の省略形を定義するのに使える。<br />
もちろん<br />
</p>
<blockquote><p>pp.Bind(&#8220;output&#8221;, &#8220;o&#8221;);<br />
pp.Bind(&#8220;output&#8221;, &#8220;out&#8221;);</p></blockquote>
<p>
の様に多重にBindも可能。<br />
<br />
<br />
<a href="http://shokai.org/blog/archives/2325">VS2008で単体テスト</a>のとおり今回はテスト駆動開発した。<a href="http://www.bitbucket.org/shokai/consolelibnet/src/tip/ConsoleLibTest/ParamsParserTest.cs">テストコード</a>の方が<a href="http://www.bitbucket.org/shokai/consolelibnet/src/tip/ConsoleLib/ParamsParser.cs">本体</a>よりも多いが、全然生産性は高く感じる。<br />
<br />
今回は特に正規表現を何度も使っているので、1つの関数に3つ4つテストコードが先に書かれている方が一度にチェックできる量が多い。テストは素晴らしい。<br />
<br />
<br />
<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/2352/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>VS2008で単体テスト</title>
		<link>http://shokai.org/blog/archives/2325</link>
		<comments>http://shokai.org/blog/archives/2325#comments</comments>
		<pubDate>Sat, 06 Dec 2008 18:47:03 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[VS2008]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=2325</guid>
		<description><![CDATA[VisualStudio2008 professionalからIDE標準で単体テスト機能（ブラックボックステスト）が付いているので使ってみた。 俺は今まで単体テストはRSpecぐらいしかやったことがなかったし、何かライブ [...]]]></description>
			<content:encoded><![CDATA[<p>
VisualStudio2008 professionalからIDE標準で単体テスト機能（ブラックボックステスト）が付いているので使ってみた。<br />
俺は今まで単体テストは<a href="http://jp.rubyist.net/magazine/?0021-Rspec">RSpec</a>ぐらいしかやったことがなかったし、何かライブラリを作った時はそれを使うGUI付きサンプルアプリケーションを作ることでしか動作確認してこなかったけど、これは次回からどんどん使っていく事にした。<br />
<br />
この種のテストをブラックボックステストと呼ぶらしい。テスト対象のクラスの関数1つずつをブラックボックスと見るテストで、入出力の値に注目する。ある値を関数に入れてみて、予想した値が返ってくるかチェックすることで、関数が仕様を満たしているかチェックする。<br />
<br />
今回は<a href="http://www.bitbucket.org/shokai/benchmark-counter-net/">BenchmarkCounter.NET</a>の中の処理時間を計るためのOrg.Shokai.Util.Benchmark.Counterクラスのテストを作った。Startメソッドで計測開始し、Stopメソッドで停止、その間の処理時間をミリ秒で保存できる。Start/Stopを複数回行った場合、その間の平均処理時間も求める事が出来る。<br />
<br />
テストでは、出力値が正しい値になっているかどうかチェックする。このBenchmarkCounterのテストでは<br />
<ul>
	<li>処理時間を取得するメソッドの場合<br />
→ 時間の値が0以上でなければエラー</li>
	<li>計測回数を取得するメソッドの場合<br />
→ 何回か計測してみて、計測回数が合わなければエラー</li>
	<li>計測中かどうか？フラグの場合<br />
→ Startメソッドにfalseだったらエラー<br />
→ Stopメソッド後にtrueだったらエラー</li>
</ul>
という感じ。<br />
<br />
<span id="more-2325"></span><br />
■テストする<br />
その前に<br />
<a href="http://www.atmarkit.co.jp/fdotnet/special/vs2008test01/vs2008test01_01.html">Visual Studio 2008単体テスト機能のすべて − ＠IT</a><br />
この記事が詳しい。<a href="http://www.atmarkit.co.jp/fdotnet/special/vs2008test01/vs2008test01_04.html">4ページ目</a>に値を比較するAssertの関数の説明もある。<br />
<br />
こちらのテストサンプルプロジェクトも参考にさせてもらった。<br />
<a href="http://blogs.msdn.com/tomohn/pages/MSDNOFF2007.aspx">長沢智治のライフサイクルブログ : MSDN オフラインセミナー＜全国ツアー｜チーム開発編＞ 2007 Winter フォローアップページ</a><br />
<br />
<br />
ソリューションを右クリックして新しいプロジェクトを追加する。「テスト プロジェクト」というのがある<br />
<a href="http://www.flickr.com/photos/shokai/3086595995/" title="vs2008 TDD by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3084/3086595995_c327c0c375_o.png" width="392" height="363" alt="vs2008 TDD" /></a><br />
Benchmarkプロジェクトのテストなので、BenchmarkTestという名前にした。<br />
<br />
<br />
テストプロジェクトを右クリックしてテストクラスを追加する。<br />
（元からあるテストクラス使わないので削除してよい）<br />
<a href="http://www.flickr.com/photos/shokai/3087436238/" title="vs2008 TDD by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3055/3087436238_db646998ed.jpg" width="409" height="322" alt="vs2008 TDD" /></a><br />
<br />
<br />
「単体テストウィザード」を選択<br />
<a href="http://www.flickr.com/photos/shokai/3086670225/" title="vs2008 TDD by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3226/3086670225_b59f6771c3.jpg" width="500" height="396" alt="vs2008 TDD" /></a><br />
<br />
<br />
現在あるメソッドのテストを一括して作成できる。<br />
とりあえず全メソッド選択して作ってしまう<br />
<a href="http://www.flickr.com/photos/shokai/3086672197/" title="vs2008 TDD by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3056/3086672197_1c6f8ed5d8.jpg" width="479" height="424" alt="vs2008 TDD" /></a><br />
<br />
<br />
ちなみに、関数を右クリックしてテストを作る事もできる。<br />
テストはクラス毎に1つのテストクラスになるので、右クリックから行った場合は既にあるテストクラスの一番下に追加される。<br />
<a href="http://www.flickr.com/photos/shokai/3086674293/" title="vs2008 TDD by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3235/3086674293_530fc1195c.jpg" width="429" height="238" alt="vs2008 TDD" /></a><br />
<br />
<br />
テストプロジェクトを右クリックして「スタートアッププロジェクトに設定」する<br />
これでこのテストプロジェクト内のテストが行える。<br />
<a href="http://www.flickr.com/photos/shokai/3086628101/" title="vs2008 TDD by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3209/3086628101_8a0f990f53_o.png" width="289" height="393" alt="vs2008 TDD" /></a><br />
<br />
<br />
とりあえず、動かしてみる。<br />
F5もしくはツールメニューから「デバッグ開始」すればテストプロジェクトが走り、テスト結果が表示される。<br />
まだテストコードを書いていないので全て「結果を作成できません」になる。<br />
<br />
ある程度テストコードを書いていくと、こんな風に失敗したり成功したりする。<br />
<a href="http://www.flickr.com/photos/shokai/3086632819/" title="vs2008 TDD by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3264/3086632819_0b8a50b56a.jpg" width="500" height="119" alt="vs2008 TDD" /></a><br />
<br />
<br />
■テストコードの書き方<br />
例として、Countingアクセサ（実体は関数）のテストを書く。計測中かどうかを表す関数で、Startして計測中はtrueになり、Stopするとfalseになる。この切り替えがちゃんと動いているかを確認したい。<br />
<br />
Testを作成した直後はこうなっているはず<br />
</p>
<blockquote><p>///&nbsp;&lt;summary&gt;<br />
///Counting&nbsp;のテスト<br />
///&lt;/summary&gt;<br />
[TestMethod()]<br />
public&nbsp;void&nbsp;CountingTest()<br />
{<br />
&nbsp;&nbsp;Counter&nbsp;target&nbsp;=&nbsp;new&nbsp;Counter();&nbsp;//&nbsp;TODO:&nbsp;適切な値に初期化してください<br />
&nbsp;&nbsp;bool&nbsp;actual;<br />
&nbsp;&nbsp;actual&nbsp;=&nbsp;target.Counting;<br />
&nbsp;&nbsp;Assert.Inconclusive(&quot;このテストメソッドの正確性を確認します。&quot;);<br />
}</p></blockquote>
<p>
<br />
このまま実行すると「このテストメソッドの正確性を確認します」と出るが、これは「これから私がテストコードを書き直して確認します」という意味なので削除して、自分で書く。<br />
<br />
<br />
2種類チェックしたいのでCountingTest2も作った。手書きでテストを追加してもちゃんとテスト実行時に呼び出される。</p>
<blockquote><p>[TestMethod()]<br />
public&nbsp;void&nbsp;CountingTest()<br />
{<br />
&nbsp;&nbsp;Counter&nbsp;target&nbsp;=&nbsp;new&nbsp;Counter();&nbsp;//&nbsp;TODO:&nbsp;適切な値に初期化してください<br />
<br />
&nbsp;&nbsp;target.Start();<br />
&nbsp;&nbsp;target.Stop();<br />
&nbsp;&nbsp;target.Start();<br />
&nbsp;&nbsp;bool&nbsp;actual&nbsp;=&nbsp;target.Counting;<br />
&nbsp;&nbsp;Assert.IsTrue(actual,&nbsp;&quot;計測中フラグが立っていません&quot;);<br />
}<br />
<br />
[TestMethod()]<br />
public&nbsp;void&nbsp;CountingTest2()<br />
{<br />
&nbsp;&nbsp;Counter&nbsp;target&nbsp;=&nbsp;new&nbsp;Counter();<br />
&nbsp;&nbsp;target.Start();<br />
&nbsp;&nbsp;target.Stop();<br />
&nbsp;&nbsp;bool&nbsp;actual&nbsp;=&nbsp;target.Counting;<br />
&nbsp;&nbsp;Assert.IsFalse(actual,&nbsp;&quot;計測中フラグが消えていません&quot;);<br />
}</p></blockquote>
<p>
Assert.条件(値1, &#8220;エラーメッセージ&#8221;);や<br />
Assert.条件(値1, 値2, &#8220;エラーメッセージ&#8221;); という風に書く。<br />
Assert条件文の最後の引数がエラーメッセージなのがちょっとわかりにくいが<br />
Assert.AreEqual(a, b, &#8220;error! a != b&#8221;);<br />
の場合、aとbが同じかどうか確かめてみて、違ったらerror!と表示する。<br />
<br />
他にも色々条件式があって<a href="http://www.atmarkit.co.jp/fdotnet/special/vs2008test01/vs2008test01_04.html">この記事の下の方</a>で解説されている<br />
<br />
<br />
全部テストが通るとこうなる。<br />
<a href="http://www.flickr.com/photos/shokai/3087473284/" title="vs2008 TDD by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3273/3087473284_4a68a858d4_o.png" width="514" height="263" alt="vs2008 TDD" /></a><br />
<br />
チェック項目が2つ以上ある関数の場合、1つのテスト関数で複数回Assertする事も出来るが、1つのテスト関数につき1つAssertする事にした。こうしておいた方がどちらの条件でエラーがでたのかわかりやすい為。<br />
<br />
<br />
今回は先に出来ていたクラスのテストを後から作ったが、次は先にテストを作成して後から実装するテスト駆動開発でやりたい。先にテストを書き、Assertのエラー文を<br />
</p>
<blockquote><p>Assert.IsTrue(actual,&nbsp;&quot;Startメソッドで実行した後はtrueになるべきです&quot;);</p></blockquote>
<p>
のように書けば、これがそのまま詳細設計になる。<br />
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/2325/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# &#8211; FeliCaリーダでIDを読む</title>
		<link>http://shokai.org/blog/archives/1573</link>
		<comments>http://shokai.org/blog/archives/1573#comments</comments>
		<pubDate>Mon, 11 Aug 2008 03:00:27 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[FeliCa]]></category>
		<category><![CDATA[Tech]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=1573</guid>
		<description><![CDATA[felicalibとC#用ラッパーを使ってFelicaのIDを読んだ。 参考：felicalib C#での利用方法 MNPして使わなくなった（財布機能1回も使ってない）auのお財布ケータイW51Sを乗せたところ。 普段使 [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://felicalib.tmurakam.org/">felicalib</a>とC#用ラッパーを使ってFelicaのIDを読んだ。<br />
参考：<a href="http://sourceforge.jp/projects/felicalib/wiki/CSharp">felicalib C#での利用方法</a><br />
<br />
<a href="http://www.flickr.com/photos/shokai/2752139164/" title="Reading felica ID by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3049/2752139164_cee0cdb721_o.png" width="265" height="276" alt="Reading felica ID" /></a><br />
MNPして使わなくなった（財布機能1回も使ってない）auのお財布ケータイW51Sを乗せたところ。<br />
<br />
普段使ってるSuicaを読むと違うIDが出てきた。<br />
<br />
<br />
■作ったもの<br />
<a href="http://shokai.org/archive/cs3.0/0808_Felica/080811_Felica.zip">080811_Felica.zip</a> (VisualStudio2008 / C#3.0)<br />
<a href="http://www.microsoft.com/downloads/details.aspx?FamilyId=333325fd-ae52-4e35-b531-508d977d32a6&#038;DisplayLang=ja">.NET Framework3.5</a>が必要<br />
<br />
<br />
■準備<br />
RC-S320を使った。付属のCDからドライバだけインストールしておく。<br />
<div class="amazlet-box" style="margin-bottom:0px;"><div class="amazlet-image" style="float:left;"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/B0009YVAW4/shokai-22/ref=nosim/" name="amazletlink" target="_blank"><img src="http://ecx.images-amazon.com/images/I/312WXC455AL._SL160_.jpg" alt="SONY RC-S320 非接触ICカードリーダ/ライタ PaSoRi 「パソリ」" style="border: none;" /></a></div><div class="amazlet-info" style="float:left;margin-left:15px;line-height:120%"><div class="amazlet-name" style="margin-bottom:10px;line-height:120%"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/B0009YVAW4/shokai-22/ref=nosim/" name="amazletlink" target="_blank">SONY RC-S320 非接触ICカードリーダ/ライタ PaSoRi 「パソリ」</a><div class="amazlet-powered-date" style="font-size:7pt;margin-top:5px;font-family:verdana;line-height:120%">posted with <a href="http://www.amazlet.com/browse/ASIN/B0009YVAW4/shokai-22/ref=nosim/" title="SONY RC-S320 非接触ICカードリーダ/ライタ PaSoRi 「パソリ」" target="_blank">amazlet</a> at 08.08.11</div></div><div class="amazlet-detail">ソニー <br />売り上げランキング: 99<br /></div><div class="amazlet-review" style="margin-top:10px; margin-bottom:10px"><div class="amazlet-review-average" style="margin-bottom:5px">おすすめ度の平均: <img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-4-5.gif" alt="4.5" /></div><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-4-0.gif" alt="4" /> あれば便利かもしれないが、無くても困らない製品<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> 便利アイテムです<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> 便利です。<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-5-0.gif" alt="5" /> 飛行機に乗れなくてもマイルが貯まる<br /><img src="http://images-jp.amazon.com/images/G/09/x-locale/common/customer-reviews/stars-4-0.gif" alt="4" /> edyを常用してる人ならお勧め<br /></div><div class="amazlet-link" style="margin-top: 5px"><a href="http://www.amazon.co.jp/exec/obidos/ASIN/B0009YVAW4/shokai-22/ref=nosim/" name="amazletlink" target="_blank">Amazon.co.jp で詳細を見る</a></div></div><div class="amazlet-footer" style="clear: left"></div></div>
<br />
<br />
<a href="http://felicalib.tmurakam.org/">felicalib</a>をダウンロードしてくる。中にC#用ラッパー（FelicaLib.cs）も入っているので自分のプロジェクトに追加。<br />
felicalib.dllは「参照の追加」から使うのではなく、bin/Debug, bin/Releaseなどにファイルを直接コピペして置く。実行時にFelicaLib.csからP/Invokeで読み込まれる。<br />
<br />
■コード<br />
ラッパーを読み込んで<br />
</p>
<blockquote><p>using&nbsp;FelicaLib;</p></blockquote>
<p>
<br />
IDmを読むとbyte配列が来るので、Stringに直す。<br />
</p>
<blockquote><p>try<br />
{<br />
&nbsp;&nbsp;using&nbsp;(Felica&nbsp;felica&nbsp;=&nbsp;new&nbsp;Felica())<br />
&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;felica.Polling(0xFFFF);<br />
&nbsp;&nbsp;&nbsp;&nbsp;byte[]&nbsp;data&nbsp;=&nbsp;felica.IDm();<br />
&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;id&nbsp;=&nbsp;&quot;&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;for&nbsp;(int&nbsp;i&nbsp;=&nbsp;0;&nbsp;i&nbsp;&lt;&nbsp;data.Length;&nbsp;i++)<br />
&nbsp;&nbsp;&nbsp;&nbsp;{<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id&nbsp;+=&nbsp;data[i].ToString(&quot;X2&quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;Console.WriteLine(id);&nbsp;//&nbsp;ID出力<br />
&nbsp;&nbsp;}<br />
}<br />
catch&nbsp;(Exception&nbsp;ex)<br />
{<br />
&nbsp;&nbsp;Console.Error.WriteLine(ex.Message);<br />
}</p></blockquote>
<p>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/1573/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>C#3.0 &#8211; DirectShow.NET2.0でwebcam撮影、JPEG保存する</title>
		<link>http://shokai.org/blog/archives/1546</link>
		<comments>http://shokai.org/blog/archives/1546#comments</comments>
		<pubDate>Mon, 16 Jun 2008 18:04:16 +0000</pubDate>
		<dc:creator>shokai</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[DirectShow]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[VS2008]]></category>
		<category><![CDATA[webcam]]></category>

		<guid isPermaLink="false">http://shokai.org/blog/?p=1546</guid>
		<description><![CDATA[Windowsでカメラからの画像入力を使うには、Flash(Air)やProcessing、Max/MSPを除くとDirectXかVideo for Windowsを使わなければならないんだけど、これらをC#から直接使う [...]]]></description>
			<content:encoded><![CDATA[<p>
<p>Windowsでカメラからの画像入力を使うには、<a href="http://shokai.org/blog/archives/1479">Flash(Air)</a>や<a href="http://shokai.org/blog/archives/1332">Processing</a>、Max/MSPを除くとDirectXかVideo for Windowsを使わなければならないんだけど、これらをC#から直接使うのはとてもめんどい。</p>
<p>で、DirectX自体はラッパーを介して使えるので問題ないんだけど、DirectShow（カメラの入力に使う）だけはなぜかC#用のラッパーが無いので<a href="http://directshownet.sourceforge.net/">DirectShow.NET</a>の出番になる。このライブラリは<a href="http://shokai.org/blog/archives/1207">s.h.log  DirectShow.NETで静止画キャプチャ</a>でも使ったんだけど、去年ぐらいからDirectShow.NETがver 2.0になってさらに良くなっていた。</p>
<p>ちょっといじってみたが、C++が苦手な馬鹿には便利すぎて感動したので、<br /><br />
webcam撮影→JPEG画像に保存のサンプルを作って置いておきます</p>
<p>■作ったもの<br /><br />
→ <a href="http://shokai.org/archive/cs3.0/0806_DshowNetCapture/">Download (VisualStudio 2008 + C#3.0)</a></p>
<p>昨日の朝に<a href="http://d.hatena.ne.jp/shokai/20080616/1213567007">DirectShow.NET2.0でwebcamキャプチャ、JPEG保存 &#8211; 橋本詳解</a>で書いたのとほぼ同じだが、デバイスの選択ができるようになった。<br /><br />
<a href="http://www.flickr.com/photos/shokai/2582231672/" title="select capture devices by shokai, on Flickr"><img src="http://farm4.static.flickr.com/3090/2582231672_ac922404c1_o.png" width="481" height="302" alt="select capture devices" /></a></p>
<p>あと、DirectShow.NETを使えば、インストールすると1GBぐらいになるDirectX SDKを入れなくても済むのも嬉しい。</p>
<p>■プログラムの準備<br /><br />
まず準備として<a href="http://directshownet.sourceforge.net/">DirectShow.NET</a>のサイトからDirectShowLib-2005.dll本体と、サンプルを手に入れる。<br /><br />
DirectShowLib-2005.dllにパスを通し、sampleに入っているCapture.csもpublic domainなのでコピーしてありがたく使わせていただく。</p>
<p>そして、いくつか使うnamespaceを通す<br /><br />
<code>usingDirectShowLib;<br /><br />
usingSnapShot;<br /><br />
usingSystem.Runtime.InteropServices;<br /><br />
usingSystem.Drawing.Imaging;</code></p>
<p>■カメラデバイスを取得してプレビュー表示する<br /><br />
なんでもいいが、System.Windows.Forms.Controlを継承しているPanelやPictureBoxやFormなどを、カメラのプレビュー用に用意しなければならない。プレビューを画面に出したくなければVisible = falseしておけばいい。<br /><br />
そのコントロールをCaptureクラスのコンストラクタに渡してやると、cameraのプレビュー表示がリアルタイムに表示されるようになる。<br /><br />
<code>PanelpanelPreview=newPanel();<br /><br />
this.Controls.Add(panelPreview);<br /><br />
Capturecam=newCapture(0,640,480,24,panelPreview);//device,x,y,24FPS,preview</code><br /><br />
Capture()の第一引数は画像入力デバイスのindexで、0からはじまる。存在しないデバイスindexを選んでしまうとエラーになるので注意。FPSやカメラのXYサイズも指定できる。</p>
<p>■現在のカメラ表示を保存する<br /><br />
別のコントロールを用意して、そっちに保存する。<a href="http://www.flickr.com/photos/shokai/2582231672/">今回のサンプルアプリ</a>の場合は、左の動画が右に静止画としてキャプチャされる。<br /><br />
PictureBoxにキャプチャするなら<br /><br />
<code>PictureBoxpicBox=newPictureBox();<br /><br />
this.Controls.Add(picBox);<br /><br />
IntPtrm_ip=cam.Click();<br /><br />
Bitmapb=newBitmap(cam.Width,cam.Height,cam.Stride,PixelFormat.Format24bppRgb,m_ip);<br /><br />
b.RotateFlip(RotateFlipType.RotateNoneFlipY);//上下反転しているので直す<br /><br />
picBox.Image=b;</code></p>
<p>Image型で静止画をコピーできたので、JpegファイルやPNGファイルなどに書き出すのも簡単。<br /><br />
<code>picBox.Image.Save("captured.jpg",ImageFormat.Jpeg);</code></p>
<p>もちろんPictureBoxを経由しないで、直接保存もできる<br /><br />
<code>b.Image.Save("captured.jpg",ImageFormat.Png);</code></p>
<p>カメラを閉じるのを忘れずに。<br /><br />
FormのFormClosedイベント内などでDispose()を呼べば良い<br /><br />
<code>cam.Dispose();</code></p>
<p>ちなみに、現在接続してあるデバイスの一覧はDsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice)の中に入っている。<br /><br />
今回のサンプルでコンボボックスの中にデバイス名一覧を突っ込んだのはこんな感じでやった<br /><br />
<code>comboBoxDevices.Items.Clear();<br /><br />
foreach(DsDevicedsinDsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice))<br /><br />
{<br /><br />
comboBoxDevices.Items.Add(ds.Name);<br /><br />
}<br /><br />
comboBoxDevices.SelectedIndex=0;</code></p>
<p>ComboBox.SelectedIndexで現在選ばれたデバイス名のindexがわかって、それをCaptureのコンストラクタのデバイスindexとして使えば良い。</p>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/1546/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# &#8211; Flickr.NETでFlickrアップローダ</title>
		<link>http://shokai.org/blog/archives/1482</link>
		<comments>http://shokai.org/blog/archives/1482#comments</comments>
		<pubDate>Sun, 13 Jan 2008 17:59:18 +0000</pubDate>
		<dc:creator>moblog</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Flickr]]></category>
		<category><![CDATA[Flickr.NET]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[VS2005]]></category>

		<guid isPermaLink="false">http://shlog.sakura.ne.jp/blog/?p=1482</guid>
		<description><![CDATA[前の記事に続き、Flickr.NETを使う。 今度はFlickr Uploaderを作ってみた。Flickr.NETには ・Flickr APIへの認証（read/write/delete権限の取得） ・ファイル名を指定 [...]]]></description>
			<content:encoded><![CDATA[<p>
<p><a href="http://web.sfc.keio.ac.jp/~shokai/archives/2008/01/cs-flickr-net-search-tag.html">前の記事</a>に続き、<a href="http://www.codeplex.com/FlickrNet">Flickr.NET</a>を使う。</p>
<p>今度はFlickr Uploaderを作ってみた。Flickr.NETには<br /><br />
・Flickr APIへの認証（read/write/delete権限の取得）<br /><br />
・ファイル名を指定してアップロード<br /><br />
などの機能が揃っているのでさくっと作れた。</p>
<p>できたもの => <a href="http://shokai.org/archive/cs2.0/0801_FlickrAPI/">Archive</a><br /><br />
ドラッグアンドドロップした写真1枚をアップロードする<br /><br />
<a title="uploader by shokai, on Flickr" href="http://www.flickr.com/photos/shokai/2189326366/"><img src="http://farm3.static.flickr.com/2021/2189326366_e924e883a6_o.png" alt="uploader" width="369" height="336" /></a></p>
<p>tagやtitleなどが適当に付いている<br /><br />
<a title="using Flickr.NET by shokai, on Flickr" href="http://www.flickr.com/photos/shokai/2188583024/"><img src="http://farm3.static.flickr.com/2019/2188583024_b8fa19bc1c.jpg" alt="using Flickr.NET" width="500" height="401" /></a></p>
<p>■oAuthでの認証のためのtoken発行<br /><br />
今回はAPI keyに加えて、secretも使ってfrobを作ってtokenの発行を行わないといけない。<br /><br />
まずkeyとsecretを取りに行く→<a href="http://flickr.com/services/api/keys/">Flickr Services</a><br /><br />
その辺の仕組みは<a href="http://web.sfc.keio.ac.jp/~shokai/archives/2008/01/cs-flickr-net-search-tag.html">1つ前の記事</a>と、<br /><br />
・<a href="http://www.machu.jp/diary/20051101.html#p01">Flickr API の認証 &#8211; まちゅダイアリー (2005-11-01)</a><br /><br />
・<a href="http://web.sfc.keio.ac.jp/~shokai/archives/2006/09/flickrupload.html">s.h.log: Flickr::Uploadで写真をアップロード</a><br /><br />
を参考に。</p>
<p>■プログラムを書く<br /><br />
まずfrobを作る。あとで使うのでとっておく（2回作ると違う値ができてしまうので）</p>
</p>
<blockquote><p><p>Flickr flickr = new Flickr();<br /><br />
flickr.ApiKey = &#8220;your-api-key&#8221;;<br /><br />
flickr.ApiSecret = &#8220;your-api-secret&#8221;;<br /><br />
String flickr_frob = flickr.AuthGetFrob(); // frobの作成</p></p></blockquote>
<p>
<p>で、認証画面をwebブラウザで開いて「OK」ボタンを押してもらう</p>
</p>
<blockquote><p><p>System.Diagnostics.Process.Start(flickr.AuthCalcUrl(flickr_frob, AuthLevel.Write)); // 認証画面をブラウザで開く</p></p></blockquote>
<p>
<p>OK押してもらってから、さっき作ったfrobを使ってtokenを取りに行く。</p>
</p>
<blockquote><p><p>try{<br /><br />
Auth auth = flickr.AuthGetToken(flickr_frob);<br /><br />
flickr.AuthToken = auth.Token; // token取得<br /><br />
}<br /><br />
catch (FlickrApiException ex)<br /><br />
{<br /><br />
Console.WriteLine(ex.Message);<br /><br />
}</p></p></blockquote>
<p>
<p>無事tokenを取って、Flickrオブジェクトにセットできたら、ファイル名を指定すればアップロードできる。tagやtitleやdescriptionを適当に付けてみた。</p>
</p>
<blockquote><p><p>Photo p = new Photo();<br /><br />
p.PhotoId = flickr.UploadPicture(&#8220;PhotoFileName&#8221;, &#8220;test photo&#8221;, &#8220;これはてすとです&#8221;, &#8220;test,uploadertest&#8221;);<br /><br />
p.UserId = auth.User.UserId;<br /><br />
System.Diagnostics.Process.Start(p.WebUrl);</p></p></blockquote>
<p>
<p>uploadされた写真のphotoIdが返ってくるので、それを使ってWeb上でのURLを求めることも出来る。今回はまたブラウザで開いてみた。</p>
<p>UploadPictureメソッドはどうやら内部でThread.Sleep()を呼んでいるみたいなので、そのままThreadで実行すればマルチスレッド化できる。<br /><br />
uploadを途中で止めるメソッドが無いみたいだけど、途中で止めたい時はスレッドで実行してAbort()してしまえば止まった。</p>
<p>詳しくは今回作ったアプリのソース参照</p>
<p><span id="more-1482"></span></p>
<p>手順を強制するGUIのコードは長くなりがちだな。認証前にuploadボタンを押せないようにしておくとか。2回認証しないようにするとか。<br /><br />
<a href="http://shokai.org/archive/cs2.0/0801_FlickrAPI/FlickrAPI/FlickrUploadTest/FormFlickrUpload.cs">FormFlickrUpload.cs</a></p>
</p>
<blockquote><p><p>using System;<br /><br />
using System.Collections.Generic;<br /><br />
using System.ComponentModel;<br /><br />
using System.Data;<br /><br />
using System.Drawing;<br /><br />
using System.Text;<br /><br />
using System.Windows.Forms;<br /><br />
using System.IO;<br /><br />
using System.Threading;</p>
<p>using FlickrNet;</p>
<p>namespace FlickrUploadTest<br /><br />
{<br /><br />
public partial class FormFlickrUpload : Form<br /><br />
{<br /><br />
private Flickr flickr;<br /><br />
private String flickr_apikey = &#8220;cce8e143a8b4fd19c1e4026909643c67&#8243;;<br /><br />
private String flickr_secret = &#8220;5b58a24a5826ce2a&#8221;;<br /><br />
private String flickr_frob;<br /><br />
private String fileName;<br /><br />
/// <summary><br /><br />
/// Uploadするファイル<br /><br />
/// </summary><br /><br />
public String FileName<br /><br />
{<br /><br />
get<br /><br />
{<br /><br />
return this.fileName;<br /><br />
}<br /><br />
set<br /><br />
{<br /><br />
if (!new FileInfo(value).Exists) return;<br /><br />
panelDD.BackgroundImage = Image.FromFile(value);<br /><br />
this.fileName = value;<br /><br />
buttonUpload.Enabled = true;<br /><br />
}<br /><br />
}<br /><br />
private Auth auth;<br /><br />
private Thread threadUpload;</p>
<p>public FormFlickrUpload()<br /><br />
{<br /><br />
InitializeComponent();<br /><br />
buttonUpload.Enabled = false;<br /><br />
progressBar.Visible = false;<br /><br />
panelDD.AllowDrop = true;</p>
<p>flickr = new Flickr();<br /><br />
flickr.ApiKey = flickr_apikey;<br /><br />
flickr.ApiSecret = flickr_secret;<br /><br />
flickr_frob = flickr.AuthGetFrob();</p>
<p>System.Diagnostics.Process.Start(flickr.AuthCalcUrl(flickr_frob, AuthLevel.Write)); // 認証画面をブラウザで開く</p>
<p>flickr.OnUploadProgress += new Flickr.UploadProgressHandler(flickr_OnUploadProgress);<br /><br />
}</p>
<p>private void buttonGetToken_Click(object sender, EventArgs e)<br /><br />
{<br /><br />
try<br /><br />
{<br /><br />
auth = flickr.AuthGetToken(flickr_frob);<br /><br />
flickr.AuthToken = auth.Token;<br /><br />
buttonGetToken.Visible = false;<br /><br />
groupBoxDrop.Text = &#8220;Drop Photo here&#8221;;<br /><br />
if (auth.User.Username != null) Text = &#8220;Flickr Upload Test &#8211; &#8221; + auth.User.Username;<br /><br />
else Text = &#8220;Flickr Upload Test &#8211; &#8221; + auth.User.UserId;<br /><br />
}<br /><br />
catch (FlickrApiException ex)<br /><br />
{<br /><br />
Console.WriteLine(ex.Message);<br /><br />
}<br /><br />
}</p>
<p>#region Drag and Drop<br /><br />
private void panelDD_DragEnter(object sender, DragEventArgs e)<br /><br />
{<br /><br />
if (e.Data.GetDataPresent(DataFormats.FileDrop))<br /><br />
e.Effect = DragDropEffects.All;<br /><br />
else<br /><br />
e.Effect = DragDropEffects.None;<br /><br />
}</p>
<p>private void panelDD_DragDrop(object sender, DragEventArgs e)<br /><br />
{<br /><br />
string[] items = (string[])e.Data.GetData(DataFormats.FileDrop, false);<br /><br />
FileName = items[0]; // 1つ目のファイル<br /><br />
}<br /><br />
#endregion</p>
<p>#region Upload<br /><br />
private void buttonUpload_Click(object sender, EventArgs e)<br /><br />
{<br /><br />
if (FileName == &#8220;&#8221;) return;<br /><br />
buttonUpload.Enabled = false;<br /><br />
panelDD.AllowDrop = false;<br /><br />
progressBar.Visible = true;<br /><br />
progressBar.Maximum = (int)(new FileInfo(this.FileName).Length/1000);<br /><br />
try<br /><br />
{<br /><br />
Photo p = new Photo();<br /><br />
threadUpload = new Thread(delegate()<br /><br />
{<br /><br />
p.PhotoId = flickr.UploadPicture(fileName, &#8220;test photo&#8221;, &#8220;これはてすとです&#8221;, &#8220;test,uploadertest&#8221;);<br /><br />
p.UserId = auth.User.UserId;<br /><br />
System.Diagnostics.Process.Start(p.WebUrl);<br /><br />
this.Invoke((MethodInvoker)delegate()<br /><br />
{<br /><br />
buttonUpload.Enabled = true;<br /><br />
panelDD.AllowDrop = true;<br /><br />
progressBar.Visible = false;<br /><br />
});<br /><br />
});<br /><br />
threadUpload.Start();<br /><br />
}<br /><br />
catch (FlickrApiException ex)<br /><br />
{<br /><br />
Console.WriteLine(ex.Message);<br /><br />
buttonUpload.Enabled = true;<br /><br />
}<br /><br />
}</p>
<p>void flickr_OnUploadProgress(object sender, UploadProgressEventArgs e)<br /><br />
{<br /><br />
if (e.UploadComplete) // アップロード完了<br /><br />
{<br /><br />
this.Invoke((MethodInvoker)delegate()<br /><br />
{<br /><br />
progressBar.Value = 0;<br /><br />
});<br /><br />
}<br /><br />
else<br /><br />
{<br /><br />
this.Invoke((MethodInvoker)delegate()<br /><br />
{<br /><br />
progressBar.Value = e.Bytes / 1000;<br /><br />
});<br /><br />
}<br /><br />
}<br /><br />
#endregion</p>
<p>private void FormFlickrUpload_FormClosed(object sender, FormClosedEventArgs e)<br /><br />
{<br /><br />
if(threadUpload != null) threadUpload.Abort(); // スレッド強制終了<br /><br />
}</p>
<p>}<br /><br />
}</p></p></blockquote>
<p>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/1482/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>C# &#8211; Flickr.NETでtag検索</title>
		<link>http://shokai.org/blog/archives/1481</link>
		<comments>http://shokai.org/blog/archives/1481#comments</comments>
		<pubDate>Sun, 13 Jan 2008 17:30:11 +0000</pubDate>
		<dc:creator>moblog</dc:creator>
				<category><![CDATA[未分類]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Flickr]]></category>
		<category><![CDATA[Flickr.NET]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[VS2005]]></category>

		<guid isPermaLink="false">http://shlog.sakura.ne.jp/blog/?p=1481</guid>
		<description><![CDATA[Flickr.NETという.NET Framework用のライブラリを使って、Flickr APIからタグ検索してみた。2年ぐらい前に使った時より、dllのファイルサイズが1.5倍に増えててた。 できたもの => Arc [...]]]></description>
			<content:encoded><![CDATA[<p>
<p><a href="http://www.codeplex.com/FlickrNet">Flickr.NET</a>という.NET Framework用のライブラリを使って、Flickr APIからタグ検索してみた。2年ぐらい前に使った時より、dllのファイルサイズが1.5倍に増えててた。</p>
<p>できたもの => <a href="http://shokai.org/archive/cs2.0/0801_FlickrAPI/">Archive</a><br /><br />
<a title="using Flickr.NET by shokai, on Flickr" href="http://www.flickr.com/photos/shokai/2188281686/"><img src="http://farm3.static.flickr.com/2350/2188281686_8713b5eb04_o.png" alt="using Flickr.NET" width="473" height="416" /></a></p>
<p>■dllを手に入れる<br /><br />
<a href="http://www.codeplex.com/FlickrNet">FlickrNet API Library &#8211; Home</a><br /><br />
[Release]から2.1.5をダウンロードしてきた。<br /><br />
んで、[参照の追加]でリンクして、</p>
</p>
<blockquote><p><p>using FlickrNet;</p></p></blockquote>
<p>
<p>する。</p>
<p>■API keyを手に入れる<br /><br />
<a href="http://flickr.com/services/api/keys/">Flickr Services</a>からAPI keyを手に入れないといけない。メールアドレスを登録してすぐ発行してもらえる。<br /><br />
今回は「デスクトップアプリ用」を選択。<br /><br />
（検索だけなら、secretとtokenを使ってoAuthで認証する必要は無い）</p>
<p>■プログラムを書く<br /><br />
<a href="http://www.flickr.com/services/api/">Flickr API</a>のラッパーなので、基本的な仕様はFlickr APIの方を見た方が良い。<br /><br />
今回は<a href="http://www.flickr.com/services/api/flickr.photos.search.html">flickr.photos.search</a>を叩いてみた。</p>
<p>まずFlickrというクラスが全ての根になっている</p>
</p>
<blockquote><p><p>using FlickrNet;<br /><br />
Flickr flickr = new Flickr(&#8220;your-api-key&#8221;);</p></p></blockquote>
<p>
<p>flickr.photos.searchでは色々なパラメータを渡すが、Flickr.NETではPhotoSearchOptionsクラスで集約されている。今回はタグだけでeveryoneから検索するのでこれだけだけど、もっと色々パラメータが指定できる。</p>
</p>
<blockquote><p><p>PhotoSearchOptions opt = new PhotoSearchOptions();<br /><br />
opt.Tags = &#8220;food, sfc&#8221;;<br /><br />
opt.TagMode = TagMode.AllTags;<br /><br />
Photos photos = flickr.PhotosSearch(opt); // 検索</p></p></blockquote>
<p>
<p>Photosクラスで返ってきた結果からURLを取り出して、表示する。<br /><br />
PictureBox.Imageにストリームから読み込ませるための関数 DownloadPicture(&#8220;URL&#8221;) を利用してダウンロードする。</p>
</p>
<blockquote><p><p>Photo p = photos.PhotoCollection[0]; // 1枚目<br /><br />
pictureBox.Image = Image.FromStream(flickr.DownloadPicture(p.MediumUrl));<br /><br />
textBoxPhotoUri.Text = p.WebUrl;</p></p></blockquote>
<p>
<p><span id="more-1481"></span></p>
<p>今回のメインクラス => <a href="http://shokai.org/archive/cs2.0/0801_FlickrAPI/FlickrAPI/FlickrDotNetTest/FormFlickrSearch.cs">FormFlickrSearch.cs</a></p>
</p>
<blockquote><p><p>using System;<br /><br />
using System.Collections.Generic;<br /><br />
using System.ComponentModel;<br /><br />
using System.Data;<br /><br />
using System.Drawing;<br /><br />
using System.Text;<br /><br />
using System.Windows.Forms;<br /><br />
using System.IO;<br /><br />
using System.Net;</p>
<p>using FlickrNet;</p>
<p>namespace FlickrDotNetTest<br /><br />
{<br /><br />
public partial class FormFlickrDotNetTest : Form<br /><br />
{<br /><br />
private Flickr flickr;<br /><br />
private String flickr_apikey = &#8220;17bd602a83ec433b0ed9fafd93549e1a&#8221;;<br /><br />
private Photos photos;<br /><br />
private int index;</p>
<p>public FormFlickrDotNetTest()<br /><br />
{<br /><br />
InitializeComponent();</p>
<p>buttonNext.Enabled = false;<br /><br />
buttonPrev.Enabled = false;<br /><br />
index = 0;</p>
<p>flickr = new Flickr(flickr_apikey);<br /><br />
}</p>
<p>public void reloadPhoto()<br /><br />
{<br /><br />
try<br /><br />
{<br /><br />
Photo p = photos.PhotoCollection[index];<br /><br />
pictureBoxResult.Image = Image.FromStream(flickr.DownloadPicture(p.MediumUrl));<br /><br />
textBoxPhotoUri.Text = p.WebUrl;<br /><br />
this.Text = &#8220;Flickr Search Test (&#8221; + index + &#8220;/&#8221; + photos.PhotoCollection.Length + &#8220;)&#8221;;<br /><br />
if (index < 1) buttonPrev.Enabled = false;<br /><br />
else buttonPrev.Enabled = true;<br /><br />
if (index >= photos.PhotoCollection.Length &#8211; 1) buttonNext.Enabled = false;<br /><br />
else buttonNext.Enabled = true;<br /><br />
}<br /><br />
catch (Exception ex)<br /><br />
{<br /><br />
Console.WriteLine(ex.Message);<br /><br />
}<br /><br />
}</p>
<p>private void buttonLoad_Click(object sender, EventArgs e)<br /><br />
{<br /><br />
buttonLoad.Enabled = false;<br /><br />
textBoxTags.Enabled = false;<br /><br />
PhotoSearchOptions opt = new PhotoSearchOptions();<br /><br />
opt.Tags = textBoxTags.Text;<br /><br />
opt.TagMode = TagMode.AllTags;<br /><br />
photos = flickr.PhotosSearch(opt);</p>
<p>index = 0;<br /><br />
reloadPhoto();<br /><br />
buttonLoad.Enabled = true;<br /><br />
textBoxTags.Enabled = true;<br /><br />
}</p>
<p>private void buttonPrev_Click(object sender, EventArgs e)<br /><br />
{<br /><br />
index&#8211;;<br /><br />
reloadPhoto();<br /><br />
}</p>
<p>private void buttonNext_Click(object sender, EventArgs e)<br /><br />
{<br /><br />
index++;<br /><br />
reloadPhoto();<br /><br />
}</p>
<p>private void textBoxTags_TextChanged(object sender, EventArgs e)<br /><br />
{<br /><br />
if (textBoxTags.Text == &#8220;&#8221;) buttonLoad.Enabled = false;<br /><br />
else buttonLoad.Enabled = true;<br /><br />
}<br /><br />
}<br /><br />
}</p></p></blockquote>
<p>
</p>
]]></content:encoded>
			<wfw:commentRss>http://shokai.org/blog/archives/1481/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

