PC tabanlı görüntü işleme uygulamalarında, paralel programlama teknikleri kullanmak çok radikal hız artışları sağlayabilir. Yazılımımız, gerçekten sahip olduğumuz donanımın hakkın veriyor mu? Günden güne hızlanan bilgisayarlar, çok çekirdekli işlemciler, devasa hafızalar… Bu kaynakları gerçekten etkin olarak kullanabiliyor muyuz?
Düzgün yönetilmememiş paralel programlama (Multi threaded programming) uygulamalarında çoğu kez olan yukarıdaki gibidir 🙂 Bilmem kaç çekirdekli cep telefonlarının neden bu kadar yavaş olduğu sorusunun da cevabı? Tamam çekirdek çok da, uygulama onları nasıl kullanıyor?
Paralel programlama derken tam olarak neyi kastediyoruz?
Paralel programlama, bilgisayar işlemcisinde gerçekleşen işlemlerin, birinin diğerini beklemediği, aynı anda bir çok işlemin çalıştığı uygulamalardır. Visual Studio .NET dilinden konuşursak, çok kanallı programlar (Multiple threads), parallel tasks, background worker v.b. yapılar ile çoğu programcının bir şekilde aşina olduğu yapılardır. Bu yapılar ile uğraşanlar iyi bilir, duruma göre tam bir başağrısıdırlar. Geliştirmesi zor, debug etmesi zor, sonuçların ekranda gösterilmesi bile ayrı bir teknik gerektirir. Lock objects ler, autoreset, manual reset eventler, mutexler, semaphore lar v.b. .NET yapıları, durduk yere hiç bir programcının severek bulaşacağı yapılar değildir, kabul edelim.
Eğer öyle ise, görüntü işleme uygulamam gerçekten paralel çalışmalı mı?
Bu sorunun cevabı, eğer zaman sorunum varsa, ya da birim sürede çok daha fazla kontrol etmem gerekiyorsa EVET, aksi halde HAYIR dır.
Gerçek hayattan örnek vermek gerekirse, Derby traş bıçakları fabrikasında bir makinada kurulu olan sistemimiz, her 600 milisaniyede bir, üretilen traş bıçağını kontrol etmektedir. Böyle bir sistemde,
- Kameradan Görüntünün Alınması (80 ms.)
- Alınan Görüntünün İşlenmesi (60 ms)
sürmektedir. Özetle, tetik sinyali geldikten sonra, en geç 150 ms. sonra, OK ya da NOK cevabını sisteme bildirmekteyiz. Geri kalan 450 ms. içinde de sistem diğer ürünün gelmesini beklemektedir. Dolayısıyla, bir zaman sorunu yoktur, işlemleri paralel yapmak kimseye bir şey kazandırmayacaktır. Bu durumda, eski tip, ardışıl programlama (görüntü al, işle, dijital çıkış ver, bekle, başa dön..) en doğru seçenek olacaktır.
Peki ya sürekli ve çok hızlı kontrol etmem gerekirse, mesela araçlardaki şerit takip sistemi örneği gibi. Sistem sürekli ve olabildiğince hızlı görüntü almalı, işlemeli ve hiç beklemeden yeniden görüntü almalı, yeniden işlemeli. bu alma-işleme süreci ne kadar kısa olursa, sistem o kadar sağlıklı / gerçeğe yakın çalışacaktır.
Yine gerçek bir örnek verelim;
Halı Kesme makinası olarak kurulumunu yaptığımız sistemde 13 adet kamera vardır. 50 m/dk hızıyla üretilen halıları dikey olarak tam kesim çizgisinden kesmek istiyoruz. Bunun için 13 bıçağın, kameralar yardımıyla anlık olarak sağa-sola yönlendirilmesi ve tam çizgi üzerinden kesim yapılması sağlanmalıdır.
Halı, esnek olduğundan, kesim çizgisi sağa sola kayabilmekte ve ancak kamera yardımıyla çizgiyi görüp takip etmesi sağlanabilmektedir. Sorun şu ki, 50 m/dk. hızında üretim yapılırken, 120 ms. içinde halı 10 cm kaymaktadır. Dolayısıyla, bu projede, tipik olarak 1. kameradan görüntü al, işle, 2. ye geç al işle, sonra 3. ye… şeklinde bir yaklaşım izlenmiş olsa, algoritmalar ne kadar düzgün çalışırsa çalışsın, sonuç tam bir felaket olacaktır. Tek bir kameradan görüntü alınıp yine aynı kameraya sıra gelene kadar, halı 1 m. den fazla ilerleyecektir ve böyle bir sistem elbette kabul edilemez.
HALCON 12 ile Paralel Programlama
Visual Studio kullanarak geliştireceğimiz, çok kameralı tipik bir paralel programlama algoritması genel hatları ile şu şekildedir.
3 adet genel thread vardır.
- Grabbing Threads : Var olan kamera sayısı kadar thread açılır. Her bir thread sonsuz bir döngüde görüntü alır. Diyelim ki 4 kamera var. 4 ü de eş zamanlı olarak görüntü alır. Biri diğerini beklemez, her biri bağımsız olarak kendi görüntüsünü alır.
- Processing Thread : Yine kamera sayısı kadar thread açılır. Her bir thread, sonsuz bir döngü içinde, kendi kamerasından görüntü alınmışsa, bunu işler yine başa döner (yeni görüntü alınmasını bekler) görüntüyü işlemeye başladığı anda, grabbing thread yeniden resim alma işi ile meşgul olur. Diyelim ki, resim alma (grabbing) 60 ms, işleme ise 20 ms sürsün. bu durumda, tek bir kamera 60 ms içinde sonucu verecektir (80 değil) çünkü 20 ms. işleme sürerken, grabbing thread görüntü almaya başlamıştı ve işleme bittikten 40 ms. sonra (60 değil) yeni görüntü gelecektir.
- User Interface Thread : Benim kullanmadığım ama genel amacı, bulunan sonuçların ekranda gösterilmesi, label buton panel v.b. form kontrollerinin çizilmesi amacıyla kullanılır. Ben, HALCON fonksiyonlarına, DisplayHandle gibi bir değişken gönderiyorum ve ekran işlemlerini de HALCON içinden yaptırıyorum. Böylece, sonuçların toparlanması ekranlarda gösterilmesi gibi işleri C# tarafında değil, HALCON tarafında hallediyorum.
Bu yapı, kendi içinde gayet hızlı çalışacak ve CPU kullanımı tüm çekirdeklerde %100 e vuracaktır. bu iyiye işarettir, tek bir cpu birimini boşa harcamaya gerek yoktur ve uygulamamız resmen donanımın hakkını veriyor demektir.
Ayrıca, bellek kullanımına dikkat edin, sonsuz döngüde çalışan thread (kanal) yapıları, nesneleri hafızadan atamıyorsa, çok çabuk hafıza dolabilir. İdealde hafızanın sabit kalması gerekmektedir.
HALCON 12 ile Paralel Programlama
Visual Studio ile, paralel programlama tekniklerini etkin bir şekilde kullanarak, çok kameralı sistemde, tüm görüntü alma ve işleme kanallarını paralel çalıştırarak, çok büyük bir hız avantajı sağladık. Şimdi HALCON ile bu yapıyı daha da geliştirmek mümkün.
Öncelikle HALCON, tecrübeli olmayan programcılar ya da .NET çok kanallı yapılarını sevmeyen tercih etmeyen kullanıcılar için bir çok yenilik barındırmaktadır. Artık tüm paralel programlama işlemlerini HALCON kendisi yerine getirebilmektedir. HALCON12, yazdığınız kod parçalarını (HDevelop procedure) tek bir tıklama ile paralel olarak çalıştırabilmektedir. (Bizim C# ile tabir yerinde ise, o kadar kastırarak yaptığımız dümenlerin hepsi boşa mı gitti şimdi 🙁 )
Ve hala daha da fazlasını sunmaktadır. O da şu :
diyelim ki, her bir kameradan alınan görüntüde, tek bir işlem değil de, birden fazla işlem yapmak durumundayım. Mesela alınan görüntüde hem barkod, hem karekod, hem de OCR yapmak durumundayım diyelim.
Barkod bulma 40 ms, OCR 90 ms, karekod okuma ise 70 ms. civarı sürsün.
HDevelop içinde bu işi yapan 3 güzel procedure yazdığımı varsayalım. HALCON 12, bu 3 procedure ü paralel olarak başlatabilmekte (par_start komutu ile) Buraya kadar olan, zaten tecrübeli C# kullanıcılarının daha önceden yaptığına denk gelen kısım. HALCON, par_join komutu ile, bu 3 procedure ü de aynı anda çalıştırmakta, en son hangisi biterse, diğerleri onu beklemekte, ve tek bir yapı çalıştırmışım gibi sonlanmakta. Dolayısıyla, bu yapıları paralel çalıştır diyorum, sanki hepsi tam da aynı anda çalışıp aynı anda bitmiş gibi, bir alt satırda da hepsinin sonuçlarını toplayabiliyorum. Bizim örneğimizde, 90 ms. sonunda barkod, karekod ve OCR işlemim bitmiş, elimde hazır sonuçlar olmuş oluyor.
Bu güçlü yapıyı, C# daki özgün multi thread yapım ile birleştirdim. Ortaya, C# tarafında, tüm kameralardan görüntü alma ve işleme işlemlerinin paralel koşturulduğu, HALCON tarafında da bir çok procedure (alt programı) aynı anda çalıştırıldığı, hibrit bir yapı çıktı. Sistemi 13 kamera için çalıştırdığımda, cpu fanı hemen devreye girmekte CPU maksimum performansa zorlanmakta. (Bu aşamada i7 gibi işlemcilerin gerçek farkını ve hızını hissedebilmek de bir programcı olarak ayrı bir mutluluk kaynağı oluyor.)
Peki, neden aynı anda bir çok procedure start edilir. Ya da ne gibi uygulamalar buna ihtiyaç duyar.
Açıkçası bu çok sık karşılaşılan bir yapı veya ihtiyaç değildir.
Bizim halı kesme makinasında, siztem kesim çizgisini aramaktadır. Yazdığım algoritmalarda bazen var_threshold ile sonuca gitmiş, bazen de binary_threshold işe yaramıştı. Bazı durumlarda median_rect filtresi güzel sonuçlar vermiş, bazen ise label_to_region işe yaramıştı. Bazen GMM classification imdada yetişmiş, bazen resmi decompose edip hsv kanallarına bakmam gerekmişti?
İyi ama, bunların hangisini kullanmam en doğrusuydu? Apaçık ki, hiç biri tek başına yeterli değil. Hepsini tek tek denesem, bu sefer çok uzun sürebilir. İşte tam da bu anda, yazdığım tüm alt programları (ki aslında hepsinin derdi aynı, hepsi de çizgi arıyor) aynı anda start ediyorum. Resmi grab etmem (kameradan almam) ortalama 60 ms. kadar sürüyor (bendeki pixel clock, exposure değerleri ile inebildiğim minimum değer) ve bir sonraki resim gelene kadar, tüm yapıları HALCON aynı anda start ediyor. bunlardan bir veya daha fazlası sonucu zaten buluyor ve bulduğum sonucu işliyorum.
Sonuç?
Eğer bu kadar fazla multitasking sonucu yazdığınız kodlar halıya çıkmadıysa, iyi yoldasınız demektir.
Yazının Özeti :
HALCON 12 güçlü bir multithreading (paralel programlama) desteği sunmaktadır. par_start, par_join, mutex, message queue yapılarını inceleyin, örneklere bakın, dokümanları okuyun, çok yardımcı olacaktır. Buna rağmen danışmanız gereken bir yer olursa, buradan ya da info@mavis.com.tr ile bana istediğiniz zaman ulaşabilirsiniz.
kolay Gelsin 😉