Bu yazıda Aforge kütüphanesini kullanarak şekil tespiti yapacağız. Bu konuyu daha kolay anlayabilmek için Aforge kütüphanesi , bitmap sınıfı , graphics sınıfı ve blob bulma yazılarını okumanızı tavsiye ederim.

SimpleShapeChecker ile Şekil Tespiti

SimpleShapeChecker Aforge kütüphanesinde yer alan şekillerin tespiti için kullanılan bir sınıftır. Şekilleri bulmadan önce bloblar çıkarılır. Çıkarılan bloblar SimpleShapeChecker sınıfına gönderilir. Bu sınıfta blobları yorumlayarak  şekillerin tespitini sağlar.

Şekil tespiti yapmadan önce resmi bir ön işlemeye tabi tutacağız. Resimdeki şekillerin daha kolay tespitini sağlamak için arkaplanı siyah yapmamız gerekiyor. Bunun için öncelikle resmi grayscale‘e çevireceğim. Resmi grayscale çevirmeden önce grayscale fonksiyonun desteklediğini bildiğim Format24bppRgb  formatına çeviriyorum.

Rectangle rct = new Rectangle(0, 0, bmp.Width, bmp.Height);
bmp = bmp.Clone(rct, PixelFormat.Format24bppRgb);

Ardından grayscale filtresini uyguluyorum.

Grayscale gfilter = new Grayscale(0.2125, 0.7154, 0.0721);
bmp = gfilter.Apply(bmp);

Daha sonra BradleyLocalThresholding filtresi uygulayacağım. Bu algoritma parlaklığı, belirtilen boyuttaki pencerenin çevre piksellerin ortalama parlaklığının altındaysa, her görüntünün pikselinin siyaha ayarlanması, aksi halde beyaza ayarlanmasını sağlar.Detaylı bilgiye buradan ulaşabilirsiniz. Aşağıda bir örneği verilmiştir.

bradleylocalthresholding
Before
bradleylocalthresholding
After

 

 

 

 

 

 

BradleyLocalThresholding thfilter = new BradleyLocalThresholding();
thfilter.ApplyInPlace(bmp);

Daha sonra Invert filtresi uygulayarak resmi tersine çevirerek  beyaz olan yerleri siyah, siyah olan yerleride beyaz yapıyorum.  Böylelikle arka planı siyah renge çevirmiş oldum.

Invert ifilter = new Invert();
ifilter.ApplyInPlace(bmp);

Bütün ön işleme adımları bir fonksiyonda topluyorum.

public Bitmap PreProcess(Bitmap bmp)
{
Rectangle rct = new Rectangle(0, 0, bmp.Width, bmp.Height);
bmp = bmp.Clone(rct, PixelFormat.Format24bppRgb);
Grayscale gfilter = new Grayscale(0.2125, 0.7154, 0.0721);
Invert ifilter = new Invert();
BradleyLocalThresholding thfilter = new BradleyLocalThresholding();
bmp = gfilter.Apply(bmp);
thfilter.ApplyInPlace(bmp);
ifilter.ApplyInPlace(bmp);
return bmp;
}

Öncelikle graphics kullanarak bulduğum şekilleri çizdireceğim. Bunun için resmin bir kopyasını oluşturarak graphics sınıfının desteklediği formata çeviriyorum. Ve resmi ön işlemeye fonksiyona göndererek ön işleme adımını gerçekleştiriyorum.

Rectangle rct2 = new Rectangle(0, 0, bmp.Width, bmp.Height);
Bitmap bmp2 = bmp.Clone(rct2, PixelFormat.Format24bppRgb);
bmp = PreProcess(bmp);

Ardından resimdeki blobları buluyorum.

BitmapData bitmapData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height),
ImageLockMode.ReadWrite, bmp.PixelFormat);
            BlobCounter blobCounter = new BlobCounter();
            blobCounter.FilterBlobs = true;
            blobCounter.MinHeight = 4;
            blobCounter.MinWidth = 4;
            
            blobCounter.ProcessImage(bitmapData);
            Blob[] blobs = blobCounter.GetObjectsInformation();
            bmp.UnlockBits(bitmapData);

Ardından SimpleShapeChecker nesnesi yaratıyorum. Graphics sınıfı ile bulduğum şekilleri resmin üzerinde çizdireceğim.Resimleri çizdirirken şekilleri ayırmak için farklı renkler kullanacağım bu yüzden her biri için ayrı bir Pen nesnesi yaratıyorum.

SimpleShapeChecker shapeChecker = new SimpleShapeChecker();     
Graphics g = Graphics.FromImage(bmp2);       
Pen yellowPen = new Pen(Color.Yellow, 2); // bilinmeyen şekiller
Pen redPen = new Pen(Color.Red, 2);       // Dikdörgenler
Pen DarkGreenpen = new Pen(Color.DarkGreen, 2);   // Yamuk
Pen OrangePen = new Pen(Color.Orange, 2);   // 
Pen bluePen = new Pen(Color.Blue, 2);     // Kare

Resimde her bir blobu yorumlamak için for döngüsü kullanıyorum. GetBlobsEdgePoints methodu ise bize blobların kenar noktalarını verir.

 for (int i = 0, n = blobs.Length; i < n; i++)
{
             
  List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
  List<IntPoint> corners;
      if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
       {
        PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);
                 //işlemler
       }

}

IsConvexPolygon methodu bize eğer kenar noktaları bir çokgen ise true değerini döndürür. ve köşe noktalarını da geri alırız. (Referans türü değişkenler olduğu için).CheckPolygonSubType çokgenin köşe noktalarını alır ve bize çokgenin tipini döndürür.Daha sonra PolygonSubType’ı kullanarak şekil ayrımı yaparız.Çokgenin tipine göre de farklı renklere boyarız. Örnek program çıktısı

Şekiller

Kodların tamamı:

for (int i = 0, n = blobs.Length; i < n; i++)
{
  List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
  List<IntPoint> corners;
  if (shapeChecker.IsConvexPolygon(edgePoints, out corners))
  {
  PolygonSubType subType = shapeChecker.CheckPolygonSubType(corners);
  Pen pen;
     if (subType == PolygonSubType.Unknown)
      {
        pen = yellowPen;
      }
       else if (subType == PolygonSubType.Square)
      {
        pen = bluePen;
                      
      }
      else if (subType == PolygonSubType.Rectangle)
      {
        pen = redPen;

      }
      else if (subType == PolygonSubType.Trapezoid)
      {
       pen = DarkGreenpen;
      }         
      else
      {
       pen = OrangePen;   
      }
        g.DrawPolygon(pen, ToPointsArray(corners));
   }
            
                pictureBox1.Image = bmp2;

}
private System.Drawing.Point[] ToPointsArray(List<IntPoint> points)
{
 System.Drawing.Point[] array = new System.Drawing.Point[points.Count];

 for (int i = 0, n = points.Count; i < n; i++)
 {
  array[i] = new System.Drawing.Point(points[i].X, points[i].Y);
  }
  return array;
}

 

CEVAP VER

Lütfen yorum giriniz!
Lütfen isminizi giriniz