タグ:C# ( 7 ) タグの人気記事

XAMLデザインビューのエラーについて

「x64 および ARM ターゲット プラットフォームではデザイン ビューを使用できません。」

という謎エラーでデザインビューが見られない問題
x64でカスタムコントロールを参照する時とかによく出るやつなんだが
とにかくウザったい、ビルドは通るのにデザイナで出てこない

どうやらソースのネットワーク管理設定の周辺で起きてるものらしい
ソリューションファイル(*.sln)と同階層にある(*.suo)を削除してリビルドすると消えた

毎度毎度悩まされてるやつなんだけど
今回はガチで原因を追って解決策を発見できたので備忘録として


[PR]
by onigirism | 2016-06-14 16:46 | VisualStudio | Comments(0)

VisualStudioでAndroid開発

VisualStudioでもAndroidアプリの開発が出来るようになったので
勉強がてら色々いじってみた

取りあえずデフォルトフォームのビューをデバッグして・・・
・・・遅い
Androidのシミュレータは昔っからモッサモサなことで一定の評価があるが
やはりこれもダメだった

ということで実機をつないでデバッグするしかねーと考え
その設定方法を備忘録として残す(2016/02時点の資料です)

まずAndroidSDKをインスコする(環境はWin10,64bit)
SDKのDLページ

ここはAndroidStudio推しなのでスタンドアロンの方を選ぶ
ASが使えるんならVSなんか使わずそっち使った方がいい、本家なんだし

まずはSDK Tools Onlyの方のインストーラかzipをDLしましょう
フォルダ1個好きなとこに置くだけのホントの意味でスタンドアロンなので
exeでもzipでもどっちでもいいと思う、ここではインストーラ版で説明

デフォルトでは

C:\Program Files (x86)\Android\android-sdk

に入る、はず
こだわりが無ければそのままで
JDKが入ってなかったらその前に入れる流れになると思うけど割愛
インストールの終了時にSDKマネージャを起動します

e0349767_12230675.png
余計なものを入れないよう一旦「Deselect All」を押してから
・Android SDK Tools
・Android SDK Platform-tools
・Googlel USB Driver
この3つの入ってない奴をインストールします
(初めてやるなら多分全部入れることになるはず)

インストールが終わったら
adb shell を使えるようにするため環境変数にPathを通します

C:\Program Files (x86)\Android\android-sdk\platform-tools
を追加(重要)

ネットでAndroidSDKについて探すと分かりますが
「adbがtoolsの中にあるのでここにpathを適用する」という資料が散見されますが
これは誤り、というか情報が古い

現行Ver.ではplatform-toolsにadbが移動しているので注意
(ここで小一時間はまる)

Pathを通したらほんとに使えるのか確認
e0349767_12373329.png
いけてそう

次に実機をPCにつないで端末のドライバをインストールする
ここについては各機種手順が色々異なると思うので省略

ちゃんとドライバが入ってたらこうなる
e0349767_12462147.png
プロパティを開いて「詳細」タブのハードウエアIDを選択
ここの情報をGoogle USB Driverのandroid_winusb.infに追記する

infファイルの場所はデフォルトなら
C:\Program Files (x86)\Android\android-sdk\extras\google\usb_driver
android_winusb.inf内の

[Google.NTx86]
[Google.NTamd64]

の各セクション内に

%SingleAdbInterface% = USB_Install, USB\VID_XXXX&PID_XXXX
%CompositeAdbInterface% = USB_Install, USB\VID_XXXX&PID_XXXX&MI_XX

を記述する(Xは端末ごとに異なるのでそれに合わせて)
使うのはVID,PID,MIなのでREVとかよく分からない数字とかは無視してOK
設定周りはこれ終わりなのでadbがちゃんと端末を認識するか確認

端末が繋がってるのを確認してadb devices

e0349767_13030683.png
それっぽいのが出てきたのでOKなんでしょう

最後にVisualStudioを起動してシミュレート目的のプロジェクトを開く
デバッグ端末の選択にアタッチした端末が出てるはずなのでそのままデバッグ実行
e0349767_13080824.png
端末側でアプリが起動すれば設定完了

e0349767_13144243.png


[PR]
by onigirism | 2016-02-19 13:15 | Android | Comments(0)

Kinect.Faceの落とし穴

顔認識のライブラリを使用して
書割の画像と合成するオモチャを作ってる際にそれは起きた

e0349767_12473936.png

あわわわわ、Eceptionが止まらない・・・
ObejctDisposedExceptionがKinect.Face.dllで起きてるから
FaceFrameReaderかFrameSource辺りで変なことしてるのかなと思い
該当のソースを見てみる

e0349767_12501209.png
うーん?別に何もおかしくないんだけどな・・・
各Disposeメソッドをコメントアウトするとエラーは消えるものの
これだと画面遷移してもインスタンスが残ったままになるのでよろしくない
ステップで追おうにもpdbを吐かないからどうにもならない

これが昨日の晩からさっきまで頭を悩ませていたけど・・・解決!

e0349767_12530787.png
どうやらFaceFrameReaderのアクティブな状態を止めないといけないらしい
IsPausedプロパティをTrueに切り替えてからDisposeを行うとエラーが出なくなった
SDKのサンプルソースだとWindowのClosingイベント時に同様のことをしているものの
FrameArrivedのイベントハンドラはそのまんま放置してるので、こういうことをしないといけないってのは明記されてない
このハマり状態から抜け出せただけで今日の仕事終わっていいんじゃないのって思うレベル

しかしMSさんよ、IsPausedを何に使うかってことぐらいどこかに書いといてくれないかねぇ・・・。

[PR]
by onigirism | 2016-01-26 13:01 | プログラミング | Comments(0)

SmoothingFilter拡張

以前書いたPointの平滑化をさらに拡張、
一度インスタンスを作れば各JointType全てに平滑処理が走るように実装してみた。
でもコレの違いってやってる人じゃないと分かんないかもしれない。
個人的にはかなりヌルヌル動いてて結果に満足だけど・・・。

以下ソース

using System;
using System.Windows;
using System.Collections.Generic;
using Microsoft.Kinect;

namespace Microsoft.Samples.Kinect.BodyBasics
{
class SmoothingPoint
{
private static Dictionary<JointType, Queue<Point>> pointBufferS = new Dictionary<JointType, Queue<Point>>();
private static Dictionary<JointType, Queue<Point>> pointBufferE = new Dictionary<JointType, Queue<Point>>();

public SmoothingPoint()
{
foreach (JointType jt in Enum.GetValues(typeof(JointType)))
{
pointBufferS.Add(jt, new Queue<Point>());
pointBufferE.Add(jt, new Queue<Point>());
}
}

public Point Smoothing(JointType jType, Point p)
{
return DoubleMovingAverage(jType, p);
}

private Point SimpleAverageFilter(JointType jt, Point newPoint, int parameter)
{
pointBufferS[jt].Enqueue(newPoint);
if (pointBufferS[jt].Count <= parameter)
{
return newPoint;
}
pointBufferS[jt].Dequeue();
Point[] list = pointBufferS[jt].ToArray();
Point point = new Point();
double x = 0;
double y = 0;

int n = pointBufferS[jt].Count;
for (int i = 0; i < pointBufferS[jt].Count; i++)
{
Point p = list[i];
x += p.X;
y += p.Y;
}
point.X = x / n;
point.Y = y / n;

return point;
}

private Point DoubleMovingAverage(JointType jt, Point newPoint, int parameter = 5)
{
Point newSimpleAverage = SimpleAverageFilter(jt, newPoint, parameter);
pointBufferE[jt].Enqueue(newSimpleAverage);
if (pointBufferE[jt].Count <= parameter)
{
return newSimpleAverage;
}
pointBufferE[jt].Dequeue();
Point[] list = pointBufferE[jt].ToArray();
Point point = new Point();
double x = 0;
double y = 0;

int n = pointBufferE[jt].Count;
for (int i = 0; i < pointBufferE[jt].Count; i++)
{
Point p = list[i];
x += p.X;
y += p.Y;
}
point.X = x / n;
point.Y = y / n;

return point;
}
}
}


[PR]
by onigirism | 2015-12-10 18:26 | C# | Comments(0)

ColorFrameReader その2

夏休みを挟んで久々に再開

前回の続きです。
最後にこうなってましたね。

public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;

kinect = KinectSensor.GetDefault();
cReader = kinect.ColorFrameSource.OpenReader();
cDesc = kinect.ColorFrameSource.FrameDescription;
cBuff = new byte[cDesc.Width * cDesc.Height * 4];
wBitmap = new WriteableBitmap(cDesc.Width, cDesc.Height, 96.0, 96.0, PixelFormats.Bgra32, null);

cReader.FrameArrived += cReader_FrameArrived;
}

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
kinect.Open.();
}

private void cReader_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
{

}

さて、この段階でアプリを実行すると、画面上には何も出ないけど
一応Kinectは起動すると思います。
何も出ないのは当然、Kinectが取得するデータに何にも手を付けてないからです。

ということで手を付けます。
カラーデータを毎フレーム取得するイベントハンドラが登録されていますね。(一番下のproc)
ここに色々書いていきます。

まずKinectのデータ取得についてのお約束として
毎回フレームデータを取得⇒使い終わったら破棄
という流れを覚えておきましょう。
それを踏まえて以下のように書きます。

using ( ColorFrame cFrame = e.FrameReference.AcquireFrame() )
{
if ( cFrame != null )
{

}
}

IDisposableオブジェクトであるColorFrameはusingステートメントを使うことで
記述をおもっくそ簡略化出来ますね、最後にDisposeとかやらんでも勝手にやってくれます。
一時データとして取得したcFrameを使ってデータを加工します。

次、

if ((cDesc.Width == wImage.PixelWidth) && (cDesc.Height == wImage.PixelHeight))
{
if (cFrame.RawColorImageFormat == ColorImageFormat.Bgra)
{
cFrame.CopyRawFrameDataToArray(cBuff);
}
else
{
cFrame.CopyConvertedFrameDataToArray(cBuff, ColorImageFormat.Bgra);
}
}

バッファにcFrameのデータをコピーします。
ここでフレームのColorImageFormatの場合分けをしてますが、意図的にイジりでもしない限り、
あるいはIDEがVisualStudioである限りはBGRA形式で渡ってきます。
これがUnityの場合だとyuv(だっけ?)で来ちゃうのでBytesPerPixelがRGBAと違ってエラーになります。
念のため的な処置ですがデータコピーにはこういう手順を踏んでおきましょう。

あとはWriteableBitmapに取得したデータをオラオラするだけです。
wImage.WritePixels(
new Int32Rect(0, 0, wImage.PixelWidth, wImage.PixelHeight),
cBuff,
wImage.PixelWidth * (int)bpp,
0
);
オフセットって言うのがイマイチよく分かってません、ごめんなさい。
ただ、0から1にしたりするとエラーを吐くのでそういうもんなんでしょう(適当)
書き込み始める位置の調整なのかな?

さて、長々書きましたが全体でこうなります。

public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;

kinect = KinectSensor.GetDefault();
cReader = kinect.ColorFrameSource.OpenReader();
cDesc = kinect.ColorFrameSource.FrameDescription;
cBuff = new byte[cDesc.Width * cDesc.Height * 4];
wBitmap = new WriteableBitmap(cDesc.Width, cDesc.Height, 96.0, 96.0, PixelFormats.Bgra32, null);

cReader.FrameArrived += cReader_FrameArrived;
}

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
kinect.Open.();
}

private void cReader_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
{
using ( ColorFrame cFrame = e.FrameReference.AcquireFrame() )
{
if ( cFrame != null )
{
if ((cDesc.Width == wImage.PixelWidth) && (cDesc.Height == wImage.PixelHeight))
{
if (cFrame.RawColorImageFormat == ColorImageFormat.Bgra)
{
cFrame.CopyRawFrameDataToArray(cBuff);
}
else
{
cFrame.CopyConvertedFrameDataToArray(cBuff, ColorImageFormat.Bgra);
}

wImage.WritePixels(
new Int32Rect(0, 0, wImage.PixelWidth, wImage.PixelHeight),
cBuff,
wImage.PixelWidth * (int)bpp,
0
);
}
}
}
}

これで出来る限り最小のカメラ画像取得ロジックの完成

ではないです。

wImageにデータを書き込んだはいいがそれをコントロール側に渡していませんね。
この辺はちょっとジャンルの違う話になってくるのでテキトーですいません。

public ImageSource cameraImg
{
get { return wImage; }
}

こんな感じでcameraImgをXAML側にバインドすれば完成です。
あぁ長かった。

[PR]
by onigirism | 2015-09-02 11:35 | Kinect | Comments(0)

ColorFrameReader

発売から約2年ぐらい経ったv2、最近の動向はどうなんだろう
ニュース検索してもめっきり話題が少ない気がしてちょっと悲しい・・。

けどこれからv2のプログラミングを始める人もいるだろうから
ちょっとずつではあるけど自分の得た知識・知恵を書き連ねていこうと思う。
ちなみに自分はWPFで制作してるのでC++に関してはさっぱりです。

いい歳してCとC++、果てはjavaまでもよく分かってないんでちょっと将来が心配。。。

さて今回はもっとも基本となるColorFrameReaderについて。
RGB映像を出力するのに必要なFrameReader、色情報だけなので扱い方もすぐ覚えられます。
極力少ないロジックでRGBカメラを起動させましょう。

■用意するもの
・当たり前だけどKinect
・今回の主役ColorFrameReader
・一応のFrameDescription
・カラーデータを退避させるバッファ領域の配列byte[]
・WriteableBitmap

上から順にこう。
private static KinectSensor kinect = null;
private ColorFrameReader cReader = null;
private FrameDescription cDesc = null;
private byte[] cBuff = null;
private WriteableBitmap wBitmap = null;


まずはKinectをスタートさせる前に下準備としてもろもろ定義しておく。
FrameDescriptionはメモリへの負荷と言う面でFrameArrived内で毎回読み出すのはナンセンスのようなので、
自分はいつもWindowのコンストラクタかLoaded時にやってます。
(むしろ固定値でも構わないとすら思ってるけど・・・)

kinect = KinectSensor.GetDefault();
cReader = kinect.ColorFrameSource.OpenReader();
cDesc = kinect.ColorFrameSource.FrameDescription;
cBuff = new byte[cDesc.Width * cDesc.Height * 4];
wBitmap = new WriteableBitmap(cDesc.Width, cDesc.Height, 96.0, 96.0, PixelFormats.Bgra32, null);


1つ1つ解説しておくと
kinect はいいでしょう、インスタンスを得るためのおまじない。
cReader はカラーデータを取得するためのおまじない。
cDesc はカラーフレームソースの定義情報を得るためのおまじない。
cBuff はカラーデータを入れる領域を確保してるわけだけど、自分は最初「4」ってなんやねんって思った。
これは色情報が1ピクセル/4バイトだから1920*1080の画角にはその4倍のバイトデータがあるってことだね、そりゃそうだね。
wBitmap はまぁそのまま、描画する大きさをちゃんと定義すればおk。

定義が済んだらこれらを操作するプロシージャを用意する。
cReader.FrameArrived += cReader_FrameArrived;

こうすることでColorFrameReaderが毎フレームデータを取得してくるので
その度にフレームごとの操作をしてあげればよい。

KinectをOpenするのを忘れずに。
Kinect.Open.();

ここまで通して書くとこうなる。
public MainWindow()
{
InitializeComponent();
this.Loaded += MainWindow_Loaded;

kinect = KinectSensor.GetDefault();
cReader = kinect.ColorFrameSource.OpenReader();
cDesc = kinect.ColorFrameSource.FrameDescription;
cBuff = new byte[cDesc.Width * cDesc.Height * 4];
wBitmap = new WriteableBitmap(cDesc.Width, cDesc.Height, 96.0, 96.0, PixelFormats.Bgra32, null);

cReader.FrameArrived += cReader_FrameArrived;
}

private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
kinect.Open.();
}

private void cReader_FrameArrived(object sender, ColorFrameArrivedEventArgs e)
{

}


さて、思ったより長くなったので次回へ続く・・・笑
(捕捉)
kinect.Openのところですが、Exciteブログの仕様なのか
Openメソッドとして記述するとエラーが起こり投稿出来ませんでした。
多分jsの記述とバッティングするのを防ぐためだろうけど。
エスケープかなんかすればいいんだろうけど調べるのがめんどいので
Openと()の間にドットを入れてます。

[PR]
by onigirism | 2015-08-25 11:34 | Kinect | Comments(0)

ジェネリックコレクション所感

今さらまとめる話でもないのでここには書かないが、一応

こちらのサイト様がすごく参考になる

なんかもう便利だねぇ、ジェネリック何某いうのは。

ListやDictionaryはセオリーだからいいとしても

Queueってのはみんなプログラマ始めてどこで情報仕入れたんだろう、これもメジャーなのかな?

自分がQueueの存在を知ったのは、実はごく最近で
Kinectのスムージングを実装した時の話。
Pointをバッファに貯め込んで毎フレーム順番に平均化した値を算出する部分でQueueが登場した。
ソースは以下のような感じ

private Queue<CameraSpacePoint> pointBuffer = new Queue<CameraSpacePoint>();
private Queue<CameraSpacePoint> pointBuffer2 = new Queue<CameraSpacePoint>();

private CameraSpacePoint SmoothingFilter(CameraSpacePoint newPoint, int parameter=5)
{
pointBuffer.Enqueue(newPoint);
if (pointBuffer.Count <= parameter)
{
return newPoint;
}
pointBuffer.Dequeue();
CameraSpacePoint[] list = pointBuffer.ToArray();
CameraSpacePoint point = new CameraSpacePoint();
float x = 0;
float y = 0;
float z = 0;
int n = pointBuffer.Count;
for (int i = 0; i < pointBuffer.Count; i++)
{
CameraSpacePoint p = list[i];
x += p.X;
y += p.Y;
z += p.Z;
}
point.X = x / n;
point.Y = y / n;
point.Z = z / n;

return point;
}

確か上記もどこかのサイト様を参考にさせていただいた。
あと、この手の処理はCameraSpacePointよりはColorSpacePointの方が多いから
これを丸々Color系に書き換えたソースも作った。CoordinateMapperで変換した後にzが消えるだけなんだけどw
引数のparameterは無くてもいいと思うから、デフォルトで5ぐらい与えてるけど固定でもいい気がする。

てかExciteはjsアップロードできねーのか、ソースがクソみたいな表示だ。
インデントもプレビューがバカっぽくて何かやだなぁ。


[PR]
by onigirism | 2015-08-11 11:00 | C# | Comments(0)