Fotografik Kalibrasyon

Herhangi bir nedenden dolayı, alınan görüntüler dikey ya da yatay eksende bir miktar uzama/çekme şeklinde deformasyona uğramış ise, ölçüm gibi uygulamalar bazı istenmeyen sonuçlar verebilir.

Dikey/Yatay bozulmalar neden meydana gelir?

  • Kameraların yatay ve dikey çözünürlüğü birbirinden farklı olabilir
  • Hareketli bir cismin görüntüsü alındığı için, görüntüde uzama meydana gelmiş olabilir
  • Çizgi taramalı (linescan) kameralarda, konveyör ya da dönme hızından çok daha yüksek hızda fotoğraf alınmış olabilir

Özetle, bir çok farklı sebepten dolayı görüntü olması gerekenden farklı çıkmış olabilir. İdealde, bu tür görüntüleri, kaynağında (kamera tarafı) düzeltmek ve yazılıma (görüntü işleme uygulaması) düzgün halini vermek gerekir. Ne yazık ki bu durum her zaman mümkün olmayabilir. Bu tür durumlarda, yazılım ile görüntüyü düzeltmek mümkündür.

Aşağıdaki kod, eliptik şekilde uzamış bir görüntünün, tekrar mükemmel daire şekline getirilmesini göstermektedir. (Eğer, üzerinde çalıştığımız nesnenin tam dairesel olduğunu biliyorsak, alınan görüntü eliptik bile olsa, bunu tam daire şekline getirme işlemi)

Soldaki şekli paint ile çizdim. Mükemmel daire yerine yatay eksende biraz genişleterek, elips haline getirdim. İstediğim, bir HALCON kodu ile, bu şekli tekrar mükemmel daire haline getirmek. Şeklin sadece yatay eksende bozulduğunu varsayıyoruz. Yani yüksekliği (boyu) sabit fakat yana doğru uzamış olan bu elipsi, boy ve en oranı korunacak şekilde ideal daireye geri dönüştürmek istiyoruz. Yazmamız gereken kısa HALCON kodu aşağıdaki gibi olabilir.


read_image (E, 'E.png')
bin_threshold (E, Region)
smallest_rectangle1(Region, Row1, Column1, Row2, Column2)
W := Column2 - Column1
H := Row2 - Row1
R := 1.0 * W / H
hom_mat2d_identity(HomMat2DIdentity)
hom_mat2d_scale_local (HomMat2DIdentity, R, 1, HomMat2DScale)
affine_trans_image (E, ImageAffinTrans, HomMat2DScale, 'constant', 'false')
affine_trans_region(Region, RegionAffineTrans, HomMat2DScale, 'false')

Fabric/Leather Mesh and Pattern Identification Application for Car Seats

Automotive companies today offer users a wider range of choices. Specially with “Build your own car” option, user can change almost every detail in his/her car. Despite the this great convenience for customers, it brings lots of difficulties for manufacturers. In “Just In Time” production model, manufacturer must produce each model with “correct” details for “correct” user. This means, manufacturer must check every part in production line just after part is assembled.

BMW's build your own car site for US

We installed our HALCON based “Fabric Mesh and Pattern Identification Vision System” for one of the leading company of the world’s automotive supplier industry. The Company produces car seats, cockpits, internal door panels, sound systems, front- and back-end bumpers and exhaust systems. Our system is checking car seat’s size, model, fabric/leather color, pattern, texture and mesh and detecting original artikel number. If detected artikel number is different than the expected number, system is stopping production line and raising an alert signal/message.

Fabric patterns and colors has lots of variationVision system must distinguish more than hundreds of fabrics/leathers with lots of color and pattern combination. Furthermore, new models (fabrics/leathers/colors/patterns…) must be teach to the system easily. Sometimes patterns can be very close to each other so finding differences isn’t so easy even checking by eye. At first, we used HALCON 10 and Fast Fourier Transforms to detect textures. The algorithms run fine but the problem was in teaching methodology. Sometimes we have to write “special” codes for “special” products. But for end user (operator) we have to find easier way to define new models.

Some fabric patterns to distinguishFor our 2. version, we turned our matching algorithms (usually FFT and RFT) to HALCON 11’s sample based matching technology. By this newly technology not only we reduced our thousands of lines of codes to tens (!!!) but also teaching new models became very easily for end user.

HDevelop code redesigned by Yaqi Zeng (MVTec support team) is look like below.

dev_update_off ( )
dev_close_window ( )
list_image_files ('.', 'default', [], ImageFiles)
read_image (Image, ImageFiles[0])
dev_open_window_fit_image (Image, 0, 0, -1, -1, WindowHandle)
set_display_font (3600, 16, 'mono', 'true', 'false')
dev_set_draw ('margin')
dev_set_line_width (3)
dev_set_color ('yellow')
*
* I. Creation of identifier
create_sample_identifier ('add_texture_info', 'true', SampleIdentifier)
* II. Adding Information for preparation
for Index := 0 to |ImageFiles|-1 by 1
    read_image (Image, ImageFiles[Index])
    tuple_split (ImageFiles[Index], '/', Substrings)
    tuple_split (Substrings[|Substrings|-1], '.', Substrings1)
    FileName := Substrings1[0]
    dev_display (Image)
    disp_message(WindowHandle, 'Image ' + FileName + ' added for preparation of training', 'image', 12, 12, 'blue', 'true')
    add_sample_identifier_preparation_data (Image, SampleIdentifier, Index, [], [], ObjectSampleIdx)
    set_sample_identifier_object_info (SampleIdentifier, Index, 'preparation_object_name', FileName)
    disp_continue_message (WindowHandle, 'black', 'true')
    stop ()
endfor
*
* III. Preparation and training
*      use the preparation data to train the identifier
dev_clear_window ()
disp_message (WindowHandle, ['Prepare and train the sample identifier','(this might take some seconds)'], 'window', 12, 12, 'black', 'true')
prepare_sample_identifier (SampleIdentifier, 'true', [], [])
train_sample_identifier (SampleIdentifier, [], [])
disp_continue_message (WindowHandle, 'black', 'true')
stop ()
*
* IV. Applying
*     on randomly selected run-time image
RandomIndices := sort_index(rand(|ImageFiles|))
for Index := 0 to |ImageFiles|-1 by 1
    IndexR := RandomIndices[Index]
    read_image (Image, ImageFiles[IndexR])
    dev_display (Image)
    apply_sample_identifier (Image, SampleIdentifier, 1, 0, [], [], ObjectIdx, Rating)
    get_sample_identifier_object_info (SampleIdentifier, ObjectIdx, 'training_object_name', ResultObjectName)
    disp_message(WindowHandle, 'Identified as: '+ ResultObjectName, 'window',12, 12, 'green', 'true')
    stop()
endfor
*
* V. Clean-up
clear_sample_identifier (SampleIdentifier)

Source code and related images can be download by clicking this link.

partition_dynamic kullanımı

Bir region üzerinde işlem yaparken sık sık connection komutu ile region da kaç adet nesne olduğu ile ilgileniriz. connection komutu, birbirinden bağımsız nesneleri seçeceği için, nesneler arasında 1 pixel lik dahi bağlantı olsa, onu tek bir nesne olarak algılayacaktır. Özellikle OCR işlemi gibi, her nesnenin ayrı olarak değerlendirilmesi gereken durumlarda, bu problemi gidermek gerekir. Yollardan biri partition_dynamic komutunun kullanılmasıdır.

 

Yukarıdaki resimde görüldüğü gibi, 1 ve 2 ile 6 ve 7 arasını birer çizgi ile birleştirdim. Burada threshold komutu ile bir region oluşturduğumda ve hemen sonra connection ile her bir rakamı seçmek istediğimde,

yukarıdaki gibi bir seçim yapacaktır. (1-2 ve 6-7 nin tek bir nesne olarak seçildiğine dikkat edin)

partition_dynamic komutu tam da bu gibi durumlarda istenen sonuçları üretebilir. partition_dynamic, nesneleri dikey olarak bölmeye yarayan bir komuttur. Ortalama bir nesnenin genişliğini belirtip, belirli bir yüzde toleransı da verdiğimizde, komut nesleneri olması gerektiği yerden parçalayacaktır. (Aşağıdaki resimdeki gibi)

 

partition_dynamic komutuna verilecek, ideal nesne genişliği ne olmalıdır?

nesne genişliğini komutla ya da HDevelop içindeki Feature Inspection aracı ile görebiliriz.

Yukarıdaki resimde görüldüğü gibi, seçtiğim nesnenin özelliklerini (features) gözlemledim. İlgilendiğim width değerinin 85 olduğunu gördüm. Programda direk olarak bu değeri kullanabilirim.

Dilersem daha dinamik bir yapı kurarak, olması gereken değeri kendim belirlerim. Aşağıdaki kod, hem sabit olarak bu 85 değerini kullanan, hem de dinamik olarak kendi belirlediği değere göre (tuple_median) çalışan HDevelop kodudur.

 

read_image (Image, 'C:/Users/Mustafa/Desktop/Adsız.png')
threshold (Image, Regions, 0, 139)
connection(Regions, ConnectedRegions)
* Sabit 85 değerine göre partition
partition_dynamic(ConnectedRegions, Partitioned, 85, 20)

*kendi belirleyeceği değere göre partition
smallest_rectangle1(ConnectedRegions, Row1, Column1, Row2, Column2)
W := Column2 - Column1
tuple_median (W, WOrta)
partition_dynamic(ConnectedRegions, Partitioned, WOrta, 20)

Silindirik İç yüzeyde Çapak, Kof, Çizik Tespiti

Mercedes ve Chrysler için yan sanayi üretimi yapan Mita Kalıp‘ta, silindirik iç yüzey barındıran parçaların, kamera ile çizik, kof, çapak ve fatura varlık kontrolleri yapan sistemi devreye aldık. Otomasyon sistemi Prestij Endüstri tarafından yapılan test ve montaj masasında, parça montajı, kameralı kontroller ve basınçlı hava ile mikron boyutunda hassas ölçüm  yapılmaktadır.

Kontrol edilecek olan parça, yukarıdaki gibidir. Prestij Otomasyon montaj masasında, parça monte edilerek kameranın altına getirilir. Özel bir açıyla yerleştirilmiş ayna sistemi, silindirik iç yüzeyin tam merkezine getirilir. Konik yüzeye sahip olan ayna, silindirik görüntüyü küresel geometriye çevirir. (Aynadan yansıyan görüntülerin kameradaki görünümü aşağıdaki gibidir)

Yukarıdaki şekilde, hatalı ve sağlam parça görünümleri verilmiştir. Bu görüntülerde Çapak, Kof, Çizik gibi hataları ayırmak için yapılacak görüntü işleme yazılımında, ilk iş, dairesel formda olan görüntüyü, düzlemsel forma dönüştürmektir. Dairesel formda olan görüntü ile çalışmak ta mümkün olmakla birlikte, yapılan testler, düzlemsel geometride çok daha sağlıklı sonuçlar alındığını göstermiştir.

 

Yukarıdaki resimde, orijinal resim ve polar transform edilmiş hali görülmektedir. bu görüntüden de kolayca anlaşılabileceği gibi, Polar olarak transform edilmiş hali, çok daha kolay işlenebilir ve çok daha kesin sonuçlar üretir.

Projenin HALCON kodu ve kullanılan gerçek kamera görüntüleri (resimler) ilgililere mail ile ulaştırılabilir. (info@mavis.com.tr)

Tüm proje hakkında bilgi almak için, Mavis’e (www.mavis.com.tr) veya Prestij Endüstri’den Hakan Bey’e ulaşabilirsiniz.

 

//–>

Dikiş Varlık Kontrolü

Dynamic Threshold ve Shock Filter Kullanımı

Yakın zamanda yaptığımız bir projede, yapılacak kontrollerden biri kumaşın desenini algılamaktı. Texture olarak bilinen bu çalışma, görüntü işlemenin en zor yanlarından biridir. Her ne kadar HALCON texture algılama üzerine bol miktarda fonksiyon barındırsa da, texture gibi genel bir konuda, her hangi bir fonksiyondan sihirli bir işlev beklenemez. Yapılması gereken, projeye özgü kodlamada bulunmak…

Projede, kumaşın deseni kadar, kenarında dikiş olup olmadığının da kontrol edilmesi gerekiyordu.

Resimdeki orijinal resimde göründüğü gibi, araba koltuk başlığının yan tarafında dikiş olup olmadığının belirlenmesi gerekiyordu. İlk başta kolay gibi görünen bazı uygulamalar, iplik renginin değişmesi, kumaş renginin / deseninin değişmesi vb. faktörlerden dolayı hiç hata vermeden çalışacak bir yapıda olmalıydı. aşağıdaki kod, dikiş izini hatasız olarak tesbit edebilen bir HALCON kodudur. (Denemek için bu resmi alarak kaydedebilirsiniz.)

 

sonuç görüntü :

HALCON kodu

 

read_image (Image, 'K.bmp')
bin_threshold (Image, Region) 
reduce_domain (Image, Region, ImageReduced)
shock_filter(ImageReduced, SharpenedImage, 0.5, 10, 'canny', 1)
gray_opening_shape(SharpenedImage, ImageOpening, 25, 25, 'octagon')
gray_closing_shape(SharpenedImage, ImageClosing, 25, 25, 'octagon')
dyn_threshold (ImageOpening, ImageClosing, RegionDynThresh, 50, 'not_equal')
dilation_circle(RegionDynThresh, RegionDilation, 5)
connection(RegionDilation, ConnectedRegions)
select_shape(ConnectedRegions, SelectedRegions, 'area', 'and', 1000, 99999)
count_obj(SelectedRegions, Number)
if (Number > 0)
    skeleton(SelectedRegions, Skeleton)
    dev_set_line_width(2)    
    *set_line_style (3600, [20,10])
    dev_display(Image)
    dev_display(Skeleton)
endif

Burada asıl işi yapan dynamic_threshold kullanımıdır. shock_filter alınan görüntüde, kenarları belirginleştirmeye yarar. (Datamatrix, karekod, barkod okuma vb. işlemlerde önerilir) Kodda comment edilmiş set_line_style (3600, [20,10]) kodunu da açıp çalıştırırsanız, bulanan dikiş çizgisinin, kesikli olarak gösterildiğini göreceksiniz. set_line_style, HALCON çizgi gösterim biçimini formatlama fonksiyonudur.

Akıllı Şekil Tamamlama

Bazen alınan görüntüde eksik kalan yerlerin tamamlanması gerekebilir. Aşağıdaki örnek kod, tamamlama işini akıllı bir biçimde yapmaktadır.

Yukarıda görüldüğü gibi parçalar arasındaki boşluk, olabildiğince gerçeğe yakın bir şekilde birleştirilmiştir. Birçok yerde kullanılabilecek olan, prosedürel olarak yazılmış HALCON kodu :

read_image (Image, 'C:/Users/Mustafa/Desktop/aa.png')
bin_threshold (Image, Region)
connection (Region, ConnectedRegions)
CombineSplittedRegions (ConnectedRegions, RegionCount)
dev_set_draw ('fill')
dev_display(Image)
dev_display(RegionCount)

Burada asıl işi yapan CombineSplittedRegions prosedürü ise

count_obj(ConnectedRegions, Number)
if (Number > 1)
    while (Number > 1)
        select_obj (ConnectedRegions, Obj1, 1)
        select_obj (ConnectedRegions, Obj2, 2)
        inner_circle(Obj1, Row, Column, Radius1)
        inner_circle(Obj2, Row, Column, Radius2)
        minR := Radius1
        if (Radius2 < Radius1)
            minR := Radius2
        endif
        distance_rr_min(Obj1, Obj2, MinDistance, Row1, Column1, Row2, Column2)
        gen_region_line (RegionLines, Row1, Column1, Row2, Column2)
        dilation_circle(RegionLines, RegionDilation, minR)
        union2(ConnectedRegions, RegionDilation, RegionUnion)
        union1(RegionUnion, RegionCombine)
        connection(RegionCombine, ConnectedRegions)
        count_obj(ConnectedRegions, Number)
    endwhile
else
    copy_obj(ConnectedRegions, RegionCombine, 1, -1)
endif
inner_circle(RegionCombine, Row, Column, Radius)
rank_region(RegionCombine, RegionCount, Radius, Radius, 50)
return ()

programda kullanılan orijinal resim aşağıdadır. Programı denemek için bunu kullanabilirsiniz.

OCR Öncesi Resmi Döndürme

HALCON ile OCR işlemine başlamadan önce, resmin üzerindeki yazının yatay eksene paralel olacak şekilde döndürülmesi gerekmektedir.

resmi döndürdükten sonra ise,

haline gelecektir. Burada, sadece resmi değil, resimle birlikte Region da döndürmek gerekeceğinden, rotate_image komutu yerine transformation komutları (HomMat2DRotate) kullanmak gerekecektir.

Region ile birlikte döndürme yapan HALCON kodu :

 

read_image (Image, 'C:/Users/Mustafa/Desktop/RenPics/142856.bmp')
*Region bulalım
var_threshold(Image, Region, 460, 240, 0.2, 2, 'light')
closing_circle(Region, RegionClosing, 15)
opening_circle(RegionClosing, RegionOpening, 45)
fill_up(RegionOpening, RegionFillUp)
connection(RegionFillUp, ConnectedRegions)
select_shape (ConnectedRegions, SelectedRegions, ['area','inner_radius'], 'and', [700000, 200], [2000000, 280])
*
shape_trans(SelectedRegions, RegionTrans, 'convex')

*Resim ve Region birlikte Rotate Edelim
area_center(RegionTrans, Area, Row, Column)
text_line_orientation (RegionTrans, Image, 180, -0.523599, 0.523599, OrientationAngle)
hom_mat2d_identity (HomMat2DIdentity)
hom_mat2d_rotate (HomMat2DIdentity, -OrientationAngle, Row, Column, HomMat2DRotate)
affine_trans_image (Image, ImageRotate, HomMat2DRotate, 'constant', 'false')
affine_trans_region(RegionTrans, RegionAffineTrans, HomMat2DRotate, 'false')

Programın çalışmasını test etmek için kullanılabilecek 2 adet resmi buradan indirebilirsiniz

Çoklu Karekod Okumada Gelişmiş Yöntemler – 1

Geliştirdiğimiz çoklu karekod okuma cihazı, gerçek zamanlı üretim ortamında (5 farklı ürün, 2 farklı hatta) test edilmiş ve %100 okuma başarısı sağlamıştır. Çoklu karekod okuma işlemi, kamera önündeki tüm karekodları okumayı gerektirdiğinden, gelişmiş okuma teknikleri kullanmak gerekmektedir. Üretim anında her bir karekod yazıldıktan sonra doğrulamasaı (verification) yapılmasına rağmen, shrink, koli, bandaj vb. yöntemlerle birleştirildiğinde, ışık açısı, kutunun dönmesi vb. sebeplerle bazı karekodlar okunamayacak ya da zor okunacak şekle gelebilir. Bu gibi durumlarda, “ileri” teknikler kullanarak, çoklu okuma işlemini %100 başarılı hale getirmek mümkündür.

Bu yazı  dizisinde, zaman buldukça Gelişmiş Yöntemler olarak adlandırdığım bu tekniklere ana başlıklar altında değinmeyi düşünüyorum. Özellikle ilaç üretimi yapılan yerlerde, okuma kalitesi kadar okuma hızı da çok önemlidir. (Karekod okuyacam diye üretimi durdurmanız/bekletmeniz düşünülemez) Dolayısıyla burada hem okuma kalitesini iyileştirecek hem de çok yüksek hızlarda okuma yapabilecek teknikler ele alınacaktır.

Mavis olarak, geliştirdiğimiz çoklu karekod okuma cihazı (konveyör, kameralar, sensörler, aydınlatma ekipmanı ve karekod basma makinasından meydana gelen cihaz) ile yaptığımız testlerde, 25 lik shrinkler için her bir shrink içindeki karekodları (her birinde 25 karekod olduğu durumda) okuma işlemi maksimum 1.5 sn. kadar sürmektedir. Okuma işlemi esnasında konveyör bu 1.5 sn. boyunca sabit olarak durdurulmakta, okuma işlemi bitince yeniden hareket ettirilmektedir. Konveyör çıkışında, okunan karekodlara ilişkin tek bir koli karekodu (master kod) üretilmekte ve kolinin / shrinkin üzerine basılmaktadır. Shrinkin konveyöre baştan girmesi ve en sondan çıkması arasındaki süre 4 sn. dir. (1.5 sn okuma, 2.5 sn. baştan sona yürüme)

Gelişmiş Yöntem – 1 : Okunamayan Karekodların tespiti ve sadece bu karekodları içerecek yeni bir resim alınarak yeniden denenmesi.

Karekodları içeren resim alındıktan sonra bazı durumlarda beklenen tüm karekodların okunamayabilir. Işık yansımaları, perspektif bozulmalar gibi etkenler, görüntünün tam orta noktasındaki karekod ile köşelerdeki karekodların farklı görünmelerine yol açabilir. Bu durumda, hemen pes etmeden önce çeşitli filtreler uygulayarak yeniden denemek gerekir. (Daha önceki bu makalede bahsedildiği gibi) Uygulanan filtrelere rağmen, hala bir ya da birkaç karekod okunamamış ise, şimdi yapılması gereken;

  1. Okunamayan Karekodların Yerlerinin Tespiti
  2. Tespit edilen yerlere göre AOI (Area of Interest) belirterek yeniden resim alınması
  3. Alınan resmin yeniden değerlendirilmesi

Burada püf noktası AOI belirtilmesidir. AOI, donanımsal olarak kameraya belirli koordinatların resmini al demektir. 10 Megapixel bir kamera ile çalışıldığını varsayalım. Tüm resmi almak 500 ms. kadar sürecekse, tek bir karekodun bulunduğu bölgenin resmini almak (değişebilir) 30-50 ms. kadar sürecektir. Böylece çok hızlı bir süre içinde sistem 2. 3. 4. denemelerini de yapar, gerçekten okunamayan bir kod var ise o zaman “NOK” olarak işaretler.

 

 

Yukarıdaki resimde sarı ile çerçevelenmiş tüm karekodların okunduğunu, kırmızı çerçeveli karekodun okunamadığını varsayalım. Okunamayan karekodun yeri HALCON find_barcode_2d fonksiyonu ile verilmekle birlikte, foundation fonksiyonları ile de belirlenebilir (Ben daha hızlı olması açısından, daha akıllı bir yapı kurarak, grid içinde okunamayan yerleri tespit eden bir yapı kurdum mesela) Şimdi yapılması gereken, bu karekodu içeren bir AOI kameraya bildirip yeniden fotoğraf almaktır.

AOI Bildirimi

open_framegrabber ('uEye', 1, 1, 0, 0, 0, 0, 'default', 8, 'default', -1, 'false', 'default', '1', 0, -1, AcqHandle)
count_seconds(T1)
grab_image(Image, AcqHandle)
count_seconds(T2)
set_framegrabber_param (AcqHandle, 'roi', [80,80,240,240])
count_seconds(T3)
grab_image(Image, AcqHandle)
count_seconds(T4)
FullGrabTime := (T2-T1)*1000
AOISetTime := (T3-T2)*1000
AOIGrabTime := (T4-T3) * 1000
close_framegrabber (AcqHandle)

Burada da kolayca görülebileceği gibi asıl işlem
set_framegrabber_param (AcqHandle, ‘roi’, [80,80,240,240]) fonksiyonu tarafından yapılmaktadır. Kendi makinamda bu kodu çalıştırdığımda; 1.3 MP kamera ile Full Grab (AOI verilmeden alınan resim) süresi : 118 ms.
set_frame_grabber için harcanan süre : 30 ms.
80-80-240-240 koordinatlarından resim almak için geçen süre : 20 ms.

olarak ölçüldü. Eğer 5 ya da 10 MP kamera kullanacak olsaydım, çok daha radikal zaman kazancım olacaktı.

Eş zamanlı olarak, her bir denemeden önce, kamera pozlama süresi bir miktar değiştirilebilir. Böylece ardışıl alınan her iki resmin birbirinden farklı olması sağlanır, varsa ışık parlamalarının önüne geçilmiş olunur.

Eğer işin içine bir miktar da bulanık mantık katılmak istenirse, pozlama miktarının değişimi sabit bir sayı ile değil, rastgele bir değer ile yapılabilir. Hala yeterli vaktimiz varsa, okuma metodolojisi “enhanced_recognition” ile zorlanır, pattern tolerance olarak “low” değeri denenir ve kod içinde yumuşatma fonksiyonu varsa mean_image yerine mean_curvature_flow ile değiştirilir. Threshold parametreleri yine bir miktar rastlantısal değerler ile ötelenir. İşlem tekrar denenir. (Bu şekilde sistem tarafından parametrelerin belirsiz bir şekilde zorlanarak tekrar denenmesi ve sonuçta başarıya ulaşılması, çoğu kez beni de heyecanlandıran bir durumdur. Mekanik bir sistem gibi OK/NOK vermek yerine, yapay zeka algoritması gibi çalışması, NOK durumunun üstüne gidilmesi ve beklenen süre içinde kalmak kaydıyla belirsiz zamanlarda OK diyebilmesi, test ya da demo esnasında gerçekten heyecanlı durumlara yol açabilmektedir.) Tam da bu arada, karekod okumaişlemi için timeout belirtmeyi de unutmamak gerekir. Yoksa HALCON hiç olmaması gerektiği kadar uzun oyalanabilir. Ben tüm proses için de timeout kullanıyorum. Şu alt programcığı 300 ms. içinde sonlandır gibi. (Birşeyler belirsiz olsun ama yine de sınırlar içinde kalsın)

Vakit buldukça burada karekod üzerine gelişmiş algoritmalardan bahsetmeye devam edeceğim. Bugünlük bu kadar. İletişime geçmek isteyenler için, info@mavis.com.tr mail adresini yeniden hatırlatayım…

Nesne Adedi Bulan HALCON Kodu, erosion ve dilation kullanımı

 

Soldaki resimde (HALCON da pellets adı ile kaydedilmiştir) kaç adet pellet (topak) var. Bunu farklı yaklaşımlarla bulan HALCON kodu üzerinde kafa yoralım.  Ben ve Kağan tarafından geliştirilen farklı algoritmalar, burada alt alta verilecektir.

Buradaki tek zorluk, nesneler birbirine bitişik olduğu için, connection kullandığımızda bitişik olan nesneleri tek bir nesne olarak değerlendirecektir. opening_circle kullanıldığında ise yine istenen sonucu elde edebilmek her zaman mümkün olmamaktadır. Basit gibi görünen bu örnekte biraz daha farklı yaklaşımlar gerekebilir.

 

 

Kağan tarafından geliştirilen HALCON kodu

read_image (Image, 'pellets')
scale_image_range (Image, ImageScaled, 100, 200)
gray_erosion_shape (ImageScaled, ImageMin, 3, 3, 'octagon')
bin_threshold (ImageMin, Region)
difference (ImageMin, Region, RegionDifference)
opening_circle (RegionDifference, RegionOpening, 10)
connection (RegionOpening, ConnectedRegions)
count_obj (ConnectedRegions, Number)

 

 

 

 

 

 

 

 

 

Kağan tarafından yukarıda yazılan kod çalıştırıldığında yukarıdaki sonuç elde edilmiştir. Aradığımız da tam olarak buydu. Kodu tam 1000 defa çalıştırdığımda 3.175 sn. sürdü. Şimdi farklı mantıklar ile yeniden kodu geliştirmeyi düşünelim.
Benim geliştirdiğim HALCON kodu

read_image (Image, 'pellets')
bin_threshold(Image, RegionDark)
difference(Image, RegionDark, RegionLight)
connection(RegionLight, ConnectedRegions)
erosion_circle(RegionLight, RegionErosion, 8 )
connection(RegionErosion, ConnectedRegions)
dilation_circle(ConnectedRegions, RegionDilation, 8 )
count_obj(RegionDilation, Number)

Benim yazdığım kodu 1000 defa çalıştırdığımda 1.439 sn. sürdü 🙂  Buradaki püf noktası, önce erosion_circle kullanarak birbirine yapışık nesneleri sınırlarından erimeye tabi tutarak (erosion) ayırmak, sonra dilation_circle kullanarak eski boyutlarına geri ulaştırmak. (Hız her zaman ilk göz önüne alınması gereken parametre değildir.)

HALCON da bir çok farklı yaklaşım ile istenen sonuca ulaşmak mümkündür. Bir diğer yaklaşım,

distance_transform

HALCON fonksiyonunu kullanmak olabilir. Belritilen sınır mesafeye göre en uzak olanları en parlak, en yakın olanları en koyu olarak çizecek şekilde transform edilmiş yeni resim işleri çok kolaylaştırabilir.

distance_transform (ConnectedRegions, DistanceImage, ‘euclidean’, ‘true’, Width, Height)

fonksiyonu uygulandıktan sonraki orijinal resmimiz aşağıdaki gibi olacaktır. Bundan sonrasını, HALCON programcıları için yazmaya gerek bile görmüyorum.

 

 

Defne Yaprağı Ayrıştırmada Matematiksel Yaklaşım

Daha önceki blog kayıtlarımızda sıklıkla bahsettiğimiz Hatalı Defne Yaprağı Ayrıştırma Projemize tamamen matematiksel yöntemlerle çalışan, daha hızlı ve daha güvenilir sonuçlar veren yeni bir yaklaşım ekledik.

Matematikte Saddle Point (Semer Noktası) olarak bilinen fonksiyonun,  defne yapraklarına uyarlanması temelinde yapılan işlemler, daha kısa sürede ve daha hızlı sonuçlar vermektedir. Görüntü işleme fonksiyonları ile matematiksel fonksiyonların eş zamanlı olarak kullanıldığı bu yeni yaklaşımda, işlemci (cpu) hızı artırıldıkça, doğru orantılı olarak işlemin sonlanma hızı da artmaktadır. (Salt görüntü işleme fonksiyonları kullanılsaydı, işlemci hızının artışı yine olumlu sonuçlar verecekti fakat işlemcide geçmeyen süreler – kameralardan görüntünün alınması, veriyolunda kaybedilen zamanlar, hafızaya okuma/yazma süreleri vb. – yüzünden beklenen hız artışı daha sınırlı kalacaktı.)

 

 

 

 

 

 

 

Yukarıdaki resimde, sağlam ve hatalı yaprağın, üst yarısının kenar çizgileri gösterilmiştir. İdeal bir yaprakta (hatasız) semer noktası (saddle point) hiç olmamalıdır.

Analiz Yöntemi :

  1. Yaprak yatay düzlem ile sıfır derece açı yapacak şekilde döndürülür
  2. Yaprağın alt ve üst bölgelerinin konturları (contours) çıkartılır
  3. Çıkartılan konturlara ait, satır-sütun değerleri fonksiyonel olarak çıkartılır
  4. Oluşturulan 2 boyutlu fonksiyonda semer noktaları (saddle points) aranır
  5. Semer noktaları derinliği belirlenen değerlerden fazla ise yaprak hatalıdır
  6. Yaprak yatay eksenle 90 derece açı yapacak şekilde döndürülür (Sol ve Sağ tarafı baş aşağı gelecek şekilde)
  7. Tüm kontroller yeniden yapılır.

Tüm bu işlemlerde kullanılan belli başlı HALCON operatörleri :

  • Contour processing (edge-detection, smooth contours, union contours…)
  • 1d fonksiyonel işlemleri (create_funct_1d_pairs, derivate_funct_1d  …)
  • Semer Noktası işlemleri (saddle_points_sub_pix …)

Bu kez çalışan HALCON kodu örneği yerine kullanılan fonksiyonları ve yöntemi açıkladım. Konuyla ilgilenenlerin olması ve ulaşması durumunda çalışan gerçek kodlar ile daha detaylı paylaşımlarda bulunabiliriz.