【C#】24bitと32bitカラー画像の表示速度の比較

カラー画像の24bitカラーと32bitカラーの画像はR,G,Bの成分はそれぞれ8bitで表現され、32bitの時に、残りの8bit部分で画像の透過率として使われる場合もありますが、画像処理的には、あまり使われる事はありません。

そのため、カラー画像と言えばメモリ容量の少ない24bitカラー画像を扱う事が、個人的には多かったのですが、GPU処理やSIMD処理などを考慮すると、メモリアクセス的に有利な32bitカラーの方が都合が良い場合もあります。

 

そこで今回は、24bitカラーと32bitカラーとで、表示速度に違いがあるか?調べてみました。

 

評価に用いたプログラムのイメージはこちら↓

 

プログラムは以下のような物で、PictureBoxのImageに指定するBitmapクラスオブジェクトのPixelFormatが

  • Format24bppRgb
  • Format32bppRgb
  • Format32bppArgb
  • Format32bppPArgb

の違いによって違うか?

また、表示する画像データが24bitのカラー画像と32bitのカラー画像で違いが出るか?を検証してみました。

 

 

表示に用いた画像サイズは1024×1024画素で24bitと32bitのカラー画像となります。

この画像を1000回表示した時の表示時間から1秒あたりに表示できた画像枚数(フレームレート[fps])を算出し、この値を5回計測し平均したものが以下の結果となります。

 

24bitカラー画像 32bitカラー画像
Format24bppRgb 139.7 142.3
Format32bppRgb 140.3 150.1
Format32bppArgb 123.6 126.6
Format32bppPArgb 182.0 187.8

 

これを見ると、32bitカラー画像の方が少し表示速度が速く、Graphicsオブジェクトに用いたPixelFormatは Format32bppPArgb が少し突出して速い事が分かりました。

 

この Format32bppPArgb とは何か?調べてみると

 

1 ピクセルあたり 32 ビットの形式であることを指定します。つまり、アルファ、赤、緑、および青のコンポーネントに、それぞれ 8 ビットを使用します。 アルファ コンポーネントに応じて、赤、緑、および青のコンポーネントが事前乗算されます。

 

とのこと。

いまいち理解できませんが、事前乗算している事で速いのか??

 

という事で、FromImageメソッドで使うGraphicsオブジェクトは Format32bppPArgb を使うと良さそうです。

 

少し前(32bitOSがメインだった時代)では、搭載できるメモリサイズは2GBだし、実質的にプログラムが使用できるのは1GB程度しか無かったため、メモリサイズはできるだけ節約したかったため、カラー画像と言えば24bitと思っていたのですが、今では64bitOSが当たり前で、メモリも4~8GBぐらいは普通に搭載されているので、32bitカラーデータもありですね。

 

画像処理のためのC#テクニックへ戻る

【C#3.0~】拡張メソッド

C#3.0(Visual Studio 2008)からは、拡張メソッドよ呼ばれる、既存の型やクラスにメソッドを追加することが出来るようになりました。

 

と、聞くと、クラスを継承すれば出来るでしょ!という意見があろうかと思いますが、拡張メソッドでは、そもそも継承できない sealed のクラスに対しても、元の型やクラスを変更することなく、メソッドを追加することが出来ます。

 

この拡張メソッドの記述方法は

staticクラスに、staticのメソッド(これが拡張メソッドとなる)を追加し、最初の引数に拡張元の型やクラスの引数を書き、型やクラスの前に this を付けます。

 

具体的には以下のようになります。

static class ExtensionMethod
{
    public static void ScaleAt(
        this System.Drawing.Drawing2D.Matrix matrix, 
        float scaleX, 
        float scaleY, 
        System.Drawing.PointF point
        )
    {
        // 原点へ移動
        matrix.Translate(-point.X, -point.Y, System.Drawing.Drawing2D.MatrixOrder.Append);
        // 倍率変換
        matrix.Scale(scaleX, scaleY, System.Drawing.Drawing2D.MatrixOrder.Append);
        // 元の位置へ戻す
        matrix.Translate(point.X, point.Y, System.Drawing.Drawing2D.MatrixOrder.Append);
    }
}

この例は、System.Drawing.Drawing2D.Matrixクラスに、指定した点を中心に拡大縮小を行うメソッド(ScaleAt)を追加しています。

(指定した点を中心に回転するRotateAtメソッドはあるのに何で??と思っていたんですよ)

 

この拡張メソッドを使用する側では、以下のように、通常のMatrixクラスのRotateAtメソッドと同じように、今回拡張したメソッド(ScaleAt)を使う事が出来るようになります。


var mat = new System.Drawing.Drawing2D.Matrix();

// (20,30)を中心に30°回転(通常のメソッド)
mat.RotateAt(30, new PointF(20, 30), System.Drawing.Drawing2D.MatrixOrder.Append);

// (100, 150)を中心にX方向に2倍、Y方向に3倍(拡張メソッド)
mat.ScaleAt(2, 3, new PointF(100, 150));

 

← C#2.0からの脱却 へ戻る

ELP ソニー800万画素センサ搭載の激安USBカメラ購入

ELPというメーカーからソニーの800万画素センサを搭載し、CSマウントレンズ付きでケース付きの筐体でありながら、アマゾンで¥9,145という激安カメラがあり、気になって買ってみました。

8MP USBカメラ Webcam Linux windows video camera Webカメラ800万画素 Sony IMX179 sensor ウェブカメラ (2.8-12mm 可変焦点レンズ)

 

 

なぜか?コンクリートに固定用のネジが付いています。

三脚ねじ用の固定プレートも付いています。

CSマウントレンズもちゃんと取り外せます。

USBケーブルは本体から地下出しです。中継コネクタも見たことない。。

 

この構成で¥9,145って、どうしたら、この値段にできるんだろうか???

 

気になるのは画質ですが、少し古いのですが、LogicoolのC910というUSBカメラと撮影した画像を比較してみました。

 

Logicoolのカメラ(左側)と、ELPのカメラ(右側)を置いてキーボードを撮影しました。

ELPのカメラは最大3264×2448画素で撮影できるのですが、Logicoolのカメラが2592×1944画素までだったので、両方とも2592×1944画素で撮影しました。

ELP Logicool

 

こうして比べてみると、ELPのカメラは発色もいいし、くっきりしているので、すごく良く見えるのですが、ブロックノイズのような、変なノイズが目立つ事が多かったです。

 

ノイズの多い画像↓(画像をクリックして拡大して見てみてください)

上の画像の一部拡大↓

ただ、OpenCV等でこのカメラを使う事前提であれば、撮影した画像にメディアンフィルタをかけると、そこそこ良い感じの絵になってくれます。

メディアンフィルタを掛けた画像↓

 

カラー画像の比較(WD=300mmぐらいで撮影)

ELP Logicool

 

ということで、くっきりとは撮影できますが、ノイズが少し多めのこのカメラ。

自信をもって勧める事ができるか?!と言われると微妙なところですが、なにせ安いので、とりあえず買ってみるのもアリな感じのカメラでした。

 

(2020.3.31追記)

OpenCVで 3264 x 2448 画素 で撮影した画像がこちらです。

SoftBankからY!mobileへの乗り換えでの注意点(私の失敗談)

これまで約10年間、ソフトバンクを使ってきたのですが、いつのまにか毎月の料金も6000円ちょっとに。

そこでY!mobileにMNPで乗り換えたのですが、その時に私がやらかした失敗を共有しておきます。

 

iPhoneに保存された@i.softbank.jpのメールが見れなくなる

キャリアを乗り換えるので、当然、キャリアのメール(@i.softbank.jp)のメールも使えなくなるのは理解していたつもりでしたが、iPhone内に保存されているメールも見れなくなるのは、あまり理解していなかった。。

iPhone内に保存されているメールは約1年間分ぐらいのメールは、メール本文も含めてiPhone内にメールデータが保持されているのですが、それよりも古いメールは、メールタイトルのみが保持されて、メール本文は、メールを開くたびにサーバーから取得されるようになっています。

古いメールを開こうとすると、以下のようなメッセージが表示され、開くことができません。

 

 

このメッセージが表示されてしまうメールは、すでにソフトバンクとの契約が解除された今となっては、何も出来る術がなく。。

 

そこで、かろうじて見る事のできた約1年分のメールはこのページ↓

iphoneのメールをバックアップする3つの方法とは?機種変更/乗り換えMNPもOK【令和元年版】

を参考にしながらGmailへとメールを移動することができました。

この記事を読んでくれている方は、キャリアのメールが使える間に、メールも移動して下さいね。

私は昔の思い出メールを失いました。メールのプレビューで少しだけ見れますが、本文は見れない状態です。

 

回線の切り替えは突然やってくる

私はソフトバンクからMNPの予約番号の取得や、Y!mobileの申し込みもネットで行ったのですが、手続きそのものは簡単にできましたが、回線が切り替わるのは自分のタイミングではなく、Y!mobileのタイミングで回線が切り替わります。

Y!mobileへの申し込みをしている間は、これまで使っていたSoftBankの回線が使えますが、突然、電波が圏外になりiPhoneが使えない状態に!!

新しいiOSでは電波がつながらない不具合もあると聞いていたので、もしやそれか?!

とも思ったのですがず~っとつながらない状態に。

しょうがないので、自宅に帰りWiFiにつながる環境でメールを確認してみたら、Y!mobileから

【ワイモバイルWeb申込事務所】開通通知のお知らせ

なるメールが来ていました。

そんなメール、圏外になったiPhoneじゃ見れないよ!

 

回線がつながらない状態が嫌な人は、Y!mobileの店舗で契約するか、新しいSIMを持ち歩く方がいいでしょうね。

 

ちなみに、Webでの申し込みは木曜日の21時ぐらいに行い、次の日の11時ぐらいに回線が切り替わりました。

つまり、11時から家に帰る20時ぐらいまで、ずっと圏外に。

 

【まとめ】乗り換え前にやっておくこと

・SIMロック解除を行っておくこと

スマホ本体のSIMロック解除はMy SoftBankのページから行うのですが、

回線が切り替わるとMy SoftBankのページに行けなくなります。

・消したくない@i.softbank.jpのメールは他のアカウントのメール(Gmailなど)に移動しておくこと。

受信トレイはもちろん、保存してあるフォルダや送信済みフォルダなど消したくない

メールがないか?確認しておく。

 

以上、私の失敗談でした。

これさえ注意しておけば、料金が安くなって、通信速度も遅くは無さそうなので、きっと快適?だと思います。(まだ、Y!mobile開通2日目なので、よく分かってない。)

iPhone 11 Pro Max購入、レビュー

遅ればせながらiPhone 11 Pro Max(256GB)をアップルストアで\135,000(税別)で購入しました。

GoogleのPixel4と比べてどうかな?と思っていたのですが、Pixel4の夜景モードは気になるところではありますが、iPhoneはこれまでのデータを引き継ぎ易いし、Apple Watchも持っているので、結局、iPhone11にしました。

 

開封の儀

このヘッドフォンはいつもコードレス!?と騙されますよね。

アダプタ側がUSB Type-Cとなり、付属されているケーブルも USB Type-C ⇔ Lightning となりました。

 

付属品の購入

今回のiPhoneと同時に、カバーガラス、本体ケース、ストラップを購入しました。

 

画面のカバーガラス。

この製品にしたのはフチの処理がキレイ(切りっぱなしではない)でガラスの物。

実際に使ってみるとガイド付きで貼りやすかったし、触った感触もヌルスベな感じで、スベスベなんどけど、滑りも良く、満足度の高い製品でした。

ただ、1枚で良かったのですが、1枚の製品が見つからなかった…

本体ケース

これを選んだポイントとしては透明でストラップ穴付き、画面までダンパー部分がまわり込んでいること。

こちらもおおむね良かったのですが、背面はガラス??って感じ。

カバー単体で触ってみると、ポリカーボネイトっぽい感触。

iPhoneに取り付けるとガラスっぽい感触(硬くて少しひんやり)なのですが、まぁ、キレイなのでどちらでもいっか。

しかし、指紋が少し目立ちます。

ストラップ

電車とかでiPhoneを使っている時に落とすのが怖くて、使っている時にはストラップを指に絡めて使用しています。

同様の目的ならスマホリングとかもありますが、スマホの背面が平らにならないのが、どうも気になるので、ストラップを使用しています。

 

付属品を付けた状態

 

カメラの比較

新しいiPhoneに期待するところは、やはりカメラは重要なポイントの一つ。

私はiPhoneXからの機種変更なのですが、iPhoneXとiPhone11ProMaxとを特に差の出やすい夜景の撮影で比較してみました。

 

倍率 iPhone 11 Pro Max iPhoneX
x0.5
x1.0
x2.0

最初はiPhoneXからは、そんなに変わらない??と思っていたのですが、結構、違いが出てて、ビックリ!。ただ、必要以上に明るすぎる感じもするので、場合によっては ☀マーク で明るさを調整した方が良いかも?しれませんね。

 

この撮影場所は約9年前に富士フィルムとHS10というカメラとiPhone3GSとのカメラの比較で撮影した場所なのですが、画像を比べてみると、

HS10
iPhone3GS
iPhoneX
iPhone11Pro

(参考)https://imagingsolution.blog.fc2.com/blog-entry-217.html

 

9年間には夜景を撮るにはやっぱデジカメじゃないと!と思っていましたが、時代の進化ってすごいですね。

 

ここまで夜景がキレイに撮影できるとなると、以前、ソニーのNEX-5Rというカメラを使って撮影した川崎の工場の夜景ももっとキレイに撮影できるかな??

 

ちなみに、今回、夜景の撮影比較に使った場所は海老名駅すぐ横のビナウォークという場所でTBSの「G線上のあなたと私」というドラマの撮影地にもなっていて、ちょっと楽しい。

こんな感じ↓のアングルもありました。

 

…と概ね納得の性能でしたが、iPhone11(↓の左側)は、画面の表示がなんかオレンジ色っぽく見えます。

例えるならLED電球の蛍光灯と電球色ぐらいの違い。

設定→画面表示と明るさ で調整してみても、iPhoneXと同じようにならず。。

画面に貼ったカバーガラスのせいかな??

 

あと、ナイトモード(夜景撮影)で撮影したとき、画像の四隅がちょっと暗いかな。

【C#6.0~】文字列補間($を使った文字列書式設定)

C#6.0(Visual Studio 2015)からは$を使った文字列の書式設定を行う事ができます。

 

C#6.0より前では、String.Format を使って

double a = 355;
double b = 113;
double c = a / b;
var str = String.Format("a = {0}, b = {1}, a / b = {2}", a, b, c);
Console.WriteLine(str); // a = 355, b = 113, a / b = 3.14159292035398

と書いていたところを、C#6.0からは $”{xxx}” を使って

double a = 355;
double b = 113;
double c = a / b;
var str = $"a = {a}, b = {b}, a / b = {c}";
Console.WriteLine(str); // a = 355, b = 113, a / b = 3.14159292035398

のように $ の後に ” ” で文字列を囲って、変数部分は {}の中に直接変数を記入すると、文字列として、文字を連結してくれます。

とても直観的だし、こちらの方が自然な書き方ですよね。

(参考)

https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/tokens/interpolated

 

文字列の書式設定もString.Formatで用いていた文字と同じ書式設定子が使えて、{}内の文字列に : (コロン) を付けて書式指定の文字を記入します。

double a = 355;
double b = 113;
double c = a / b;
var str = $"a = {a:F3}, b = {b:F3}, a / b = {c:F6}";
Console.WriteLine(str); // a = 355.000, b = 113.000, a / b = 3.141593

書式の文字については、以下のページが参考になります。

標準の数値形式文字列

カスタム数値形式文字列

標準の日時形式文字列

カスタム日時形式文字列

書式設定操作の実行

 

← C#2.0からの脱却 へ戻る

【C#4.0~】引数の省略と名前付き引数

C#4.0(Visual Studio 2010)からは引数の省略および名前付き引数が使えるようになりました。

 

引数の省略

なにはともあれ、サンプルをご覧ください。

public static double AddScale(double a, double b, 
                              double scale = 1.0, double offset = 0.0)
{
    return (a + b) * scale + offset;
}

このように、 引数=初期値 のように書くと、その引数は省略して呼びだすことができます。

呼び出し側は

double ans;
ans = AddScale(10, 5);            // ans = 15.0
ans = AddScale(10, 5, 1.0);       // ans = 15.0
ans = AddScale(10, 5, 1.0, 0.0);  // ans = 15.0

のようにすると、どれも同じ結果となります。

もちろん、初期値以外を以下のように

var ans = AddScale(10, 5, 2.0, 1.0); // ans = 31.0

指定することもできます。

 

ただし、省略する引き数の次に省略しない引数を続けることはできません。


public static double AddScale(double a, double b, 
                              double scale = 1.0, double offset)  // これはエラー
{
    return (a + b) * scale + offset;
}

 

名前付き引数

今度はメソッドを呼び出す側のテクニックです。

サンプルとして、前回と同じメソッドを用います。

public static double AddScale(double a, double b, 
                              double scale = 1.0, double offset = 0.0)
{
    return (a + b) * scale + offset;
}

名前付き引数では、引数の名前にコロン(:)を付けてメソッドを呼び出します。

var ans = AddScale(a: 10, b: 5, scale: 1.0, offset: 0.0); // ans = 15.0

この例だと面倒なだけですが、名前を付けて呼び出すと、引数を書く順番はどうでもよくなります。

var ans = AddScale(scale: 2.0, offset: 5.0, b: 5, a: 10); // ans = 35.0

また、引数の省略も同様に出来て、

var ans = AddScale(a: 10, b: 5, offset: 2.0); // ans = 17.0

var ans = AddScale(10, 5, offset: 3.0); // ans = 18.0

と書くことができます。

最初の引数の省略だけでは引数の順番を飛ばして省略(scaleだけを省略)することは出来ませんでしたが、名前付き引数では引数を飛ばして省略することが可能になります。

 

(参考)

https://docs.microsoft.com/ja-jp/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments

 

← C#2.0からの脱却 へ戻る

【C#3.0~】varによる暗黙的な型宣言

C#3.0(Visual Studio 2008)からはvarを用いた暗黙的な型宣言を行う事ができます。

 

例えば、以下のような例

string text = "Sample";

では text の型は = の右辺を見ると 文字列型(string)である事は明白なので、 var を使って

var text = "Sample";

と書くことができます。

一番、使い勝手の良い使い方は、クラスを new する時に、

System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

と書いていたところを var を用いると

var sw = new System.Diagnostics.Stopwatch();

となります。

他にも

List<string> a = new List<string>();

が var だと

var a = new List<string>();

となります。

 

逆に使えないのは、

var a; // これはエラーになる

のように = で初期化されていないと、 var 単独では型がわからないためエラーとなります。

 

他にもクラスのフィールドでは用いる事ができず、メソッド内のローカル変数のみの対応となります。

class Test
{
    var a = "Sample";   // エラー

    public Test()
    {
        var b = "Sample";   // OK
    }
}

 

C#2.0からの脱却 へ戻る

C#2.0(Visual Studio 2005)からの脱却

私が本格的にC#を始めたのはC#2.0(Visual Studio 2005)からなのですが、会社でプログラムをしていると、お客様向けのサンプルプログラムを作成することから、むやみにVisual Studioのバージョンを上げる事もできず、Visual Studio 2005をかなり長い事使用してきました。

現在ではVisual Studio 2015をメインに使用しているのですが、C#の構文はC#2.0をひきずっておりまして。。

最近では、お客様が使っているVisual Studioは古くてもVisual Studio 2010ぐらいでしょうか。

ここでは、少しずつ、便利な機能は取り入れていこう!というのが目的でC#2.0より新しい構文についてまとめていこうかと思います。

 

varによる暗黙的な型宣言 C#3.0~
自動実装プロパティ C#3.0~
拡張メソッド C#3.0~
Parallel.Forによる並列処理 C#4.0~
引数の省略と名前付き引数 C#4.0~
文字列補間($を使った文字列書式設定) C#6.0~

ちなみに、C#のバージョンとVisual Studioのバージョンの対応は以下の通りです。

C#2.0 Visual Studio 2005
C#3.0 Visual Studio 2008
C#4.0 Visual Studio 2010
C#5.0 Visual Studio 2012,2013
C#6.0 Visual Studio 2015
C#7.0 Visual Studio 2017
C#8.0 Visual Studio 2019

(参考)https://en.wikipedia.org/wiki/C_Sharp_(programming_language)#Versions

 

画像処理100本ノックをC#でやってみた

画像処理100本ノック

https://github.com/yoyoyo-yo/Gasyori100knock

https://qiita.com/yoyoyo_/items/2ef53f47f87dcf5d1e14

 

というページがあるのをご存じでしょうか?

最近の画像処理と言えば、OpenCVをPythonでやってみた!

という情報にあふれているのですが、この画像処理100本ノックでは、画像処理の処理部分はOpenCVに頼らずにベタにPythonやC++でプログラムしています。

 

実際、今どきは画像処理のプログラムをベタに組んだところで、車輪の再開発になるだけで意味があるのか??という意見もあろうかと思いますが、1度はやっておくと画像処理の理解が深まるので、おススメです。

 

そこで私も画像処理100本ノックの問題をC#で作ってみました。

ソースコードはGitHubに置いてあります。

https://github.com/ImagingSolution/ImagingDotNet

 

表向きは画像処理100本ノックに沿ってプログラムしていますが、目指すところはC#だけで、そこそこ処理が速くて、OpenCVのPython版のように簡単に使えるC#の画像処理ライブラリ(ImagingDotNet)を作るのが目標です。

本気で使うとなると、エラー処理は甘いし、処理もすごく速い訳ではないので、あくまでも、C#で作る画像処理プログラムのお勉強用です。

 

Q.1.チャンネル入れ替え

var src = new Bitmap("Lena.bmp");
var dst = ImagingDotNet.CvtColor(src, ImagingDotNet.COLOR_BGR2RGB);
入力 出力

C# >> CvtColor.cs cvt_COLOR_BGR2RGB部分

 

Q.2.グレースケール化

var src = new Bitmap("Lena.bmp");
var dst = ImagingDotNet.CvtColor(src, ImagingDotNet.COLOR_BGR2GRAY);
入力 出力

C# >> CvtColor.cs cvt_COLOR_BGR2GRAY部分

 

Q.3.二値化

(参考)https://imagingsolution.net/imaging/binarization/

var src = new Bitmap("Lena.bmp");
var dst = (Bitmap)src.Clone();
ImagingDotNet.Threshold(src, dst, 128, 255, ImagingDotNet.THRESH_BINARY);
入力 出力

C# >> Threshold.cs

 

Q.4.大津の二値化

(参考)https://imagingsolution.net/imaging/discriminant-analysis-method/

var src = new Bitmap("Lena.bmp");
var gray = ImagingDotNet.CvtColor(src, ImagingDotNet.COLOR_BGR2GRAY);
var dst = (Bitmap)src.Clone();
ImagingDotNet.Threshold(gray, dst, 128, 255, ImagingDotNet.THRESH_OTSU);
入力 出力

C# >> Threshold.cs

 

 

4問やったところで、力尽きました…

100問分、問題を考えてプログラムを作成した100本ノックの著者は、ほんとスゴイ!!

 

画像処理のためのC#テクニック へ戻る

【C#】画像の輝度値の取得設定速度の比較

C#で画像の輝度値を取得/設定を行う場合は、GetPixel、SetPixelメソッドを使うと遅いのでLockBits~UnlockBitsでポインタをむき出して輝度値の取得/設定を行うのが定番となっていますが、自分自身でGetPixel、SetPixelメソッドを使った事が無かったので、いくつかの方法で処理時間を比較してみました。

 

【評価環境】

OS Windows10 64bit ver.1809
CPU Intel Core i7-7700K 4.2GHz
メモリ 32GB
.NET Framework 4.5.2
プラットフォーム Any CPU(32ビットを優先)
評価画像 jpeg 6000×4000画素 24bitカラー

です。

 

評価プログラムとしては、カラー画像の輝度値をR,G,Bそれぞれ取得し、値を明暗反転して輝度値を入れなおすプログラムを作成しています。

 

処理結果は、以下のようにポジ→ネガ→ポジ→ネガと繰り返すようになっています。

 

処理時間は処理を5回行い平均した時間となります。

 

 

GetPixel、SetPixelを使った方法

平均処理時間は27439msec

本当に遅かった。。

しかもGetPixel、SetPixelではモノクロ画像(Format8bppIndexed)に対応していないので、モノクロ画像も多く扱う画像処理には不向きとなります。

 

LockBits~UnlockBitsでポインタ(Scan0)を取得し、データを配列にコピーしてから処理を行い、結果を元にコピーしなおす方法

平均処理時間は101msec

さすがにGetPixel、SetPixelよりはぜんぜん速いです。

 

MarshalクラスのReadByte、WriteByteメソッドでポインタ(Scan0)に直接、値を読み書きする方法

平均処理時間は273.6msec

この方法に少し期待していたのですが、配列にコピーした方が速かった。。

 

unsafeを使ったポインタ(Scan0)を直接読み書きする方法

平均処理時間は25.4msec

やっぱりunsafeはできれば使いたくないのですが、ここまで速いと使うのもあり??

ポインタを使うなら、C言語のライブラリにしておきたい気もしますが、C#だけで完結できるのもちょっと惹かれます。

 

ポインタで読み書きし、Parallel.Forをつかって処理を並列化する方法

平均処理時間は11.4msec

もう、unsafeは使うしかないでしょ!というレベルですが、やっぱり抵抗がある。。

 

処理を呼び出す側のプログラム

 

まとめ

それぞれの処理時間をまとめると以下の通りでした。

 

方法 処理時間(msec)
GetPixel、SetPixel 27439
LockBits、UnlockBitsで配列を介して処理 101
MarshalクラスのReadByte、WriteByte 273.6
unsafeのポインタで参照 25.4
unsafeのポインタの並列処理 11.4

 

結局GetPixel、SetPixelは論外でした。

あとは好みというか、ポリシーというか、意見の分かれるところだと思いますが、ポインタで処理するのは、やはり魅力です。

 

(2019.11.8追記)

.NET Framework4.5.232ビットを優先で評価を行っていたので、この部分を変えると処理速度に差が出るか?確認しました。

 

.NET Framework 4.7.2  32ビットを優先

方法 処理時間(msec)
GetPixel、SetPixel 27293.4
LockBits、UnlockBitsで配列を介して処理 101.8
MarshalクラスのReadByte、WriteByte 290.8
unsafeのポインタで参照 24.4
unsafeのポインタの並列処理 9.8

 

.NET Framework 4.7.2  32ビットを優先なし

方法 処理時間(msec)
GetPixel、SetPixel 21281.2
LockBits、UnlockBitsで配列を介して処理 85.4
MarshalクラスのReadByte、WriteByte 213.6
unsafeのポインタで参照 27.2
unsafeのポインタの並列処理 9.2

 

となりました。

ということで、.NET Frameworkの4.5.2と4.7.2の差はほとんどありませんでしたが、「32ビットを優先」のあるなしでは優先しない(64bitで動作)方が少し速い結果となりました。

 

関連記事

【C#】Bitmap画像データのメモリ構造

 

画像処理のためのC#テクニックへ戻る

【C#】ボタンの背景色を元に戻す方法

C#でボタンの背景色を元に戻す方法!

とか言って、ボタンのBackColorプロパティをシステムのControlに設定すればいいんでしょ?!

と思っていたのですが、実際にボタンの背景色を別の色に設定し、元のシステムのControlに戻してみると、下図のように初期状態(button2が初期状態)に比べて、少し明るい色になってしまいます。

 

これを回避するには、UseVisualStyleBackColorプロパティをTrueに設定することでボタンの背景色が元に色に戻す事ができます。

 

 

元の色に戻した結果がこちら↓

 

このUseVisualStyleBackColorプロパティはボタンの背景色(BackColorプロパティ)を変更後、勝手にFalseに変わってしまうので、元のTrueに変更する必要があります。

 

そもそもUseVisualStyleBackColorプロパティとは何?

と思い、調べてみたのですが、

 

visual スタイルがサポートされている場合に、visual スタイルを使用して背景を描画するかどうかを決定する値を取得または設定します。

 

という説明だったのですが、結局、良く分からず。。

 

という事で、詳細は分からないのですが、ボタンのBackColorプロパティをシステムカラーのControlに設定する時は、UseVisualStyleBackColorプロパティもTrueに設定すること!と覚えておくしかなさそうです。

 

この設定をコードで書くと、

 

button1.BackColor = SystemColors.Control;
button1.UseVisualStyleBackColor = true;

 

となります。