長年、虎視眈々?猫目がちに狙っていた画像処理ですが、OpenCVは基本的に C++ か C#、ああるいはPython という雰囲気が強いと感じてました。ラッパーを利用するにも、少し失敗したら時間が取られそうで。。。
OpenCVも3の時代が広がってきたこと、同じ .NET 族なのでいっそC#も勉強しておこうか、と思いつつ調べていましたら、いまは nuget にいいライブラリが配信されていることを知りました。
【導入方法】
導入方法は簡単。
1.ダミーでも何でも、プロジェクトを作成
「新規作成」で「新しいプロジェクト」を作成する。
2.nygetで OpenCV3 sharp をインストールする
・「ツール」のサブメニュー(または ソリューションエクスプローラーのソリューション名で右クリック)で、「ソリューションのnugetパッケージの管理」を開く。
・「参照」のタグから “OpenCV” などで検索
・ 検索結果の “OpenCvSharp3-AnyCPU ” を選択してインストール
3. インストール済みの確認
インストール終了のメッセージ
検索結果のアイコン右下に緑のマーク
「インストール済み」タグのリストに表示
3. 動作確認
ダーミーで作成したコードのアタマに Imports文を打つ。
コード補完で候補が表示され、その中に “OpenCvSharp” があればOK。
これで、VB.NET でOpenCV の関数が利用できるようになります。
OpenCVsharp リファレンス Documents(name space)
OpenCVsharp 作者のサイトOpenCVsharp記事一覧
※ OpenCVsharp3
OpenCVsharp3 は確かに Nuget には名称が乗っていますが、バージョン名あるいはラッパー名としての呼称は存在しているのでしょうか?作者さんの記事だと、OpenCVsharpを penCV3 に対応させたとありますから(ありがとうございます m(_ _)m)、呼称としては OpenCVsharp のままワンシリーズなのかもしれません。
※ OneDrive
OneDrive上で共有指定すると「クラウド ファイル プロバイダーが実行されていません。」と怒られるときがあります。うまくDriveを更新してやってください。。。(あっちこっちで開いてる場合は一旦使わない環境は閉じないと保留のまま動きません)
さて、 VB.net でやる、といっておきながら、いきなり C#.net で作業をしています。時間制限のため、考えたあげくの選択です。苦渋の選択です、断腸の思いです(本日、高名な相撲部屋がひとつ、消滅しました。この団体はどっかの団体そっくりです。日本をむしばむ厚顔とはいつもおぞましいモノです・・・)。
さて、さて、先の作者のサイトの最初の記事にあるサンプルをまずはコピーアンドペーストで少し修正して動かしてみました。
ところが早速動きません。
まず、名前空間 Cv が拒否されます。
したがって、IplImage ing のインスタンスが作れないようです。
同様に、NuGet の紹介の記事のサンプルも同様です。Cv名前空間の関数は基本的には転けます。これを突破しないとなかなか前には進めないよう、、、です。
今のところ動いているのは、以下の3つです。
ちなみに以下のソースは、オープンファイルダイアログで読み込んだファイル名を、配列 Imgs に読み込んで、その先頭のファイル名 Imgs[0] を読み込んだ後、各処理を行っています。
●グレースケール化
private void trialGrayScaleToolStripMenuItem_Click(object sender, EventArgs e)
{
// 画像 img に元画像 imgs[0] を読み込んで OpenCV のウインドウに表示する
var img = new Mat(Imgs[0]);
Cv2.ImShow(“Original Image”, img);
Cv2.WaitKey();
// 画像を直接読み込んでそのままグレースケール化する
Cv2.ImShow(“gray”, img);
{
Mat ImgGray = new Mat();
// img を ImgGray へグレー化モード BGRA2GRAY を使ってコピーする
Cv2.CvtColor(img, imgGray,ColorConversionCodes.BGRA2GRAY);
// 結果 ImgGray を OpenCVのウインドウに表示する
using (new Window(“Gray Image”, ImgGray))
{
Cv2.WaitKey();
}
}
}
●白黒二値化
private void trialBlackWhiteToolStripMenuItem_Click(object sender, EventArgs e)
{
var img = new Mat(Imgs[0]);
Cv2.ImShow(“Original Image”, img);
Cv2.WaitKey();
Cv2.ImShow(“gray”, img);
{
{
// Img[0] を グレーに変換しながら ImgBW に読み込む
Mat ImgBW = new Mat(Imgs[0], ImreadModes.GrayScale);
//Cv2.CvtColor(img, ImgBW, ColorConversionCodes.BGRA2GRAY);
// グレー画像 ImgBW を 大津法で二値化処理して再び ImgBW に代入
ImgBW = ImgBW.Threshold(0, 255, ThresholdTypes.Otsu | ThresholdTypes.Binary);
using (new Window(“Gray Image”, ImgBW))
{
Cv2.WaitKey();
}
}
}
}
●エッジ検出
private void toolStripMenuItem2_Click(object sender, EventArgs e)
{
Mat src = new Mat(Imgs[0], ImreadModes.GrayScale);
Mat dst = new Mat();
// Canny で二値化処理してグレーと二値化結果をウインドウで表示
Cv2.Canny(src, dst, 50, 200);
using (new Window(“src image”, src))
using (new Window(“dst image”, dst))
{
Cv2.WaitKey();
}
}
ここで、画像の宣言が var と Mat が混在しています。
# C#では、変数の定義式でインスタンス化したりするときに、
# 代入符号=の左辺右辺でともに型を指定します。
# このときあんまり長い名前空間だとコードが見にくくなるので、
# 右辺の型を踏襲する var 型で左辺を宣言しておくと、
# コードがすっきりするので便利、という使い方をするそうです。
エッヂ処理の Canny は、内部で賢く二値化して、その結果をエッジ検出しているそうです。したがって入力はグレー画像です。
パラメーター設定とかできていないので使い勝手がいまいちです。やっぱり直接要素をいじくれるようにならないと最終的にはいろんなことが実行できないでしょう。もっと関数、というかメソッドを Cv名前空間 に対応するものを Cv2名前空間 から探してこないといけないようです。作者さんの記事を読み込むところから始めないと。
円検出とパターン検出は、今日はまだ遠いようです。
孤高の戦士に捧ぐ
追記
こちらのサイトは Cv2 名前空間の関数を使ってましたのでたいへん参考になって助かりました
ラインアートのサンプル
private void maskToolStripMenuItem_Click(object sender, EventArgs e)
{
var img = new Mat(240, 320, MatType.CV_8UC3, new Scalar(0, 0, 0));
var mat3 = new MatOfByte3(img);
var indexer = mat3.GetIndexer();
var lineNum = 20; // 描画する線の数
for (var i = 0; i < lineNum; i++)
{
var val = (float)i / lineNum;
var x = val * img.Width;
var y = val * img.Height;
Cv2.Line(img, new OpenCvSharp.Point(0, y), new OpenCvSharp.Point(x, img.Height), new Scalar(0, val * 255, 255 – (val * 255)));
}
Cv2.ImShow(“image”, img);
Cv2.WaitKey();
}
ネットを彷徨しても能率が上がりません。ここらで少し情報整理を始めます。
画像 image.jpg を img に読み込む/画像の変数 img のインスタンス化
●ファイルを読み込む
var img = new Mat(@“image.jpg”);
●青(255,0,0)く塗りつぶした 8bit, 3ch の 240×320 の画像
var img = new Mat(240, 320, MatType.CV_8UC3, new Scalar(255, 0, 0));
● 画像ファイルを読み込む
img = cv2.imread(“input.jpg”)
画像のコピー(複製)作成
var clone = img.Clone();
画像の切り抜き(四角)
var imgPartClone = img.Clone(new Rect(100, 100, 200, 150));
●画像をファイルに書き込む
cv2.imwrite(“image.jpg”, img)
MAT(マトリックス)形式画像の情報を得る(メンバー変数)
●画像 img の巾 : img.Width
● 画像 img の高さ : img.Height
● 画像 img の色数 : img.Cols
● 画像 img の行列サイズ : img.Size() / img.Rows / img.cols
● 画像 img の チャンネル(色)数 : img.Channels()
● 画像 img の色調(深さ)のコード : img.Depth()
画像の色調深さの種類と表記
CV_8U – 8-ビット符号なし整数 ( 0..255 )
CV_8S – 8-ビット符号あり整数 ( -128..127 )
CV_16U – 16-ビット符号なし整数 ( 0..65535 )
CV_16S – 16-ビット符号あり整数 ( -32768..32767 )
CV_32S – 32-ビット符号あり整数 ( -2147483648..2147483647 )
CV_32F – 32-ビット浮動小数点数 ( -FLT_MAX..FLT_MAX, INF, NAN )CV_64F – 64-ビット浮動小数点数 ( -DBL_MAX..DBL_MAX, INF, NAN )
画像 img をOpenCVのウインドウで表示
● window関数で画像を表示
using(var win = new Window(“Window Title”, img))
● ImShow関数で画像を表示
Cv2.ImShow(“WindowTitle”, img);
● 表示ウインドウの破棄/すべて破棄
Cv2.DestroyWindow()
Cv2.DestroyAllWindows
画像の大きさの変更
● 数値指定
Cv2.Resize(img0, img1, new Size(320, 240), 0, 0, InterpolationFlags.Cubic);
● 比率指定
Cv2.Resize(src, dst, Size.Zero, 1, 0.5, InterpolationFlags.Cubic);
画像の反転操作
● 左右水平反転
Cv2.Flip(src, dst, FlipMode.X);
● 上下垂直反転
Cv2.Flip(src, dst, FlipMode.Y);
C# の実行を休憩(Return キーを押すまで待機)
Cv2.WaitKey();
グレー処理をする
imgGray = rgb_to_gray(imgOrgn)
ネガ処理をする
imgNega = Cv2.BitwiseNot(img, result1);
var imgNega = ~img;
ガウシアンぼかし処理をする
Cv2.Blur(img, imgGauss, new Size(5, 5));
Cv2 名前空間の関数等のリファレンスはこちらに。
MATデーターの要素へのアクセス
● 要素のベクトルデーターを分解して変数に代入
var px = img.Get<Vec3b>(y, x);
● 読み込み要素の呼び出し方法( 0ch のデーター)
px[0]
byte変数で計算可能:px[0] = (byte)(255 – px[0]);
● 要素の元の変数への格納方法
img.Set(y, x, px);
描画方法
●直線
Cv2.Line(img, new Point(10, 10), new Point(300, 10), new Scalar(0, 0, 255));
Cv2.Line(img, new Point(10, 30), new Point(300, 30), new Scalar(0,255, 0), 2);
●矩形(四角)
Cv2.Rectangle(img, new Rect(50, 50, 100, 100), new Scalar(255, 0, 0), 2);
● 文字記入
Cv2.PutText(img, “Hello OpenCvSharp!!”, new Point(10, 180), HersheyFonts.HersheyComplexSmall, 1, new Scalar(255, 0, 255), 1, LineTypes.AntiAlias);
図形や形状、パターンの検索検出
円 : Cv2.HoughCircles(引数8つ)
CircleSegment[] HoughCircles(入力画像, 方式, dp, param1, param2, min_radius, max_radius)
【引数】
入力画像: 8ビット,シングルチャンネル,グレースケールの入力画像。グレースケール画像を入力にし 内部で2値化(Canny)している。
方式: 検出方式。Standard,Probabilistic,MultiScale,Gradient の4択。
dp : 検査領域比(逆比) (Double実数)、解像度を 1/n に。
minDist : 検出円の中心間の最小距離(Double実数)
param1 : 前処理「Cannyのエッジ検出」係数の最小値(Double実数,省略可)。小さいほど細かくなる
param2 :中心検出計算時しきい値。(Double実数,省略可)小さいほどあいまいな円を検出
minRadius : 最小半径(整数 int32,省略可)
maxRadius : 最大半径(整数 int32,省略可)
以下は動いたソースです。引数が適当なのでたくさん誤検出します。
円中心の距離制限を大きくしてみてください。
Mat img = new Mat(Imgs[0]);
Mat gray = new Mat(Imgs[0], ImreadModes.GrayScale);
using (new Window(“Imput Gray Image”, gray)) ;
CircleSegment[] circls = Cv2.HoughCircles(gray, HoughMethods.Gradient, 1.8,5);
if (circls.Length == 0)
{
MessageBox.Show(“Circle can NOT found.”,”Result Message”, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
FncDrwCircles(circls, img);
}
// 円描画用の関数
private void FncDrwCircles(CircleSegment[] circles, Mat img)
{
Mat imgi = img;
OpenCvSharp.Point pt = new OpenCvSharp.Point();
foreach (CircleSegment ccl in circles)
{
Cv2.Circle(imgi, ccl.Center, (int)ccl.Radius, new Scalar(0, 255, 255), 1);
}
using (new Window(“Circle Result Image”, imgi))
{
Cv2.WaitKey();
}
}
線1(オーソドックスタイプ) : HoughLineHoughLinesStandard
線2(自動範囲調整タイプ) : HoughLines
線3(確率利用タイプ) : HoughLines2
動画の読み込みと表示
var capture = new VideoCapture(@“Path/To/MovieFile.xxx”);
using (var win = new Window(“capture”))
using (var mat = new Mat())
{
while (true)
{
capture.Read(mat);
// 読み込めるフレームがなくなったら終了
if (mat.Empty()) { break; }
win.ShowImage(mat);
Cv2.WaitKey(33);
}
}
動画ファイルの保存
// デフォルトのカメラをオープン
using (var capture = new VideoCapture(0))
using (var writer = new VideoWriter(“test.avi”, FourCC.Default, capture.Fps, new Size(capture.FrameWidth, capture.FrameHeight)))
using (var win = new Window(“capture”))
using (var mat = new Mat())
using (var dst = new Mat())
{
while (true)
{
capture.Read(mat);
Cv2.CvtColor(mat, dst, ColorConversionCodes.BGR2GRAY);
win.ShowImage(dst);
writer.Write(dst);
if (Cv2.WaitKey(30) >= 0) { break; }
}
}
はじめに、
大学(や社会)は自由な文化と国際的な感覚のなかで(妙な政治的拘束やローカルな社会習慣などの影響なく)最小限の倫理を遵守していろんな活動ができるべきところです(理想論)。したがって、日本的な考え方では非常識で倫理観欠落でも、野良猫がいればえさを与えて命を守るのが先進的国家標準の理念のようです。だから、捕鯨船は攻撃されイルカ猟なども悪事になるのですね。
法人経営陣、大学執行部や職員、教員、一般学生はさておき、キャンパス内ではとりわけ留学生の複数の方々が、日々、さまよえる猫たちにえさをやり、声を掛けに来られます。そのおかげで、近隣には親猫仔猫総勢20匹弱たちが、かなり優雅に寝そべり、穏やかな性格になり、この冬を迎えるまえに毛並みもよく、それなりに肥えています。あぁ、あなたたち、愛されてるのね、うらやましい。。。。^^;
おかげで?あちこちに穴が開き耐震強度のないままの実験棟および関連施設には、隙あらば複数の猫たちが侵入して寝そべっています。実は結構獣害も発生しているのですが、ま、現状では近隣諸国のサイレントアタックを受ける我が国のように、実効支配を阻止しつつ専守防衛しかありません。ーー;
# 獣害被害限定化のために猫砂トイレ購入したら経費で落ちるでしょうか???^_^;;
さて、
周りの仔猫たちのほっこりした環境とは違い、C#やVBで、OpenCVsharp3 を使い始めたばかりのわれら初習者にとって、大もとの OpenCV の CV2、3へのアップデート、それによる C APIから C++API への移行、それに伴う関数の変更、OpenCVsharp という wrapper(フィルターのようなもの)を介してプログラムを記述する、という環境の下、新旧、異プラットフォーム、異言語の入り交じったネットの荒波のコードのなか、さまよってしまうのが現実です。
OpenCV 簡単な歴史、経緯(Wikipediaより)
1999 プロジェクト始動
2000 アルファ版公開
2006 Ver.1.0 公開
2009 Ver. 2.0 公開、 Ver.2.4.4 で Java対応 ~2.4.13.6 (2018/2)
2015 Ver. 3.0 公開、 C API から C++API へ移行 ~3.4.3 (2018/8)
2018 Ver. 4.0 ベータ版公開、OpenVINO toolkit (Accerarator Computer Vision と Deep Learninng ) 公開
でもどうして公式サイトには OpenCV3 の項目があんまりないのでしょうか??
とりあえず、
OpenCVsharp3 の庇護の下、.net 言語でWindowsアプリケーションの作成を目指す私たち初習者は、OpenCV については CV2 の名前空間にある関数の情報に絞り、そのリファレンスをもとに、OpenCVsharp3 で使える関数を探す。その場合には、Visual Studio のコード補完機能で表示される候補リストが結構便利です。OpenCVsharp や Cv2 の名前空間を入力したうえでドットを入力したとき、そこに表示されるメソッドなどを、ネットの中から探して、引数の定義や意味を検索して探すことで、少しだけ、迷子になることが減るかもしれません。2015年以前の情報は、C++ API 以前なので新しい情報に絞り込むのもよいかもしれません。特に、以下のモジュールが記述してあったら、それは古いコードです。通り過ぎるようにしましょう。
ocl (Mat へ統合吸収)、
nonfree 、legacy、contrib (opencv_contrib へ統合吸収)
リンク
OpenCV.jp いろんな形式のマニュアル集@opencv.org
schima.hatenablog.com (OpenCVsharp 作者ブログ)
SourceChode (minami_SC さんのOpenCVsharp 関連記事)
などなど、適宜追加。
約2週間で結構初歩的なところまで動くようになりました。でも、行列がMAT、配列がMAT、MATの配列は?その実在化は?動画のフレーム操作で混乱中です。
来月になって落ち着いたら,共同研究諸兄のためにチュートリアルソースを公開する予定です、予定、です。。。