VISOKOŠOLSKI STROKOVNI ŠTUDIJ Informatika in tehnologije komuinciranja Sistemska podpora informatiki in tehnologijam komuniciranja POROČILO PRAKTIČNEGA IZOBRAŽEVANJA v Inel Industrijska eletronika d.o.o - Celje Čas opravljanja od 17.3.2014 do 22.5.2014 Mentor v GD Črt Cencelj Študent Igor Hojnik Vpisna številka E1056637 E pošta igor.hojnik@gmail.com Telefon 031-418-347
Kazalo vsebine 1. Uvod... 4 2. Opis gospodarske družbe... 4 2.1. Vizija... 4 2.2. Poslanstvo... 4 2.3. Vrednote... 4 2.4. Kratek opis podjetja... 4 3. Opis praktičnega izobraževanja... 5 3.1. Uporabljene tehnologije in orodja v času izobraževanja... 5 3.1.1. Visual studio 2013... 5 3.1.2. C#... 6 3.1.3. MS SQL server 2012... 6 3.1.4. SQL ( Structured Query Language)... 6 3.1.5. MWtec Halcon... 6 3.1.6. HDevelop... 6 3.1.7. AVT (allied vision technologies)... 7 3.2. Projektno delo... 7 3.3. Urejevalnik XML dokumentov... 7 3.3.1. Izdelava projekta... 7 3.3.2. Primerjava z šolskim znanjem... 16 3.4. Pregledovalnik in urejevalnik delovnih nalogov v bazi... 16 3.4.1. Izdelava projekta... 16 3.4.2. Primerjava z šolskim znanjem... 20 3.5. Program za iskanje defektnih stekleničk... 21 3.5.1. Izdelava projekta... 21 3.5.2. Primerjava z šolskim znanjem... 31 4. Sklep... 32 2
Kazalo slik Slika 1: Program Halcon za pregled in preizkus funkcij obdelave slike... 6 Slika 2: Program Vimba za urejenje nastavitev kamere... 7 Slika 3: Podatki v excel datoteki... 8 Slika 4: E-R diagram baze za shranjevanje podatkov... 8 Slika 5: Izgled aplikacije v delovanju... 9 Slika 6: Funkcionalnosti aplikacije predstavljene z gumbi... 9 Slika 7: Funkcionalnosti aplikacije predstavljene z gradniki... 9 Slika 8: Dnevnik aktivnosti... 14 Slika 9: Primer iskanja po besedah... 14 Slika 10: Izgled, kako izbirati med jeziki v aplikaciji... 15 Slika 11: Izgled datotek z jeziki v Visual Studiu... 15 Slika 12: Zapisi prevodov v datoteki, ki jih zagotovi Visual Studio... 15 Slika 13: Struktura programa... 16 Slika 14: Struktura podatkovne baze... 17 Slika 15: Vstopni meni v aplikaciji... 17 Slika 16: Meni za prijavo v sistem... 18 Slika 17: Okno v katerem se izpisujejo delovni nalogi... 18 Slika 18: Okno v katerih lahko pregledujemo "batche" zapise... 19 Slika 19: Osvetlitev, flaška in kamera v delovanju zaradi testiranje aplikacije... 21 Slika 20: Izgled aplikacije v delovanju... 22 Slika 21: Risanje trackerja... 22 Slika 22: Test aplikacije na idealni obliki flaške... 25 Slika 23: Test aplikacije na deformirani obliki flaške... 25 Slika 24: Statistika, ki se izpisuje tekom delovanja aplikacije.... 30 3
1. Uvod V tretjem letniku študija ITK-VS (Informatike in tehnologije komuniciranja) mora vsak študent, ki želi opraviti letnik oz. diplomirati, opraviti praktično izobraževanje, ki obsega 350 ur dela v podjetju, ki se ukvarja z njegovo smerjo študija. Ker sem sam vpisan v ta študij in sicer v pod smer sistemska podpora informatiki, sem prakso iskal v podjetjih, ki se ukvarjajo z splošno informatiko. Delo sem si našel v podjetju INEL d.o.o, kjer sem bil dodeljen v oddelek programiranja in razvoja. Dodeljen mi je bil mentor, glavni programer Črt Cencelj. Prakso sem začel opravljati dne 17.3.2014 in končal z dnem 22.5.2014. Delovni dan je trajal od 7. do 15. ure in sicer od ponedeljka do petka. 2. Opis gospodarske družbe 2.1. Vizija Postati vodilni na področju izdelave naprav za označevanje, kontrolo in verifikacijo v farmaciji ter (specializiranih) naprav za avtomatizacijo in označevanje v industriji. Utrditi ugled in prepoznavnost na domačih trgih ter se čim bolje uveljaviti na tujih trgih. 2.2. Poslanstvo Z odgovornim poslovanjem stremimo k doseganju vrhunskih rezultatov in ustvarjanju dolgoročnih in varnih delovnih mest za naše zaposlene. Vlaganje v raziskave in razvoj in posledično ustvarjanje proizvodov z visoko dodano vrednostjo. 2.3. Vrednote * Visoka kakovost proizvodov * Dolgoročna strateška usmeritev * Konkurenčnost * Zadovoljstvo kupcev in zaposlenih * Izobraževanje in usposabljanje * Sodelovanje * Odgovornost 2.4. Kratek opis podjetja INEL je hitro rastoče podjetje strokovnjakov z visoko zahtevnimi znanji s področij elektronike, informatike in strojništva. Ukvarjamo se z razvojem in proizvodnjo: specializiranih naprav za avtomatizacijo v industriji, etiketiranih naprav, naprav za označevanje izdelkov, naprav za označevanje, kontrolo in verifikacijo v farmaciji. 4
Pri proizvodnji se prilagajamo potrebam naročnikov. Sodelujemo z največjimi slovenskimi podjetji na področju farmacije, živilske industrije, industrije avtomobilskih sestavnih delov, elektroindustrije, industrije gradbenega materiala in drugimi. Prav tako sodelujemo s podjetji s področja nekdanje Jugoslavije, od leta 2010 naprej pa smo prisotni tudi na zahodnih trgih. Svojim strankam po opravljeni dobavi naprave nudimo tudi podporne in servisne storitve ter dobavo reprodukcijskega materiala. Pri svojem delu sledimo zahtevam in pričakovanjem trgov ter s stalnim izobraževanjem zaposlenih in odzivnim razvijanjem novih rešitev širimo svojo ponudbo. Kolektiv sestavljajo tako izkušeni strokovnjaki, kot mladi diplomanti, vsem pa je skupna strast do inovacij. Podjetje je bilo registrirano leta 1989, vendar je začelo z intenzivnejšim delovanjem leta 2000, ko se je solastnik in direktor družbe Ivan Cencelj, univ.dipl.inž. elektrotehnike redno zaposlil v podjetju. Največja prednost našega podjetja pred konkurenco z velikoserijskimi proizvodnjami je v popolni prilagoditvi potrebam uporabnikov. Prav zaradi te značilnosti, po kateri smo poznani, povpraševanje po naših produktih strmo narašča. Stabilno povečevanje povpraševanja je pripeljalo do trenutnega stanja, ko imamov podjetju že 26 zaposlenih. 3. Opis praktičnega izobraževanja Prvi dan ko sem prispel na delo, me je pričakal mentor in mi predstavil sodelavce v pisarni, v kateri sem nato delal in mi predstavil "drugega" mentorja, kateri mi je kasneje največ pomagal saj mi je bil na voljo kadarkoli skozi vse projekte ker sva bila v istem prostoru. Pred začetkom, dela sem se še seznanil z vsemi pravili in podpisal nekaj dokumentov o zaupnosti podatkov in tajnosti. Po predstavitvi z sodelavci mi je glavni mentor prinesel računalnik z vso strojno opremi, ki sem jo potreboval za delo. Priložil mi je tudi, programsko opremo (operacijski sistem in razvojno programsko opremo). Najprej sem si moral naložiti operacijski sistem in si ustvariti uporabniško ime in geslo, za dostop do računalnika. Ko sem si uredil delovno postajo, mi je mentor povedal katera programska orodja si moram namestiti za razvijanje programske opreme. Seznanil me je tudi z različni standardi in dogovori znotraj podjetja(imena spremenljivk, datotek, razredov itd.). Ko sva z mentorjem ustno obnovila znanje sem se lotil zastavljenih projektov. 3.1. Uporabljene tehnologije in orodja v času izobraževanja 3.1.1. Visual studio 2013 Visual studio je okolje oz. programska oprema Microsofta, ki nam omogoča razvoj računalniških programov kot so spletne strani, spletne aplikacije in spletne storitve. Visual studio uporablja microsoftove platforme, kot so windows forms, WPF(windows presentation foudnation), windows store itd. Omogoča različno podporo programskih jezikov kot so C + + in C + + / CLI, VB.NET, C # in F #. Podpora tudi druge jezike, kot so M, Python in Ruby. Prav tako podpira XML / XSLT, HTML / XHTML, JavaScript in CSS. Prednost samega visual studia je intellisesne in sicer to je nekakšno pomagalo, ki nam z namigi omogoča hitrejše pisanje kode. 5
3.1.2. C# C# je Microsoftov objektno orientiran programski jezik.c# je bil oblikovan za delo s Microsoftovo.NET platformo(.net Framework). NET Framework je knjižnica/platforma, ki predstavlja osnovno ogrodje za vse.net orientirana programska orodja in aplikacije za osebne računalnike, dlančnike, pametne telefone itd. 3.1.3. MS SQL server 2012 Microsoft SQL Server je relacijski sistem za upravljanje baz podatkov, ki jih je razvil Microsoft. Baze podatkov so sestavni del aplikacij, saj omogočajo shranjevanje in pridobivanje podatkov. 3.1.4. SQL ( Structured Query Language) SQL ali strukturirani povpraševalni jezik za delo s podatkovnimi bazami in je najbolj razširjen in standardiziran povpraševalni jezik za delo s podatkovnimi zbirkami, s programskimi stavki, ki posnemajo ukaze v naravnem jeziku. 3.1.5. MWtec Halcon Je celovita standardna programska oprema za "strojni vid". Je knjižnica oz. skupek funkcij, ki nam omogočajo upravljanje z kamerami in nato obdelovanje slike (npr. stetje steklenic v zaboju, pregled nivoja polnila v steklenicah). V knjižnici najdemo več kot 1800 funkcij, ki jih je mogoče uporabljati z različnimi programskimi jeziki na različnih platformah(windows, linux..). 3.1.6. HDevelop Je del programske opreme Halcona in sicer v njej lahko vidimo primere in pa tudi sami preizkusimo funkcije, ki jih nato uporabljamo v naših programih. Slika 1: Program Halcon za pregled in preizkus funkcij obdelave slike 6
3.1.7. AVT (allied vision technologies) Je eden izmed vodilnih svetovnih proizvajalcev visokozmogljivih kamer oz. fotoaparatov za obdelavo industrijskih slik. Nudi tudi programsko opremo, ki nam pokaže nastavitve kamere in druge nastavitve v povezavi z njo. Slika 2: Program Vimba za urejenje nastavitev kamere 3.2. Projektno delo Kot sem omenil na začetku sem najprej obnovil znanje programiranja. Rad bi omenil, da sem na pod smeri sistemska podpora in se v tretjem letniku, nisem nikjer srečal z programiranjem kar je pomenilo, da več kot pol leta programiranja nisem obnavljal. Ko sem se spomnil in obnovil osnove, sem z mentorjem raziskal možnosti kaj bi lahko programiral. 3.3. Urejevalnik XML dokumentov 3.3.1. Izdelava projekta Mentor je omenil, da imajo v podjetju prevode za svoje aplikacije zapisane v excel datotekah in bi jih potrebovali v tekstovni datoteki v XML zapisu. Zato se je porodila ideja projekta, da naredim aplikacijo, ki mi bo pretvorila excel datoteko v XML zapis in da bom lahko to XML datoteko, kasneje urejal(odpiral, spreminjal, shranjeval itd.). 7
Slika 3: Podatki v excel datoteki Da pa bi obnovil tudi, znanje iz podatkovnih baz sem dobil tudi nalogo, da lahko to XML datoteko oz. zapise prevodov direktno shranim v bazo podatkov z isto aplikacijo. Postopoma sem sprogramiral vse funkcionalnosti in z pomočjo grafičnega vmesnika, ki je last podjetja ustvaril svoj izgled aplikacije. Slika 4: E-R diagram baze za shranjevanje podatkov 8
Slika 5: Izgled aplikacije v delovanju Slika 6: Funkcionalnosti aplikacije predstavljene z gumbi Slika 7: Funkcionalnosti aplikacije predstavljene z gradniki Izpostavil bi funkcionalnost uvozi excel saj mi je ta predstavljala največji izziv kako iz excela uvoziti v XML. najprej sem si moral zamisliti kako bo izgledal XML zapis glede na zapis v excelu. Sam še nikoli nisem uporabljal XML zapisov zato mi je pri tem pomagal mentor in mi zelo dobro razložil osnove in princip in tako sem na koncu le uspel narediti to funkcionalnost. 9
Izsek kode, ki prebere excel datoteko in direktno shrani v XML zapis : private void btnexcel_click(object sender, RoutedEventArgs e) try OpenFileDialog filedialog = new OpenFileDialog(); string filename; // Set filter for file extension and default file extension //filedialog.defaultext = ".xlsx"; //filedialog.filter = "Execl files (*.xlsx) *.xlsx"; // Display OpenFileDialog by calling ShowDialog method Nullable<bool> result = filedialog.showdialog(); // Open document filename = filedialog.filename; // Create Data Table System.Data.DataTable dtexcel = new System.Data.DataTable(); //DataTable Name dtexcel.tablename = "dataexcel"; //Path of excel file string SourceConstr = @"Provider=Microsoft.ACE.OLEDB.12.0;Data Source='" + filename + "';Extended Properties= 'Excel 8.0;HDR=Yes;IMEX=1'"; //connecting OleDbConnection con = new OleDbConnection(SourceConstr); //Query string string query = "Select * from [Controls$]"; //DataAdapter object OleDbDataAdapter data = new OleDbDataAdapter(query, con); //fill record into DataTable data.fill(dtexcel); XmlDocument doc = new XmlDocument(); XmlElement fileelement = doc.createelement("file"); XmlElement controlselement = doc.createelement("controls"); XmlElement translateselement = doc.createelement("translates"); XmlElement keyboardelement = doc.createelement("keyboard"); //header XmlElement header = doc.createelement("header"); XmlElement language; XmlAttribute atributidh; XmlAttribute atributvaluelangh; fileelement.appendchild(header); int counter = dtexcel.columns.count; ; //header 0 key 1 property.. then languages for (int i = 2; i < counter; i++) language = doc.createelement("language"); atributidh = doc.createattribute("id"); atributvaluelangh = doc.createattribute("value"); atributvaluelangh.value = dtexcel.columns[i].tostring(); atributidh.value = (i - 2).ToString(); language.setattributenode(atributidh); language.setattributenode(atributvaluelangh); header.appendchild(language); 10
fileelement.appendchild(controlselement); opencontrolsexcel(dtexcel, doc, controlselement, counter); dtexcel = new System.Data.DataTable(); //translates query = "Select * from [Translates$]"; data = new OleDbDataAdapter(query, con); data.fill(dtexcel); fileelement.appendchild(translateselement); opentranslatesexcel(dtexcel, doc, translateselement, counter); dtexcel = new System.Data.DataTable(); query = "Select * from [Keyboard$]"; data = new OleDbDataAdapter(query, con); data.fill(dtexcel); fileelement.appendchild(keyboardelement); openkeyboardexcel(dtexcel, doc, keyboardelement, counter); doc.appendchild(fileelement); SaveFileDialog savefiledialog = new SaveFileDialog(); savefiledialog.filter = "Xml (*.xml) *.xml"; if (savefiledialog.showdialog().value) doc.save(savefiledialog.filename); //////////////////////// cmessagebox.show(gui.languages.gettranslate("fileconvertedexcel")); lvitem = new ListViewItem(); lvitem.content = (GUI.Languages.getTranslate("fileSaved")); //Replace("%s",System.IO.Path.GetFileName(saveFileDialog.FileName)) lvitem.tag = (""); lvlog.items.add(lvitem); edited = false; catch (Exception ex) cmessagebox.show(ex.message); In še funkcija, ki je potrebna za delovanje. Zgornja funkcija uporablja tri pod-funkcije, ki so si vsebinsko enake, samo, da vsaka prebere natanko en list v excel datoteki in pretvori zapis v XML zapis. private static void opencontrolsexcel(system.data.datatable dtexcel, XmlDocument doc, XmlElement controlselement, int counter) for (int i = 0; i < dtexcel.rows.count; i++) DataRow drow = dtexcel.rows[i]; XmlElement element1; XmlElement element2; XmlAttribute atributvalue = doc.createattribute("value"); XmlAttribute atributpropety = doc.createattribute("property"); XmlAttribute atributid; XmlAttribute atributvaluelang; element1 = doc.createelement("entry"); atributvalue.value = drow[0].tostring(); atributpropety.value = drow[1].tostring(); element1.setattributenode(atributvalue); element1.setattributenode(atributpropety); controlselement.appendchild(element1); 11
for (int j = 2; j < counter; j++) atributid = doc.createattribute("id"); atributvaluelang = doc.createattribute("value"); element2 = doc.createelement("language"); if (j < dtexcel.columns.count) atributid.value = (j - 2).ToString(); atributvaluelang.value = drow[j].tostring(); else atributid.value = (j - 2).ToString(); atributvaluelang.value = ""; element2.setattributenode(atributid); element2.setattributenode(atributvaluelang); element1.appendchild(element2); 12
<File> <Header> <Language Id="1" Value="Slovenski" /> <Language Id="2" Value="English" /> <Language Id="3" Value="German" /> <Language Id="4" Value="Francoski" /> </Header> <Controls> <Entry Value="Main.gbMachineStatus" Property="Header"> <Language Id="1" Value="Stanje naprave" /> <Language Id="2" Value="Machine State" /> <Language Id="3" Value="Machinery" /> <Language Id="4" Value="ouii" /> </Entry> <Entry Value="Main.gbMachineStatus.bMachineStart" Property="Content"> <Language Id="1" Value="Zacetek" /> <Language Id="2" Value="Start" /> <Language Id="3" Value="German start" /> <Language Id="4" Value="" /> </Entry> </Controls> <Translates> <Entry Value="EmptyString"> <Language Id="1" Value="32" /> <Language Id="2" Value="empty" /> <Language Id="3" Value="" /> <Language Id="4" Value="" /> </Entry> <Entry Value="Error"> <Language Id="1" Value="Error" /> <Language Id="2" Value="German Error" /> <Language Id="3" Value="" /> <Language Id="4" Value="" /> </Entry> </Translates> 13
Ko sem to uredil, so mi manjkale le še malenkosti, kot so shranjevanje, in odpiranje, pri katerih sem moral biti pazljiv, da si stvari en povozim in lovljenje izjem. Ker sem pomislil, da uporabniki radi vidijo, kaj se dogaja v programu, sem naredil tudi "log" okenček katerem lahko vsak vidi, kaj se dogaja(shranjevanje, kaj manjka, ali je datoteka odprta itd.). Pomisli sem tudi na to, da ne moremo po pomoti zapreti programa, brez da nas ta ne praša ali želimo hraniti če se nismo in tudi če shranimo, imam v dnevniku zapisano, kje imamo prosta polja in to tudi izpišemo. Če kliknemo na dnevnik, kjer je zapisano kaj nam manjka nam program avtomatsko poišče ta zapis. Lahko pa tudi ročno iščemo po zapisih v okenčku iskanje. Slika 8: Dnevnik aktivnosti Slika 9: Primer iskanja po besedah Ko sem to vse uredil sem sprogramiral tudi funkcionalnost, ki mi te prevode zapiše v bazo in jih tam trajno hrani kot nekakšno varnostno verzijo. Ker je to aplikacija kjer hranim prevode, sem za podjetje preizkušal tudi večjezičnost programa oz. kako bi jaz hranil previde za kontrole aplikacije(gumbe, menije...), zato sem naredil, da lahko spreminjamo jezik aplikacije na svoj način z tehnologijo ki, jo ponuja visual studio z resource datotekami. 14
Slika 10: Izgled, kako izbirati med jeziki v aplikaciji Slika 11: Izgled datotek z jeziki v Visual Studiu Slika 12: Zapisi prevodov v datoteki, ki jih zagotovi Visual Studio 15
Na koncu je moj projekt izgledal v visual studio drevesno tako. Imam več oken, in pa pomožnih razredov ter drugih pripomočkov. Slika 13: Struktura programa 3.3.2. Primerjava z šolskim znanjem Moram priznati, da sem se na univerzi na predavanjih in vajah naučil veliko stvari, ki so mi prišle prav, šele sedaj sem spoznal kje oz. zakaj se uporablja XML in kako ga uporabljati, kako je sestavljen. Iz univerze sem odnesel dosti znanja, da sem lahko brez problema razvil aplikacijo po izgledu in funkcionalnosti. Prav mi je prišlo tudi znanje excela in odpiranje datoteke v C#-u. 3.4. Pregledovalnik in urejevalnik delovnih nalogov v bazi 3.4.1. Izdelava projekta Naslednji projekt, ki so mi ga dodeli je bil za potrebo podjetja naročnika, ki si je zaželel, da lahko produkte, ki jih naša naprava tehta sami pregledajo rezultate in vnašajo delovne naloge.pri tem projektu sem se moral seznaniti z že v naprej definirano bazo in jo preučiti.ko sem jo preučil in razumel sem lahko to tudi uporabil. 16
Slika 14: Struktura podatkovne baze Pri načrtovanju izgleda aplikacije in detajlnih funkcionalnostih sem imel proste roke zato sem si zamislil preprosti meni, ki mi je omogočal prijavo uporabnika. Če uporabnik ni prijavljen je lahko samo pregledoval podatke, ne pa tudi urejal. Slika 15: Vstopni meni v aplikaciji 17
Slika 16: Meni za prijavo v sistem Iz menija lahko odpremo dve novi okni in sicer urejanje nalogov kje lahko urejamo, dodajamo in brišemo same naloge. Lahko pa tudi iščemo po identu in na kliku na stolpec tabele filtriramo po izbranem stolpcu. Slika 17: Okno v katerem se izpisujejo delovni nalogi Izberemo pa lahko tudi pregled izmerjenih tež produktov in enako iščemo po batchu in filtriramo po tabeli. Izpisujemo tudi statistiko vseh izmerjenih tež, ki se v grobem delijo na uspešne in neuspešne. 18
Slika 18: Okno v katerih lahko pregledujemo "batche" zapise 19
Glavna lastnost, te naloge je bila podatkovna baza, zato bi rad izpostavil funkcijo, v kateri sem iz podatkovne baze pridobil podatke z SQL stavki: public static List<WeightResult> loadweightresult(batchinfo batch) List<WeightResult> list = new List<WeightResult>(); try using (SqlConnection sqlcon = new SqlConnection(Data)) sqlcon.open(); using (SqlCommand sqlcom = new SqlCommand("", sqlcon)) sqlcom.commandtext = "SELECT * FROM tbl_weighingresults WHERE BATCH=@batch"; sqlcom.parameters.addwithvalue("batch", batch.batch); using (SqlDataReader reader = sqlcom.executereader()) while (reader.read()) WeightResult result = new WeightResult(); result.batch= reader["batch"].tostring(); result.measuredweight = reader["measured_weight"].tostring(); result.topweight = reader["top_weight"].tostring(); result.bottomweight = reader["bottom_weight"].tostring(); if (reader["control_result"].tostring() == "1") result.controlresult = "Uspešno"; else result.controlresult = "Neuspešno"; result.timestamp = (DateTime)reader["timestamp"]; list.add(result); catch (Exception ex) MessageBox.Show("Napaka " + ex); return list; 3.4.2. Primerjava z šolskim znanjem Pri tej nalogi je bila glavna nit podatkovna baza in ugotovil sem, da mi sama podatkovna baza ni delala težav saj smo na univerzi to lepo izpilili pri podatkovnih bazah 1 na vajah. Večji problem, mi je predstavljala povezava podatkovne baze v moj projekt oz. kako potem podatek pridobiti v moji aplikaciji in kako jih zapisovati v samo bazo. 20
3.5. Program za iskanje defektnih stekleničk 3.5.1. Izdelava projekta Na konci prakse sem dobil najtežji projekt karkoli sem ga kdaj koli programiral. In sicer navodila, so bila, da sem v roke dobil steklenice, ki so bile tako deformirane in tudi nedeformirane, da moram sprogramirati aplikacijo, ki bo ločevala med dobrimi in slabimi steklenicami. Pod slabe steklenice spadajo tiste, ki so deformirane in ali majo praske ali pike na vratu steklenice.dobil sem tudi kamero in pa osvetlitev, ki jih imam na voljo. Slika 19: Osvetlitev, flaška in kamera v delovanju zaradi testiranje aplikacije Najprej sem se lotil dela tako, da sem "odprl" kamero v programski opremi od kamere in se poigral z nastavitvami, da sem sploh spoznal delovanje. Kasneje sem lotil pogledati primere, ki jih ponuja programska oprema od Halcona in pred sabo sem imel odprto tudi dokumentacijo, ki ima preko 2400 strani, kjer so opisane funkcije za obdelavo slike. Sam sem si začrtal kako bo aplikacija izgledala in kako delovala, odločil sem se, da bo uporabnik moral kreirati idealni model stekleničke po katerem se bo nato zgledoval cel program. Odločil sem se, da bo program lociral steklenico glede na njen prvi rob in nato pregledal vrat za praske in kapico za obliko. Program bo izpisoval statistiko in omogočal različne kamere in nastavitve posameznih kamer. Modele steklenic in trackerja sem shranjeval za naslednjo uporabo aplikacije, tako,da ni potrebe vsakič na novo določiti idealne steklenice in trackerja. 21
Slika 20: Izgled aplikacije v delovanju Na začetku z miško narišemo na idelani steklenici tracker in kje naj iščemo napake na steklenici in to shranimo. Slika 21: Risanje trackerja 22
Koda, ki je potrebna za risanje trackerja, ki vsebuje zunanje funkcije Halcon knjižnjice: //drawing tracker on good bottle private void bdrawtracker_click(object sender, RoutedEventArgs e) Picture pic = VimbaHelp.picture; //user draw line hwhalcon2.halconwindow.dispobj(pic.image); MessageBox.Show("Draw line!"); HOperatorSet.DrawLine(hwHalcon2.HalconWindow, out LineRow1, out LineColumn1, out LineRow2, out LineColumn2); bool edge = false; double firstedge = 0; HTuple grayvalue; for (double i = LineColumn1; i < LineColumn2; i++) HOperatorSet.GetGrayval(pic.Image, LineRow1, i, out grayvalue); if (grayvalue > 180) hwhalcon2.halconwindow.setcolor("green"); HOperatorSet.DispLine(hwHalcon2.HalconWindow, LineRow1, i, LineRow1, i + 1); else 10); if (edge == false) hwhalcon2.halconwindow.setcolor("red"); HOperatorSet.DispLine(hwHalcon2.HalconWindow, LineRow1, i - 10, LineRow1, i + edge = true; firstedge = i; i = i + 10; else hwhalcon2.halconwindow.setcolor("green"); HOperatorSet.DispLine(hwHalcon2.HalconWindow, LineRow1, i, LineRow1, i+1); //user draw neck rectangle MessageBox.Show("Draw neck rectangle!"); HOperatorSet.DrawRectangle1(hwHalcon2.HalconWindow, out rectangle1row1, out rectangle1column1, out rectangle1row2, out rectangle1column2); // if rectangle is in correct position if (rectangle1column1 < firstedge-20 rectangle1column2 < firstedge-20 rectangle1row1 > LineRow1 rectangle1row2 > LineRow1) MessageBox.Show("Neck rectangle position error!"); else hwhalcon2.halconwindow.disprectangle1(rectangle1row1, rectangle1column1, rectangle1row2, rectangle1column2); //vertical position distancerectangle1uprow = LineRow1 - rectangle1row1; 23
distancerectangle1downrow = LineRow1 - rectangle1row2; //horizontal position distancerectangle1leftcolumn = rectangle1column1 - firstedge; distancerectangle1rightcolumn = rectangle1column2 - firstedge; //user draw neck rectangle MessageBox.Show("Draw cap rectangle!"); HOperatorSet.DrawRectangle1(hwHalcon2.HalconWindow, out rectangle2row1, out rectangle2column1, out rectangle2row2, out rectangle2column2); //if rectangle is in correct position if (rectangle2column1 < firstedge-20 rectangle2column2 < firstedge-20 rectangle2row1 > LineRow1 rectangle2row2 > LineRow1) MessageBox.Show("Cap rectangle position error!"); else hwhalcon2.halconwindow.disprectangle1(rectangle2row1, rectangle2column1, rectangle2row2, rectangle2column2); //vertical position distancerectangle2uprow = LineRow1 - rectangle2row1; distancerectangle2downrow = LineRow1 - rectangle2row2; //horizontal position distancerectangle2leftcolumn = rectangle2column1 - firstedge; distancerectangle2rightcolumn = rectangle2column2 - firstedge; //model of good bottle HOperatorSet.GenEmptyObj(out model); HObject shape; HOperatorSet.GenEmptyObj(out shape); HOperatorSet.Rectangle1Domain(pic.Image, out shape, LineRow1 - distancerectangle2uprow, firstedge + distancerectangle2leftcolumn, LineRow1 - distancerectangle2downrow, firstedge + distancerectangle2rightcolumn); //creating shape model try HOperatorSet.CreateShapeModel(shape, "auto", 0, 50, "auto", "auto", "use_polarity", "auto", 30, out modelid); HOperatorSet.GetShapeModelContours(out model, modelid, 1); hwhalcon2.halconwindow.dispobj(model); MessageBox.Show("Tracker updated!"); catch MessageBox.Show("Eror, re-draw tracker!"); 24
Slika 22: Test aplikacije na idealni obliki flaške Slika 23: Test aplikacije na deformirani obliki flaške 25
Osnova te aplikacije pa so tri funkcije in sicer prva funkcija preverja flaškin»vrat«za nepravilnosti oz. za praske in pike: private void checkbottleneck(hobject inspectedarea) HTuple counter = 0; Picture picture = VimbaHelp.picture; bdrawtracker.isenabled = true; //setting window hwhalcon.halconwindow.setdraw("margin"); hwhalcon.halconwindow.setlinewidth(1); hwhalcon.halconwindow.setcolored(12); hwhalcon.halconwindow.dispobj(picture.image); HObject ImageMean; HOperatorSet.GenEmptyObj(out ImageMean); ImageMean = inspectedarea; HOperatorSet.MeanImage(inspectedArea, out ImageMean, 7, 7); HOperatorSet.DynThreshold(inspectedArea, ImageMean, out ImageMean, 5, "dark"); HOperatorSet.Connection(ImageMean, out ImageMean); HOperatorSet.SelectShape(ImageMean, out ImageMean, "area", "and", 10, 1000); //counting scratches.. HOperatorSet.CountObj(ImageMean, out counter); HOperatorSet.Union1(ImageMean, out ImageMean); HOperatorSet.DilationCircle(ImageMean, out ImageMean, 1); //displaying scratches hwhalcon.halconwindow.dispobj(imagemean); hwhalcon.visibility = Visibility.Visible; //if there are scratches if (counter > 0) lneckresult.content = "Z praskami!"; lneckresult.background = new SolidColorBrush(Colors.Red); scratched = true; else lneckresult.content = "Brez prask!"; lneckresult.background = new SolidColorBrush(Colors.Green); Druga funkcija preverja obliko flaške: //inspection of bottle cap private void checkbottlecap(hobject inspectedarea, HObject model, HTuple modelid) //positions of founded bottle cap HTuple row; HTuple column; HTuple angle; HTuple score; HTuple hommat; Picture picture = VimbaHelp.picture; hwhalcon.halconwindow.setdraw("margin"); hwhalcon.halconwindow.setlinewidth(1); hwhalcon.halconwindow.setcolored(12); hwhalcon.halconwindow.setcolor("green"); HObject objectxld; HOperatorSet.GenEmptyObj(out objectxld); 26
HObject image; HOperatorSet.GenEmptyObj(out image); image = inspectedarea; //search and displays founded shape //if model doesnt exist if (modelid == null) MessageBox.Show("Model is null!"); lcapresult.background = new SolidColorBrush(Colors.Red); lcapresult.content = "Miss match!"; //if model exists else //finding model in inspected area HOperatorSet.FindShapeModel(image, modelid, 0, 0, 0.5, 1, 0.5, "interpolation", 0, 0, out row, out column, out angle, out score); //if shape exists if (row.type.tostring()!= "EMPTY") // score is matching % score = score * 100; HOperatorSet.VectorAngleToRigid(0, 0, 0, row, column, angle, out hommat);//error HOperatorSet.AffineTransContourXld(model, out objectxld, hommat); if ((double)score >= upermatching) lcapresult.background = new SolidColorBrush(Colors.Green); if ((double)score < upermatching && (double)score >= lowermatching) lcapresult.background = new SolidColorBrush(Colors.OrangeRed); if ((double)score < lowermatching) lcapresult.background = new SolidColorBrush(Colors.Red); deformed = true; //displaying founded countours and matching score hwhalcon.halconwindow.dispobj(objectxld); lcapresult.content = (score).tostring() + " %"; //if shape doesnt exists else lcapresult.background = new SolidColorBrush(Colors.Red); lcapresult.content = "Match not founded!"; deformed = true; 27
Ter tretja funkcija, ki združi drugi dve funkciji v celoto in poskrbi za praviln delovanje aplikacije: private void checkbottle() scratched = false; deformed = false; bool edge = false; double firstedge = 0; HOperatorSet.GenEmptyObj(out rectangle1); Picture picture = VimbaHelp.picture; if (picture.image!= null) hwhalcon2.halconwindow.dispobj(picture.image); hwhalcon2.halconwindow.setlinewidth(2); //searching of first edge HTuple grayvalue; for (double i = LineColumn1; i < LineColumn2; i++) HOperatorSet.GetGrayval(picture.Image, LineRow1, i, out grayvalue); //drawing line colors and searching of first edge if (grayvalue > 180) hwhalcon2.halconwindow.setcolor("green"); HOperatorSet.DispLine(hwHalcon2.HalconWindow, LineRow1, i, LineRow1, i + 1); i + 10); 1); else //if first edge occurs if (edge == false) hwhalcon2.halconwindow.setcolor("red"); HOperatorSet.DispLine(hwHalcon2.HalconWindow, LineRow1, i - 10, LineRow1, edge = true; firstedge = i; i = i + 20; else hwhalcon2.halconwindow.setcolor("green"); HOperatorSet.DispLine(hwHalcon2.HalconWindow, LineRow1, i, LineRow1, i + //setting window hwhalcon2.halconwindow.setlinewidth(3); hwhalcon2.halconwindow.setcolor("yellow"); hwhalcon2.halconwindow.setdraw("margin"); //if edge is founded if (edge == true) //rectangle1 hwhalcon2.halconwindow.disprectangle1(linerow1 - distancerectangle1uprow, firstedge + distancerectangle1leftcolumn, LineRow1 - distancerectangle1downrow, firstedge + distancerectangle1rightcolumn); HOperatorSet.Rectangle1Domain(picture.Image, out rectangle1, LineRow1 - distancerectangle1uprow, firstedge + distancerectangle1leftcolumn, LineRow1 - distancerectangle1downrow, firstedge + distancerectangle1rightcolumn); //rectangle2 28
hwhalcon2.halconwindow.disprectangle1(linerow1 - distancerectangle2uprow, firstedge + distancerectangle2leftcolumn, LineRow1 - distancerectangle2downrow, firstedge + distancerectangle2rightcolumn); HOperatorSet.Rectangle1Domain(picture.Image, out rectangle2, LineRow1 - distancerectangle2uprow, firstedge + distancerectangle2leftcolumn, LineRow1 - distancerectangle2downrow, firstedge + distancerectangle2rightcolumn); //calling isnepction of bottle parts checkbottleneck(rectangle1); checkbottlecap(rectangle2, model, modelid); //displaying counters.. if (scratched == true deformed == true) badbottles++; lbad.content = string.format(" Bad Bottles : 0", badbottles.tostring()); if (scratched == true && deformed == true) scratcheddeformed++; lscratcheddeformed.content = string.format(" Scratched and deformed : 0", scratcheddeformed.tostring()); else if (scratched == true) scratchedbottles++; lbadscratches.content = string.format(" Scratched Bottles : 0", scratchedbottles.tostring()); if (deformed == true) deformedbottles++; lbaddeformed.content = string.format(" Deformed Bottles : 0", deformedbottles.tostring()); else goodbottles++; lgood.content = string.format(" Good Bottles : 0", goodbottles.tostring()); //--if edge is not founded else lcapresult.content = "Bottle not founded!"; notfoundedbottle++; lnotfounded.content = string.format(" Not founded: 0", notfoundedbottle.tostring()); lcapresult.background = new SolidColorBrush(Colors.Yellow); bdrawtracker.isenabled = true; 29
Slika 24: Statistika, ki se izpisuje tekom delovanja aplikacije. Na koncu samega projekta, ki še ni dokončno narejen ampak je samo idejno razvit sem naredil, da lahko uporabnik shrani nastavitve kamere, pozicije trackerja, model idealne steklenice itd. 30
<configuration> <startup uselegacyv2runtimeactivationpolicy="true"> <supportedruntime version="v4.0"/> <requiredruntime version="v4.0.20506"/> </startup> <appsettings > <clear /> <add key="upermatching" value="90" /> <add key="lowermatching" value="80" /> <add key="exposuretime" value="363" /> <add key="gain" value="5" /> <add key="rectangle1row1" value="0" /> <add key="rectangle1row2" value="0" /> <add key="rectangle1column1" value="0" /> <add key="rectangle1column2" value="0" /> <add key="distancerectangle1uprow" value="0" /> <add key="distancerectangle1downrow" value="0" /> 3.5.2. Primerjava z šolskim znanjem Pri tem projektu, so mi za programiranje prišle prav samo osnove, ki sem se jih naučil na univerzi. Sedaj sem videl, kaj bi lahko na univerzi še učili pa se nismo. Po mojem mnenju je to uporaba zunanjih knjižnic, saj sem imel težave, kako zunanje knjižnice delujejo in kako jih uporabljati. Zanimivo bi bilo videti na univerzi, da bi kdaj delali oz. združili sliko in programiranje saj bi šele potem videli kako in kaj je v resničnem življenju programiranje. Ali pa če bi karkoli programirali iz resničnega življenja. 31
4. Sklep Ko sem se odpravil na prakso, si nisem znal predstavljati kolikšno je moje znanje in kako bi to znanje lahko uporabil. Ko sem se spoprijel z prvim problem se ga tudi nisem znal lotiti, dokler mi ni pomagal mentor. V tem obdobju prakse sem se naučil veliko novih stvari, ki jih prej niti nisem poznal in nadgradil svoje predhodno znanje. Naučil sem se tudi to, da programiranja se ne da v celoti naučiti saj se vsak dan na novo učiš stvari, ki si jih še nisi znal ali pa tudi že. Spoznal sem delo v skupini, samostojno delo in da je pomoč med sodelavci več kot pomembna. Sedaj si ne predstavljam več dela brez pomoči in vnaprejšnjega načrtovanja. Zanimivo je, da po 7 letih obiskovanja šol na katerih smo se učili programiranje še vedno najdeš nekaj povsem novega in zanimivega. Čeprav sem sedaj videl nekaj primerov programiranja v resničnem življenju in ne samo v šolah se mi zdi, nekaj stvari še vedno popolnoma nejasnih, zato mislim, da je še veliko stvari, ki jih je treba preučiti in jih poizkusiti sprogramirati. Rad bi se zahvalil podjetju Inel d.o.o, da so mi omogočil opravljanje praktičnega usposabljanja in mentorju Črt Cenclju. Posebej pa bi se zahvalil Darku Jeriniću za pomoč in odgovore na vsa moja vprašanja in za predstavitev dela v vsakdanu. 32