【C#】四捨五入

C#で、これまで四捨五入というと何となく

 

double y = (int)(x + 0.5);

 

とか、

 

double y = System.Math.Round(x);

 

と、行っていたのですが、画像処理で補間処理を行う時に、座標を四捨五入しようとすると、実は自分の思う通りに動いていなかった事に今更ながらに気が付いた...

 

何はともあれ、int、Roundを使った方法にプラスして、Floorを使って、このようなコード↓

int i; 
double x; 
double y_int, y_Round, y_Floor; 

for (i = -30; i <= 30; i++) 
{ 
	x = i * 0.1; 
	y_int = (int)(x + 0.5); 
	y_Round = System.Math.Round(x); 
	y_Floor = System.Math.Floor(x + 0.5); 

	System.Diagnostics.Debug.WriteLine( 
		x.ToString() + ", " + 
		y_int.ToString() + ", " + 
		y_Round.ToString() + ", " + 
		y_Floor.ToString() 
	); 
}

を実行すると、結果は下図のようになります。

 

 

これを見ると、intを使った方法では、-1.4~+0.4までがとなり、マイナス側の結果がいまいち。

Roundを使った方法では、一見良さそうなのですが、よ~く結果を見てみると、

0.50に、1.52になっている。

 

これは銀行型丸め(偶数丸め)と言うらしく、整数の間の値は、最も近い整数に丸めこまれるが、距離が同じ場合は偶数の値を返すとのこと。

(参考)

Math.Round メソッド

http://msdn.microsoft.com/ja-jp/library/wyk4d9cy.aspx

 

そんな事、全く知らなかった~

 

という事で、結局はFloorを使うと、小数の値が10個ずつ整数へ変換されているので、画像の座標に関する四捨五入では、ムラなく整数へ変換されているFloorを使うのが良さそうです。-0.5⇒0, -1.5⇒-1へと変換される部分が、ちょっと気持ち悪いですが。

 

(追記)
コメントにもあるように、数学的には四捨五入は
double y = System.Math.Round(x, MidpointRounding.AwayFromZero);
とすると良いと思います。

ここでの記事は、あくまで、座標を丸める場合のお話です。

 

C#へ戻る

【C#】手動ダブルバッファによる高速描画

先日、Graphicsオブジェクトの違いによる描画速度の比較として、割と一般的なGraphicsオブジェクトに対して、描画速度を比較を行いましたが、結果、DoubleBufferedが有効な時にPaintイベントで取得するGraphicsオブジェクトに対して描画するのが一番、良さそうな結果となりました。

 

しかし、Paintイベント内で描画処理を行うには、描画する内容を変えたい時など、面倒なので、手動でダブルバッファによる描画方法を検討してみました。

 

手動のダブルバッファの方法については、このページ↓に分かりやすくまとまっています。

 

バッファリングされたグラフィックスを手動で描画する

http://msdn.microsoft.com/ja-jp/library/ka0yazs1%28v=vs.90%29.aspx

 

この手動のダブルバッファについて、前回と同様に描画速度を比較してみると、以下のようになりました。(BufferedGraphicsの部分が結果です。)

 

【描画速度の比較】

 

 

画像を描画する方法は、他のどの方法よりも高速に描画する事ができました。

 

【線の描画速度の比較】

 

線を描画する分には自動のDoubleBufferを使った方法をさほど変わらない結果となりました。

(処理時間にも多少ばらつきがあります。)

 

この画像描画、線の描画の両方を見ても、手動で行うダブルバッファの描画は効果的な用です。

 

参考までに、手動で行うダブルバッファの描画のサンプルプログラムを置いておきます。

 

BufferedGraphicsContext.zip  (Visual Studio C# 2008 Express)

 

C#へ戻る

【C#】Graphicsオブジェクトの違いによる描画速度の比較

C#に限らず.NETのプログラムでは絵や線などを描画するにはGraphicsオブジェクトに対して描画を行いますが、Graphicsオブジェクトの作成方法で描画速度や挙動が異なります。

 

Graphicsオブジェクトを取得するメソッドにはCreateGraphics、FromHwnd、FromImageと、コントロールのPaintイベントのPaintEventArgsクラスのGraphicsプロパティから取得する方法があります。

 

まずは、結果から。

評価は画像を描画する速度と、線を描画する速度とで比較しました。

 

【描画速度の比較】

こちらはフォームのクライアント領域のサイズ、および描画するGraphicsオブジェクトを変えながら、サイズ1024×1024の画像を2枚、交互に表示した場合の結果です。

 

(評価プログラムのイメージ)

 

(描画速度)

 

上記結果はフレームレートなので、値が大きいほど描画速度が速くなります。

 

これを見ると、CreateGraphicsを使った場合は、描画する領域が小さい場合は速くなりますが、DoubleBufferedの時が比較的速い結果となりました。

 

DoubleBufferedとはフォームのDoubleBufferedプロパティをtrueに設定し、PaintイベントのPaintEventArgsクラスから取得したGraphicsプロパティに描画した場合です。

 

FromImageはフォームのクライアント領域と同じBitmapオブジェクトを作成して、そのBitmapをフォームのBackgroundImageに指定し、このBitmapからFromImageメソッドでGraphicsオブジェクトを取得した場合です。

 

【線の描画速度の比較】

こちらも同様にフォームのクライアント領域のサイズ、および描画するGraphicsオブジェクトを変えながら、フォームのクライアント領域に1画素おきの縦、横の線を描画した時の結果です。

 

(評価プログラムのイメージ)

 

(描画速度)

 

上記結果は描画が完了するまでの時間なので、値が小さいほど描画速度が速くなります。

こちらもDubleBufferedが圧倒的に速い結果となりました。

 

【考察】

結果からするとフォームのDoubleBufferedプロパティをtrueにしてPaintイベントのPaintEventArgsクラスから取得したGraphicsプロパティに描画するのがベストのようです。
ただし、Paintイベント内で描画してもBackgroundImageがnullでない場合は、描画速度が遅くなるので注意して下さい。

ちなみに、今回はフォームに描画しましたが、PictureBoxではDoubleBufferedプロパティがありません。

しかし、PictureBoxでも試してみた限り、PictureBoxではDoubleBufferedプロパティがtrueの時と同じ動作をしてくれるようです。

 

画像を描画する場合、DrawImageメソッドで描画したあとにフォームのRefreshメソッドが必要なFromImageを使った描画が遅くなりました。

 

線を描画する場合は、線を一本一本描画する様子が見えるか?見えないか?で差が出ています。

FromaImageとDoubleBufferedの場合は一旦、メモリに描画してからフォーム上に表示されるので、高速な結果となりました。

逆にCreateGraphicsなどを使った線の描画はちょっと遅すぎ...

 

ただ、Paintイベントで画像や線を描画するのは、ちょっと面倒くさいかと思います。

そんな時に、ダブルバッファを手動で行う手法を別途まとめました。↓

手動ダブルバッファによる高速描画

 

C#へ戻る

【Visual Studio】コントロールの配置順序を変更する方法

フォーム上に先にピクチャボックスを配置してしまい、後からツールバーを配置したくなった時、ピクチャボックスを親にドッキングしたときに、ピクチャボックスがツールバーの下側に回り込んで、困った事は無いでしょうか?(私はたまにやってしまいます。)

 

ピクチャボックスを先に配置し、ツールストリップを後から追加し、ピクチャボックスを親にドッキングする場合

 

 

ピクチャボックスがツールストリップの下に回り込んでしまう例↓

 

 

本来であるなら、ツールストリップを先に配置し、次にピクチャボックスを配置すれば問題ないのですが、上図の様になってしまった場合は、ピクチャボックスをマウス右クリックで選択し、最前面へ移動をクリックすすると、ピクチャボックスがツールストリップの下へ配置されます。

 

もしくは逆に、ツールストリップを右クリックし、最背面へ移動をクリックすると、同様にピクチャボックスがツールストリップの下側へ配置させます。(こっちの方が汎用的ですね。)

 

 

すると、このよう↓にピクチャボックスがツールストリップの下側に来てくれます。

 

 

これを知る前までは、ピクチャボックスを切り貼りして、順番を変えていました...

 

Visual Studioへ戻る

【C#】ユーザーコントロールに『親コンテナにドッキングする』を追加する

ピクチャボックスなどのコントロールでは、コントロールの右上に黒い三角のマークが表示され、この三角のマークをクリックすると「親コンテナにドッキングする」などを行う事ができます。

 

 

自作のユーザーコントロールには、この三角のマークが表示されず、親コンテナにドッキングするにはDockプロパティを Fill に設定していると思います。

 

しかし、PictureBoxなどで慣れ親しんでいるので、この三角マークを出したい!

という事で、調べてみましたが、意外と簡単。

 

クラスの属性に

 

[Docking(DockingBehavior.Ask)]

 

を追加するのみ。(クラス宣言の直前に記載して下さい。)

例えば、こんな感じ↓

namespace WindowsControlLibrary1
{
    [Docking(DockingBehavior.Ask)]
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }
    }
}

これで、ユーザーコントロールにも親コンテナにドッキングするを追加する事ができます。

 

 

ちなみに、この黒の三角マークはスマートタグというそうです。

【C#】XMLドキュメントコメント

クラスやメソッドのコメントは以前は

//--------------------------------------------------------------- 
//【関数名 】:Test 
//【処理概要】:評価用の関数 
//【引数  】:Para1 = パラメータ1 
//      :Para2 = パラメータ2 
//      :Para3 = パラメータ3 
//【戻り値 】:エラー内容 
//【備考  】: 
//--------------------------------------------------------------- 
int Test(int Para1, float Para2, double Para3){

のような感じで書いていたのですが、.NET環境、特にC#においてはXML形式でコメントを書くことで、より応用が広がります。

 

と言っても、C#ではXMLの部分は自動で書いてくれるので、かなり便利です。

やり方は以下の通り。

 

まず、クラスやメソッド、フィールドのある程度の大枠(メソッドの場合は、少なくとも引数の部分)を書いておきます。

public int Test(int Para1, float Para2, double Para3) 
{ 
	return 0; 
}

次に、コメントを付けるクラスやメソッドなどのすぐ上の行で////を3個入力します。
すると、自動で以下のようなコメントが付いてくれます。

/// <summary>
/// 
/// </summary> 
/// <param name="Para1"></param> 
/// <param name="Para2"></param> 
/// <param name="Para3"></param> 
/// <returns></returns> 
public int Test(int Para1, float Para2, double Para3) 
{ 
    return 0; 
}

<summary>はクラスやメソッドなどの概要
<param>は引数の説明
<returns>は戻り値の説明
を表します。
他にも使えるタグがあるので、詳細は下記msdnを参照下さい。
http://msdn.microsoft.com/ja-jp/library/5ast78ax

 

このタグに挟まれた部分にそれそれの説明を下記のように記載します。

/// <summary>
/// Testメソッドの概要
/// </summary> 
/// <param name="Para1">Para1の説明</param> 
/// <param name="Para2">Para2の説明</param> 
/// <param name="Para3">Para3の説明</param> 
/// <returns></returns> 
public int Test(int Para1, float Para2, double Para3) 
{ 
    return 0; 
}

するとインテリセンスの表示の時に

 

 

のように、コメントに記載した部分がヒントで表示してくれます。

 

各引数の説明も、このように↓

 

 

表示しれくれます。

 

さらに、プロジェクトのプロパティでビルド→XMLドキュメントファイルの部分にチェックをいれ、XMLファイルを出力させる設定にすると、Sandcastleというようなヘルプファイル作成ソフトを使って、このXMLファイルを渡すとmsdnのようなヘルプファイルを作る事も可能になります。

 

他のVB.NETやC++/CLIでは、自動でXMLの部分を作ってくれないのですが、XMLの部分は同じ文法で書く事ができます。

 

やっぱC#ってすごい!

【参考書籍】〔速攻入門〕 C#プログラミング すぐに現場で使える知識

最近はC#を基礎から勉強しようと思い、わんくま同盟でも活躍されている著者の面々にあこがれて買ったこの本。
サブタイトルの「JavaかC++の知識があれば、いっそう有利な最短ルート」とあるように、この本はC++やJavaと比較しながら説明されています。

 

とくに良かった点は、「C#の××はC++では○○に相当しますが、△△な点が異なります。」というような表現は多かった事。
知りたかったポイントや、知らなくてちょっとヒヤっとした点など、簡素にまとまっています。

 

C#は過去に何かしらのプログラムをやった事があって、.NETの名前空間に慣れれば何となくプログラムできてしまいますが、逆に過去の知識が邪魔をして陥り易いミスもあると思います。

 

そんなC#をある程度やって、初級から中級、上級をめざす方にお勧めな本だと思います。
逆にまったくC#が初めてだと、ちょっと難しく感じると思います。

 

 

目次

Part 1 C#の文法 速攻入門
Chapter 1 C#とは?
1.1 C#の特徴
1.2 .NET Framework
Chapter 2 プログラム構造
2.1 基本的な構文―Hello World
2.2 コメント
2.3 名前空間
2.4 型―名前空間に属するメンバー
2.5 Mainメソッド
Chapter 3 手続きの記述
3.1 式の概要
3.2 ステートメントの概要
3.3 変数の宣言
3.4 演算子
3.5 制御構文
3.6 オーバーフローのチェック
3.7 例外処理
3.8 usingステートメント
3.9 型情報
3.10 既定値
3.11 lockステートメント
3.12 ラムダ式
3.13 クエリ式
Chapter 4 型
4.1 値型と参照型の違い
4.2 組み込み型
4.3 ジェネリック
Chapter 5 クラス
5.1 クラスの定義
5.2 アクセシビリティ
5.3 クラスのメンバー
5.4 静的メンバー
5.5 継承
5.6 クラスの分割定義
5.7 外部メソッド
5.8 匿名クラス
Chapter 6 インターフェイス
6.1 インターフェイスの定義
6.2 インターフェイスの実装
Chapter 7 構造体
7.1 構造体の定義
7.2 クラスあるいは構造体の選択
Chapter 8 列挙型
8.1 列挙型の定義
8.2 列挙型の利用
8.3 ビットフラグ
8.4 拡張メソッドの利用
Chapter 9 デリゲート
9.1 デリゲートの定義
9.2 デリゲートの利用
9.3 匿名関数
Chapter 10 配列
10.1 配列の利用
10.2 多次元配列
10.3 System.Array型
10.4 配列の共変性
Chapter 11 Null許容型
11.1 Null許容型の利用
11.2 Nullable構造体
11.3 型変換
11.4 演算子
Chapter 12 属性
12.1 属性の例
12.2 属性の定義
12.3 属性の適用
12.4 属性値の実行時取得
12.5 C#コンパイラが使用する属性
12.6 相互運用のための属性
Chapter 13 安全でないコード
13.1 ポインターとは?
13.2 「安全でないコード」の注意点
13.3 unsafeコンテキスト
13.4 ポインター型
13.5 sizeof演算子の利用
13.6 アドレスの固定化
13.7 スタックの割り当て
13.8 固定サイズバッファーの埋め込み
Part 2 C#のポイント 速攻入門
Chapter 1 ジェネリック
1.1 ジェネリックの利用方法
1.2 内部的な方式の比較
1.3 実装方式の比較
1.4 メンバー参照
1.5 強い型付け
Chapter 2 定数と読み取り専用
2.1 バージョニング問題
2.2 フィールドの再代入禁止とオブジェクトの不変性
2.3 引数の既定値
Chapter 3 例外処理
3.1 例外の利用場面
3.2 try-catchとtry-finally
Chapter 4 リソース管理
4.1 ガベージコレクション
4.2 デストラクター
Chapter 5 イベント駆動
5.1 イベント構文
5.2 イベントとメモリリーク
Chapter 6 暗黙的な型指定
6.1 冗長性の排除
6.2 オーバーロードとジェネリック
6.3 varと匿名型
Chapter 7 データ処理
7.1 反復子構文
7.2 反復子構文を使ったデータの加工
7.3 LINQ
Part 3 C#活用 速攻入門
Chapter 1 ファイルの読み書き
1.1 サンプルの内容
1.2 LINQを使ったCSVファイルの読み書き
1.3 ReadLinesの内部挙動
1.4 LINQを使わない例
1.5 ファイルの読み書きに関係するその他のクラス
Chapter 2 GUI
2.1 簡単なGUIアプリケーションの例
2.2 GUIと非同期処理
2.3 視覚的デザインツールの利用
2.4 ビューの分離
Chapter 3 Webアクセス
3.1 Webページの表示
3.2 Webアクセスのためのクラス
3.3 Webサービスの利用
3.4 Webアクセスに関係するその他のクラス
Chapter 4 Win32 APIとCOMの扱い
4.1 単純なP/Invokeの例
4.2 文字列を受け渡しするP/Invoke
4.3 文字列を渡す場合のその他の方法
4.4 構造体を利用したP/Invoke
4.5 COMのやり取り
4.6 MS Officeなどとのやり取り
Chapter 5 データベースアクセス
5.1 一番シンプルなADO.NET
5.2 ExecuteReaderとMARS
5.3 DataSetを使ったデータアクセス方法
5.4 DataSetなどで隠蔽されたデータの行方
5.5 DataSetを使ってデータの絞り込みを行う方法
5.6 DataSetを使ったデータの更新削除
5.7 LINQ to SQLを使ってデータの絞り込みを行う方法
5.8 LINQ to SQLを使った更新方法
5.9 LINQ to SQLのその他の違い
5.10 LINQ to SQLのSELECTでストアドプロシージャを使う方法
5.11 Entity Frameworkを利用したデータアクセス
5.12 Entity FrameworkのSELECTでストアドプロシージャを使う方法
5.13 どの技術を使うのが良いのか?
Chapter 6 並列処理
6.1 Threadクラスを利用する方法
6.2 同期化の方法
6.3 プロセスをまたいだ排他処理
6.4 スレッドセーフなコレクション
6.5 デリゲートを利用する方法
6.6 BackgroundWorkerを利用する方法
6.7 Taskを利用する方法
6.8 Parallel.For,Parallel.ForEachを利用する方法
6.9 Parallel LINQを利用する方法
Chapter 7 実行時コード生成
7.1 静的なコード
7.2 リフレクション
7.3 動的に生成したコードのキャッシュ

 

 

【参考書籍】C#.NETアプリケーション開発 徹底攻略 C#3.0/.NET Framework3.5対応

この本はたまたま本屋で見つけた本なのですが、よくあるTipsやリファレンス系の参考書籍とは違い、実際のプログラムでどのようにすべきか?みたいな事が書かれています。

 

.NETのプログラムをしていると、結果は同じ様になる事でも幾つかのメソッドが用意されているため、これで本当にいいのか?.NETを使っていると処理が遅くないか?ガーベージコレクションはどうなってるのか?というようなモヤモヤ感が残る場合があります

これらの事が理論的に書かれているので、とても参考になりました。

 

あまり初心者向けな本ではありませんが、C#である程度プログラムできるようになった人が、読むと良いと思います。

 

 

目次

Chapter 01 導入:.NET Frameworkと開発環境

1.1 本書の目的

1.2 対象とする読者

1.3 本書の構成

1.4 .NET Framework概要

1.5 .NET Frameworkの現在

1.6 開発環境

1.7 コードサポート

Chapter 02 .NET Frameworkアプリケーション設計

2.1 設計概要

2.2 イベント/デリゲートをベースとしたイベント駆動型設計

2.3 型セーフな設計

2.4 Windows Formsアプリケーション設計

2.5 マルチスレッド/非同期制御

2.6 例外設計

2.7 データ型

2.8 リフレクション

2.9 ネイティブアプリケーション層の利用

Chapter 03 チューニング

3.1 .NET Frameworkの性能

3.2 チューニングポイント

3.3 メモリー管理/メモリチューニング

3.4 パフォーマンスプロファイリング

3.5 最初の.NET Frameworkチューニング

Chapter 04 リリース管理/セキュリティ

4.1 .NET Frameworkの実行環境

4.2 ClickOnce

4.3 ソースコードの保護

Chapter 05 COMアプリケーション連携

5.1 .NET FrameworkとCOM

5.2 レジストリ登録不要なCOM

5.3 .NET Frameworkを使用したCOMコンポーネント

Chapter 06 新しい.NET Framework/Silverlight

6.1 最新の.NET Framework

6.2 C# 3.0

6.3 Silverlight

6.4 Silverlightアプリケーションの作成

 

 

C#(.NET)からOpenCVを使う方法、OpenCvSharpのインストール方法

OpenCVはシンプルな画像表示用のウィンドウも用意されているので、簡単に画像処理を試したい場合には非常に良いのですが、少し凝ったウィンドウを作成しようとすると、やっぱり.NETからOpenCVを触りたくなります。

 

.NETの言語(VB.NET、C#、C++/CLI)からOpenCVを使う方法は、だいたい以下の通り

  • .NETのラッパーライブラリを使う
  • 自作でラッパーライブラリを作成する
  • C++/CLIから直接使う

となりますが、実質的にはOpenCvSharpを使う事になると思います。

 

OpenCvSharpのインストール方法は、現在ではNuGetによりプロジェクトごとにインストールします。

 

OpenCvSharpのインストール方法

まず、インストールするC#プロジェクトを用意します。

新規でC#プロジェクトを作成する場合は、次のように行います。

Visual Studio を起動後、新しいプロジェクトの作成をクリックします。

次に Windowsフォームアプリケーション(.NET FRamework)を選択し、次へをクリックします。

プロジェクト名、場所を指定し、作成をクリックします。

これで、以下のようにフォームが表示されたらベースとなるC#プロジェクトが作成されています。

 

次に、このC#プロジェクトにNuGetでOpenCvSharpをインストールします。

メニューのプロジェクト→NuGetパッケージの管理をクリックします。

表示された画面で、 参照 を選択し、その下のテキストボックスに OpenCvSharp と入力すると、OpenCvSharpの一覧が表示されるので、この中から OpenCvSharp.Windows を選択します。

OpenCvSharp.Windows を選択すると、右側に インストール ボタンが表示されるので、これをクリックします。

しばらくすると、インストールが完了します。

OpenCvSharpがインストールされたか?確認するには、プロジェクトの参照の部分の表示を展開すると、OpenCvSharpの名前空間が表示されている事を確認します。

簡単にOpenCvSharpの動作を確認します。

ツールボックスの中から Button を選択し、フォーム上にドラッグ&ドロップします。

ボタンをダブルクリックし、C#コードを表示し、上の方に、

using OpenCvSharp;

と入力し、ボタンイベントの部分に以下のように記載します。

private void button1_Click(object sender, EventArgs e)
{
    var img = new Mat(new OpenCvSharp.Size(256, 256), MatType.CV_8UC3, new Scalar(35, 123, 254));

    Cv2.ImShow("Image", img);
}

参考までに、Formの全コードを示します。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

using OpenCvSharp;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            var img = new Mat(new OpenCvSharp.Size(256, 256), MatType.CV_8UC3, new Scalar(35, 123, 254));
            Cv2.ImShow("Image", img);
        }
    }
}

この状態で、▶開始 ボタンをクリックし、以下のように表示されれば OpenCvSharp のインストールは成功しています。

 

OpenCvSharpを使うポイント

2021年現在、OpenCVの情報はPythonであふれているので、OpenCvSharpの情報を探すのは難しくなってきています。

OpenCvSharpの情報を入手するには、少し古くなりましたが、作者であるSchimaさんのページを参照することをお勧めします。

http://schima.hatenablog.com/archive/category/OpenCvSharp

リファレンスは英語になりますが、こちらです。

http://shimat.github.io/opencvsharp/api/OpenCvSharp.html

 

あとは、OpenCvSharpは基本的にOpenCVのC++版のラッパーライブラリであるため、OpenCVのC++の情報を検索し、OpenCvSharpでは、どうするのか?を推測するのもイイかと思います。

 

参考

https://github.com/shimat/opencvsharp

http://shimat.github.io/opencvsharp/api/OpenCvSharp.html

OpenCVへ戻る