linqで画像処理
DESCRIPTION
CLR/H #74 のLTで発表したものTRANSCRIPT
LINQで画像処理
momo_*(@tututen)
自己紹介
● 某北見市で働く職業プログラマ● 趣味でもプログラム書くことがあります● お仕事:C言語、(Python、C#)● 趣味:ほぼ何でも(※アセンブリを除く)● パネルでポン(以下、パネポン)ができます● タグ「友達がいないとこうなります」で検索!● あと、手元を映したUst動画もあったりします
地図
地図
自己紹介
● 某北見市で働く職業プログラマ● 趣味でもプログラム書くことがあります● お仕事:C言語、(Python、C#)● 趣味:ほぼ何でも(※アセンブリを除く)● パネルでポン(以下、パネポン)ができます● タグ「友達がいないとこうなります」で検索!● あと、手元を映したUst動画もあったりします
検索結果
最近のタグ(7/7 13:00現在)
Ust風景
http://www.ustream.tv/recorded/20923039
LINQについて
Language Integrated Query の略称で、 C# や VB
などの .NET Framework 対応言語に、 リレーショナルデータや XML に対するデータ操作構文を組み込む (+ データベースや XML 操作用のライブラリ)
引用:http://ufcpp.net/study/csharp/sp3_linq.html
LINQについて
0 1 2
1098
7654
3
11
141312 15
0 2
8
64
1412
10Where(p => p % 2 == 0)
LINQについて
Select(p => p.ToString())
0 2
8
64
1412
10
"0" "2"
"8"
"6""4"
"14""12"
"10"
今回の説明する機能
今回の説明する機能
画像処理の主な手順
● 画像をグレースケール(モノクロ)化● 画像を二値化● テンプレート画像とのマッチング
グレースケール(モノクロ)化
● 中間値法● NTSC系加重平均法
(NTSC=National Television System Commitee(全米テレビジョン放送標準化委員会))
R * 0.298912 + G * 0.586611 + B * 0.114478
グレースケール(モノクロ)化
● 中間値法● NTSC系加重平均法
(NTSC=National Television System Commitee(全米テレビジョン放送装標準化委員会))
グレースケール(モノクロ)化
※画像はイメージです!
二値化
● 各画素の値を取る● しきい値によって「0」or「255」を設定するだけ
※画像はイメージです!
LINQ的にどう書く?
1. 画像を画素のシーケンシャルに変換2. 各画素に対してグレースケール化3. グレースケールした画素に対して、二値化
LockBits1. Bitmap型のデータをByte配列にする2. 画像のフォーマットによって、1画素の情報が違
う3. PixelFormat.Format32bppArgbの場合byte[4]
に1画素の情報が入り、1byteごとにBlue、Green、Red、Alphaのデータが入る。
LockBits
各画素をグレースケール化
1. [0 .. 画像サイズ*4byte分]のシーケンシャルデータを生成
2. 4の倍数のシーケンシャルデータにフィルタ3. NTSC系加重平均法の公式を当てはめる
各画素をグレースケール化
Enumerable.Range(0, bmp.Width * bmp.Height * 4) // 1
各画素をグレースケール化
Enumerable.Range(0, bmp.Width * bmp.Height * 4) // 1 .Where(p => p % 4 == 0) // 2
各画素をグレースケール化
Enumerable.Range(0, bmp.Width * bmp.Height * 4) // 1 .Where(p => p % 4 == 0) // 2 .AsParallel() // 並列化 .ForAll(p => { double cr = 0.298912, cg = ..., cb = ...; byte g = (byte)(cr * ba[i + 0] + cg * ba[i + 1] + cb * ba[i + 2]) ba[i + 0] = ba[i + 1] = ba[i + 2] = g; });
各画素を二値化
Enumerable.Range(0, bmp.Width * bmp.Height * 4) // 1 .Where(p => p % 4 == 0) // 2 .AsParallel() // 並列化 .ForAll(p => { double cr = 0.298912, cg = ..., cb = ...; byte g = (byte)(cr * ba[i + 0] + cg * ba[i + 1] + cb * ba[i + 2]) ba[i + 0] = ba[i + 1] = ba[i + 2] = g < th ? 0 : 255; });
テンプレート画像でマッチング
● 空白・数字「1−9」までのテンプレート画像を用意
● 上記のテンプレート画像を二値化した画像と、マスの画像を二値化した画像を比較
● 比較結果が最も似ているものをその数値と断定する。
37
370
テンプレート画像でマッチング
Enumerable.Range(0, 10) // 1
テンプレート画像でマッチング
Enumerable.Range(0, 10) // 1 .Select((p, i) => new {
})
テンプレート画像でマッチング
Enumerable.Range(0, 10) // 1 .Select((p, i) => new { Num = i, })
テンプレート画像でマッチング
Enumerable.Range(0, 10) // 1 .Select((p, i) => new { Num = i, Count = Enumerable.Range(0, 37 * 37) .Count( q => CellImgByte[q] == TmplImgByte[i * 37 + q % 37 + q / 37 + i * 370] ) // 2 })
テンプレート画像でマッチング
Enumerable.Range(0, 10) // 1 .Select((p, i) => new { Num = i, Count = Enumerable.Range(0, 37 * 37) .Count( q => CellImgByte[q] == TmplImgByte[i * 37 + q % 37 + q / 37 + i * 370] ) // 2 }) .OrderByDescending( p => p.Count )
テンプレート画像でマッチング
Enumerable.Range(0, 10) // 1 .Select((p, i) => new { Num = i, Count = Enumerable.Range(0, 37 * 37) .Count( q => CellImgByte[q] == TmplImgByte[i * 37 + q % 37 + q / 37 + i * 370] ) // 2 }) .OrderByDescending( p => p.Count ) .First()
テンプレート画像でマッチング
Enumerable.Range(0, 10) // 1 .Select((p, i) => new { Num = i, Count = Enumerable.Range(0, 37 * 37) .Count( q => CellImgByte[q] == TmplImgByte[i * 37 + q % 37 + q / 37 + i * 370] ) // 2 }) .OrderByDescending( p => p.Count ) .First() .Num; // 3
まとめ
● 各画素に対して行う画像処理とLINQの相性はばっちし!
● 今日からあなたもわたしもLINQ!LINQ!
ご清聴ありがとうございました