Software pro rozpoznání jednotlivých zvířat v chovné hale na základě obrazových dat
-
Název výstupu:
Software pro rozpoznání jednotlivých zvířat v chovné hale na základě obrazových dat
-
Klíčová slova:Zemědělství 4.0; precizní zemědělství; strojové vidění; chov drůbeže
-
Dosažení výstupu:
06/2024
-
Autoři:
Petr Bartoš, Roman Bumbálek, Radim Kuneš, Luboš Smutný, Jean de Dieu Marcel Ufitikirezi, Tomáš Zoubek
-
Vlastníci:Jihočeská univerzita v Českých Budějovicích, IČ: 60076658, podíl na výsledku: 50 %.
AGROSOFT Tábor, s.r.o., IČ: 25169165, podíl na výsledku: 50 %. -
Kód důvěrnosti:C = podléhá obchodnímu tajemství
Popis aplikace
V rámci projektu TM04000023 byl vytvořen Software pro rozpoznávání zvířat v chovné hale na základě obrazových dat. Software je natolik robustní, že dokáže spolehlivě s pravděpodobností minimálně 90 % detekovat chované brojlery ve výkrmové hale. Na obrázcích 1–3 jsou uvedeny výstupy z uvedeného softwaru, pro rozpoznání chovaných brojlerů. Uvedené podklady reprezentují chov v různých fázích výkrmu a demonstrují spolehlivost software při detekování brojlerů z datových vstupů, které nesou známky šumu (zvíře je z části zakryté chovnou technologií, zvířata se navzájem překrývají, apod.).

Obrázek 1: Začátek výkrmového cyklu

Obrázek 2: Pokročilá fáze výkrmu

Obrázek 3: Finální fáze výkrmu
Popis použitého programovacího jazyka a doplňujících balíků
Pro vytvoření softwaru k systému analýzy obrazu umožňující automatizované hodnocení welfare chovu byl využit interpretovaný programovací jazyk Python 3.9 společně s následujícími knihovnami, které byly využity pro své specifické vlastnosti a funkce potřebné k vytvoření výsledného softwaru:
- numpy 1.23.5
- torch 1.13.1
- cv2 1.0.0
- datetime 4.9
- multiprocessing 2.6.2.1
- psycopg2 2.9.5
- matplotlib 3.6.3
Balík NumPy je základním nástrojem pro provádění vědeckých výpočtů v jazyce Python. Mezi jeho hlavní funkcí je poskytování možností využití N-rozměrných polí, sofistikovaných funkcí, funkce lineární algebry, Fourierovy transformace a náhodných čísel.
Balík PyTorch umožňuje implementaci metod hlubokého učení v rámci Pythonu včetně výpočtů na bázi tenzorů poskytujících silnou akceleraci na GPU.
OpenCV je knihovna s otevřeným zdrojovým kódem, která obsahuje široké spektrum konvenčních algoritmů zpracování obrazu.
Balík DateTime usnadňuje práci s časovými formáty a umožňuje využití speciálních funkcí pro jejich úpravu a zpracování.
Knihovna Multiprocessing podporuje paralelní souběh procesů pomocí API podobného modulu Threading. Je schopen místo vláken využívat podprocesy, čímž je schopen umožnit lokální i vzdálenou souběžnost procesů.
Psycopg je implementací nejpoužívanějšího, spolehlivého a funkčně bohatého adaptéru PostgreSQL pro Python.
Matplotlib je komplexní knihovna pro vytváření statických, animovaných a interaktivních vizualizací v jazyce Python
Popis vytrénovaného modelu
Pro vytrénování modelu sloužícího ke stanovení hmotnosti zvířete byla využita architektura konvoluční neuronové sítě YOLO. V rámci trénovacího procesu bylo nutné optimalizovat hyperparametry Learning rate, Batch size a Optimizér.
Learning rate (LR) je hyperparametr optimizéru, který určuje velikost změny v každé iteraci, tj. jak rychle se posunujeme ve směru lokálního optima. Z praktického pohledu na kvalitu nalezených výsledků, příliš velké LR způsobí tzv. overfitting, tj. model se příliš rychle specializuje na nalezené lokální optimum, a nedosáhne optima globálního. Což vede v konečném důsledku k horším dosaženým výsledkům. Příliš malé LR naopak vede k velmi pomalému procesu trénování, tedy v přiděleném čase nemusí konvergovat do optima.
Batch size (BS) je velikost mini batch v každém kroku trénovaní. BS ovlivňuje trénování následujícím způsobem. Větší BS znamená vetší nároky na paměť GPU během trénování, vede k lineárnímu zrychlení trénování a dále velikost BS ovlivňuje stabilitu konvergence, a tedy nalezeného řešení.
Optimizér je z obecného pohledu postup, který říká, jak se v modelu při backpropagaci mají upravit váhy. Z praktického hlediska výběr vhodného optimizéru ovlivňuje jak kvalitu výsledného nalezeného řešení (konvergenci), tak dobu trénovaní.
Na základě porovnání vybraných metrik (Precision, Recall, mAP_0.5 a mAP_0.5:0.95) došlo k nalezení ideálních nastavení výše zmíněných hyperparametrů na hodnoty uvedené v tabulce 1.
Tabulka 1: Zjištěné optimální hodnoty hyperparametrů použitých pro vytrénování modelu
Hyperparametr | Získaná hodnota |
---|---|
Learning rate | 0,01 |
Batch size | 48 |
Optimizér | SGD |
Schopnost klasifikace vytrénovaného modelu je znázorněna pomocí matice záměn predikcí vyobrazené na obrázku 4, kde je zaznamenán počet případů, kdy nedošlo k detekci kuřat na obrazcích a byly tak vyhodnoceny jako pozadí. Na obrázku 5 je vizualizován průběh pozorovaných metrik během procesu trénování detekčního modelu. V průběhu všech 300 epoch se získané hodnoty všech metrik zlepšovaly, čímž se zpřesňoval výsledný vytrénovaný model. Predikce detekce sledovaných objektů vytrénovaným modelem konvoluční neuronové sítě architektury YOLO je představena na obrázku 6.

Obrázek 4: Matice záměn predikcí pro vytrénovaný model CNN s architekturou YOLO

Obrázek 5: Vizualizace průběhu metrik sledovaných v průběhu trénovacího procesu

Obrázek 6: Predikce polygonální masek sledovaných objektů vytrénovaným modelem
Doporučené hardwarové požadavky na přetrénování modelu
Pro nasazení v rozdílných stájových prostředích je doporučen nejprve testovací provoz spojený se sběrem dat, která jsou následně použita k přetrénování původního modelu, čímž dojde k zpřesnění predikce definovaných tříd. Samotné přetrénování modelu pro konkrétní podmínky provozu probíhá na výkonném GPU serveru, pro následnou aplikaci SW v reálném provozu zahrnující provedení inferencí vedoucí k získání detekcí požadovaných objektů již není potřeba tak velké množství výpočetního výkonu, avšak nároky nelze generalizovat, jelikož se odvíjí od počtu kamer snímající vstupní data, požadované frekvence prováděného vyhodnocení i složitosti implementovaného CNN modelu. Pro analýzu obrazu ze dvou kamer o frekvenci jednou za sekundu lze doporučit výpočetní stanici obsahující GPU s níže uvedenými minimálními hardwarovými parametry.
Tabulka 2: Doporučené minimální hardwarové parametry GPU
Parametr | Hodnota |
---|---|
Velikost paměti | 6 GB |
Typ pamětí | GDDR6/HBM |
Propustnost paměti | 360 GB/s |
Počet CUDA jader | 3 500 |
Teoretický výkon v FP32 | 12 TFLOPS |
Příloha
Přílohou dokumentace softwarového řešení je také zdrojový kód. Z důvodu ochrany know-how řešitelů jsou uvedeny pouze určité pasáže.
class Camera:
def __init__(self, IP, inDir, fps, username, password, dur=None, st_date=None, st_time=None):
self.IP = IP
self.inDir = inDir
self.fps = fps
self.username = username
self.password = password
self.duration = dur
self.get_stime(st_date, st_time)
self.capCam()
def capCam(self):
self.cap = cv2.VideoCapture(f'rtsp://{self.username}:
{self.password}.@{self.IP}:554')
self.cap.get(1)
if self.start_time is not None:
while self.start_time != datetime.datetime.now().replace
(microsecond=0):
time.sleep(0.5)
self.get_im()
else:
self.get_im()
self.cap.release()
def get_im(self):
if self.duration is not None:
mFrame = self.getMaxFrames()
else:
mFrame = 0
c = 0
while (True):
_, frame = self.cap.read()
name = f'{self.inDir}/c{str(self.IP)[-2:]}_{str(t)[0:10]}_
{str(t)[11:].replace(":", "-")}.jpg'
cv2.imwrite(name, frame)
c += 1
time.sleep(0.5)
if mFrame > 0 and c >= mFrame:
break
def getMaxFrames(self):
h = (self.time.find(':'))
mFrame = (int(self.time[0:h]) * 3600 + int(self.time[h+1:h+3]) * 60 + int(self.time[h+4:])) * self.fps
return mFrame
def get_stime(self, st_date, st_time):
if st_date is None:
st_date = str(datetime.datetime.now().date())
if st_time is None:
st_time = str(datetime.datetime.now().replace(microsecond=0).
time())
self.start_time = f'st_date st_time'
def det_chicken(model, source, th, imgsz, name, camset):
detect_stall_1r.run(weights=model, source=source, conf=th, imgsz=imgsz, device=device, line_thickness=2, view_img=False, save_txt=True, save_conf=False, nosave=False, project=inDir, name=name, exist_ok=True, color='yes', camset=camset, c_names=['chicken'], showMask=False)
procs = []
if __name__ == '__main__':
procDet = multiprocessing.Process(target=det_chicken, args=(model, source, th, imgsz, name, camset))
procDet.start()
procs.append(procDet)
time.sleep(1)
for i in range(0, len(camset)):
ip = '192.168.1.' + camset[i]
proc = multiprocessing.Process(target=Camera, args=(ip, inDir, fps, t))
proc.start()
procs.append(proc)
procIm = multiprocessing.Process(target=i2f, args=(inDir, camset))
procIm.start()
procs.append(procIm)
for proc0 in procs:
proc0.join()