İstanbul Altın Borsası’nda

Mavis, Altın Borsasında her bir külçe altının üzerindeki üretici rafine logosu ve külçe seri no sunu okuyan shape matching – ocr uygulamasının testlerine başladı.

Karaköy Rıhtımda yer alan Altın Borsası, görüntü işleme uygulamaları için iyi bir mekan 😉

VYP ye bir standart kontrol daha eklendi

Mavis, Kameralı Kontrol yazılımı VYP ye, yeni bir standart kontrol daha ekledi : “Araparça Boy ve Yükseklik Ölçümü”.

Standart kontrol, kullanıcı tarafından görsel olarak parametreleri değiştirilmek suretiyle uyarlanabilen kontrollerdir. Mavis VYP, Standart kontroller (alan bulma, var-yok kontrolleri, pozisyon kontrolleri, renk kontrolleri vb.), Gelişmiş kontroller (karekod, ocr vb.) ve projeye özgü kontrollerden oluşmaktadır.

Araparça Boy ve Yükseklik Ölçümü :

Karmaşık parçalar grubunda belirli özellikleri bilinen bir parçanın seçilip, en boy yükseklik gibi değerlerinin ölçülebilmesine yarar.

Son yapılan ilave değişiklikle birlikte (01.07.2010) araparça ölçümünde döndürme işlemi, sonda değil başta yapılmaktadır. Böylece Clip Region (sp_eliminate_run) işlemi daha sağlıklı değer verdiğinden daha hassas ölçüm mümknü olmaktadır.

Yukarıdaki şekilde, mavi dörtgen içindeki civatanın boyunu ölçmeye çalışalım. Normalde mavi dörtgen içine, hem civata hem de somun girdiğinden, ilave kontroller yapılmaksızın sadece civatayı ölçmek mümkün değildir. Mavis VYP ye yeni eklenen “Araparça Ölçüm” kontrolü ile görsel olarak programlama yapmaksızın bu kontrol bildirilebilmektedir.

Şekilde görüldüğü gibi, Araparça kontrolü kullanılarak, somun ve civatadan oluşmuş şeklin sadece  civata kısmının boyu ölçülebilmektedir.

Görev Parametreleri

  • Standart ReduceDomain İşlemi
  • Standart ApplyThreshold İşlemi
  • Standart ApplySelection İşlemi
  • Clip değişkeni : ölçülecek araparçanın min ve max Run değeri (bu değerler arasındaki parçalar dikkate alınır)
  • CheckHeight : Yükseklik ölçümü isteniyorsa bool 1 (yes, on, ok, evet değerlerinden biri) kullanılır
  • CheckWidth : Genişlik ölçümü isteniyorsa kullanılır
  • CheckLong : Uzun kenar ölçümü isteniyorsa (en ya da boy, hangisi daha büyükse)
  • CheckShort : Kısa kenar ölçümü isteniyorsa (en ya da boy. hangisi daha kısaysa)
  • RHeight : minHeight..maxHeight arası değer (beklenen geçerli yükseklik değeri. CheckHeight değeri 1 ise anlamlı)
  • RWidth : minWidth..maxWidth arası değer (beklenen geçerli genişlik değeri. CheckWidth değeri 1 ise anlamlı)
  • RLong : minLong..maxLong arası beklenen uzun kenar değeri. (CheckLong değeri 1 ise anlamlı)
  • RShort : minShort..maxShort arası beklenen kısa kenar değeri. (SheckShort değeri 1 ise anlamlı)

alt programın HALCON ve C# kodlarını edinmek ve yorum yapmak için, blog sitesinde veya bizimle (info@mavis.com.tr) yazışabilirsiniz.

ilk Bakışta HALCON 10 a

HALCON 10, birçok yeni özellikleri ile birlikte neredeyse hazır. Final Release olmadığı için, yorum yapmak için henüz erken olmakla birlike, HALCON 9.0.2 ye göre radikal bir değişimden bahsetmek zor. (HALCON 7 den HALCON 8 e geçiş, gerek HDevelop ortamı, gerek Engine kısmına yapılan değişiklikler ile ciddi bir ilermelemeydi. HALCON 9.0 a geçişte, HDevelop daha kullanışlı hale getirilmiş, COM türü bileşenlerden .NET arabirimine geçiş daha fazla desteklenmişti.)

Alpha versiyonun ilk testleri sırasında göze çarpan yenilikler

Hedevelop ortamı gerek yetenek gerek görsellik açısından daha da geliştirilmiş. Burada da radikal bir değişimden bahsetmek zor olmakla birlikte, getirilen yenilikler HDevelop kullanımını daha da zevkli hale getirmiş.

Measurement Assistant

Daha önceden var olan assistant pencerelerine yeni eklenen Measurement asisstant, ilk kullanımda tüm ölçüm işlemlerine hizmet edebilecek yetenekte görülüyor. özellikle Fuzzy measurement öğeleri içermesi, World coorditanes işlemlerini (px, mm) otomatik yapabilmesi gibi avantajlar, programcının işini olabildiğince hafifletmiş.

Editördeki Yenilikler

Editör, code insight kısmına yenilikler getirmiş. Daha önce 9.0.2 de getirilen yenilikler biraz daha iyileştirilmiş. Gelişmiş editörlerde (mesela Visual Studio) olduğu gibi değişkenleri de içeren daha zengin bir code insight seçeneği gelmiş.

Runtime Yenilikleri

Program output windows yardımıyla, çalışan her bir satırı ve detay bilgilerini artık yeni bir pencerede izleyebiliyoruz. Statusbar da hint olarak görünen bilgiler, daha da zenginleştirilerek yeni pencereye taşınmış. Artık hangi operatör bloğunun ne kadar sürede çalıştığını anlamak vb. işlemler için Count_seconds ile milisaniyeleri saymaya son 🙂

Diğer tüm yenilikleri MVTec kendi sitesinden duyuracağı için Alpha test sonuçlarına burada ayrıntılı olarak girilmemiştir. Zaten MVTec bu aşamada HALCON 10 lisansının dağıtımını da sınırlamıştır.

3D Eşleştirme, Robotik

Mavis, Teknodrom firması ile başlattığı robot yönlendirme ve parça bulma yakalama ayıklama çalışmalarına yeni bir boyut ekledi. Robotun yakalayacağı parçaları öğrenebilmesi için son derece pratik bir arayüz geliştirildi.

Sistemin Çalışması

Öncelikle kameranın dış etkenlerden (değişken ışık kaynakları, gün ışığı vb.) etkilenmemesi için düzgün aydınlatılmış bir ortam oluşturulur. Bu ortam robotun çalışmasını engellemeyecek şekilde yapılmalıdır.

1. İşlem olarak, kameraya yakalayacağı parçalar öğretilir. Her parça farklı bir yerinden tutulmak istenebilir. Tutma noktası parçanın belirli köşeleri, uçları gibi daha önceden tahmin edilemeyen bir yer olabilir. Robot operatörü, parçanın ideal tutma noktasını,  kameralı görüntü işleme yazılımında bir değişiklik istemeden (programlamaya ihtiyaç olmadan) kolayca gösterebilmelidir. (Programa  tutma noktası öğretilmelidir) Programda hiç değişiklik yapılmadan son derece kolay bir arabirimde (UI) parçalar sisteme tanıtılabilmelidir. Mavis’in kendi geliştirdiği sistem bu sorunu en kolay şekilde çözmüştür.

Menüden “yeni parça öğretme” işlemi seçildiğinde, kameranın altında bulunan parçanın resmi ekranda belirir. “Öğretme İşlemine Başlamak İstiyor musunuz?” sorusuna Evet dendiğinde, interaktif bir şekilde tutma noktası kullanıcıdan alınır.

Öğretilecek parçanın en ideal parça olmasına özen gösterilir. Buna rağmen ekranda parça sınır çizgileri belirlenir ve kenar iyileştirme algoritmaları ile çapak ve pürüzler ön işlemden geçirilerek temizlenir.

Bu noktada sistem parçanın modellenmiş ve temizlenmiş halini model kodu ile kaydeder. Herhangi bir görüntü işleme programı ile (Paint, Photoshop vb.) bu modellenmiş fotoğraf üzerinde daha da hassas çalışmalar yapılabilir. (Filtreleme, yuvarlatma, kenarları düzleştirme vb.)

Üstelik, tüm bu işlemler gerçek parça resmi yerine parçanın direk CAD çizimi baz alınarak ta yapılabilir.

Program çalışma anında, öğretilen parçayı tanıyacak ve tutma noktasının koordinatlarını ve açılarını robota iletecektir.

Sistem tüm robotlarla haberleşebilecek altyapıya göre tasarlanmıştır. Testler ve uyarlamalar Teknodrom firmasında Motoman Robot kullanılarak yapılmıştır. Haberleşme olarak seri port ve dijital Input/output modülü kullanılmıştır. Ethernet haberleşme için de arayüz geliştirilmiştir. Sistem Fanuc, kuka gibi robotlar ile de çalışabilecek şekildedir. Test ve geliştirmeler; Teknodrom firmasından Emrah Hünerlitürkoğlu, Mavis firmasından Mustafa Sarı ve Hüseyin Çelik tarafından gerçekleştirilmiştir.

Mavis Targovishte’de

Mavis Yapay Görme Ekibi, Bulgaristan Targovishte deki bir tesiste, kameralı kontrol kurulumu için yerinde çalışmalar yaptı. 1 gün boyunca süren çalışmalarda, üretim esnasında ve laboratuvar ortamında birçok farklı tip ürün üzerinde çalışılarak sonuca varıldı. Yapılan çalışmalar, proje sahibine rapor olarak sunulacaktır. Proje gerçeklenme aşamasında, daha detaylı bilgi verilecektir.

Mavis, Bugün Bulgaristanda kurulumunu yaptığı bir diğer proje olan robot kontrollü kameralı kontrol sisteminin kontrol ve iyileştirme çalışmalarına devam etmektedir.

Mavis İzmir’de

Mavis, Kameralı Yaprak Kontrolü makinasının montaj ve ilk testleri için İzmirde.

14 Haziran itibariyle, İzmirde sıcaklık : 34 derece.  Öğle saatlerinde 40 a yaklaşacağı söyleniyor.

(Müşteri Bilgi Gizliliği politikamız gereği, yapılan çalışma ve teknolojisi hakkında daha fazla bilgi verilmemiştir)

VYP ye Yeni Bir Standart Kontrol

Mavis VYP Kameralı Kontrol Yazılımı standart kontrollerine yeni bir tane daha eklendi : Parça Yönelimi.

Mavis VYP de, kameralı kontroller 3 gruba ayrılır.

  • Standart Kontroller
  • Projeye Özgü Kontroller
  • Gelişmiş Kontroller

Bir projenin sadece standart kontroller kullanılarak gerçeklenmesi en ideal durumdur. Projeye özgü kontroller bazı durumlarda kaçınılmaz olabilir. VYP, standart kontrol setini zenginleştirerek Projeye özgü kontrolleri olabildiğince minimuma indirgemiştir.

Standart kontrol kullanmanın avantajları

  • Kod yazımına gerek kalmaz
  • Defalarca test edilmiş olduğundan hatalara açık değildir
  • İyi Dökümante edilmiş ve eğitimlerde anlatılmış olduğundan kullanıcılar kolay uyum sağlar
  • Modüler / parametrik  olduğundan zahmetsizce uyarlanabilir
  • Güncelleştirmeler veya arayüz iyileştirmelerinden var olan tüm kurulumlar ek işlem yapılmaksızın yükseltilmiş olur

Parça Yönelimi :

Bu kontrol, sıkça karşılaştığımız “ters yönde takılmış” parçaları yakalamaya yarar. Kullanıcı arayüzü oldukça basittir.

Zorunlu kullanıcı seçimleri

  • bağlantı noktası (_juncPoint)
  • parçanın doğrultusu (_partDirection) Yatay / Dikey
  • parçanın beklenilen yönelimi (_expectingOrientation) Sol / Sağ / Üst / Alt

Opsiyonel kullanıcı seçimleri

  • Yaklaşma dörtgeninin kenar uzunluğu (_juncHeight) Varsayılan Değer : 10

Böylece sadece 3 seçimle birlikte kullanıcı parçanın olması gereken yönü sisteme kolayca bildirmiş olur.

(VYP Parça Yönelimi İçeren Kontrolleri Çalıştırıyor)

VYP Ekranında %800 zoom edildiğinde, parçanın yönelimi görülüyor.

Yönelim kullanıcının beklediği doğrultuda ise yeşil ok, aksi halde kırmızı ok (ters istikamete) ekranda belirecektir.


Yeni kontrolün C# kodlaması :

 

		private bool CheckDirection(JobDefs job)
		{

			if (masterFailed)
			{
				DrawCurrentRoi(job, false);
				return false;
			}

			HObject ho_ImageReduced;
			HObject ho_Region, ho_SelectedRegions, ho_Open, ho_Rect;
			HTuple hv_R1, hv_C1, hv_R2, hv_C2;

			bool retval = false;

			// Initialize local and output iconic variables 
			HOperatorSet.GenEmptyObj(out ho_ImageReduced);
			HOperatorSet.GenEmptyObj(out ho_Region);
			HOperatorSet.GenEmptyObj(out ho_SelectedRegions);
			HOperatorSet.GenEmptyObj(out ho_Open);
			HOperatorSet.GenEmptyObj(out ho_Rect);

			ho_ImageReduced.Dispose();
			if (imagesource.ReduceJobDomain(job, out ho_ImageReduced))
			{
				ho_Region.Dispose();
				imagesource.ApplyThreshold(job, ho_ImageReduced, out ho_Region);

				if (job.ValDouble("area") > 0)
				{

					ho_SelectedRegions.Dispose();
					imagesource.ApplySelection(job, ho_Region, out ho_SelectedRegions);

					int openR = job.VarInt32("OpeningRadius", 1);
					ho_Open.Dispose();
					HOperatorSet.OpeningCircle(ho_SelectedRegions, out ho_Open, openR);

					imagesource.DisplayObj(ho_Open, "blue");

					// Yaklaşma Bölgesini oluşturalım
					HOperatorSet.SmallestRectangle1(ho_Open, out hv_R1, out hv_C1, out hv_R2, out hv_C2);
					int tutamac = job.VarInt32("_juncPoint", 3); //L R U D
					int rHeight = job.VarInt32("_juncHeight", 10); // Yaklaşma Dörtgeninin Yüksekliği
					int yonelim = job.VarInt32("_partDirection", 0); // Horizontal, Vertical
					int beklenenYon = job.VarInt32("_expectingOrientation", 0); // L R U D

					if (tutamac == 0) // Soldan tutturulmuş				
						HOperatorSet.GenRectangle1(out ho_Rect, hv_R1, hv_C1-rHeight, hv_R2, hv_C1);
					else if (tutamac == 1) // Sağdan tutturulmuş				
						HOperatorSet.GenRectangle1(out ho_Rect, hv_R1, hv_C2, hv_R2, hv_C2 + rHeight);
					else if (tutamac == 2) // Üstten tutturulmuş				
						HOperatorSet.GenRectangle1(out ho_Rect, hv_R1 - rHeight, hv_C1, hv_R1, hv_C2);
					else if (tutamac == 3) // Alttan tutturulmuş				
						HOperatorSet.GenRectangle1(out ho_Rect, hv_R2, hv_C1, hv_R2 + rHeight, hv_C2);

					imagesource.SetColor("yellow");

					ho_ImageReduced.Dispose();
					HOperatorSet.ReduceDomain(imagesource.Image, ho_Rect, out ho_ImageReduced);

					ho_Region.Dispose();
					if (imagesource.ApplyThreshold(job, ho_ImageReduced, out ho_Region))
					{
						double yRow = job.ValDouble("row"); // yaklaşma Row
						double yCol = job.ValDouble("column"); // yaklaşma col

						HOperatorSet.DispCross(imagesource.DisplayHandle, yRow, yCol, 12, 0);

						if (yonelim == 0) // Yatay bir parça ise
						{
							double pC1 = TupleToDbl(hv_C1);
							double pC2 = TupleToDbl(hv_C2);

							double lFark = Math.Abs(pC1 - yCol); // merkez ile sol noktanın farkı
							double rFark = Math.Abs(pC2 - yCol); // merkez ile sağ noktanın farkı

							//imagesource.SetColor("blue");
							if (beklenenYon == 0) // Soldan bekleniyor
							{
								retval = lFark > rFark; // Solda bekleniyordu, geldi.
								imagesource.SetColor(retval ? "green" : "red");
								if (retval)
									HOperatorSet.DispArrow(imagesource.DisplayHandle, yRow, yCol, yRow, hv_C1, 1);
								else
									HOperatorSet.DispArrow(imagesource.DisplayHandle, yRow, yCol, yRow, hv_C2, 1);

							}
							else if (beklenenYon == 1) // Sağdan bekleniyor
							{
								retval = rFark > lFark;
								imagesource.SetColor(retval ? "green" : "red");								
								if (retval)
									HOperatorSet.DispArrow(imagesource.DisplayHandle, yRow, yCol, yRow, hv_C2, 1);
								else
									HOperatorSet.DispArrow(imagesource.DisplayHandle, yRow, yCol, yRow, hv_C1, 1);
							}
						} 
						else  // Dikey Parça
						{
							double pR1 = TupleToDbl(hv_R1);
							double pR2 = TupleToDbl(hv_R2);

							double uFark = Math.Abs(pR1 - yRow); // merkez ile üst noktanın farkı
							double dFark = Math.Abs(pR2 - yRow); // merkez ile alt noktanın farkı

							if (beklenenYon == 2) // Üstte bekleniyor
							{
								retval = uFark > dFark;
								imagesource.SetColor(retval ? "green" : "red");
								if (retval)
									HOperatorSet.DispArrow(imagesource.DisplayHandle, yRow, yCol, hv_R1, yCol, 1);
								else
									HOperatorSet.DispArrow(imagesource.DisplayHandle, yRow, yCol, hv_R2, yCol, 1);
							}
							else if (beklenenYon == 3) // Altta bekleniyor
							{
								retval = dFark > uFark;
								imagesource.SetColor(retval ? "green" : "red");
								if (retval)
									HOperatorSet.DispArrow(imagesource.DisplayHandle, yRow, yCol, hv_R2, yCol, 1);
								else
									HOperatorSet.DispArrow(imagesource.DisplayHandle, yRow, yCol, hv_R1, yCol, 1);
							}

						}
						PutLog(job, retval, "Parça Beklenen Yönde " + (retval ? "Geldi" : "Gelmedi"));
					}

				}
				else RedLog(job, "Seçili Bölg Bulunmamadı!");
			}
			else RedLog(job, "ROI indirgenemedi!");

			ho_ImageReduced.Dispose();
			ho_Region.Dispose();
			ho_SelectedRegions.Dispose();

			int compela = job.VarInt32("Complement", 0);
			if (compela == 1) retval = !retval;

			if (!retval)
			{
				DrawCurrentRoi(job, retval);
				int masterJob = job.VarInt32("MasterJob", 0);
				if (masterJob == 1)
					masterFailed = true;
			}

			return retval;
		}

Tek Lokasyonda 10 Farklı Kameralı Kontrol İstasyonu


Mavis, Volkswagen yan sanayilerinden Kros Otomotiv Kütahya fabrikasında, 10. kameralı kontrol istasyonunu kurmaya hazırlanıyor.

Fabrika genelindeki kameralı kontrol istasyonlarımıza ilişkin ortalama rakamlar…

  • Çalışan 7, Yapım aşamasında 3 istasyon mevcuttur
  • Her bir istasyonda ortalama 4 kamera bulunmaktadır
  • En az kamera sayısı olan istasyonda 2 kamera bulunmaktadır
  • En çok kameralı istasyon ise 7 kameralıdır
  • Her bir istasyonda ortalama 4 farklı çeşit (tip) ürün kontrol edilmektedir.
  • Her istasyon 3 vardiya çalışmaktadır

Böylece Kros Otomotiv 10 farklı istasyon ile en çok kurulum yaptığımız yer olmuştur. Kros Otomotiv’i, B/S/H/ ve Renault ve Derby izlemektedir.

Kros Otomotiv’de kurulu istasyonlarımızdan görüntüler…

Bir görevi belirli bir zaman sonra çalıştırma

Bir görevi belirli ve kesin bir süre sonra çalıştırmak gerekirse ne yapılır?

En basit yöntem, bir Timer kurmak ve bu Timer ın interval değerini belirli değere set ederek TimerTick olayında görevin çalışmasını tetiklemektir.  Daha komplex uygulamalarda bu yöntemi kullanmak zahmetli ya da sorunlu olabilir (Genelde de olur).

Böyle durumlarda thread kullanmak ve thread çalışması için belirli bir zaman atamak daha profesyonel bir yaklaşımdır. .NET halihazırda thread tetiklenmesi, bekletilmesi, sonlandırılması vb. işlemler için güçlü API desteği sunar.

Kameralı Kontrol uygulamamız, yakaladığı hatalı parçayı bir t süre sonra üflemek suretiyle konveyörden atacak olsun.

		public void UfleP(int t)
		{
			System.Threading.Thread.Sleep(t);
			SetDigitalOutput(1);
		}

gibi bir kod çalıştırıldığında, sistem t süresi kadar bekleyecek sonra dijital output set etmek suretiyle üfleme yapacaktır. Bu kod, bekleme süresinde (Sleep) sistemi uyutacağından, görüntü işleme uygulamalarında akla bile getirilmemelidir. Yapılması gereken, bu fonksiyonu çağıran yapıyı bir thread haline getirmek, thread i start edip unutmak, thread kendi içinde beklese bile ana programın bundan hiç etkilenmemesini sağlamaktır. Thread çalışırken bekleyecek, görevini yapacak ve en nihayetinde kendi halinde  sonlanacaktır (Terminate). Tüm bu olan bitenden ne ana programın, ne de programcını haberdar olması bile gerekmez. (Tam ideal durum. Yaz ve unut. Hiçbir Timer bu kadar kullanışlı olamazdı.)

Burada bir sorun, thread için parametre geçirmektir. Normal thread çağırırken parametre kullanımına izin vermez. Parametre kullanımı için ParameterizedThreadStart kullanmak gerekir.

Yapıyı yeniden kodlarsak;

		public void UfleP(object t)
		{
			int iSleep = (int)t;
			System.Threading.Thread.Sleep(iSleep);
			SetDigitalOutput(1);
		}

şekline dönüştürerek (parametrenin object türünden olduğuna dikkat edin. Dolayısıyla birden fazla parametre vermek, dizi geçmek vb. object türünün sağladığı sınırsız avantajlar burada kullanılabilir…)

		private void PickAfterMilliSecond(int msAfter)
		{
			System.Threading.ParameterizedThreadStart starter = new System.Threading.ParameterizedThreadStart(UfleP);
			new System.Threading.Thread(starter).Start(msAfter);
		}

gibi bir yapı ile, Parametrik Thread yapımızı programda istediğimiz yerden çağırabiliriz. Dertsiz tasasız çalışacaktır…