Classes
Class | Description | |
---|---|---|
CFviBlob | 2値ブローブ解析クラス | |
CFviBlobData | 2値ブローブ解析データ構造クラス | |
CFviBlobFilterRange | 2値ブローブ解析結果フィルタ条件構造クラス | |
CFviBlobList | 2値ブローブ解析データリスト | |
CFviBlobParam | 2値ブローブ解析処理パラメータ構造クラス | |
CFviBlobResult | 2値ブローブ解析結果クラス | |
ErrorCode | エラーコード(2値ブローブ解析関連) | |
Function | 2値ブローブ解析関数群 |
Enumerations
Enumeration | Description | |
---|---|---|
ContinueOption | 継続オプション | |
FeatureFlag | 特徴量計算フラグ | |
FeatureType | フィルタ種別 | |
Neighborhood | 連結条件 | |
ObjectColor | 対象物の色 | |
SortDirect | ソート方向 | |
SortOrder | 配置順序 |
Remarks
ここには、2値ブローブ解析関連のクラスを集約しています。
トピック:
構成:
この機能は、2値ブローブ解析の本体と、解析結果やパラメータを保有するデータ構造で構成されます。
-
本体:
クラス 内容 CFviBlob 2値ブローブ解析機能を持つクラスです。 -
データ構造:
クラス データID 内容 CFviBlobData 1100 1件分の解析データを格納するクラスです。 下記の CFviBlobResult から取得できます。 CFviBlobList (なし) 2値ブローブ解析結果ハンドルとブローブ番号を保有するリストクラスです。 下記の CFviBlobResult から取得できます。 CFviBlobResult 1101 解析結果を格納するクラスです。 CFviBlobParam 1102 2値ブローブ解析パラメータを保有するクラスです。 CFviBlobFilterRange 1103 解析結果フィルタ条件です。 フィルタまたはソートして CFviBlobResult から CFviBlobData を取得する際に使用します。
コンポーネント:
本体の2値ブローブ解析クラス(CFviBlob)は、 解析対象の2値画像(CFviImage)を要求し、 解析結果を格納するオブジェクト(CFviBlobResult)を提供します。 解析対象の2値画像は実行前にユーザが設定する必要があります。 パラメータ(CFviBlobParam)は、 本体の内部に保有しており、設定を変更するか否かは任意です。 設定を変更する場合は、CFviBlob.Param プロパティを介して行えます。 本体の CFviBlob.Execute を実行すると、解析結果を CFviBlob.Result に格納します。
解析対象色:
本ブローブ解析では、解析時に前景色のみを解析するか、前景色と背景色の両方を解析するかを選択する事が出来ます。 通常は前景と背景両方を解析するモードを設定する事を推奨しますが、 前景のみ解析出来れば良い場合は、単色解析モードとする事で処理時間の短縮を図る事が出来ます。
前景・背景共に計測するモードでは、ブローブの親子関係を作成します。 背景を計測しないモードでは、ブローブの親子関係を作成しません。 背景を計測しないモードでは親子関係を作成しないため、処理は高速になりますが、 親子関係を利用する特徴量などの一部の機能が使用不可能となります。
図) 解析対象色モードによる親子関係の違い
関連:
背景ブローブ:
本ブローブ解析は、解析対象領域の外側にはブローブ番号0番の背景色ブローブが広がっていると定義しています。(下図参照)
この領域の外側と連結する背景色ブローブを「背景ブローブ」と呼び、特殊な扱いをします。 背景ブローブはブローブ番号が必ず0番になります。 背景ブローブが1画素も存在していない時でも、0番ブローブは背景を指す番号として存在し、 この場合は0番はヌル領域を指し示します。 また 親子関係 において、0番ブローブは必ずツリーの最上位になります。
但し、解析対象色の設定(ColorMode)で、前景色のみを解析するよう設定した場合は、 0番ブローブは存在するものの、常にヌル領域となります。 下図は解析対象色に前景=白・背景=黒を指定した時の例です。 この時、青で示した領域は、解析領域の外側の0番ブローブと連結していると見なせる為、0番ブローブとなります。
連結条件:
ある画素とその近傍にある画素が同一ブローブに属しているか否かを決定する条件です。 4近傍の画素に対して連結させる場合を4連結、8近傍の画素に対して連結させる場合を8連結と呼びます。
例えば、下図の黒画素について考えると、4連結の場合は5個のブローブとなり、8連結の場合は1個のブローブになります。
解析対象色の設定(ColorMode)で、前景と背景の両方を解析するよう設定した場合、 前景の連結条件と背景の連結条件は逆になります。 つまり、前景が4近傍の時は背景は8近傍、前景が8近傍の時は背景が4近傍となります。 下図に例を示します。
- 前景を白、背景を黒とし、連結条件を4近傍にした場合 上図の青部は赤部と連結せず、背景にあたる緑部は連結する事になります。 青は緑の子供になり、緑は赤の子供になります。 -
- 前景を白、背景を黒とし、連結条件を8近傍にした場合 上図の青部と赤部が連結し、背景にあたる緑部は連結しない事になります。 緑は赤と青が連結したブローブの子供になります。 -
関連:
親子関係:
親子関係とは、ブローブの幾何的な位置関係を木構造にて表したものです。 あるブローブAがあった時に、このブローブAの穴ブローブをブローブAの子供と呼びます。 逆に、この穴ブローブから見たブローブAを親と呼びます。 また、同じ階層にあるブローブ同士は兄弟と呼びます。
上図において、1,2,3 はそれぞれ兄弟ブローブです。 また、1,2,3 の親は 0 であり、0 の子供は 1,2,3 となります。 全てのブローブにはブローブ番号が割り振られており、この番号によるリンクによって親子関係の木構造が取得できます。 但し、全てのリンクは1対1の関係で表されるため、親から子への関係など1対多の関係を取得する際には リンクを辿って行くことになります。各リンクの取得には、以下の関数を使用します。
親ブローブの取得 | GetParentData()()()() |
子ブローブ数の取得 | GetChildNum()()()() |
子ブローブの取得 | GetChildData()()()() |
兄弟ブローブ数の取得 | GetSiblingNum()()()() |
次の兄弟ブローブの取得 | GetNextSiblingData()()()() |
前の兄弟ブローブの取得 | GetBackSiblingData()()()() |
上図のブローブ例でのリンクを表したのが下図です。
GetChildData()()()() で取得される子供リンクは1番目の子供となります。 全ての子供を取得するには、1番目の子供を取得した後、その子供の兄弟を GetNextSiblingData()()()() 又は GetBackSiblingData()()()() にて辿っていく事で取得できます。 また、兄弟リンクは双方向循環リストになっており、リンクを辿っていくと自分に戻ってきます。 尚、兄弟の順番 及び 親からリンクされる子供(=兄弟の先頭)には特別の意味は無く、処理の都合によって決定されるものです。
また、全てのブローブは背景の子供か又はその子孫になるため、親子関係の木構造のルートは必ず0番ブローブになります。 0番が背景以外のブローブに割り当てられる事はないため、0番から順に親子関係の木構造を辿っていけば全てのブローブを参照できます。 前述の背景の説明でも述べたとおり、背景が1画素も存在していない場合や、解析対象色の設定(ColorMode) で前景のみを解析対象とするよう設定した場合でも、0番ブローブは存在するため、この事は成り立ちます。 但し、全てのブローブは0番の子供となります。
サンプルコード:
C# | Copy |
---|---|
// $Revision: 1.2 $ using System; using System.Collections.Generic; using System.Text; using System.Drawing; using fvalgcli; // FvPluginXXXX attribute requires fvalgcli namespace User.SampleCode { public partial class Blob { /// <summary> /// ブローブデータの階層 /// </summary> [FvPluginExecute] public void Stratum() { FVIL.Data.CFviImage image = null; FVIL.Blob.CFviBlobList list = null; FVIL.Blob.CFviBlobResult result = new FVIL.Blob.CFviBlobResult(); try { // 画像処理の実行. image = new FVIL.Data.CFviImage("blob_BIN_3.png"); FVIL.Blob.CFviBlobParam param = new FVIL.Blob.CFviBlobParam( FVIL.Blob.ObjectColor.WhiteFG_BlackBG, FVIL.Blob.Neighborhood.Four ); FVIL.Blob.CFviBlob parser = new FVIL.Blob.CFviBlob(image, result, param); parser.Execute(); list = result.GetBlobList(); if (list.Count == 0) return; Console.WriteLine("-) result.Count = {0}", result.Count); // 親子兄弟の探索. FVIL.Blob.CFviBlobData data = new FVIL.Blob.CFviBlobData(list[0]); BlobSibling(data, 0); } catch (FVIL.CFviException ex) { Console.WriteLine("code={0}, func={1}", ex.ErrorCode, ex.Function); } finally { if (image != null) image.Dispose(); if (list != null) list.Dispose(); if (result != null) result.Dispose(); } } /// <summary> /// 兄弟ブローブの探索 /// </summary> /// <param name="data">ブローブデータ</param> /// <param name="level">階層 [0~]</param> static void BlobSibling(FVIL.Blob.CFviBlobData data, int level) { // 自信の子ブローブ. BlobChild(data, level); // 兄弟の子ブローブ. for (int i = 0; i < data.GetSiblingNum(); i++) { data = data.GetNextSiblingData(); BlobChild(data, level); } } /// <summary> /// 子ブローブの探索 /// </summary> /// <param name="data">ブローブデータ</param> /// <param name="level">階層 [0~]</param> static void BlobChild(FVIL.Blob.CFviBlobData data, int level) { string tree = (level == 0) ? "" : "|-"; for (int i = 1; i < level; i++) tree = "|" + tree; // 自信と子ブローブ. Console.WriteLine(tree + "{0} (Color={1}, Parent={2}, ChildNum={3})", data.BlobNo, data.Color, data.GetParentData().BlobNo, data.GetChildNum()); if (data.GetChildNum() > 0) BlobSibling(data.GetChildData(), level + 1); } }; } |
Visual Basic | Copy |
---|---|
' $Revision: 1.1 $ Imports System.Collections.Generic Imports System.Text Imports System.Drawing Imports fvalgcli ' FvPluginXXXX attribute requires fvalgcli Namespace SampleCode Public Partial Class Blob ''' <summary> ''' ブローブデータの階層 ''' </summary> <FvPluginExecute> _ Public Sub Stratum() Dim image As FVIL.Data.CFviImage = Nothing Dim list As FVIL.Blob.CFviBlobList = Nothing Dim result As New FVIL.Blob.CFviBlobResult() Try ' 画像処理の実行. image = New FVIL.Data.CFviImage("blob_BIN_3.png") Dim param As New FVIL.Blob.CFviBlobParam(FVIL.Blob.ObjectColor.WhiteFG_BlackBG, FVIL.Blob.Neighborhood.Four) Dim parser As New FVIL.Blob.CFviBlob(image, result, param) parser.Execute() list = result.GetBlobList() If list.Count = 0 Then Return End If Console.WriteLine("-) result.Count = {0}", result.Count) ' 親子兄弟の探索. Dim data As New FVIL.Blob.CFviBlobData(list(0)) BlobSibling(data, 0) Catch ex As FVIL.CFviException Console.WriteLine("code={0}, func={1}", ex.ErrorCode, ex.[Function]) Finally If image IsNot Nothing Then image.Dispose() End If If list IsNot Nothing Then list.Dispose() End If If result IsNot Nothing Then result.Dispose() End If End Try End Sub ''' <summary> ''' 兄弟ブローブの探索 ''' </summary> ''' <param name="data">ブローブデータ</param> ''' <param name="level">階層 [0~]</param> Private Shared Sub BlobSibling(data As FVIL.Blob.CFviBlobData, level As Integer) ' 自信の子ブローブ. BlobChild(data, level) ' 兄弟の子ブローブ. For i As Integer = 0 To CType(data.GetSiblingNum(), Integer) - 1 data = data.GetNextSiblingData() BlobChild(data, level) Next End Sub ''' <summary> ''' 子ブローブの探索 ''' </summary> ''' <param name="data">ブローブデータ</param> ''' <param name="level">階層 [0~]</param> Private Shared Sub BlobChild(data As FVIL.Blob.CFviBlobData, level As Integer) Dim tree As String = If((level = 0), "", "|-") For i As Integer = 1 To level - 1 tree = "|" & tree Next ' 自信と子ブローブ. Console.WriteLine(tree & "{0} (Color={1}, Parent={2}, ChildNum={3})", data.BlobNo, data.Color, data.GetParentData().BlobNo, data.GetChildNum()) If data.GetChildNum() > 0 Then BlobSibling(data.GetChildData(), level + 1) End If End Sub End Class End Namespace |
出力結果:
-) result.Count = 7 1 (Color=1, Parent=0, ChildNum=3) |-6 (Color=0, Parent=1, ChildNum=0) |-5 (Color=0, Parent=1, ChildNum=0) |-4 (Color=0, Parent=1, ChildNum=0) 3 (Color=1, Parent=0, ChildNum=0) 2 (Color=1, Parent=0, ChildNum=0)
有効/無効ブローブ:
継続処理オプションの設定(ContinueOption)で継続実行が指定された状態で 解析を行った場合は、無効ブローブが現れます。 無効ブローブとは、元々有効ブローブとして存在していたブローブが、継続実行で追加された部分によって 他のブローブに連結するなどして無くなってしまったブローブの事を言います。
ブローブの有効/無効を調べるには IsValid()()()() を使用してください。 無効ブローブは親子関係の木構造から切り離されるため GetParentData()()()() などのリンク取得関数でリンクを取得することは出来ません。 また、特徴量も取得することは出来ず、取得しようとした場合は例外が発行されます。
ブローブ塗りつぶし (リージョンの取得):
解析後のブローブに対して後処理を行いたい場合は、そのブローブのリージョンを取得して処理を行います。
例えば、ブローブの塗り潰しを行いたい場合は、解析結果から取得したリージョンオブジェクトを塗り潰して、
それを画像に描画します。下記に処理手順を記載します。
1) 解析実行
2値ブローブ解析を実行します。
2) リージョン取得
2値ブローブ解析結果からリージョンオブジェクトを取得します。
リージョンオブジェクトは CFviBlobData の
GetRegion()()()() で取得できます。
3) リージョン塗り潰しと画像への変換
上記で取得したリージョンの Fill()()()() メソッドを使用して、
リージョンの塗り潰しを行います。(塗り潰されるのはリージョンの穴です)
次に Draw(CFviImage, Double) メソッドに画像を渡して描画します。
この時点では、リージョンを画像に変換しただけなので、2値ブローブ解析結果には反映されていません。
反映するには、下図 ※1 の画像で再度、2値ブローブ解析を実行する必要があります。
サンプルコード:
C# | Copy |
---|---|
static void _region_fill() { FVIL.Data.CFviImage image = new FVIL.Data.CFviImage(); FVIL.File.CFviImageFilePng filer = new FVIL.File.CFviImageFilePng(); filer.Load(System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "srcimage.png"), image); // 計測. FVIL.Blob.CFviBlob blob = new FVIL.Blob.CFviBlob(); blob.Param.ColorMode = FVIL.Blob.ObjectColor.BlackFG_WhiteBG; blob.SrcImages[0] = image; blob.Execute(); // リージョン取得と塗り潰し. // (1) 取得. FVIL.Data.CFviRegion region = blob.Result[2].GetRegion(); // (2) 塗り潰し. region.Fill(); // (3) 画像へ描画. region.Draw(image, 0); // (-) 確認用. filer.Save(System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "region_fill.png"), image); // 再計測. blob.Execute(); } |
処理手順:
- 処理対象画像の読み込み -
- 2値ブローブ解析実行 -
- リージョンの取得と塗り潰し
この例では2番目のブローブのリージョン(下図左の赤い部分)を取得しています。 取得したリージョンを塗り潰して、元画像に描画します。 - - 再計測
塗り潰された画像(下図右)を再度計測します。 -
※注) ここでは説明の為、処理部分を赤くしていますが、実際は黒です。
特徴量:
本ブローブ解析で取得可能な特徴量については CFviBlobData をご参照ください。
Examples
下記は、最も基本的な処理例を示します。
前景を白/背景を黒で解析し、
各ブローブの番号・重心・慣性等価楕円をオーバレイ表示します。
ソースコード:
C# | Copy |
---|---|
// $Revision: 1.4 $ using System; using System.Collections.Generic; using System.Text; using System.Drawing; using fvalgcli; // FvPluginXXXX attribute requires fvalgcli namespace User.SampleCode { public partial class Blob { /// <summary> /// 両解析. /// </summary> [FvPluginExecute] public void Measure1() { // 1) インスタンスの準備. FVIL.Data.CFviImage src = new FVIL.Data.CFviImage(Defs.TestImageDir + "/blob_BIN.png"); FVIL.Blob.CFviBlobResult result = new FVIL.Blob.CFviBlobResult(); FVIL.Blob.CFviBlob parser = new FVIL.Blob.CFviBlob(src, result); // 2) 処理対象画像の有効性検査. if (FVIL.ErrorCode._SUCCESS != FVIL.Blob.CFviBlob.CheckValidity(src)) return; try { // 3) パラメータ設定. FVIL.Blob.CFviBlobParam param = parser.Param; param.ColorMode = FVIL.Blob.ObjectColor.WhiteFG_BlackBG; // 前景:白/背景:黒. param.MaxBlobs = 0; // 0:上限なし. param.MaxRows = 0; // 0:上限なし. param.MaxRuns = 0; // 0:上限なし. param.Neighborhood = FVIL.Blob.Neighborhood.Eight; // 8近傍. param.PrecalcFeatures = 0; // 4) 画像処理実行. parser.Execute(); // E) 確認用. Measure1_SaveImage(parser); } finally { src.Dispose(); result.Dispose(); parser.Dispose(); } } /// <summary> /// 確認用 /// </summary> private void Measure1_SaveImage(FVIL.Blob.CFviBlob parser) { FVIL.Data.CFviImage src = parser.SrcImages[0]; // 画像表示の準備. FVIL.GDI.CFviDisplay display = new FVIL.GDI.CFviDisplay(); display.Image = src; display.DisplayRect = src.Window; // オーバレイの生成. FVIL.GDI.CFviOverlay pOverlay0 = new FVIL.GDI.CFviOverlay(); pOverlay0.Scaling = true; display.Overlays.Add(pOverlay0); // 有効ブローブの取得. FVIL.Blob.CFviBlobList list = parser.Result.GetBlobList(); FVIL.Blob.CFviBlobData data = new FVIL.Blob.CFviBlobData(); foreach (object item in list) { data.CopyFrom(item); // 特徴量の取得. FVIL.Data.CFviPoint center = data.Center; // 重心. FVIL.Data.CFviEllipse ellipse = data.EquivalentEllipse; // 慣性等価楕円. System.String strBlobNo = System.String.Format("{0}", data.BlobNo); // ブローブ番号. // 描画用: 重心. FVIL.GDI.CFviGdiPoint _center = new FVIL.GDI.CFviGdiPoint(center); _center.Size = new Size(5, 3); _center.Angle = ellipse.Angle; _center.Pen.Color = Color.FromArgb(0xFF, 0x00, 0x00); // 描画用: 慣性等価楕円. FVIL.GDI.CFviGdiEllipse _ellipse = new FVIL.GDI.CFviGdiEllipse(ellipse); _ellipse.Pen.Color = Color.FromArgb(0x00, 0x00, 0xFF); // 描画用: ブローブ番号. FVIL.GDI.CFviGdiString _blobno = new FVIL.GDI.CFviGdiString(); _blobno.Text = strBlobNo; _blobno.Position = center; _blobno.Align = FVIL.GDI.TextAlign.Left | FVIL.GDI.TextAlign.Top; _blobno.BkMode = FVIL.GDI.BkMode.Transparent; _blobno.Color = Color.FromArgb(0x3F, 0x3F, 0xFF); // 追加. pOverlay0.Figures.Add(_center); pOverlay0.Figures.Add(_ellipse); pOverlay0.Figures.Add(_blobno); } // 保存. using (FVIL.Data.CFviImage canvas = new FVIL.Data.CFviImage()) { display.SaveImage(canvas, display.DisplayRect, 1.0); canvas.Save(Defs.ResultDir + "/Blob.Measure1.png"); } } }; } |
Visual Basic | Copy |
---|---|
' $Revision: 1.2 $ Imports System.Collections.Generic Imports System.Text Imports System.Drawing Imports fvalgcli ' FvPluginXXXX attribute requires fvalgcli Namespace SampleCode Public Partial Class Blob ''' <summary> ''' 両解析. ''' </summary> <FvPluginExecute> _ Public Sub Measure1() ' 1) インスタンスの準備. Dim src As New FVIL.Data.CFviImage(Defs.TestImageDir & "\blob_BIN.png") Dim result As New FVIL.Blob.CFviBlobResult() Dim parser As New FVIL.Blob.CFviBlob(src, result) ' 2) 処理対象画像の有効性検査. If FVIL.ErrorCode._SUCCESS <> FVIL.Blob.CFviBlob.CheckValidity(src) Then Return End If Try ' 3) パラメータ設定. Dim param As FVIL.Blob.CFviBlobParam = parser.Param param.ColorMode = FVIL.Blob.ObjectColor.WhiteFG_BlackBG ' 前景:白/背景:黒. param.MaxBlobs = 0 ' 0:上限なし. param.MaxRows = 0 ' 0:上限なし. param.MaxRuns = 0 ' 0:上限なし. param.Neighborhood = FVIL.Blob.Neighborhood.Eight ' 8近傍. param.PrecalcFeatures = 0 ' 4) 画像処理実行. parser.Execute() ' E) 確認用. Measure1_SaveImage(parser) Finally src.Dispose() result.Dispose() parser.Dispose() End Try End Sub ''' <summary> ''' 確認用 ''' </summary> Private Sub Measure1_SaveImage(parser As FVIL.Blob.CFviBlob) Dim src As FVIL.Data.CFviImage = parser.SrcImages(0) ' 画像表示の準備. Dim display As New FVIL.GDI.CFviDisplay() display.Image = src display.DisplayRect = src.Window ' オーバレイの生成. Dim pOverlay0 As New FVIL.GDI.CFviOverlay() pOverlay0.Scaling = True display.Overlays.Add(pOverlay0) ' 有効ブローブの取得. Dim list As FVIL.Blob.CFviBlobList = parser.Result.GetBlobList() Dim data As New FVIL.Blob.CFviBlobData() For Each item As Object In list data.CopyFrom(item) ' 特徴量の取得. Dim center As FVIL.Data.CFviPoint = data.Center ' 重心. Dim ellipse As FVIL.Data.CFviEllipse = data.EquivalentEllipse ' 慣性等価楕円. Dim strBlobNo As System.String = System.[String].Format("{0}", data.BlobNo) ' ブローブ番号. ' 描画用: 重心. Dim _center As New FVIL.GDI.CFviGdiPoint(center) _center.Size = New Size(5, 3) _center.Angle = ellipse.Angle _center.Pen.Color = Color.FromArgb(&Hff, &H0, &H0) ' 描画用: 慣性等価楕円. Dim _ellipse As New FVIL.GDI.CFviGdiEllipse(ellipse) _ellipse.Pen.Color = Color.FromArgb(&H0, &H0, &Hff) ' 描画用: ブローブ番号. Dim _blobno As New FVIL.GDI.CFviGdiString() _blobno.Text = strBlobNo _blobno.Position = center _blobno.Align = FVIL.GDI.TextAlign.Left Or FVIL.GDI.TextAlign.Top _blobno.BkMode = FVIL.GDI.BkMode.Transparent _blobno.Color = Color.FromArgb(&H3f, &H3f, &Hff) ' 追加. pOverlay0.Figures.Add(_center) pOverlay0.Figures.Add(_ellipse) pOverlay0.Figures.Add(_blobno) Next ' 保存. Using canvas As New FVIL.Data.CFviImage() display.SaveImage(canvas, display.DisplayRect, 1.0) canvas.Save(Defs.ResultDir & "/Blob.Measure1.png") End Using End Sub End Class End Namespace |