Emgu CV – SURF Algoritması İle Nesne Takibi
Merhaba,
Şuana kadar görüntü işleme üzerine yapmış olduğumuz tüm çalışmalar neticesinde bir çok Image Processing algoritmasının mevcut olduğundan bahsetmiş bulunmaktayız. Bu algoritmalar arasında; görüntü üzerinde bir nesneyi algılamamızı sağlayan ve bu işlemi yaparken boyut, renk vs. gibi özelliklerinden bağımsız bir şekilde çalışan SURF algoritmasını ele alacağız.
SURF algoritması, yukarıda da ifade etmeye çalıştığım gibi ölçekleme ve rotasyondan bağımsızdır. Bu yüzden değişik bakış açılarına ve ışınsal açılara karşı gayet dirençli olmasından dolayı nesneyi algılamada doğruluk oranı oldukça yükse ve performanslıdır.
Bizler bu makalemizde SURF algoritmasını kullanacağımız sınıf yapımızı inşa edeceğiz ve çalışmamızı bir form üzerinde örneklendireceğiz. Eğer ki, sizlerde bu makaleyle birlikte paralel icraatte bulunmayı düşünüyorsanız hali hazırda bir Windows Forms projesi açınız ve form üzerinde bir adet PictureBox nesnesi ile projeye gerekli EmguCV entegrasyonunu sağlayarak sürece eşlik etmek için hazır bekleyiniz…
Evet…
Şimdi başlayabiliriz…
Öncelikle SURF algoritmamızı barındıran sınıfımızı inşa edelim.
static class SURFAlgoritmasi { public static Image<Bgr, Byte> Draw(Image<Gray, Byte> modelImage, Image<Gray, byte> observedImage) { HomographyMatrix homography = null; SURFDetector surfCPU = new SURFDetector(500, false); VectorOfKeyPoint modelKeyPoints; VectorOfKeyPoint observedKeyPoints; Matrix<int> indices; Matrix<byte> mask; int k = 2; double uniquenessThreshold = 0.8; if (GpuInvoke.HasCuda) { GpuSURFDetector surfGPU = new GpuSURFDetector(surfCPU.SURFParams, 0.01f); GpuImage<Gray, Byte> gpuModelImage = new GpuImage<Gray, byte>(modelImage); //extract features from the object image GpuMat<float> gpuModelKeyPoints = surfGPU.DetectKeyPointsRaw(gpuModelImage, null); GpuMat<float> gpuModelDescriptors = surfGPU.ComputeDescriptorsRaw(gpuModelImage, null, gpuModelKeyPoints); GpuBruteForceMatcher<float> matcher = new GpuBruteForceMatcher<float>(DistanceType.L2); modelKeyPoints = new VectorOfKeyPoint(); surfGPU.DownloadKeypoints(gpuModelKeyPoints, modelKeyPoints); GpuImage<Gray, Byte> gpuObservedImage = new GpuImage<Gray, byte>(observedImage); GpuMat<float> gpuObservedKeyPoints = surfGPU.DetectKeyPointsRaw(gpuObservedImage, null); GpuMat<float> gpuObservedDescriptors = surfGPU.ComputeDescriptorsRaw(gpuObservedImage, null, gpuObservedKeyPoints); GpuMat<int> gpuMatchIndices = new GpuMat<int>(gpuObservedDescriptors.Size.Height, k, 1, true); GpuMat<float> gpuMatchDist = new GpuMat<float>(gpuObservedDescriptors.Size.Height, k, 1, true); GpuMat<Byte> gpuMask = new GpuMat<byte>(gpuMatchIndices.Size.Height, 1, 1); Stream stream = new Stream(); matcher.KnnMatchSingle(gpuObservedDescriptors, gpuModelDescriptors, gpuMatchIndices, gpuMatchDist, k, null, stream); indices = new Matrix<int>(gpuMatchIndices.Size); mask = new Matrix<byte>(gpuMask.Size); GpuMat<float> col0 = gpuMatchDist.Col(0); GpuMat<float> col1 = gpuMatchDist.Col(1); GpuInvoke.Multiply(col1, new MCvScalar(uniquenessThreshold), col1, stream); GpuInvoke.Compare(col0, col1, gpuMask, CMP_TYPE.CV_CMP_LE, stream); observedKeyPoints = new VectorOfKeyPoint(); surfGPU.DownloadKeypoints(gpuObservedKeyPoints, observedKeyPoints); stream.WaitForCompletion(); gpuMask.Download(mask); gpuMatchIndices.Download(indices); if (GpuInvoke.CountNonZero(gpuMask) >= 4) { int nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(modelKeyPoints, observedKeyPoints, indices, mask, 1.5, 20); if (nonZeroCount >= 4) homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(modelKeyPoints, observedKeyPoints, indices, mask, 2); } } else { modelKeyPoints = surfCPU.DetectKeyPointsRaw(modelImage, null); Matrix<float> modelDescriptors = surfCPU.ComputeDescriptorsRaw(modelImage, null, modelKeyPoints); observedKeyPoints = surfCPU.DetectKeyPointsRaw(observedImage, null); Matrix<float> observedDescriptors = surfCPU.ComputeDescriptorsRaw(observedImage, null, observedKeyPoints); BruteForceMatcher<float> matcher = new BruteForceMatcher<float>(DistanceType.L2); matcher.Add(modelDescriptors); indices = new Matrix<int>(observedDescriptors.Rows, k); Matrix<float> dist = new Matrix<float>(observedDescriptors.Rows, k); matcher.KnnMatch(observedDescriptors, indices, dist, k, null); mask = new Matrix<byte>(dist.Rows, 1); mask.SetValue(255); Features2DToolbox.VoteForUniqueness(dist, uniquenessThreshold, mask); int nonZeroCount = CvInvoke.cvCountNonZero(mask); if (nonZeroCount >= 4) { nonZeroCount = Features2DToolbox.VoteForSizeAndOrientation(modelKeyPoints, observedKeyPoints, indices, mask, 1.5, 20); if (nonZeroCount >= 4) homography = Features2DToolbox.GetHomographyMatrixFromMatchedFeatures(modelKeyPoints, observedKeyPoints, indices, mask, 2); } } #region GÖRÜNTÜNÜN İŞLENMESİ Image<Bgr, Byte> result = Features2DToolbox.DrawMatches(modelImage, modelKeyPoints, observedImage, observedKeyPoints, indices, new Bgr(255, 255, 255), new Bgr(255, 255, 255), mask, Features2DToolbox.KeypointDrawType.DEFAULT); #endregion if (homography != null) { Rectangle rect = modelImage.ROI; PointF[] pts = new PointF[] { new PointF(rect.Left, rect.Bottom), new PointF(rect.Right, rect.Bottom), new PointF(rect.Right, rect.Top), new PointF(rect.Left, rect.Top)}; homography.ProjectPoints(pts); #region TESPİT EDİLEN NESNENİN ÇİZİLMESİ result.DrawPolyline(Array.ConvertAll<PointF, Point>(pts, Point.Round), true, new Bgr(Color.Red), 3); #endregion } return result; } }
Evet… SURF algoritmasını yukarıdaki gibi oluşturmuş olduk. Yapısal olarak teknik boyutta çok fazla teferruat barındırdığı için şimdilik yukarıdaki kod bloğunun satırlarına izahet getirmiyorum. Lakin bu sınıfın sağlıklı bir şekilde çalıştığından birazdan gözlerimizle emin olacağız.
Şimdi sıra, kameradan elde ettiğimiz görüntüde SURF algoritmasıyla tarayıp algılayacağımız nesneyi sisteme tanıtmaya gelmiştir. Kullanacağımız nesne çok sevip değer verdiğim Sayın Yazar Ümit Doğan Beyefendi’nin “Atatürk’ün İstihbarat Faaliyetleri – Milli Ajanlarımız” isimli kitabıdır.(Kesinlikle okumanızı ve okutturmanızı tavsiye ederim 😉) Velhasıl bu kitabın bir görselini internetten indirip elde edebilir ya da direkt olarak nesneyi kamera üzerinden de manuel olarak tarayıp görselini sağlayabiliriz. Projede bu görseli tutmak için Resource dosyalarını kullandığımı baştan belirteyim.
Algılatacağımız nesnenin görselini temin ederek sisteme entegre ettikten sonra sıra yukarıdaki oluşturmuş olduğumuz static yapıdaki “SURFAlgoritmasi” isimli sınıfı kullanmaya yani içeriğimizin asıl işlevini icra etmeye gelmiştir.
private void Form1_Load(object sender, EventArgs e) { Capture capture = new Capture(); capture.Start(); capture.ImageGrabbed += (a, b) => { try { var image = capture.RetrieveBgrFrame(); var SURFimage = SURFAlgoritmasi.Draw(new Image<Gray, Byte>(Resimler.nesne), image.Convert<Gray, byte>()); pictureBox1.Image = SURFimage.ToBitmap(); } catch { } }; }
Yukarıdaki kod bloğunda olduğu gibi SURF algoritmasını kullanarak kameradan gelen görüntü üzerinde elimizdeki görüntüleri kıyaslamakta ve nesne tespitini gerçekleştirmekteyiz. Şuana kadar yapmış olduğumuz işlemin faaliyetini aşağıdaki videodan da inceleyebilirsiniz.
Eğer ki, nesnenin görüntü çıktısına dahil edilmeden sadece tespit edilmesini istiyorsanız “SURFAlgoritmasi” sınıfındaki “GÖRÜNTÜNÜN İŞLENMESİ” isimli regionın içerisini aşağıdaki çalışma ile değiştirmeniz yeterlidir.
Image<Bgr, Byte> result = observedImage.Convert<Bgr, byte>();
Bu şekilde projeyi derleyip çalıştırdığımız vakit SURF algoritmasını aşağıdaki videoda olduğu gibi kullanabilmekteyiz.
Gördüğünüz üzere SURF algoritması ile elimizdeki görüntü üzerinde belirlediğimiz bir nesneyi tarayabilmekte ve algılayabilmekteyiz. Her ne kadar benim ihtiyar bilgisayarım bu algoritmanın hızına hakkıyla eşlik edemesede yine de algoritmanın yüksek performanslı işleyişine ve işlevselliğine şahitlik etmiş bulunmaktasınız.
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…
NEyi nereye yapıştıracağız, nasıl yapacağız onuda söylermisiniz. Ben liseliyim ve yeni öğrenmeye başladım.
Sevgili Mustafa kardeşim.
Lütfen şu öğrenme sürecinin ilk adımlarında; doğru araştırma, doğru soru sorma ve ne istediğini doğru bir şekilde izah edebilme yetkinliklerini kazanarak süreci değerlendirmeye çalış. Emin ol bu kazanımlar sana ilk etaptan sonsuza kadar yüksek derecede yar ve yardımcı olacaktırlar.
Sevgiler…
Öncelikle emeğiniz için çok teşekkür ederim. Takıldığım bir konuc var. Resources klasöründe ya da herhangi bir listede yer alan görüntülerle kaynak üzerinde eşleştirmek istiyorum. Mesela listemde kırmızı, beyaz, siyah kutularım var. Kaynak resim üzerinde karışık halede bulunan bu kutuları eşleştirmek istiyorum. Yardımınız için şimdiden teşekkür ederim.
Merhaba,
Nezaketiniz için ben teşekkür ederim.
İsteğiniz doğrultusunda size nasıl yardımcı olabilirim?
Loaddaki Resimler.nesne nedir? tşkler.
Aranan nesne.
İyi çalışmalar Gençay Bey
Ben programı yaptım fakat load kısmındaki Resimler.nesne kısmında hata veriyor.Ne yapmalıyım?
Cevabınız için şimdiden teşekkürler.
Merhaba,
Hata?
Öncelikle merhabalar,
Yukarıdaki surf algoritma örneği size mi ait EmguCV adı altında yoksa herhangi bir yerde kullanabileceğimiz eğitim amaçlı bir çalışma mı yoksa? Bir de Surf düşük ışıkta etkili kullanabilir mi
Merhaba,
Surf algoritması bana ait değildir. Bu stratejiyi benimseyerek tarafımca pratikte bir uygulama geliştirilmiştir. İstediğiniz yerde alıp, uygulayabilirsiniz. Işık durumuna göre elimde herhangi bir veri bulunmamaktadır. O yüzden bu konuda yardımcı olamayacağım.
Çalışmayı hangi ortam ve programlama dilinde yaptınız acaba? Bu işlere yeni başladığım için anlamakta zorlandım. Yardımınız için şimdiden teşekkürler.
Merhaba,
Çalışma ortamım : Visual Studio,
Kullandığım dil : C#
🙂
Cevaplarınız için teşekkürler.
Surf Algoritmasında çok fazla hata aldım ve bundan dolayı yapamadım. Projeyi paylaşmanız mümkün mü?
Çok fazla hata var ya paylaşmayın yada düzgün paylaşım yapın boştan yere vaktimizi alıyorsunuz.