CNCを自作しよう!(その5)
材料力学
取りあえず、一番荷重の掛かりそうなリニアシャフトだけ強度計算をしておこうと思います。
「えっ?管理人は材料力学が分かるの?」
と驚かれる方がいらっしゃるかもしれません。
安心してください。「できる訳が無いじゃないですか!」
強度計算と言っても、一番初歩の式に適当な値を代入して様子を見るだけなので大した事はしません。
2013年11月30日土曜日
2013年11月28日木曜日
ドライブにショートカットキーを登録する
「win+E」キーを押せばマイコンピュータをショートカットキーで表示する事ができますが、
CドライブやDドライブ、EドライブやFドライブは一発で表示する事ができません。
(「win+E」キー⇒各ドライブをダブルクリック、する必要がありました。)
面倒なのでフリーソフトを使ってショートカットキーとして一発で表示できるようにしたいと思います。
今回使うのは「ごまランチ」と言うフリーソフトです。Vectorからダウンロードできます。
「ごまランチ」はタスクトレイ常駐型アプリケーションです。zip形式で配布されています。
このソフトは様々なキーをショートカットキーとして登録する事ができます。
この時、winキーやCtrlキーは元々割り当てられているショートカットキーが多いので、
「Alt」+「ドライブ名」で割り当てる事をお勧めします。
また、起動毎に自動起動はしないので、ショートカットをスタートアップフォルダへ言入れておいてください。
ショートカットキーの登録の仕方は簡単で、
例えば、「Alt」+「C」で、「実行:0」に「C:\」と登録すると、
「Alt+C」でCドライブを表示するようになります。
冷蔵庫の振動音を解消する。
最近、冷蔵庫の裏を掃除する為に位置を動かしたら、
床と共振を起こして凄い振動音が部屋に響くようになった。当然ながら、冷蔵庫には4本の脚がある訳ですが、
よくよく調べて見ると、4本の内の一本で、手前にある高さを調節するための足が、
フローリング(木の床)と共振を起こしている事が分かりました。
2013年11月21日木曜日
Windows API リサイズ&移動が可能な
枠なしウィンドウを作成する。(その②)
その①
その②
その③
「枠なしウィンドウ」とはつまり「ポップアップウィンドウ」の事だが、
ここでは力技の座標計算によってウィンドウサイズを変更できるようにします。
(随分と昔に作ったコードの流用なので、いろいろと余計な設定をしたままですが……)
余計な機能一覧
1.左クリックしながらの右クリックで移動
2.タスクトレイにしか表示されない。(タスクトレイのアイコンを右クリックで終了)
3.最背面に張り付くようにしてあり、
デスクトップの表示(「Windowsキー + E」あるいは「Windowsキー + M」)を押しても表示され続ける。
ブログに掲載する関係でtabを半角スペース8個に置き換えています。
tabのままがいい方は以下のリンクからダウンロードしてください。
ダウンロード
以下、サンプルコードです。
2013年11月16日土曜日
2013年11月14日木曜日
DC-DCコンバータの自作……
ヒステリシス損について考える。
このブログの自作DC-DCコンバーター・トップ
http://the-united-front.blogspot.jp/2013/09/blog-post_12.html
以下のヒステリシス曲線を見てください。
「コイルの作り出す磁場(H[A/m])」と「磁性体中の磁束密度(B[T])」の関係をグラフ化した曲線です。
2013年11月13日水曜日
2013年11月6日水曜日
2013年10月15日火曜日
Num
Lockキー を Back Space 入れ替える。(変換する。)
テンキー付きのノートPCだとBackSpaceキーを押すつもりが誤ってNumLockキーを押してしまい、
イライラした事のある人も多いのではないでしょうか?
そこで今回は常駐型のフリーソフトAutoHotkeyを使って
NumLockキーを押した場合、BackSpaceキーを押したのと同じ動作をするように
してみたいと思います。
取りあえず
http://www.autohotkey.com/
からAutoHotkeyをダウンロードしましょう。
……とおもったら私が使っているバージョンとは随分と違うようなので古いバージョンで解説します。
たぶんダウンロードするのは
http://sourceforge.jp/projects/sfnet_ahk/downloads/AutoHotkey/1.0.48.05/AutoHotkey104805.zip/
で大丈夫だと思う……。
解凍して
AutoHotkey104805
と言うフォルダの中に
AutoHotkey.ini
と言うファイルを作って開き、
NUMLOCK::BACKSPACE
と一行書いておけば終了です。
このままだと再起動しても自動で起動しないので、ショートカットをスタートアップへ入れて置いてください。
テンキー付きのノートPCだとBackSpaceキーを押すつもりが誤ってNumLockキーを押してしまい、
イライラした事のある人も多いのではないでしょうか?
そこで今回は常駐型のフリーソフトAutoHotkeyを使って
NumLockキーを押した場合、BackSpaceキーを押したのと同じ動作をするように
してみたいと思います。
取りあえず
http://www.autohotkey.com/
からAutoHotkeyをダウンロードしましょう。
……とおもったら私が使っているバージョンとは随分と違うようなので古いバージョンで解説します。
たぶんダウンロードするのは
http://sourceforge.jp/projects/sfnet_ahk/downloads/AutoHotkey/1.0.48.05/AutoHotkey104805.zip/
で大丈夫だと思う……。
解凍して
AutoHotkey104805
と言うフォルダの中に
AutoHotkey.ini
と言うファイルを作って開き、
NUMLOCK::BACKSPACE
と一行書いておけば終了です。
このままだと再起動しても自動で起動しないので、ショートカットをスタートアップへ入れて置いてください。
2013年10月14日月曜日
連打ソフトを作ろう!
Mouse_Clicker_Ver0.2の解説編。ソースファイル(プロジェクト一式)
Visual C++ 2012 Professional Windows7 x64//Ver0.2
http://ux.getuploader.com/ADMIS/download/3/Mouse_Clicker_Ver0.2_for_x64.zip
Visual C++ 2010 Express WindowsXP x86//Ver0.2
http://ux.getuploader.com/ADMIS/download/4/Mouse_Clicker_Ver0.2_for_x86_XP.zip
上のソースコードを見て分かれ、と言うにはコードが汚すぎるので、連打ソフトに必要な骨格だけ解説しようと思います。(と言ってもソースを上げるくらいですが……)上は「Mouse_Clicker_Ver0.2」ですが、解説するのは「Mouse_Clicker_Ver0.1」です。Ver0.1ではソフトの骨格を作り、Ver0.2でGUI(グラフィック・ユーザ・インターフェイス)を追加しています。
以下にVer0.1のソースを示します。
連打ソフトに必要なのは基本的にこのくらいです。
#define TIMER_ELAPSE (100) // WM_TIMERの発生間隔
がタイマーの間隔で、これがクリック間隔になります。
これで100msです。
ところで、実行してみれば分かる事ですが、GUIを実装していないので、クリック間隔を変えるにはコンパイルし直す必要があるし、
クリックする座標の数を変えるにもやはりコンパイルし直す必要があります。とても不便です。
ところでクリックする座標の数を変えるには
case WM_TIMER:
int i;
for(i=2;i<=2;i++){
のfor文の赤字の部分を書き換えればいいですね。
例えば上記のように書き換えると「3のキー」に対応する座標だけをクリックする事になります。
2なのに3、!?っと思った方は配列が0から始まる事を思い出してください。つまり一つずつずれています。
上記のVer0.1はおよそ120行ですが、Ver0.2になると340行程になっています。
つまりGUIは大変なのです。
(全てコードだけで何とかしようとするからです……
VisualStudioの別の機能を使えばもっと簡単にGUIを実装できるらしいですが、
私はやり方を知りません……)
2013年10月13日日曜日
2013年10月8日火曜日
Windows API によるファイル操作
ディレクトリを消去するための関数(態々自作しなくても、SHFileOperationで一発らしいが……)
フォルダ内にファイルが残っている場合は中のファイルを全て消去してから、指定したフォルダを消去します。
注意:
一応確認はしていますが、このプログラムの不備によってパソコン内のファイルが誤って消去されてしまっても補償できません。自己責任でお願いします。
また、実験する場合は実験用のドライブを新しく作る事を強くお勧めします。(空のUSBフラッシュなど)
なぜ別のドライブを用意するべきかと言うと、プログラムに不備がある場合、".."は親ディレクトリを示すのですが、これが誤って読み込まれて、指定したファイルより上の階層のファイルまで消去してしまう可能性があるためです。それも一回では無く複数回読み込まれてずっと上のフォルダやらファイルやらを消去してしまう可能性があります。
お気づきでしょうか?そうです、私の失敗談です。
ソースコードのダウンロード
http://ux.getuploader.com/ADMIS/download/6/File_Manager_FileOperationTest_ver0.1.cpp
コード
ディレクトリを消去するための関数(態々自作しなくても、SHFileOperationで一発らしいが……)
フォルダ内にファイルが残っている場合は中のファイルを全て消去してから、指定したフォルダを消去します。
注意:
一応確認はしていますが、このプログラムの不備によってパソコン内のファイルが誤って消去されてしまっても補償できません。自己責任でお願いします。
また、実験する場合は実験用のドライブを新しく作る事を強くお勧めします。(空のUSBフラッシュなど)
なぜ別のドライブを用意するべきかと言うと、プログラムに不備がある場合、".."は親ディレクトリを示すのですが、これが誤って読み込まれて、指定したファイルより上の階層のファイルまで消去してしまう可能性があるためです。それも一回では無く複数回読み込まれてずっと上のフォルダやらファイルやらを消去してしまう可能性があります。
お気づきでしょうか?そうです、私の失敗談です。
ソースコードのダウンロード
http://ux.getuploader.com/ADMIS/download/6/File_Manager_FileOperationTest_ver0.1.cpp
コード
Windows API によるファイル操作
ファイル名およびファイル情報(サイズ、各種日時)を列挙するための関数
以下サンプル
実行風景
ソースコードのダウンロード
http://ux.getuploader.com/ADMIS/download/7/File_Manager_DosWindowVersion_ver0.3.cpp
デフォルトだとフォルダと隠しフォルダを無視します。フォルダも読み込みたい場合は
「
// フォルダと隠しファイルは除く
if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)//ディレクトリを取得しない。
&& !(fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))//隠しファイルを取得しない。
」
を消してください。
コード
ファイル名およびファイル情報(サイズ、各種日時)を列挙するための関数
以下サンプル
実行風景
ソースコードのダウンロード
http://ux.getuploader.com/ADMIS/download/7/File_Manager_DosWindowVersion_ver0.3.cpp
デフォルトだとフォルダと隠しフォルダを無視します。フォルダも読み込みたい場合は
「
// フォルダと隠しファイルは除く
if(!(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)//ディレクトリを取得しない。
&& !(fd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))//隠しファイルを取得しない。
」
を消してください。
コード
リファラスパム一覧
http://www.vampirestat.com
http://www.adsensewatchdog.com
http://www.7secretsearch.com
http://www.seoanalyses.com
http://kallery.net
http://ourmeets.com
Google Analyticsにフィルタ登録する場合は登録
www\.vampirestat\.com
www\.adsensewatchdog\.com
www\.7secretsearch\.com
www\.seoanalyses\.com
kallery\.net
ourmeets\.com
このようなサイトはアクセス履歴を残す事でサイトの管理者にリンクをクリックさせようとします。
リンク先でウィルスに感染させたり、広告をクリックさせたりすることが目的です。
特に何もしていなくてもアクセスしてきますが、特に管理者が更新した時(一度に更新する数が多い時は特に管理者が自分たちの存在に気が付いてリンクをクリックすると見込んで)一日に200とか300とか言う勢いでアクセスしてきます。
残念ながらBolggerにはフィルタ機能が無いのでGoogle Analyticsにでも登録してフィルタを掛けると良いと思います。
フィルタの掛け方は以下のサイトが参考になりました。
http://conversion-labo.jp/report/1105/
Google Analyticsに登録する場合は
http://www.google.com/intl/ja/analytics/
http://www.adsensewatchdog.com
http://www.7secretsearch.com
http://www.seoanalyses.com
http://kallery.net
http://ourmeets.com
Google Analyticsにフィルタ登録する場合は登録
www\.vampirestat\.com
www\.adsensewatchdog\.com
www\.7secretsearch\.com
www\.seoanalyses\.com
kallery\.net
ourmeets\.com
このようなサイトはアクセス履歴を残す事でサイトの管理者にリンクをクリックさせようとします。
リンク先でウィルスに感染させたり、広告をクリックさせたりすることが目的です。
特に何もしていなくてもアクセスしてきますが、特に管理者が更新した時(一度に更新する数が多い時は特に管理者が自分たちの存在に気が付いてリンクをクリックすると見込んで)一日に200とか300とか言う勢いでアクセスしてきます。
残念ながらBolggerにはフィルタ機能が無いのでGoogle Analyticsにでも登録してフィルタを掛けると良いと思います。
フィルタの掛け方は以下のサイトが参考になりました。
http://conversion-labo.jp/report/1105/
Google Analyticsに登録する場合は
http://www.google.com/intl/ja/analytics/
2013年10月7日月曜日
残念なBloggerを使いこなしたい。
当然ながらBloggerにもリンク機能があるのですが、
「このリンクを新しいウィンドウで開く」のチェックボックスを
指定しても、指定しなくても、常に新しいウィンドウで開いてしまうと言う残念仕様。
仕方がないので手動で何とかしましょう。
例えば、以下の様に
このブログのトップ
とリンクを貼るとHTMLの編集モードでは
<a href="http://the-united-front.blogspot.jp/" target="_blank">このブログのトップ</a><br />
と表示されます。
この時「_blank」が新しいウィンドウで開く事を指定しているので
これを同じウィンドウで開く事を意味する「_self」に変えてやると
<a href="http://the-united-front.blogspot.jp/" target="_self">このブログのトップ</a><br />
このブログのトップ
のように同じウィンドウで開くようになります。
参考にしたページ:http://www.tohoho-web.com/html/attr/target.htm
当然ながらBloggerにもリンク機能があるのですが、
「このリンクを新しいウィンドウで開く」のチェックボックスを
指定しても、指定しなくても、常に新しいウィンドウで開いてしまうと言う残念仕様。
仕方がないので手動で何とかしましょう。
例えば、以下の様に
このブログのトップ
とリンクを貼るとHTMLの編集モードでは
<a href="http://the-united-front.blogspot.jp/" target="_blank">このブログのトップ</a><br />
と表示されます。
この時「_blank」が新しいウィンドウで開く事を指定しているので
これを同じウィンドウで開く事を意味する「_self」に変えてやると
<a href="http://the-united-front.blogspot.jp/" target="_self">このブログのトップ</a><br />
このブログのトップ
のように同じウィンドウで開くようになります。
参考にしたページ:http://www.tohoho-web.com/html/attr/target.htm
2013年10月6日日曜日
StretchDIBits関数によるノイズ。
StretchDIBits()を使い縮小や拡大をするとノイズが発生する。
これを回避するためにはStretchDIBits()の前にSetStretchBltMode()を実行すればいい。
例:
SetStretchBltMode(hdc , COLORONCOLOR);
//これを挿入しないと「StretchDIBits」による縮小時に発生するノイズが酷い。
StretchDIBits(
hdc ,
650 , 0 ,
640 , 360 ,
0 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS,SRCCOPY
);
このソースは
http://the-united-front.blogspot.com/2013/10/top-2-3-directshowusb-2-httpsdocs.html
の記事の一部です。
StretchDIBits()を使い縮小や拡大をするとノイズが発生する。
これを回避するためにはStretchDIBits()の前にSetStretchBltMode()を実行すればいい。
例:
SetStretchBltMode(hdc , COLORONCOLOR);
//これを挿入しないと「StretchDIBits」による縮小時に発生するノイズが酷い。
StretchDIBits(
hdc ,
650 , 0 ,
640 , 360 ,
0 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS,SRCCOPY
);
このソースは
http://the-united-front.blogspot.com/2013/10/top-2-3-directshowusb-2-httpsdocs.html
の記事の一部です。
DirectShowによるUSBカメラのリアルタイム画像処理・改良版
Top > Direct Show 関連 > 記事2及び記事3の改良版(バグ修正版)
2014_06_05_追記
バグを修正したバージョンをこの辺りに置いておく。
http://the-united-front.blogspot.jp/2014/05/directshowusb.html
追記:2013.10.07.月
バグの報告
現在(おそらくPCにカメラを複数接続している場合、)上手く認識できない場合があります。
取りあえずは何回かやり直したり、他のソフトで一旦カメラを起動してみたりすると上手く行きました。
カメラを複数接続とは最近PCにデフォルトで搭載されているWebカメラを含みます。(というか私の環境だとこれが原因なのだが、外す訳にも行かず……)
原因を特定次第修正します。
追記:2013.10.07.月
「初回例外が 0x65D913C0 (msvcr110d.dll) で発生しました (Image_Processing_Ver2.1.exe 内): 0xC0000005: 場所 0x00000000 の読み取り中にアクセス違反が発生しました。」
例外が発生するのは
「memcpy(rgbValues, grabBuffer, (pVideoInfoHeader->bmiHeader.biSizeImage));」
の部分で、カメラの表示が始まるまで発生し続け、表示が始まり次第エラーを吐かなくなるので、
カメラの初期化が終了する前に(まだ準備されていないメモリ空間である)grabBufferへアクセスしようとしている事が原因だと思われる。
⇒初期化が完了するまでの間「WM_PAINT」メッセージを抑制できれば解決する?
⇒上の遣り方は良く分からないし、取りあえずメモリのコピーを
「class cameraCB : public ISampleGrabberCB」
の内部で処理する事にする。
⇒例外こそ発生しなくなったが、「class cameraCB : public ISampleGrabberCB」と「WM_PAINT」の処理するタイミングの問題で表示がバグる。(一部処理した画像で、一部はそのままの画像)
⇒スマートな解決方法が思いつかなかったので、
「DirectShow_for_USB_Camera(hWnd);」の直後に、「Sleep(5000);」を入れておく。
「
DirectShow_for_USB_Camera(hWnd);
Sleep(5000);//Direct Showの初期化を待つ。//他のもっとスマートな方法も考えたが、簡単なので取りあえず安直にスリープを入れておく。
」
下のコードの方は書き直していないので注意してください。
その内新しい記事として書き直します。
DirectShowによるUSBカメラのリアルタイム画像処理
実行風景は記事2の
と殆ど同じです。(Click to stop.のメッセージボックスは終了処理をきちんと書き直したので無くなりました。)
ソースは
http://ux.getuploader.com/ADMIS/download/12/Image_Processing_Ver2.1.5.zip
一応以下にも掲載していますが、一部表示がバグっている上、見難いので一旦上記のファイル(プロジェクト)をダウンロードしてから見る事をお勧めします。
2014_06_05_追記
バグを修正したバージョンをこの辺りに置いておく。
http://the-united-front.blogspot.jp/2014/05/directshowusb.html
追記:2013.10.07.月
バグの報告
現在(おそらくPCにカメラを複数接続している場合、)上手く認識できない場合があります。
取りあえずは何回かやり直したり、他のソフトで一旦カメラを起動してみたりすると上手く行きました。
カメラを複数接続とは最近PCにデフォルトで搭載されているWebカメラを含みます。(というか私の環境だとこれが原因なのだが、外す訳にも行かず……)
原因を特定次第修正します。
追記:2013.10.07.月
「初回例外が 0x65D913C0 (msvcr110d.dll) で発生しました (Image_Processing_Ver2.1.exe 内): 0xC0000005: 場所 0x00000000 の読み取り中にアクセス違反が発生しました。」
例外が発生するのは
「memcpy(rgbValues, grabBuffer, (pVideoInfoHeader->bmiHeader.biSizeImage));」
の部分で、カメラの表示が始まるまで発生し続け、表示が始まり次第エラーを吐かなくなるので、
カメラの初期化が終了する前に(まだ準備されていないメモリ空間である)grabBufferへアクセスしようとしている事が原因だと思われる。
⇒初期化が完了するまでの間「WM_PAINT」メッセージを抑制できれば解決する?
⇒上の遣り方は良く分からないし、取りあえずメモリのコピーを
「class cameraCB : public ISampleGrabberCB」
の内部で処理する事にする。
⇒例外こそ発生しなくなったが、「class cameraCB : public ISampleGrabberCB」と「WM_PAINT」の処理するタイミングの問題で表示がバグる。(一部処理した画像で、一部はそのままの画像)
⇒スマートな解決方法が思いつかなかったので、
「DirectShow_for_USB_Camera(hWnd);」の直後に、「Sleep(5000);」を入れておく。
「
DirectShow_for_USB_Camera(hWnd);
Sleep(5000);//Direct Showの初期化を待つ。//他のもっとスマートな方法も考えたが、簡単なので取りあえず安直にスリープを入れておく。
」
下のコードの方は書き直していないので注意してください。
その内新しい記事として書き直します。
DirectShowによるUSBカメラのリアルタイム画像処理
実行風景は記事2の
と殆ど同じです。(Click to stop.のメッセージボックスは終了処理をきちんと書き直したので無くなりました。)
ソースは
http://ux.getuploader.com/ADMIS/download/12/Image_Processing_Ver2.1.5.zip
一応以下にも掲載していますが、一部表示がバグっている上、見難いので一旦上記のファイル(プロジェクト)をダウンロードしてから見る事をお勧めします。
//MessageBox(0, _T("I'm here!"), _T("Message"), MB_OK);
/*
バグ報告、
最大化した時、Directshowで描写している方の画面(と言うかもう一つのウィンドウ)の位置が追随しないためズレる
⇒解決方法、「case WM_PAINT:」の時、に「pVWindow->SetWindowPosition(0, 0, 640, 480);」を実行すればいいのだが、
このまま実行すると、再描写が重なるので、今している右側に表示する処理をウィンドウを新しく作ってそちらで処理させる
必要があるが、面倒なので後回し。
⇒解決。上に提案した方法とは異なるが、以下の三行にて解決。
「
case WM_GETMINMAXINFO:
pVWindow->SetWindowPosition(0, 0, 640, 360);
return 0;
」
終了時にMessageでOKをクリックして終了しようとするとCPU使用率が上昇する。
⇒Ver1.2からの症状。どうやら解放した後の「case WM_PAINT:」の時に暴走している。Messageで「OK」を押しても処理してもプログラムが終了せずに、解放したリソースにアクセス
しようとするのが原因だが、最終的な実装で解決するはずなので放置
⇒解決
重心の描写時に、ターゲットが存在しないとCPU使用率が上がる
⇒SoTPが0の時0で割り算しているため
⇒解決
縮小表示にバグを発見(処理した画像をディスプレイに表示するときに一部表示されない、つまり、縮小表示すべき所を切り取り表示していた。)
「
SetDIBitsToDevice(
hdc , 650 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
0 , 0 , 0 , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS
);
」
を
「
SetStretchBltMode(hdc , COLORONCOLOR);
//これを挿入しないと「StretchDIBits」による縮小時に発生するノイズが酷い。
StretchDIBits(
hdc ,
650 , 0 ,
640 , 360 ,
0 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS,SRCCOPY
);
」
とする事で解決
⇒解決
*/
/*
http://hisoap.jugem.jp/?eid=140
のサンプルほぼそのまま
花形として
http://www.geekpage.jp/programming/directshow/renderfile.php
http://marupeke296.com/DSW_No5_FullScreenProgram.html
とかが参考になる。(結構似たような事をしてる)
http://wisdom.sakura.ne.jp/system/winapi/win32/win118.html
を参考にしてビットマップを右側に描写している。
http://tmp.junkbox.info/index.php?e=24
を参考にしてカラーフィルタを実装した。(ただしC#(涙))
http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
を参考に、RGBからHSVへ変換し色判定を行う。
*/
#include
#include
#include
#include
//#include //mallocに必要?
//#include //memcpy関数に必要?
#include bmiHeader.biHeight)-(ySoP/SoTP);//なんか良く分からんけどこのままだと画面の左下が原点(0,0)となってしまうので、次の表示のためにも原点(0,0)を画面の左上に変換しておく。
flag=TRUE;
// http://ja.wikipedia.org/wiki/%E4%B8%89%E8%A7%92%E6%B8%AC%E9%87%8F //
//角度の導出 //カメラ同士の距離を18.8cmとして計算していく。
//y:角度、x:座標
// y=((90-60)/320)*x+60
//⇔y=(3/32)*x+60
double theta1;//θ1[°]//右カメラ
double theta2;//θ2[°]//左カメラ
theta1 = ((0.09375)*xCoG)+60;//(3/32)だと何故か上手く計算してくれないので(0.09375)に書き直している。
theta2 = (0.09375)*320+60;//取りあえずカメラが一台しか無いので固定値(つまり、ターゲットが、もう一台のカメラ(右カメラ)があるべき位置の真正面上を移動すると仮定して距離を計算していく)
//ここで注意したいのはsin,cos,tanは度数法(度(°))では無く弧度法(ラジアン(rad))である事。
//そのため上記の度数法で表している角度を弧度法に変換する。(一気に弧度法で計算していないのはデバックでブレークポイントを設置した時に弧度法で言われても分度器で角度を測れないため。必要が無い場合は計算をまとめて良い)
//M_PIは自分で定義する必要がある。
double rTheta1;//θ1[rad]//右カメラ
double rTheta2;//θ2[rad]//左カメラ
rTheta1 = M_PI*theta1/180;//[rad]=2π*[°]/360⇔[rad]=π*[°]/180
rTheta2 = M_PI*theta2/180;
//ターゲットとの距離を導出
double dVertical; //垂直距離「 Vertical distance」//単位は[cm]//カメラとカメラを結ぶ直線にターゲットから垂線を下ろした時、その降ろした垂線の距離
double dHorizontal; //水平距離「 Horizontal distance」//単位は[cm]//カメラとカメラを結ぶ直線にターゲットから垂線を下ろした時、に直線の交点とカメラとカメラの間の中点との距離
double dStraight; //直線距離「Straight-line distance」//単位は[cm]//カメラとカメラの中点とターゲットとの間の直線距離
dVertical = (double)(18.8)*(double)sin(rTheta1)*(double)sin(rTheta2)/(double)sin(rTheta1+rTheta2);//三角測量と同様の方法で導出
dHorizontal = (dVertical/tan(rTheta1))-((18.8)/2);//三角関数より導出
dStraight = sqrt( (dVertical*dVertical)+(dHorizontal*dHorizontal) );//三平方より導出
}
else
{
flag=FALSE;
}
//memcpy(grabBuffer, rgbValues, (pVideoInfoHeader->bmiHeader.biSizeImage)); //これをやると画面が両方真っ赤になる。のでダメ
//背景の画像(右側の赤と黒の画像)を描写する
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint (hWnd, &ps);
//そのまま表示すると大き過ぎるので3分の1に縮小して表示する//640:480だと1920:1080に対してアスペクト比が変わるので640:360とする。
SetStretchBltMode(hdc , COLORONCOLOR);//これを挿入しないと「StretchDIBits」による縮小時に発生するノイズが酷い。
StretchDIBits(
hdc ,
650 , 0 ,
640 , 360 ,
0 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS,SRCCOPY
);
if(flag){
//重心の位置を描写する
HPEN hPen; // 論理ペンへのハンドル
hPen = CreatePen(PS_SOLID, 1, RGB(0, 0xFF, 0));
SelectObject(hdc, hPen); // 論理ペンを登録
MoveToEx(hdc, 650+xCoG/3, 0, NULL); // (20, 20) に移動
LineTo(hdc, 650+xCoG/3, (pVideoInfoHeader->bmiHeader.biHeight )/3); // (200, 20) まで直線を描画
MoveToEx(hdc, 650, yCoG/3, NULL); // (20, 20) に移動
LineTo(hdc, 650+(pVideoInfoHeader->bmiHeader.biWidth )/3, yCoG/3); // (20, 200) まで直線を描画
DeleteObject(hPen); // 論理ペンを破棄
}
EndPaint( hWnd, &ps );
return 0;
}
//case WM_CREATE:{
// return 0;
// }
case WM_GETMINMAXINFO://最大化、最小化以外にもウィンドウサイズの変更の場合もメッセージが送られるためこのままだとウィンドウサイズを変更するときにチラツクが、実質的に問題無いので放置。
pVWindow->SetWindowPosition(0, 0, 640, 360);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
int DirectShow_for_USB_Camera(HWND hWnd){
//HRESULT hr;//外で定義
// --- COMの初期化
hr = CoInitialize(NULL);
if(FAILED(hr)){
printf("CoInitialize Failed!\n");
exit(1);//return 1;と同義
}
// --- 1.フィルタグラフマネージャ作成(DirectShow の中心的なオブジェクト)
//IGraphBuilder *pGraph = NULL;//外で定義
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&pGraph);
// http://marupeke296.com/DSW_No5_FullScreenProgram.html //② フィルタグラフマネージャの取得
// フィルタグラフマネージャの取得
//
// DirectShowのプログラムは実質ここから始まります。まずはフィルタグラフを管理するフィルタグラフマネージャを作成します。取得するインターフェイスはIGraphBuilderです。このインターフェイスはWindows自体が提供するためCoCreateInstance関数というグローバルな関数を用いて生成します。
//
//IGraphBuilder *pGB = NULL;
//HRESULT hr = CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGB);
// CoCreateInstance関数はCOMとして登録されているインターフェイスを生成して返してくれます。
//第1引数にインターフェイスを含むクラスIDを指定します。IGraphBuilderを取得するときに指定するIDはCLSID_FilterGraphと決まっているので、無条件で上のように与えます。
//第2引数はCOMオブジェクトの内包状態を指定するフラグなのですが、殆どのCOMはNULLでOK。
//第3引数は生成するCOMの実装ソースがあるDLLの所在を表します。IGraphBuilderについてはDLLがローカルにありますのでインプロセスであるCLSCTX_INPROC_SERVERを指定します。
//第4引数に欲しいインターフェイスの固有IDを指定します。IGraphBuilderインターフェイスを表すIDはIID_IGraphBuilderです。
//関数が成功すると第5引数にIGraphBuilderインターフェイスへのポインタが返ります。
//
//この処理はもう決まりきっていますので、変更のしようがありません。「IGraphBuilderの取得の仕方はこうだ!」と決めてしまってよいでしょう。
//
// IGraphBuilderの役目はフィルタグラフにかかわるインターフェイスの提供、およびフィルタグラフの管理です。
// --- 2.システムデバイス列挙子の作成(接続されているデバイスを調べるためのオブジェクト) // ⑥ キャプチャデバイス(USBカメラ等)を選択するため,システムデバイス列挙子を作成する.つまり,PCに接続されているデバイスを列挙するってこと.
ICreateDevEnum *pDevEnum = NULL;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&pDevEnum);
// 列挙子の取得 // ⑦ 列挙したキャプチャデバイスのカテゴリ列挙子を取得する.音声なのか,映像なのか,とかそういうこと.ビデオキャプチャの場合は,CLSID_VideoInputDeviceCategoryを指定すればよい.
IEnumMoniker *pClassEnum = NULL;
pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
if(pClassEnum == NULL){
printf("Device does not exist!\n");
pDevEnum->Release();
CoUninitialize();
return 1;
}
pDevEnum->Release(); // 以後に不要なメモリーをリリース
//IBaseFilter *pbf = NULL;//外で定義
IMoniker *pMoniker = NULL;
ULONG cFetched; //ULONGはCOMの型……らしいのだが……???
if(pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK){ // IEnumMoniker.Next メソッド(http://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.comtypes.ienummoniker.next(v=vs.85).aspx)←ハイパーリンクがバグってる……。
// Next(1, &pMoniker, &cFetched)
//返されるモニカの数,列挙されたモニカへの参照を格納,列挙されたモニカの実数への参照を格納
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pbf); // 最初のモニカをフィルタオブジェクトにバインド
pMoniker->Release();
}
pClassEnum->Release(); // 以後に不要なメモリーをリリース
pGraph->AddFilter(pbf, L"USB Camera Capture"); // グラフにフィルタを追加
// http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑥ ソースフィルタの作成と登録
// IGraphBuilder::AddSourceFilter関数を使用した場合は自動的にフィルタグラフへの登録が行われるので、改めてIGraphBuilder::AddFilter関数を呼ぶ必要はない。
// ファイル名に関して重要な注意があります。第2引数の型は「LPCWSTR」になっています。これはワイド文字(例えばunicode)というやつです。私たちが以前まで普通に使っていたのはマルチバイト文字でして、これは「LPCSTR」です。マルチバイト文字とワイド文字は互換性がありません。ですから、ワイド文字がコンパイラオプションに設定されていない環境では、文字をプログラマが明示的にワイド文字に変換する必要があります。ただリテラル(ダブルクォーテーションで囲まれた文字)で定義する場合は「L接頭子」を付けると常にワイド文字として扱われます。
//============================================================================================
// http://www.geekpage.jp/programming/directshow/samplegrabber.php //BitMapキャプチャ用フィルタの用意
//IBaseFilter *pSampleGrabberFilter;//外で定義
// SampleGrabber(Filter)を生成
CoCreateInstance(CLSID_SampleGrabber,
NULL,
CLSCTX_INPROC,
IID_IBaseFilter,
(LPVOID *)&pSampleGrabberFilter);
//ISampleGrabber *pSampleGrabber;//外で定義
// FilterからISampleGrabberインターフェースを取得します
pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (LPVOID *)&pSampleGrabber);
AM_MEDIA_TYPE am_media_type;
// SampleGrabberを接続するフォーマットを指定。
// ここがポイントです。
// ここの指定の仕方によりSampleGrabberの挿入箇所を
// 決定できます。このサンプルのような指定をすると
// 画面出力の寸前でサンプルを取得できます。
ZeroMemory(&am_media_type, sizeof(am_media_type));
am_media_type.majortype = MEDIATYPE_Video;
am_media_type.subtype = MEDIASUBTYPE_RGB24;
am_media_type.formattype = FORMAT_VideoInfo;
pSampleGrabber->SetMediaType(&am_media_type);
// GraphにSampleGrabber Filterを追加
pGraph->AddFilter(pSampleGrabberFilter, L"Sample Grabber");
//============================================================================================
// --- 3.キャプチャグラフ作成
//ICaptureGraphBuilder2 *pCapture = NULL;//外で定義
CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **) &pCapture);
pCapture->SetFiltergraph(pGraph); // フィルタグラフをキャプチャグラフに組み込む//ICaptureGraphBuilder2インターフェイスの初期化
//
//http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑦ ICaptureGraphBuilder2インターフェイスの取得
// フィルタの接続は意外と面倒なものなのですが、これに関してヘルパーインターフェイスが用意されています。「ICaptureGraphBuilder2」というインターフェイスは、フィルタの接続をある程度自動化してくれまして、使い勝手がとても良いものです。ここではこれを使うことにしましょう。このインターフェイスの取得にもCoCreateInstance関数を用います。
// 取得したICaptureGraphBuilder2インターフェイスは初期化が必要なのですが、これはとても簡単でして先に取得したIGraphBuilderインターフェイスをICaptureGraphBuilder2::SetFiltergraph関数に渡すだけです。
// pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pbf, NULL, NULL); // キャプチャグラフの設定、グラバをレンダリング出力に設定//キャプチャ画像を表示するためのビデオプレビューグラフを作成する
pCapture->RenderStream(NULL, NULL, pbf, pSampleGrabberFilter, NULL);//上記に変わってこのように第三引数以外全てNULLに指定してもなんとかなったりする。(キャプチャするには第4引数が必要)
//
//注意:ここの第4引数に「pSampleGrabberFilter」 // http://www.crystal-creation.com/software/technical-information/library/directshownet/filter-graph/capture-graph-builder2.htm#contents-3
// を指定して、経由するフィルタを明示する。 // int RenderStream(
// これをしないとキャプチャを取れない。 // DsGuid PinCategory, // ピン カテゴリ //接続元と先が明らかである場合はNULL指定によりIntelligent Connectに接続を任せることも出来ます。
// DsGuid MediaType, // 出力ピンのメディア タイプ //NULL指定をすると、すべてIntelligent Connectに任せます。
// object pSource, // 接続先のフィルタ //ここは必ず指定する必要があります。
// IBaseFilter pfCompressor, // 経由するフィルタ (圧縮フィルタなど) //NULLが指定できます。
// IBaseFilter pfRenderer // シンク フィルタ (レンダラなど) //NULLを指定した場合、関数はデフォルトの入力フィルタへ接続を試みる。
// );
//
// http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑧ フィルタの接続 を参照
//============================================================================================
//解像度を指定する。// http://www.mvision.co.jp/WebHelpIM/_RESOURCE/MvCap_03.html // http://hisoap.jugem.jp/?eid=140 // http://d.hatena.ne.jp/shibusawa_1/20080909/1220963798 //
IAMStreamConfig *pConfig = NULL;
pCapture->FindInterface(&PIN_CATEGORY_CAPTURE ,0,pbf,IID_IAMStreamConfig,(void**)&pConfig);
//pCapture->FindInterface(&PIN_CATEGORY_PREVIEW ,0,pbf,IID_IAMStreamConfig,(void**)&pConfig);
int iCount=0, iSize=0;
hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);//ピンがサポートするフォーマット機能の数を取得
if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))// VIDEO_STREAM_CONFIG_CAPS構造体かサイズを確認
{
for (int iFormat = 0; iFormat < iCount; iFormat++)
{
VIDEO_STREAM_CONFIG_CAPS scc; // ビデオ フォーマット構造体AM_MEDIA_TYPE
AM_MEDIA_TYPE *p_am_media_type;//am_media_typeの実体は既に宣言しているのだが、ポインタで欲しいと言うので仕方がないのでポインタを宣言したものの、何とかならないかな……。
p_am_media_type = &am_media_type;
hr = pConfig->GetStreamCaps(iFormat, &p_am_media_type, reinterpret_cast(&scc));//フォーマット機能セットを取得
//VIDEO_STREAM_CONFIG_CAPS構造体で、動画対応で最大の大きさである1280*720となる場合を選択する。
if(SUCCEEDED(hr) && (int)scc.InputSize.cx==1920 && (int)scc.InputSize.cy==1080){//「if(p_am_media_type->lSampleSize==2764800){」としてもOK //1280*720*3==2764800より。*3しているのはRGBで三色あるから。(MEDIASUBTYPE_RGB24の場合、MEDIASUBTYPE_RGB32の場合は1280*720*4==3686400)
//「LifeCam Studio for Business Win USB Port 50/60 Hz 5WH-00003」を使った場合
//960:544だと31fpsくらい出る。
//1280:720だと9fpsくらい出る。←なんでだ?
//1920:1080だと16.1fpsくらい出る。
//部屋が暗かったりすると値が出ない気がするし、なんかバラバラ……。
//選択された中で条件に合う物を「SetFormat」する
if((p_am_media_type->majortype == MEDIATYPE_Video) //たぶん取得したフォーマット機能セットが期待した物である事を確認している。
&& (p_am_media_type->subtype == MEDIASUBTYPE_RGB24) //期待したフォーマット機能セットでなかった場合はfor文でそのうち引っかかる
&& (p_am_media_type->formattype == FORMAT_VideoInfo) //このif文は無くても動く。単に皆やってるから入れてみただけ。(必要の無い所にまでフレームレートを設定する必要もないので……)
&& (p_am_media_type->cbFormat >= sizeof(VIDEOINFOHEADER))
&& (p_am_media_type->pbFormat != NULL))
{
VIDEOINFOHEADER *pVih;
pVih = (VIDEOINFOHEADER *)p_am_media_type->pbFormat;
//フレームレートの設定
//pVih->AvgTimePerFrame = 30;//カメラの最高値に合せておく。
//性能を越えて100とかにしても初期設定と思われる16fpsくらいしか出ない。//ここの値に関わらず気まぐれなので放置
//レートを下げる事くらいはできるかも……。(レートはCPU依存との話もあるが……これ如何に)
// キャストして代入
p_am_media_type->pbFormat=(BYTE*)pVih;
//SetFormatでpbFormatの変更を適用
pConfig->SetFormat(p_am_media_type);
}
}
}
}
//============================================================================================
// http://www.geekpage.jp/programming/directshow/samplegrabber.php //画像の縦横のpixelとデータサイズの取得
// 接続情報取得。
// この処理はRenderFileによりGraphが構成された後に
// 行う必要があります。
pSampleGrabber->GetConnectedMediaType(&am_media_type);
pVideoInfoHeader = (VIDEOINFOHEADER *)am_media_type.pbFormat;
// ビデオ ヘッダーには、ビットマップ情報が含まれる。
// ビットマップ情報を BITMAPINFO 構造体にコピーする。
CopyMemory(&bmpInfo.bmiHeader, &(pVideoInfoHeader->bmiHeader), sizeof(BITMAPINFOHEADER));// http://www.greenwood.co.jp/~k-aki/article/directshow_movie/directshow_movie.html //のdirectshow2.cpp// http://www.greenwood.co.jp/~k-aki/article/directshow_movie/directshow2/directshow2.cpp //
hr = pSampleGrabber->SetBufferSamples(FALSE);//データを取得するか?「TRUE」or「FALSE」//コールバック関数を用いて連続キャプチャするので、FALSEで問題ない。//http://miraiware.net/memo/dshow-capture.html
pSampleGrabber->SetOneShot(FALSE);
// プレビュー開始時
cb->hWnd = hWnd;//これが無いとウィンドウを識別できない……。
pSampleGrabber->SetCallback(cb,1);
// プレビュー停止時
//pSampleGrabber->SetCallback(NULL, 1);
//============================================================================================
// http://ugd555.fc2web.com/frame.html //⑤
// IVideoWindowインタフェース(ビデオウィンドウの設定)
//IVideoWindow *pVWindow=NULL;//外で定義
hr = pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVWindow);
// http://ugd555.fc2web.com/frame.html // ⑫
// プレビューウィンドウの設定
hr = pVWindow->put_Owner((OAHWND)hWnd);
//hr = pVWindow->put_Owner(NULL);とすると子ウィンドウを切り離す事ができる。
hr = pVWindow->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);//WS_CHILD:子ウィンドウを作成します。|WS_CLIPCHILDREN:親ウィンドウの内部で描画するときに、子ウィンドウが占める領域を除外します。親ウィンドウを作成するときに使います。//WS_CLIPCHILDREN不要かと思ったけど、無いとウィンドウを消したとき?(うる覚え……)にバグる。
// RECT rc;
// GetClientRect(hWnd, &rc);//親ウィンドウのサイズを取得
// pVWindow->SetWindowPosition(0, 0, rc.right, rc.bottom);
//pVWindow->SetWindowPosition(0, 0, pVideoInfoHeader->bmiHeader.biWidth, pVideoInfoHeader->bmiHeader.biHeight);
pVWindow->SetWindowPosition(0, 0, 640, 360);//そのまま表示すると大き過ぎるので3分の1に縮小して表示する//640:480だと1920:1080に対してアスペクト比が変わるので640:360とする。
hr = pVWindow->put_Visible(OATRUE);//ウィンドウを表示する。//無くても動くけど、たぶんあった方が良いって感じのものかな?//ShowWindow()関数に相当する物だと言う事にしておく。
//画像処理用の動的メモリを確保
rgbValues = (unsigned char *)malloc((pVideoInfoHeader->bmiHeader.biWidth)*(pVideoInfoHeader->bmiHeader.biHeight)*3 * sizeof(unsigned char));
// --- 5.キャプチャ開始
pGraph->QueryInterface(IID_IMediaControl, (LPVOID *)&pMC); // MediaControlインターフェース取得(グラフの開始・停止を制御するインターフェイス)
pMC->Run();
// http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑩ フィルタグラフの実行
// フィルタグラフの接続が全て終了し、表示サイズを正しく指定すれば、いつでも動画を再生することができます。再生を担当するインターフェイスは、IGraphBuilderから生成できるIMediaControlインターフェイスです。
return 0;
}
//RGBからHSVへ変換する関数// http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93 //を元に実装
void ConvertRGBtoHSV(unsigned char * rgbValues,unsigned int *i,double *H,double *S,double *V){
if( rgbValues[*i+2] > rgbValues[*i+1] && rgbValues[*i+2] > rgbValues[*i] )//赤>緑&&赤>青
{
//赤>緑&&赤>青
if( rgbValues[*i+1] > rgbValues[*i] )//緑>青
{
//赤>緑>青
*H = 60*( ((double)rgbValues[*i+1]-(double)rgbValues[*i])/((double)rgbValues[*i+2]-(double)rgbValues[*i]) ) + 0;//60*(G-B)/(MAX-MIN)+0
*S = ((double)rgbValues[*i+2]-(double)rgbValues[*i])/(double)rgbValues[*i];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i+2];//MAX
}
else
{
//赤>青>緑
*H = 60*( ((double)rgbValues[*i]-(double)rgbValues[*i+1])/((double)rgbValues[*i+2]-(double)rgbValues[*i+1]) ) + 0;//60*(B-G)/(MAX-MIN)+0
*S = ((double)rgbValues[*i+2]-(double)rgbValues[*i+1])/(double)rgbValues[*i+1];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i+2];//MAX
}
}
else if( rgbValues[*i+1] > rgbValues[*i] )//緑>青
{
//緑>青
if( rgbValues[*i] > rgbValues[*i+2] )//青>赤
{
//緑>青>赤
*H = 60*( ((double)rgbValues[*i]-(double)rgbValues[*i+2])/((double)rgbValues[*i+1]-(double)rgbValues[*i+2]) ) + 120;//60*(B-R)/(MAX-MIN)+120
*S = ((double)rgbValues[*i+1]-(double)rgbValues[*i+2])/(double)rgbValues[*i+2];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i+1];//MAX
}
else
{
//緑>赤>青
*H = 60*( ((double)rgbValues[*i+2]-(double)rgbValues[*i])/((double)rgbValues[*i+1]-(double)rgbValues[*i]) ) + 120;//60*(R-B)/(MAX-MIN)+120
*S = ((double)rgbValues[*i+1]-(double)rgbValues[*i])/(double)rgbValues[*i];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i+1];//MAX
}
}
else//青>緑
{
//青>緑>赤
if( rgbValues[*i+1] > rgbValues[*i+2] )//緑>赤
{
//青>緑>赤
*H = 60*( ((double)rgbValues[*i+2]-(double)rgbValues[*i+1])/((double)rgbValues[*i]-(double)rgbValues[*i+2]) ) + 240;//60*(R-G)/(MAX-MIN)+240
*S = ((double)rgbValues[*i]-(double)rgbValues[*i+2])/(double)rgbValues[*i+2];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i];//MAX
}
else
{
//青>赤>緑
*H = 60*( ((double)rgbValues[*i+1]-(double)rgbValues[*i+2])/((double)rgbValues[*i]-(double)rgbValues[*i+1]) ) + 240;//60*(G-R)/(MAX-MIN)+240
*S = ((double)rgbValues[*i]-(double)rgbValues[*i+1])/(double)rgbValues[*i+1];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i];//MAX
}
}
}
2013年10月5日土曜日
Googleで英語検索する方法。
Google Japanで検索するのとGoogle USAで検索する場合、基本的に検索結果が異なる。
では、Google USAの検索結果を知りたい場合はどうすればいいのか?
大体において以下のリンクから検索できる。
Googleで日本国語検索
https://www.google.com/webhp?hl=ja
Googleで英国語検索
https://www.google.com/webhp?hl=en
Googleで中国語検索(简体中文)
https://www.google.com/webhp?hl=zh-cn
Googleで中国語検索(繁體中文)
https://www.google.com/webhp?hl=zh-tw
Googleで韓国語検索
https://www.google.co.kr/setprefs?sig=0_CJeNnnvd6vw3J0yorDCXWCsbF3U%3D&hl=ko&source=homepage
アラビア語?
https://www.google.com/webhp?hl=fa
Google Japanで検索するのとGoogle USAで検索する場合、基本的に検索結果が異なる。
では、Google USAの検索結果を知りたい場合はどうすればいいのか?
大体において以下のリンクから検索できる。
Googleで日本国語検索
https://www.google.com/webhp?hl=ja
Googleで英国語検索
https://www.google.com/webhp?hl=en
Googleで中国語検索(简体中文)
https://www.google.com/webhp?hl=zh-cn
Googleで中国語検索(繁體中文)
https://www.google.com/webhp?hl=zh-tw
Googleで韓国語検索
https://www.google.co.kr/setprefs?sig=0_CJeNnnvd6vw3J0yorDCXWCsbF3U%3D&hl=ko&source=homepage
アラビア語?
https://www.google.com/webhp?hl=fa
行列の内積を計算する。
二次元配列は多少面倒なので一次元配列で代用して計算する。
//==============================================
#include <stdio.h>//printfに必要
#include <stdlib.h>//systemに必要
using namespace std;//systemに必要
//内積の計算
//
//A[a1][a2]・B[b1][b2]
//の内積を計算する。
double InnerProduct(int a1,double* A,double* B)
{
double buf_InnerProduct=0;
for(int count1=0;count1<a1;count1++){
buf_InnerProduct+=(A[count1])*(B[count1]);
}
return buf_InnerProduct;
}
void main(void){
//内積の計算テスト
double A[8]={1,2,3,4,5,6,7,8};
double B[8]={1,2,3,4,5,6,7,8};
//実際は下のような二次元行列の計算なのだが、二次元行列で書くとコールバイリファレンスでの引き渡しが大変かつ使い勝手が悪くコードも汚くなりそうだったので一次元の配列で計算させる。
//
//double A[2][4]={{1,2,3,4},{5,6,7,8}};
//double B[2][4]={{1,2,3,4},{5,6,7,8}};
printf("%lf\n",InnerProduct(8,A,B));
system("pause");
//system("pause > NUL");
}
//==============================================
でもやっぱり二次元配列で計算したい……ので、以下
//==============================================
#include <stdio.h>//printfに必要
#include <stdlib.h>//systemに必要
using namespace std;//systemに必要
#define N1 2//動的確保は面倒なので定義しておく。
#define N2 4//動的確保は面倒なので定義しておく。
//内積の計算
//
//A[N1][N2]・B[N1][N2]
//の内積を計算する。
double InnerProduct(double A[N1][N2],double B[N1][N2])
{
double buf_InnerProduct=0;
for(int count1=0;count1<N1;count1++){
for(int count2=0;count2<N2;count2++){
buf_InnerProduct+=(A[count1][count2])*(B[count1][count2]);
}
}
return buf_InnerProduct;
}
void main(void){
//内積の計算テスト
double A[2][4]={{1,2,3,4},{5,6,7,8}};
double B[2][4]={{1,2,3,4},{5,6,7,8}};
printf("%lf\n",InnerProduct(A,B));
system("pause");
//system("pause > NUL");
}
//==============================================
動的確保による計算は……気が向いたらやってみようかな?
二次元配列は多少面倒なので一次元配列で代用して計算する。
//==============================================
#include <stdio.h>//printfに必要
#include <stdlib.h>//systemに必要
using namespace std;//systemに必要
//内積の計算
//
//A[a1][a2]・B[b1][b2]
//の内積を計算する。
double InnerProduct(int a1,double* A,double* B)
{
double buf_InnerProduct=0;
for(int count1=0;count1<a1;count1++){
buf_InnerProduct+=(A[count1])*(B[count1]);
}
return buf_InnerProduct;
}
void main(void){
//内積の計算テスト
double A[8]={1,2,3,4,5,6,7,8};
double B[8]={1,2,3,4,5,6,7,8};
//実際は下のような二次元行列の計算なのだが、二次元行列で書くとコールバイリファレンスでの引き渡しが大変かつ使い勝手が悪くコードも汚くなりそうだったので一次元の配列で計算させる。
//
//double A[2][4]={{1,2,3,4},{5,6,7,8}};
//double B[2][4]={{1,2,3,4},{5,6,7,8}};
printf("%lf\n",InnerProduct(8,A,B));
system("pause");
//system("pause > NUL");
}
//==============================================
でもやっぱり二次元配列で計算したい……ので、以下
//==============================================
#include <stdio.h>//printfに必要
#include <stdlib.h>//systemに必要
using namespace std;//systemに必要
#define N1 2//動的確保は面倒なので定義しておく。
#define N2 4//動的確保は面倒なので定義しておく。
//内積の計算
//
//A[N1][N2]・B[N1][N2]
//の内積を計算する。
double InnerProduct(double A[N1][N2],double B[N1][N2])
{
double buf_InnerProduct=0;
for(int count1=0;count1<N1;count1++){
for(int count2=0;count2<N2;count2++){
buf_InnerProduct+=(A[count1][count2])*(B[count1][count2]);
}
}
return buf_InnerProduct;
}
void main(void){
//内積の計算テスト
double A[2][4]={{1,2,3,4},{5,6,7,8}};
double B[2][4]={{1,2,3,4},{5,6,7,8}};
printf("%lf\n",InnerProduct(A,B));
system("pause");
//system("pause > NUL");
}
//==============================================
動的確保による計算は……気が向いたらやってみようかな?
2013年9月21日土曜日
256*256pixlのアイコンを取得する方法
環境:windows7 x64 Visual C++ 2012
サンプル載せておきます。例によってhttp://www.wgag.net/winapi/のスケルトンプログラムをベースにします。
実行風景
Cドライブのアイコンなのですが、人のアイコンも一緒に表示されるのは、なんとかできたような気もするのですが、もう覚えていないのでそのままにして載せました。
では、サンプルをどうぞ。
なんか微妙に表示がバグっているのでファイルでも置いておきます。(Web系は分からないのです。)
http://ux.getuploader.com/ADMIS/download/2/File_Manager_ICON_Ver0.4.zip
環境:windows7 x64 Visual C++ 2012
サンプル載せておきます。例によってhttp://www.wgag.net/winapi/のスケルトンプログラムをベースにします。
実行風景
Cドライブのアイコンなのですが、人のアイコンも一緒に表示されるのは、なんとかできたような気もするのですが、もう覚えていないのでそのままにして載せました。
では、サンプルをどうぞ。
#include#define _AFXDLL #include //AfxGetInstanceHandle #include #include #include //ExtractIconに必要//「#include 」より下に書かないとエラー……。 #include const TCHAR szWndClass[] = _T("TestProgram"); LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); // The entry point for the application int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASS wc; wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1); wc.lpszMenuName = NULL; wc.lpszClassName = szWndClass; if (!RegisterClass(&wc)) return FALSE; HWND hWnd = CreateWindow( szWndClass, _T("Title"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int) msg.wParam; } // Processes messages for the main window LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { HDC hdc; PAINTSTRUCT ps; switch (msg) { case WM_PAINT: SHFILEINFO sfi; if (!SHGetFileInfo(_T("C:\\"), 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX))//「SHGFI_SYSICONINDEX」iIconの取得に必要 return NULL; // 画像リストを取得する IImageList *pImageList; if (SHGetImageList(SHIL_LAST , IID_IImageList, (void**)&pImageList) != S_OK)//下位互換性を考えるなら「SHIL_JUMBO」と直接指定するよりも「SHIL_LAST」なのかな?(まあもうXPはサポートが切れるが……) return NULL; // アイコンを取得する if (pImageList->GetIcon(sfi.iIcon, SHGFI_ICON|SHGFI_SELECTED, &sfi.hIcon) != S_OK)//ここのフラグをきちんと設定しないと「SHIL_JUMBO」の時に正しい?マスクを取得できない?ためにバグる。 sfi.hIcon = NULL; // 画像リストを解放する pImageList->Release(); hdc = BeginPaint(hWnd, &ps); DrawIconEx(hdc,0,0,sfi.hIcon,256,256,0,NULL, DI_MASK); DrawIconEx(hdc,256,0,sfi.hIcon,256,256,0,NULL, DI_IMAGE); DrawIconEx(hdc,0,256,sfi.hIcon,256,256,0,NULL, DI_NORMAL); DrawIconEx(hdc,256,256,sfi.hIcon,256,256,0,NULL,DI_IMAGE | DI_MASK); EndPaint(hWnd, &ps); DestroyIcon(sfi.hIcon); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, msg, wParam, lParam); } return 0; }
http://ux.getuploader.com/ADMIS/download/2/File_Manager_ICON_Ver0.4.zip
2013年9月20日金曜日
Bloggerにソースコードを乗せる方法
------------------------------------------------------------------------------------------------------------------------
「Syntax Highlighter Scripts Generator」を使う方法……だったのですが、
バグる事があるのでお勧めしません。
2013_11_18_月:追記からのHTMLタグを使う方法をお勧めします。
------------------------------------------------------------------------------------------------------------------------
今まで適当に澄ましていたけど、余りにも見難いのでなんとかしてみた。
取りあえず、ググってhttp://k-1-ne-jp.blogspot.jp/2012/10/syntaxhihglighter.htmlを参考にする。
えーっとまずはhttp://www.way2blogging.org/widget-generators/syntax-highlighter-scripts-generator
にアクセスして……
必要な言語を選択。
クリップボードにスクリプトをコピー。
Bloggerに戻って、
テンプレート⇒HTMLの編集。
//ここにソースコードを挿入する。
int main(void){
return 0;
}
------------------------------------------------------------------------------------------------------------------------
「Syntax Highlighter Scripts Generator」を使う方法……だったのですが、
バグる事があるのでお勧めしません。
2013_11_18_月:追記からのHTMLタグを使う方法をお勧めします。
------------------------------------------------------------------------------------------------------------------------
今まで適当に澄ましていたけど、余りにも見難いのでなんとかしてみた。
取りあえず、ググってhttp://k-1-ne-jp.blogspot.jp/2012/10/syntaxhihglighter.htmlを参考にする。
えーっとまずはhttp://www.way2blogging.org/widget-generators/syntax-highlighter-scripts-generator
にアクセスして……
必要な言語を選択。
クリップボードにスクリプトをコピー。
Bloggerに戻って、
「12行目ぐらいにある<title>タグの後に挿入する」との事だから後ろに挿入したのだけど、これは<title></title>の中に入れる必要があるのか?(取りあえず外で動いたのでそのまま放置)
⇒やってみたらバグったのでこれで正解かと思われます。
それから記事の新しい記事の作成で
<pre class="brush: c++;">int main(void){
return 0;
}
</pre>を挿入(c++の所の言語名を変えれば対応できるはず……)つまり、作成からHTMLへ移動して……
挿入すると
//ここにソースコードを挿入する。
int main(void){
return 0;
}
のように表示される……ハズです。
------------------------------------------------------------------------------------------------------------------------
2013_11_18_月:追記
っという方法でいいかと思っていたのですが、この方法だと、
例えば
#include <stdio.h>
void main(void){
//コード
}
を表示させようとすると
#include <stdio.h>
void main(void){
//コード
}
ついでに言えば、インターネットの接続が上手く行かない場合、
普通のテキストとして表示される事も多いです。
また、正直に言って設定するのも面倒だし、行番号は表示されてもtabは半角スペース一個扱いになって見難いです。
しかし、バグっている以上は仕方がないのでこれを使うのは諦めます。
解決策:
1.取りあえず行数の表示は諦める。
2.「Syntax Highlighter Scripts Generator」の代わりに簡単なHTMLのタグを使う。
使用するタグ
「
<textarea cols="72" rows="90" style="height: 2690px; width: 800px;" wrap="off">
//ここにコードを挿入。
</textarea>
」
height⇒縦の長さ
width⇒横の長さ
の二つだけ設定すれば大丈夫です。
新しい記事の作成で、作成からHTMLへ移動してしたところに挿入すればOKです。
単なるタグなので、「Syntax Highlighter Scripts Generator」のように面倒な設定は不要です。
ただし、「Syntax Highlighter Scripts Generator」のようにウィンドウのサイズを自動で決めてはくれないので、手動で「height」と「width」を決定する必要があります。ただし、「width」については一度決めてしまえば、その値をメモしておいて次の時に見返せば済みます。
3.tabは半角スペース一個扱いになるので、ブログに書き込む前にtabを半角スペース8個に変換しておく。
標準でtabは半角スペース8個分として表示されるので変換しておきます。
この時、まさか手動では追いつかないので、エディタの置換機能を使用します。
私はterapadで置換しています。
------------------------------------------------------------------------------------------------------------------------
実例:
#include <stdio.h>
void main(void){
//コード
}
のままだとtabがスペース一個のままなので各々エディタで置換して、
#include <stdio.h>
void main(void){
//コード
}
Bloggerの編集モードをHTMLに変えて下記のコードを挿入
<textarea cols="72" rows="90" style="height: 56px; width: 800px;" wrap="off">
#include <stdio.h>
void main(void){
//コード
}</textarea>
すると、
のように表示できます。
今回の場合は一文字が14pixなのでheight=14*(4行)=56pxになります。
文字のピクセル数は調べれば出てくるのでしょうが、私はPrintScreenからペイントにコピーして
ペイントでピクセル数を数えました。
ちなみに
<textarea cols="72" rows="90" style="height: 56px; width: 800px;" wrap="off">
#include <stdio.h>
void main(void){
//コード
}
</textarea>
とすると、最後に空白が一行追加されるので注意してください。
<textarea></textarea>について分からないこ事があれば取りあえずGoogleで検索してください。
Googleで検索で検索する!
------------------------------------------------------------------------------------------------------------------------
2013_11_18_月:追記
っという方法でいいかと思っていたのですが、この方法だと、
例えば
#include <stdio.h>
void main(void){
//コード
}
を表示させようとすると
<pre class="brush: c++;">void main(void){
//コード
}
</pre>#includeのようにバグります。void main(void){ //コード }
ついでに言えば、インターネットの接続が上手く行かない場合、
普通のテキストとして表示される事も多いです。
また、正直に言って設定するのも面倒だし、行番号は表示されてもtabは半角スペース一個扱いになって見難いです。
しかし、バグっている以上は仕方がないのでこれを使うのは諦めます。
解決策:
1.取りあえず行数の表示は諦める。
2.「Syntax Highlighter Scripts Generator」の代わりに簡単なHTMLのタグを使う。
使用するタグ
「
<textarea cols="72" rows="90" style="height: 2690px; width: 800px;" wrap="off">
//ここにコードを挿入。
</textarea>
」
height⇒縦の長さ
width⇒横の長さ
の二つだけ設定すれば大丈夫です。
新しい記事の作成で、作成からHTMLへ移動してしたところに挿入すればOKです。
単なるタグなので、「Syntax Highlighter Scripts Generator」のように面倒な設定は不要です。
ただし、「Syntax Highlighter Scripts Generator」のようにウィンドウのサイズを自動で決めてはくれないので、手動で「height」と「width」を決定する必要があります。ただし、「width」については一度決めてしまえば、その値をメモしておいて次の時に見返せば済みます。
3.tabは半角スペース一個扱いになるので、ブログに書き込む前にtabを半角スペース8個に変換しておく。
標準でtabは半角スペース8個分として表示されるので変換しておきます。
この時、まさか手動では追いつかないので、エディタの置換機能を使用します。
私はterapadで置換しています。
------------------------------------------------------------------------------------------------------------------------
実例:
#include <stdio.h>
void main(void){
//コード
}
のままだとtabがスペース一個のままなので各々エディタで置換して、
#include <stdio.h>
void main(void){
//コード
}
Bloggerの編集モードをHTMLに変えて下記のコードを挿入
<textarea cols="72" rows="90" style="height: 56px; width: 800px;" wrap="off">
#include <stdio.h>
void main(void){
//コード
}</textarea>
すると、
のように表示できます。
今回の場合は一文字が14pixなのでheight=14*(4行)=56pxになります。
文字のピクセル数は調べれば出てくるのでしょうが、私はPrintScreenからペイントにコピーして
ペイントでピクセル数を数えました。
ちなみに
<textarea cols="72" rows="90" style="height: 56px; width: 800px;" wrap="off">
#include <stdio.h>
void main(void){
//コード
}
</textarea>
とすると、最後に空白が一行追加されるので注意してください。
<textarea></textarea>について分からないこ事があれば取りあえずGoogleで検索してください。
Googleで検索で検索する!
Top > Direct Show 関連 > Direct Show で取得する解像度を変更する方法
追記2013.10.06.日
このページのコード、具体的には処理した画像をディスプレイに表示する部分にバグを発見しました。
修正するには
「
SetDIBitsToDevice(
hdc , 650 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
0 , 0 , 0 , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS
);
」
を
「
SetStretchBltMode(hdc , COLORONCOLOR);
//これを挿入しないと「StretchDIBits」による縮小時に発生するノイズが酷い。
StretchDIBits(
hdc ,
650 , 0 ,
640 , 360 ,
0 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS,SRCCOPY
);
」
とする事で修正されます。
修正済みのコードは後程……。
まずは前回コードからの変更点
とまあ、こんな感じになる。
一応全体のコードも貼っておく。取得する解像度をFullHDに設定してあるが、そのまま表示されても大きすぎるので、内部での画像処理がFullHDに対応しただけで、実際のディスプレイへの表示は3分の1に縮小表示している。
追記2013.10.06.日
このページのコード、具体的には処理した画像をディスプレイに表示する部分にバグを発見しました。
修正するには
「
SetDIBitsToDevice(
hdc , 650 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
0 , 0 , 0 , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS
);
」
を
「
SetStretchBltMode(hdc , COLORONCOLOR);
//これを挿入しないと「StretchDIBits」による縮小時に発生するノイズが酷い。
StretchDIBits(
hdc ,
650 , 0 ,
640 , 360 ,
0 , 0 ,
pVideoInfoHeader->bmiHeader.biWidth , pVideoInfoHeader->bmiHeader.biHeight ,
rgbValues , &bmpInfo , DIB_RGB_COLORS,SRCCOPY
);
」
とする事で修正されます。
修正済みのコードは後程……。
まずは前回コードからの変更点
//解像度を指定する。// http://www.mvision.co.jp/WebHelpIM/_RESOURCE/MvCap_03.html // http://hisoap.jugem.jp/?eid=140 // http://d.hatena.ne.jp/shibusawa_1/20080909/1220963798 //
IAMStreamConfig *pConfig = NULL;
pCapture->FindInterface(&PIN_CATEGORY_CAPTURE ,0,pbf,IID_IAMStreamConfig,(void**)&pConfig);
//pCapture->FindInterface(&PIN_CATEGORY_PREVIEW ,0,pbf,IID_IAMStreamConfig,(void**)&pConfig);
int iCount=0, iSize=0;
hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);//ピンがサポートするフォーマット機能の数を取得
if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))// VIDEO_STREAM_CONFIG_CAPS構造体かサイズを確認
{
for (int iFormat = 0; iFormat < iCount; iFormat++)
{
VIDEO_STREAM_CONFIG_CAPS scc; // ビデオ フォーマット構造体AM_MEDIA_TYPE
AM_MEDIA_TYPE *p_am_media_type;//am_media_typeの実体は既に宣言しているのだが、ポインタで欲しいと言うので仕方がないのでポインタを宣言したものの、何とかならないかな……。
p_am_media_type = &am_media_type;
hr = pConfig->GetStreamCaps(iFormat, &p_am_media_type, reinterpret_cast(&scc));//フォーマット機能セットを取得
//VIDEO_STREAM_CONFIG_CAPS構造体で、動画対応で最大の大きさである1280*720となる場合を選択する。
if(SUCCEEDED(hr) && (int)scc.InputSize.cx==1920 && (int)scc.InputSize.cy==1080){//「if(p_am_media_type->lSampleSize==2764800){」としてもOK //1280*720*3==2764800より。*3しているのはRGBで三色あるから。(MEDIASUBTYPE_RGB24の場合、MEDIASUBTYPE_RGB32の場合は1280*720*4==3686400)
//「LifeCam Studio for Business Win USB Port 50/60 Hz 5WH-00003」を使った場合
//960:544だと31fpsくらい出る。
//1280:720だと9fpsくらい出る。←なんでだ?
//1920:1080だと16.1fpsくらい出る。
//部屋が暗かったりすると値が出ない気がするし、なんかバラバラ……。
//選択された中で条件に合う物を「SetFormat」する
if((p_am_media_type->majortype == MEDIATYPE_Video) //たぶん取得したフォーマット機能セットが期待した物である事を確認している。
&& (p_am_media_type->subtype == MEDIASUBTYPE_RGB24) //期待したフォーマット機能セットでなかった場合はfor文でそのうち引っかかる
&& (p_am_media_type->formattype == FORMAT_VideoInfo) //このif文は無くても動く。単に皆やってるから入れてみただけ。(必要の無い所にまでフレームレートを設定する必要もないので……)
&& (p_am_media_type->cbFormat >= sizeof(VIDEOINFOHEADER))
&& (p_am_media_type->pbFormat != NULL))
{
// VIDEOINFOHEADERの取得
// hr=pConfig->GetFormat(&p_am_media_type);//これをやるとバグる。何故かってp_am_media_typeはGetStreamCapsで既に取得済み。
VIDEOINFOHEADER *pVih;
pVih = (VIDEOINFOHEADER *)p_am_media_type->pbFormat;
// 解像度の変更
//pVih->bmiHeader.biWidth=1280;//最初から1280*720の場合を選択しているので不要(ブレークポイントで止めるのに役立つくらい……)
//pVih->bmiHeader.biHeight=720;//最初から1280*720の場合を選択しているので不要//これを実行してるサイトがあった気がするけど上手く行かない(たぶんやり方が間違っている)。実際にはAM_MEDIA_TYPEが期待する値の時SetFormatする事で解像度を変更できる。// http://www.freeml.com/directshow/2478/latest //を参照
//フレームレートの設定
//pVih->AvgTimePerFrame = 30;//カメラの最高値に合せておく。
//性能を越えて100とかにしても初期設定と思われる16fpsくらいしか出ない。//ここの値に関わらず気まぐれなので放置
//レートを下げる事くらいはできるかも……。(レートはCPU依存との話もあるが……これ如何に)
// キャストして代入
p_am_media_type->pbFormat=(BYTE*)pVih;
//SetFormatでpbFormatの変更を適用
pConfig->SetFormat(p_am_media_type);
}
}
}
}
}
//MessageBox(0, _T("I'm here!"), _T("Message"), MB_OK);
/*
バグ報告、
最大化した時、Directshowで描写している方の画面(と言うかもう一つのウィンドウ)の位置が追随しないためズレる
⇒解決方法、「case WM_PAINT:」の時、に「pVWindow->SetWindowPosition(0, 0, 640, 480);」を実行すればいいのだが、
このまま実行すると、再描写が重なるので、今している右側に表示する処理をウィンドウを新しく作ってそちらで処理させる
必要があるが、面倒なので後回し。
終了時にMessageでOKをクリックして終了しようとするとCPU使用率が上昇する。
⇒Ver1.2からの症状。どうやら解放した後の「case WM_PAINT:」の時に暴走している。Messageで「OK」を押しても処理してもプログラムが終了せずに、解放したリソースにアクセス
しようとするのが原因だが、最終的な実装で解決するはずなので放置
重心の描写時に、ターゲットが存在しないとCPU使用率が上がる
⇒SoTPが0の時0で割り算しているため
⇒解決
*/
/*
http://hisoap.jugem.jp/?eid=140
のサンプルほぼそのまま
花形として
http://www.geekpage.jp/programming/directshow/renderfile.php
http://marupeke296.com/DSW_No5_FullScreenProgram.html
とかが参考になる。(結構似たような事をしてる)
http://wisdom.sakura.ne.jp/system/winapi/win32/win118.html
を参考にしてビットマップを右側に描写している。
http://tmp.junkbox.info/index.php?e=24
を参考にしてカラーフィルタを実装した。(ただしC#(涙))
http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
を参考に、RGBからHSVへ変換し色判定を行う。
*/
#include
#include
#include
#include
//#include //mallocに必要?
//#include //memcpy関数に必要?
#include bmiHeader.biHeight)-(ySoP/SoTP);//なんか良く分からんけどこのままだと画面の左下が原点(0,0)となってしまうので、次の表示のためにも原点(0,0)を画面の左上に変換しておく。
flag=TRUE;
// http://ja.wikipedia.org/wiki/%E4%B8%89%E8%A7%92%E6%B8%AC%E9%87%8F //
//角度の導出 //カメラ同士の距離を18.8cmとして計算していく。
//y:角度、x:座標
// y=((90-60)/320)*x+60
//⇔y=(3/32)*x+60
double theta1;//θ1[°]//右カメラ
double theta2;//θ2[°]//左カメラ
theta1 = ((0.09375)*xCoG)+60;//(3/32)だと何故か上手く計算してくれないので(0.09375)に書き直している。
theta2 = (0.09375)*320+60;//取りあえずカメラが一台しか無いので固定値(つまり、ターゲットが、もう一台のカメラ(右カメラ)があるべき位置の真正面上を移動すると仮定して距離を計算していく)
//ここで注意したいのはsin,cos,tanは度数法(度(°))では無く弧度法(ラジアン(rad))である事。
//そのため上記の度数法で表している角度を弧度法に変換する。(一気に弧度法で計算していないのはデバックでブレークポイントを設置した時に弧度法で言われても分度器で角度を測れないため。必要が無い場合は計算をまとめて良い)
//M_PIは自分で定義する必要がある。
double rTheta1;//θ1[rad]//右カメラ
double rTheta2;//θ2[rad]//左カメラ
rTheta1 = M_PI*theta1/180;//[rad]=2π*[°]/360⇔[rad]=π*[°]/180
rTheta2 = M_PI*theta2/180;
//ターゲットとの距離を導出
double dVertical; //垂直距離「 Vertical distance」//単位は[cm]//カメラとカメラを結ぶ直線にターゲットから垂線を下ろした時、その降ろした垂線の距離
double dHorizontal; //水平距離「 Horizontal distance」//単位は[cm]//カメラとカメラを結ぶ直線にターゲットから垂線を下ろした時、に直線の交点とカメラとカメラの間の中点との距離
double dStraight; //直線距離「Straight-line distance」//単位は[cm]//カメラとカメラの中点とターゲットとの間の直線距離
dVertical = (double)(18.8)*(double)sin(rTheta1)*(double)sin(rTheta2)/(double)sin(rTheta1+rTheta2);//三角測量と同様の方法で導出
dHorizontal = (dVertical/tan(rTheta1))-((18.8)/2);//三角関数より導出
dStraight = sqrt( (dVertical*dVertical)+(dHorizontal*dHorizontal) );//三平方より導出
//int xxx;//ブレークポイントを設定でき無かったので意味は無いけど追加
//xxx=0;
}
else
{
flag=FALSE;
}
//memcpy(grabBuffer, rgbValues, (pVideoInfoHeader->bmiHeader.biSizeImage)); //これをやると画面が両方真っ赤になる。のでダメ
//背景の画像(右側の赤と黒の画像)を描写する
HDC hdc;
PAINTSTRUCT ps;
hdc = BeginPaint (hWnd, &ps);
//そのまま表示すると大き過ぎるので3分の1に縮小して表示する//640:480だと1920:1080に対してアスペクト比が変わるので640:360とする。
SetDIBitsToDevice(
hdc , 650 , 0 ,
640 , 360 ,
0 , 0 , 0 , 360 ,
rgbValues , &bmpInfo , DIB_RGB_COLORS
);
if(flag){
//重心の位置を描写する
HPEN hPen; // 論理ペンへのハンドル
hPen = CreatePen(PS_SOLID, 1, RGB(0, 0xFF, 0));
SelectObject(hdc, hPen); // 論理ペンを登録
MoveToEx(hdc, 650+xCoG/3, 0, NULL); // (20, 20) に移動
LineTo(hdc, 650+xCoG/3, (pVideoInfoHeader->bmiHeader.biHeight )/3); // (200, 20) まで直線を描画
MoveToEx(hdc, 650, yCoG/3, NULL); // (20, 20) に移動
LineTo(hdc, 650+(pVideoInfoHeader->bmiHeader.biWidth )/3, yCoG/3); // (20, 200) まで直線を描画
DeleteObject(hPen); // 論理ペンを破棄
}
EndPaint( hWnd, &ps );
return 0;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}
int DirectShow_for_USB_Camera(HWND hWnd){
HRESULT hr;
// --- COMの初期化
hr = CoInitialize(NULL);
if(FAILED(hr)){
printf("CoInitialize Failed!\n");
exit(1);//return 1;と同義
}
// --- 1.フィルタグラフマネージャ作成(DirectShow の中心的なオブジェクト)
IGraphBuilder *pGraph = NULL;
CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, IID_IGraphBuilder, (void **)&pGraph);
// http://marupeke296.com/DSW_No5_FullScreenProgram.html //② フィルタグラフマネージャの取得
// フィルタグラフマネージャの取得
//
// DirectShowのプログラムは実質ここから始まります。まずはフィルタグラフを管理するフィルタグラフマネージャを作成します。取得するインターフェイスはIGraphBuilderです。このインターフェイスはWindows自体が提供するためCoCreateInstance関数というグローバルな関数を用いて生成します。
//
//IGraphBuilder *pGB = NULL;
//HRESULT hr = CoCreateInstance( CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void**)&pGB);
// CoCreateInstance関数はCOMとして登録されているインターフェイスを生成して返してくれます。
//第1引数にインターフェイスを含むクラスIDを指定します。IGraphBuilderを取得するときに指定するIDはCLSID_FilterGraphと決まっているので、無条件で上のように与えます。
//第2引数はCOMオブジェクトの内包状態を指定するフラグなのですが、殆どのCOMはNULLでOK。
//第3引数は生成するCOMの実装ソースがあるDLLの所在を表します。IGraphBuilderについてはDLLがローカルにありますのでインプロセスであるCLSCTX_INPROC_SERVERを指定します。
//第4引数に欲しいインターフェイスの固有IDを指定します。IGraphBuilderインターフェイスを表すIDはIID_IGraphBuilderです。
//関数が成功すると第5引数にIGraphBuilderインターフェイスへのポインタが返ります。
//
//この処理はもう決まりきっていますので、変更のしようがありません。「IGraphBuilderの取得の仕方はこうだ!」と決めてしまってよいでしょう。
//
// IGraphBuilderの役目はフィルタグラフにかかわるインターフェイスの提供、およびフィルタグラフの管理です。
// --- 2.システムデバイス列挙子の作成(接続されているデバイスを調べるためのオブジェクト) // ⑥ キャプチャデバイス(USBカメラ等)を選択するため,システムデバイス列挙子を作成する.つまり,PCに接続されているデバイスを列挙するってこと.
ICreateDevEnum *pDevEnum = NULL;
CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&pDevEnum);
// 列挙子の取得 // ⑦ 列挙したキャプチャデバイスのカテゴリ列挙子を取得する.音声なのか,映像なのか,とかそういうこと.ビデオキャプチャの場合は,CLSID_VideoInputDeviceCategoryを指定すればよい.
IEnumMoniker *pClassEnum = NULL;
pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0);
if(pClassEnum == NULL){
printf("Device does not exist!\n");
pDevEnum->Release();
CoUninitialize();
return 1;
}
pDevEnum->Release(); // 以後に不要なメモリーをリリース
IBaseFilter *pbf = NULL;
IMoniker *pMoniker = NULL;
ULONG cFetched; //ULONGはCOMの型……らしいのだが……???
if(pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK){ // IEnumMoniker.Next メソッド(http://msdn.microsoft.com/ja-jp/library/system.runtime.interopservices.comtypes.ienummoniker.next(v=vs.85).aspx)←ハイパーリンクがバグってる……。
// Next(1, &pMoniker, &cFetched)
//返されるモニカの数,列挙されたモニカへの参照を格納,列挙されたモニカの実数への参照を格納
pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pbf); // 最初のモニカをフィルタオブジェクトにバインド
pMoniker->Release();
}
pClassEnum->Release(); // 以後に不要なメモリーをリリース
pGraph->AddFilter(pbf, L"USB Camera Capture"); // グラフにフィルタを追加
// http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑥ ソースフィルタの作成と登録
// IGraphBuilder::AddSourceFilter関数を使用した場合は自動的にフィルタグラフへの登録が行われるので、改めてIGraphBuilder::AddFilter関数を呼ぶ必要はない。
// ファイル名に関して重要な注意があります。第2引数の型は「LPCWSTR」になっています。これはワイド文字(例えばunicode)というやつです。私たちが以前まで普通に使っていたのはマルチバイト文字でして、これは「LPCSTR」です。マルチバイト文字とワイド文字は互換性がありません。ですから、ワイド文字がコンパイラオプションに設定されていない環境では、文字をプログラマが明示的にワイド文字に変換する必要があります。ただリテラル(ダブルクォーテーションで囲まれた文字)で定義する場合は「L接頭子」を付けると常にワイド文字として扱われます。
//============================================================================================
// http://www.geekpage.jp/programming/directshow/samplegrabber.php //BitMapキャプチャ用フィルタの用意
IBaseFilter *pSampleGrabberFilter;
// SampleGrabber(Filter)を生成
CoCreateInstance(CLSID_SampleGrabber,
NULL,
CLSCTX_INPROC,
IID_IBaseFilter,
(LPVOID *)&pSampleGrabberFilter);
ISampleGrabber *pSampleGrabber;
// FilterからISampleGrabberインターフェースを取得します
pSampleGrabberFilter->QueryInterface(IID_ISampleGrabber, (LPVOID *)&pSampleGrabber);
AM_MEDIA_TYPE am_media_type;
// SampleGrabberを接続するフォーマットを指定。
// ここがポイントです。
// ここの指定の仕方によりSampleGrabberの挿入箇所を
// 決定できます。このサンプルのような指定をすると
// 画面出力の寸前でサンプルを取得できます。
ZeroMemory(&am_media_type, sizeof(am_media_type));
am_media_type.majortype = MEDIATYPE_Video;
am_media_type.subtype = MEDIASUBTYPE_RGB24;
am_media_type.formattype = FORMAT_VideoInfo;
pSampleGrabber->SetMediaType(&am_media_type);
// GraphにSampleGrabber Filterを追加
pGraph->AddFilter(pSampleGrabberFilter, L"Sample Grabber");
//============================================================================================
// --- 3.キャプチャグラフ作成
ICaptureGraphBuilder2 *pCapture = NULL;
CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC, IID_ICaptureGraphBuilder2, (void **) &pCapture);
pCapture->SetFiltergraph(pGraph); // フィルタグラフをキャプチャグラフに組み込む//ICaptureGraphBuilder2インターフェイスの初期化
//
//http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑦ ICaptureGraphBuilder2インターフェイスの取得
// フィルタの接続は意外と面倒なものなのですが、これに関してヘルパーインターフェイスが用意されています。「ICaptureGraphBuilder2」というインターフェイスは、フィルタの接続をある程度自動化してくれまして、使い勝手がとても良いものです。ここではこれを使うことにしましょう。このインターフェイスの取得にもCoCreateInstance関数を用います。
// 取得したICaptureGraphBuilder2インターフェイスは初期化が必要なのですが、これはとても簡単でして先に取得したIGraphBuilderインターフェイスをICaptureGraphBuilder2::SetFiltergraph関数に渡すだけです。
// pCapture->RenderStream(&PIN_CATEGORY_PREVIEW, &MEDIATYPE_Video, pbf, NULL, NULL); // キャプチャグラフの設定、グラバをレンダリング出力に設定//キャプチャ画像を表示するためのビデオプレビューグラフを作成する
pCapture->RenderStream(NULL, NULL, pbf, pSampleGrabberFilter, NULL);//上記に変わってこのように第三引数以外全てNULLに指定してもなんとかなったりする。(キャプチャするには第4引数が必要)
//
//注意:ここの第4引数に「pSampleGrabberFilter」 // http://www.crystal-creation.com/software/technical-information/library/directshownet/filter-graph/capture-graph-builder2.htm#contents-3
// を指定して、経由するフィルタを明示する。 // int RenderStream(
// これをしないとキャプチャを取れない。 // DsGuid PinCategory, // ピン カテゴリ //接続元と先が明らかである場合はNULL指定によりIntelligent Connectに接続を任せることも出来ます。
// DsGuid MediaType, // 出力ピンのメディア タイプ //NULL指定をすると、すべてIntelligent Connectに任せます。
// object pSource, // 接続先のフィルタ //ここは必ず指定する必要があります。
// IBaseFilter pfCompressor, // 経由するフィルタ (圧縮フィルタなど) //NULLが指定できます。
// IBaseFilter pfRenderer // シンク フィルタ (レンダラなど) //NULLを指定した場合、関数はデフォルトの入力フィルタへ接続を試みる。
// );
//
// http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑧ フィルタの接続 を参照
//============================================================================================
//解像度を指定する。// http://www.mvision.co.jp/WebHelpIM/_RESOURCE/MvCap_03.html // http://hisoap.jugem.jp/?eid=140 // http://d.hatena.ne.jp/shibusawa_1/20080909/1220963798 //
IAMStreamConfig *pConfig = NULL;
pCapture->FindInterface(&PIN_CATEGORY_CAPTURE ,0,pbf,IID_IAMStreamConfig,(void**)&pConfig);
//pCapture->FindInterface(&PIN_CATEGORY_PREVIEW ,0,pbf,IID_IAMStreamConfig,(void**)&pConfig);
int iCount=0, iSize=0;
hr = pConfig->GetNumberOfCapabilities(&iCount, &iSize);//ピンがサポートするフォーマット機能の数を取得
if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS))// VIDEO_STREAM_CONFIG_CAPS構造体かサイズを確認
{
for (int iFormat = 0; iFormat < iCount; iFormat++)
{
VIDEO_STREAM_CONFIG_CAPS scc; // ビデオ フォーマット構造体AM_MEDIA_TYPE
AM_MEDIA_TYPE *p_am_media_type;//am_media_typeの実体は既に宣言しているのだが、ポインタで欲しいと言うので仕方がないのでポインタを宣言したものの、何とかならないかな……。
p_am_media_type = &am_media_type;
hr = pConfig->GetStreamCaps(iFormat, &p_am_media_type, reinterpret_cast(&scc));//フォーマット機能セットを取得
//VIDEO_STREAM_CONFIG_CAPS構造体で、動画対応で最大の大きさである1280*720となる場合を選択する。
if(SUCCEEDED(hr) && (int)scc.InputSize.cx==1920 && (int)scc.InputSize.cy==1080){//「if(p_am_media_type->lSampleSize==2764800){」としてもOK //1280*720*3==2764800より。*3しているのはRGBで三色あるから。(MEDIASUBTYPE_RGB24の場合、MEDIASUBTYPE_RGB32の場合は1280*720*4==3686400)
//「LifeCam Studio for Business Win USB Port 50/60 Hz 5WH-00003」を使った場合
//960:544だと31fpsくらい出る。
//1280:720だと9fpsくらい出る。←なんでだ?
//1920:1080だと16.1fpsくらい出る。
//部屋が暗かったりすると値が出ない気がするし、なんかバラバラ……。
//選択された中で条件に合う物を「SetFormat」する
if((p_am_media_type->majortype == MEDIATYPE_Video) //たぶん取得したフォーマット機能セットが期待した物である事を確認している。
&& (p_am_media_type->subtype == MEDIASUBTYPE_RGB24) //期待したフォーマット機能セットでなかった場合はfor文でそのうち引っかかる
&& (p_am_media_type->formattype == FORMAT_VideoInfo) //このif文は無くても動く。単に皆やってるから入れてみただけ。(必要の無い所にまでフレームレートを設定する必要もないので……)
&& (p_am_media_type->cbFormat >= sizeof(VIDEOINFOHEADER))
&& (p_am_media_type->pbFormat != NULL))
{
// VIDEOINFOHEADERの取得
// hr=pConfig->GetFormat(&p_am_media_type);//これをやるとバグる。何故かってp_am_media_typeはGetStreamCapsで既に取得済み。
VIDEOINFOHEADER *pVih;
pVih = (VIDEOINFOHEADER *)p_am_media_type->pbFormat;
// 解像度の変更
//pVih->bmiHeader.biWidth=1280;//最初から1280*720の場合を選択しているので不要(ブレークポイントで止めるのに役立つくらい……)
//pVih->bmiHeader.biHeight=720;//最初から1280*720の場合を選択しているので不要//これを実行してるサイトがあった気がするけど上手く行かない(たぶんやり方が間違っている)。実際にはAM_MEDIA_TYPEが期待する値の時SetFormatする事で解像度を変更できる。// http://www.freeml.com/directshow/2478/latest //を参照
//フレームレートの設定
//pVih->AvgTimePerFrame = 30;//カメラの最高値に合せておく。
//性能を越えて100とかにしても初期設定と思われる16fpsくらいしか出ない。//ここの値に関わらず気まぐれなので放置
//レートを下げる事くらいはできるかも……。(レートはCPU依存との話もあるが……これ如何に)
// キャストして代入
p_am_media_type->pbFormat=(BYTE*)pVih;
//SetFormatでpbFormatの変更を適用
pConfig->SetFormat(p_am_media_type);
}
}
}
}
//============================================================================================
// http://www.geekpage.jp/programming/directshow/samplegrabber.php //画像の縦横のpixelとデータサイズの取得
// 接続情報取得。
// この処理はRenderFileによりGraphが構成された後に
// 行う必要があります。
pSampleGrabber->GetConnectedMediaType(&am_media_type);
pVideoInfoHeader = (VIDEOINFOHEADER *)am_media_type.pbFormat;
// ビデオ ヘッダーには、ビットマップ情報が含まれる。
// ビットマップ情報を BITMAPINFO 構造体にコピーする。
CopyMemory(&bmpInfo.bmiHeader, &(pVideoInfoHeader->bmiHeader), sizeof(BITMAPINFOHEADER));// http://www.greenwood.co.jp/~k-aki/article/directshow_movie/directshow_movie.html //のdirectshow2.cpp// http://www.greenwood.co.jp/~k-aki/article/directshow_movie/directshow2/directshow2.cpp //
//// 画像(映像)の幅と高さを表示
//// サンプルをわかりやすくするために表示しているだけなので、
//// 必ず必要というわけではありません。
//printf("size = %dx%d\n",
// pVideoInfoHeader->bmiHeader.biWidth,
// pVideoInfoHeader->bmiHeader.biHeight);
//pVideoInfoHeader->bmiHeader.biWidth=1280;
//pVideoInfoHeader->bmiHeader.biHeight=720;
//// データサイズを表示
//// これも説明のために表示しています。
//printf("sample size = %d\n",
// am_media_type.lSampleSize);
// Grabを行う事を設定 //キャプチャをするかしないか選択
// SetBufferSamplesを行わないとバッファから
// データを取得できません。
// 不必要に負荷をかけたくない場合にはFALSEにしておいて、
// データを取得したくなったら、TRUEに変える
// という方法もできます。
hr = pSampleGrabber->SetBufferSamples(FALSE);//データを取得するか?「TRUE」or「FALSE」//コールバック関数を用いて連続キャプチャするので、FALSEで問題ない。//http://miraiware.net/memo/dshow-capture.html
pSampleGrabber->SetOneShot(FALSE);
// プレビュー開始時
cameraCB *cb = new cameraCB();
cb->hWnd = hWnd;//これが無いとウィンドウを識別できない……。
pSampleGrabber->SetCallback(cb,1);
//pSampleGrabber->SetCallback(this,1);
// プレビュー停止時
//pSampleGrabber->SetCallback(NULL, 1);
//============================================================================================
// http://ugd555.fc2web.com/frame.html //⑤
// IVideoWindowインタフェース(ビデオウィンドウの設定)
IVideoWindow *pVWindow=NULL;
hr = pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVWindow);
// http://ugd555.fc2web.com/frame.html // ⑫
// プレビューウィンドウの設定
hr = pVWindow->put_Owner((OAHWND)hWnd);
//hr = pVWindow->put_Owner(NULL);とすると子ウィンドウを切り離す事ができる。
hr = pVWindow->put_WindowStyle(WS_CHILD | WS_CLIPCHILDREN);//WS_CHILD:子ウィンドウを作成します。|WS_CLIPCHILDREN:親ウィンドウの内部で描画するときに、子ウィンドウが占める領域を除外します。親ウィンドウを作成するときに使います。//WS_CLIPCHILDREN不要かと思ったけど、無いとウィンドウを消したとき?(うる覚え……)にバグる。
// RECT rc;
// GetClientRect(hWnd, &rc);//親ウィンドウのサイズを取得
// pVWindow->SetWindowPosition(0, 0, rc.right, rc.bottom);
//pVWindow->SetWindowPosition(0, 0, pVideoInfoHeader->bmiHeader.biWidth, pVideoInfoHeader->bmiHeader.biHeight);
pVWindow->SetWindowPosition(0, 0, 640, 360);//そのまま表示すると大き過ぎるので3分の1に縮小して表示する//640:480だと1920:1080に対してアスペクト比が変わるので640:360とする。
hr = pVWindow->put_Visible(OATRUE);//ウィンドウを表示する。//無くても動くけど、たぶんあった方が良いって感じのものかな?//ShowWindow()関数に相当する物だと言う事にしておく。
//画像処理用の動的メモリを確保
//rgbValues = (unsigned char *)malloc(640*480*3 * sizeof(unsigned char));//unsignedにしないとバグる。具体的には「水色っぽい部分を見つけたら」「if ( rgbValues[p] > rgbValues[p + 1] && rgbValues[p] > rgbValues[p + 2]*2 )」などと判定する時にバグる。
rgbValues = (unsigned char *)malloc((pVideoInfoHeader->bmiHeader.biWidth)*(pVideoInfoHeader->bmiHeader.biHeight)*3 * sizeof(unsigned char));
// --- 5.キャプチャ開始
IMediaControl *pMC = NULL;
pGraph->QueryInterface(IID_IMediaControl, (LPVOID *)&pMC); // MediaControlインターフェース取得(グラフの開始・停止を制御するインターフェイス)
pMC->Run();
// http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑩ フィルタグラフの実行
// フィルタグラフの接続が全て終了し、表示サイズを正しく指定すれば、いつでも動画を再生することができます。再生を担当するインターフェイスは、IGraphBuilderから生成できるIMediaControlインターフェイスです。
// --- 6.終了待ち
MessageBox(NULL, TEXT("Click to stop."), TEXT("Message"), MB_OK);
// getch()で待つのはだめ、レンダリング表示のためにシステムに実行を返す必要がある
// --- 終了処理
pMC->Stop();
hr = pVWindow->put_Visible(OAFALSE);
pMC->Release(); // http://marupeke296.com/DSW_No5_FullScreenProgram.html //⑪ 終了処理
pVWindow->Release(); // 解放順番はきっと厳密ではないのだろうと思うのですが、一応作成順と逆に解放しておきます。
// プレビュー停止時
pSampleGrabber->SetCallback(NULL, 1);//これをしないと正しく終了できない。「ハンドルされない例外が 0x56F067C7 (qedit.dll) で発生しました(Image_Processing_Ver0.7.exe 内): 0xC0000005: 場所 0xFEEEFEF6 の読み取り中にアクセス違反が発生しました。」と言ってエラーを吐く。
delete cb;
pCapture->Release();
pSampleGrabber->Release();
pSampleGrabberFilter->Release();
pbf->Release();
pGraph->Release();
CoUninitialize(); // COMを終了
return 0;
}
//RGBからHSVへ変換する関数// http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93 //を元に実装
void ConvertRGBtoHSV(unsigned char * rgbValues,unsigned int *i,double *H,double *S,double *V){
if( rgbValues[*i+2] > rgbValues[*i+1] && rgbValues[*i+2] > rgbValues[*i] )//赤>緑&&赤>青
{
//赤>緑&&赤>青
if( rgbValues[*i+1] > rgbValues[*i] )//緑>青
{
//赤>緑>青
*H = 60*( ((double)rgbValues[*i+1]-(double)rgbValues[*i])/((double)rgbValues[*i+2]-(double)rgbValues[*i]) ) + 0;//60*(G-B)/(MAX-MIN)+0
*S = ((double)rgbValues[*i+2]-(double)rgbValues[*i])/(double)rgbValues[*i];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i+2];//MAX
}
else
{
//赤>青>緑
*H = 60*( ((double)rgbValues[*i]-(double)rgbValues[*i+1])/((double)rgbValues[*i+2]-(double)rgbValues[*i+1]) ) + 0;//60*(B-G)/(MAX-MIN)+0
*S = ((double)rgbValues[*i+2]-(double)rgbValues[*i+1])/(double)rgbValues[*i+1];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i+2];//MAX
}
}
else if( rgbValues[*i+1] > rgbValues[*i] )//緑>青
{
//緑>青
if( rgbValues[*i] > rgbValues[*i+2] )//青>赤
{
//緑>青>赤
*H = 60*( ((double)rgbValues[*i]-(double)rgbValues[*i+2])/((double)rgbValues[*i+1]-(double)rgbValues[*i+2]) ) + 120;//60*(B-R)/(MAX-MIN)+120
*S = ((double)rgbValues[*i+1]-(double)rgbValues[*i+2])/(double)rgbValues[*i+2];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i+1];//MAX
}
else
{
//緑>赤>青
*H = 60*( ((double)rgbValues[*i+2]-(double)rgbValues[*i])/((double)rgbValues[*i+1]-(double)rgbValues[*i]) ) + 120;//60*(R-B)/(MAX-MIN)+120
*S = ((double)rgbValues[*i+1]-(double)rgbValues[*i])/(double)rgbValues[*i];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i+1];//MAX
}
}
else//青>緑
{
//青>緑>赤
if( rgbValues[*i+1] > rgbValues[*i+2] )//緑>赤
{
//青>緑>赤
*H = 60*( ((double)rgbValues[*i+2]-(double)rgbValues[*i+1])/((double)rgbValues[*i]-(double)rgbValues[*i+2]) ) + 240;//60*(R-G)/(MAX-MIN)+240
*S = ((double)rgbValues[*i]-(double)rgbValues[*i+2])/(double)rgbValues[*i+2];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i];//MAX
}
else
{
//青>赤>緑
*H = 60*( ((double)rgbValues[*i+1]-(double)rgbValues[*i+2])/((double)rgbValues[*i]-(double)rgbValues[*i+1]) ) + 240;//60*(G-R)/(MAX-MIN)+240
*S = ((double)rgbValues[*i]-(double)rgbValues[*i+1])/(double)rgbValues[*i+1];//(MAX-MIN)/MAX
*V = (double)rgbValues[*i];//MAX
}
}
}
}
上のコードの表示が微妙にバグっているのでサンプルも置いておきます。
余談ですが、色の判定はカメラが違ったりすると上手く行かない事があります。各自で調整が必要です。それと、「LifeCam Studio for Business Win USB Port 50/60 Hz 5WH-00003」を使うために解像度の指定を実装しましたが、色の調整は行っていない状態なので環境が同じでも上手く行かなくてもそれは仕様です^^;。
http://ux.getuploader.com/ADMIS/download/11/Image_Processing_Ver1.8.zip
Top > Direct Show 関連 > Direct Show で取得する解像度を変更する方法
余談ですが、色の判定はカメラが違ったりすると上手く行かない事があります。各自で調整が必要です。それと、「LifeCam Studio for Business Win USB Port 50/60 Hz 5WH-00003」を使うために解像度の指定を実装しましたが、色の調整は行っていない状態なので環境が同じでも上手く行かなくてもそれは仕様です^^;。
http://ux.getuploader.com/ADMIS/download/11/Image_Processing_Ver1.8.zip
Top > Direct Show 関連 > Direct Show で取得する解像度を変更する方法
登録:
コメント (Atom)









