Echtzeit-Kantenerkennung mit FPGA

Einführung


Unser Projekt implementiert ein Echtzeit-Kantenerkennungssystem, das auf der Erfassung von Bilderrahmen von einer OV7670-Kamera und deren Streaming auf einen VGA-Monitor nach Anwendung eines Graustufenfilters und eines Sobel-Operators basiert. Unser Design basiert auf einer Cyclone IV-FPGA-Karte, mit der wir die Leistung mithilfe der leistungsstarken Funktionen der Low-Level-Hardware und paralleler Berechnungen optimieren können, die wichtig sind, um die Anforderungen des Echtzeitsystems zu erfüllen.


Wir haben ein ZEOWAA FPGA-Entwicklungsboard verwendet, das auf Cyclone IV (EP4CE6E22C8N) basiert. Außerdem haben wir Quartus Prime Lite Edition als Entwicklungsumgebung und Verilog HDL als Programmiersprache verwendet. Darüber hinaus verwendeten wir die integrierte VGA-Schnittstelle, um den VGA-Monitor anzusteuern, und GPIO (General Pins for Input and Output), um die externe Hardware mit unserer Karte zu verbinden.


ZEOWAA FPGA-Entwicklungsboard


Architektur


Unser Design gliedert sich in 3 Hauptteile:


  1. Lesen der Datenpixel von der Kamera.
  2. Implementierung unseres Kantenerkennungsalgorithmus (Graustufenkonverter und Sobel-Operator).
  3. Anzeigen des endgültigen Bildes durch Anbindung an einen VGA-Monitor.

Es gibt auch einen Zwischenspeicher zwischen dem Lesen / Schreiben der Daten und dem Bearbeiten dieser Daten. Zu diesem Zweck haben wir zwei Puffer implementiert, die als temporärer Speicherplatz für Pixel dienen, bevor sie verwendet werden.


Die implementierte Architektur


Beachten Sie, dass wir das Pixel, nachdem wir es von der Kamera genommen haben, nicht direkt im Zwischenspeicher gespeichert haben. Stattdessen haben wir es in Graustufen konvertiert und dann im Puffer gespeichert. Dies liegt daran, dass das Speichern von 8-Bit-Graustufenpixeln weniger Speicher benötigt als das Speichern der 16-Bit-Farbpixel. Außerdem haben wir einen weiteren Puffer, in dem die Daten nach Anwendung des Sobel-Operators gespeichert werden, damit sie auf dem Monitor angezeigt werden können.


Hier sind die Details zur Implementierung unserer Architektur:


Kamera

Wir haben eine OV7670-Kamera verwendet, die eines der billigsten Kameramodule ist, die wir gefunden haben. Diese Kamera kann auch mit 3,3 V betrieben werden und benötigt keine schwierigen Kommunikationsprotokolle wie I2c oder SPI, um die Daten des Bildes zu extrahieren. Es ist nur eine SCCB-Schnittstelle erforderlich, die der I2c-Schnittstelle ähnlich ist, um die Konfiguration der Kamera in Bezug auf das Farbformat (RGB565, RGB555, YUV, YCbCr 4: 2: 2) und die Auflösung (VGA, QVGA, QQVGA, CIF, QCIF) festzulegen. und viele andere Einstellungen.


Kameramodul OV7670


Das Video besteht aus Frames, die mit einer bestimmten Geschwindigkeit geändert werden. Ein Rahmen ist ein Bild, das aus Zeilen und Spalten von Pixeln besteht, wobei jedes Pixel durch Farbwerte dargestellt wird. In diesem Projekt haben wir die Standardkonfiguration der Kamera verwendet, bei der die Bildgröße die VGA-Auflösung 640 x 480 (0,3 Megapixel) und das Farbformat des Pixels RGB565 (5 Bit für Rot, 6 Bit für Blau, 5 Bit für Grün) beträgt ) und die Änderungsrate der Frames beträgt 30 fps.


Im Folgenden die Verbindungen der Kamera zum FPGA mithilfe des auf der Entwicklungsplatine vorhandenen GPIO:


Pin in der KameraPin im FPGABeschreibungPin in der KameraPin im FPGABeschreibung
3,3V3,3VNetzteil (+)GNDGNDBodenversorgungsniveau (-)
SdiocGNDSCCB UhrSDIODGNDSCCB-Daten
VSYNCP31Vertikale SynchronisationHrefP55Horizontale Synchronisation
PCLKP23Pixels UhrXclkP54Eingangssystemtakt (25 MHz)
D7P468. DatenbitD6P447. Datenbit
D5P436. DatenbitD4P425. Datenbit
D3P394. DatenbitD2P383. Datenbit
D1P342. DatenbitD0P331. Datenbit
RESET (Active Low)3,3VPin zurücksetzenPWDNGNDPin ausschalten

Beachten Sie, dass wir für die Konfiguration keine SCCB-Schnittstelle verwendet haben. Deshalb legen wir die entsprechenden Drähte auf den Boden, um schwebende Signale zu vermeiden, die die Daten beeinflussen können.


Um den 25-MHz-Takt für die Kamera bereitzustellen, haben wir den Phasenregelkreis (PLL) verwendet, ein Frequenzregelsystem mit geschlossenem Regelkreis, um den erforderlichen Takt aus den von der Karte bereitgestellten 50 MHz bereitzustellen. Zur Implementierung der PLL haben wir das interne IP-Katalog-Tool in der Quartus-Software verwendet.


Diese Kamera verwendet das VSYNC-Signal (Vertical Synchronization), um den Sendevorgang des Rahmens zu steuern, und das HREF-Signal (Horizontal Synchronization), um das Senden jeder Zeile des Rahmens zu steuern. Diese Kamera verwendet nur 8 Datenzeilen (D0-D7), um die Bits zu übertragen, die die Farbwerte des Pixels darstellen, wenn die Kamera den 16-Bit-RGB-Pixelwert in 2 (8-Bit) Teile aufteilt und diese einzeln sendet.


Die folgenden Abbildungen aus dem Datenblatt des Kameramoduls OV7670 veranschaulichen die Signale der vertikalen und horizontalen Synchronisation.


VGA Frame Timing


Horizontales Timing


RGB565 Ausgangszeitdiagramm


Graustufenkonverter

Um ein Graustufenbild aus dem ursprünglichen Farbbild zu erstellen, sollten viele Faktoren berücksichtigt werden, da das Bild Kontrast, Schärfe, Schatten und Struktur verlieren kann. Darüber hinaus sollte das Bild die relative Leuchtdichte des Farbraums beibehalten. Zum Konvertieren des Farbbilds in Graustufen werden verschiedene lineare und nichtlineare Techniken verwendet. Um unser Ziel zu erreichen, haben wir dementsprechend die kolorimetrische (wahrnehmungsluminanzerhaltende) Umwandlung in Graustufen verwendet, die in der folgenden Gleichung dargestellt ist:



Um die Leistung in Bezug auf Berechnungen zu verbessern, ist es schneller, den Schichtoperator zu verwenden. Daher kann die obige Gleichung auf Folgendes reduziert werden:



Nachdem ein Pixelwert (565 RGB) von der Kamera erfasst wurde, kann er sofort unter Anwendung der Konvertierungsformel in einen 8-Bit-Graustufenpixelwert konvertiert werden. Das Graustufenbild ist einfacher im Speicher zu speichern und schnell genug, um die Funktionalität unseres Echtzeitsystems zu erfüllen, da seine Komplexität ungefähr logarithmisch ist und FPGA es durch parallelen Zugriff auf den Speicher noch schneller machen kann. Danach ist das gespeicherte Bild zur Implementierung des Kantenerkennungsalgorithmus bereit.


Zwischenspeicher (Der Puffer)

Wir haben 2 Puffer, der erste wird verwendet, um die Pixel zu speichern, nachdem sie in Graustufen und ihre Größe (8 Bit x 150 x 150) konvertiert wurden, und der zweite wird verwendet, um die Pixel nach Anwendung des Sobel-Operators und des Schwellenwerts für die zu speichern Ausgabewert und seine Größe (1 Bit x 150 x 150). Leider speichern 150 x 150 Puffer nicht das gesamte Bild von der Kamera, sondern nur einen Teil davon.


Wir haben die Größe unserer Puffer aufgrund der Begrenzung des Zyklon-IV-Speichers auf 150 x 150 gewählt, da er nur 276.480 Kbit hat, während unsere beiden Puffer 202.500 Kbit (150 x 150 x 9) benötigen, was 73,24% des ursprünglichen Speichers von entspricht Der Zyklon IV und der Rest des Speichers werden zum Speichern des Algorithmus und der Architektur verwendet. Darüber hinaus haben wir (170 x 170) als Größe für unsere Puffer versucht, die 94,07% aus dem Speicher entnimmt, wodurch nicht genügend Speicherplatz für die Implementierung des Algorithmus übrig bleibt.


Unsere Puffer sind echte Dual-Port-RAMs, die gleichzeitig in verschiedenen Taktzyklen lesen und schreiben können. Hier haben wir unsere Implementierung erstellt, anstatt das IP-Katalog-Tool in der Quartus-Software zu verwenden, um mehr Flexibilität bei der Implementierung zu erhalten. Außerdem haben wir beide Puffer in nur ein Modul integriert, anstatt unterschiedliche Module zu haben.


Sobel-Betreiber

Wir haben einen ersten abgeleiteten Kantenerkennungsoperator verwendet, der ein Matrixbereichsgradientenoperator ist, der die Änderung der Luminanz zwischen verschiedenen Pixeln bestimmt. Um genauer zu sein, da dies eine einfache und effiziente Methode in Bezug auf Speichernutzung und Zeitkomplexität ist, haben wir den Sobel-Gradientenoperator verwendet, der einen 3x3-Kernel verwendet, der auf einem ausgewählten Pixel zentriert ist, um die Stärke der Kante darzustellen. Der Sobel-Operator ist die Größe des Gradienten, berechnet durch:


Besessen


Wo Gx und Gy mit Faltungsmasken dargestellt werden können:


Gx- und Gy-Faltungsmatrizen


Beachten Sie, dass die Pixel, die näher an der Mitte der Maske liegen, stärker gewichtet werden. G x und G y können auch wie folgt berechnet werden:


Gx- und gy-Gleichungen


Wobei p i das entsprechende Pixel im folgenden Array ist und der Wert von p i ein 8-Bit-Graustufenwert ist:


Pixelmatrix


Es ist üblich, die Gradientengröße des Sobel-Operators durch absolute Werte zu approximieren:


die gleichung sterben


Diese Annäherung ist einfacher zu implementieren und schneller zu berechnen, was wiederum unserer Funktionalität in Bezug auf Zeit und Speicher dient.


Hier ist das Blockdiagramm des Sobel-Operators, der 9 (8-Bit) Pixel als Eingabe verwendet und einen (8-Bit) Pixelwert erzeugt:


Sobel-Kern


Und hier ist das detaillierte Blockdiagramm der Sobel-Operator-Implementierung.


Detaillierter Sobel-Kern


Vga-Monitor

Unser Entwicklungsboard verfügt über eine integrierte VGA-Schnittstelle, die nur 8 Farben auf dem VGA-Monitor anzeigen kann, da nur 3 Bit zur Steuerung der Farben über ein Bit für Rot, eines für Grün und eines für Blau zur Verfügung stehen. Dies hat unser Debuggen erschwert, da wir das Bild von der Kamera nicht direkt auf dem Monitor anzeigen können. Daher haben wir einen Schwellenwert verwendet, um die Pixel in einen 1-Bit-Wert umzuwandeln, damit das Bild angezeigt werden kann.


Die VGA-Schnittstelle funktioniert wie die Kamera, da sie Pixel für Pixel von der oberen linken Ecke zur unteren rechten Ecke arbeitet. Mit der vertikalen und horizontalen Synchronisation können wir die Signale synchronisieren, die den Pixelfluss steuern.


Das vertikale Synchronisationssignal wird verwendet, um den Index der Zeile darzustellen, während das horizontale Synchronisationssignal verwendet wird, um den Index der Spalte darzustellen. Außerdem verwenden beide Signale die vordere Veranda, den Synchronisationsimpuls und die hintere Veranda als Synchronisationssignale, um die alte Reihe von der neuen Reihe im horizontalen Synchronisationssignal und den alten Rahmen vom neuen Rahmen im vertikalen Synchronisationssignal zu trennen.


VGA-Signal-Timing-Diagramm


Wir haben die Standard-VGA-Signalschnittstelle (640 x 480 bei 60 MHz) verwendet. Alle Standardspezifikationen des Signals werden hier beschrieben.


Testen


Bevor Sie alles zusammenbauen und das Echtzeitsystem testen. Wir mussten zuerst jedes Teil einzeln testen. Zuerst haben wir die Werte und Signale, die von der Kamera kommen, überprüft, indem wir bestimmte Pixelwerte angezeigt haben. Mithilfe von OpenCV unter Verwendung der Programmiersprache Python konnten wir dann den Sobel-Filter auf mehrere Bilder anwenden, um die Ergebnisse mit unserem Algorithmus zu vergleichen und die Richtigkeit unserer Logik zu überprüfen. Darüber hinaus haben wir unsere Puffer und den VGA-Treiber getestet, indem wir nach Anwendung des Sobel-Operators und des Schwellenwerts mehrere statische Bilder auf dem VGA-Monitor angezeigt haben. Durch Ändern des Schwellenwertwerts wird außerdem die Genauigkeit des Bildes beeinträchtigt.


Der Python-Code, den wir verwendet haben:


# This code is made to test the accuracy of our algorithm on FPGA import cv2 #import opencv library f = open("sample.txt",'w') # Open file to write on it the static image initialization lines img = cv2.imread('us.jpg') # Read the image which has our faces and its size 150x150 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #convert to grayscale sobelx = cv2.Sobel(gray,cv2.CV_64F,1,0,ksize=3) #x-axis sobel operator sobely = cv2.Sobel(gray,cv2.CV_64F,0,1,ksize=3) #y-axis sobel operator abs_grad_x = cv2.convertScaleAbs(sobelx) abs_grad_y = cv2.convertScaleAbs(sobely) grad = abs_grad_x + abs_grad_y for i in range(0,150): for x in range(0,150): #read the pixels of the grayscaled image and Store them into file with specific format to initialize the buffer in FPGA code f.write("data_a[{:d}]<=8'd{:d};\n".format(i*150+x,gray[i][x])) #apply threshold to be exactly like the code on FPGA if(grad[i][x] < 100): grad[i][x] = 255 else: grad[i][x] = 0 cv2.imshow("rgb", img) #Show the real img cv2.imshow("gray",gray) #Show the grayscale img cv2.imshow("sobel",grad)#Show the result img cv2.waitKey(0) #Stop the img to see it 

Ergebnisse


Als Ergebnis unserer Implementierung haben wir ein Echtzeit-Kantenerkennungssystem erhalten, das nach Anwendung des Graustufenfilters und des Sobel-Operators ein 150x150-Bild erzeugt. Das implementierte System bietet 30 fps. Die Kamera läuft mit einem 25-MHz-Takt und das System hält im Allgemeinen Echtzeitfristen ohne merkliche Verzögerung ein. Darüber hinaus kann der Schwellenwert die Detailgenauigkeit und das Rauschen im endgültigen Bild beeinflussen.


Hier ist ein Vergleich zwischen dem Sobel-Operator auf dem FPGA und dem OpenCV-Sobel-Operator:


Vergleich


Unten sehen Sie ein veranschaulichendes Video der Ergebnisse:


Video des Projekts


Hier ist der Link des Repositorys auf Github, das alle Quellcodes enthält.


Zukünftige Verbesserungen


Da wir FPGA Cyclone IV verwenden, sind wir auf seine Speicherkapazität und die Anzahl der Logikgatter beschränkt. Daher können wir als zukünftige Verbesserung eine externe Speicherquelle verwenden oder unsere Arbeit auf einer anderen Karte implementieren, um alle Pixel des von der Kamera empfangenen Bildes anzuzeigen.


Obwohl der Sobel-Bediener schnell und einfach zu implementieren ist, ist er außerdem spürbar geräuschempfindlich. Um das erzeugte Rauschen zu eliminieren, können wir ein Rauschfilter wie das nichtlineare Medianfilter verwenden, das mit unserem System einwandfrei funktioniert, wenn wir über genügend Speicher verfügen, um einen dritten Puffer zu implementieren. Dadurch wird ein glatteres Bild mit entfernten scharfen Merkmalen erzeugt.


Dementsprechend haben wir die integrierte VGA-Schnittstelle des FPGA verwendet, die nur ein 3-Bit-Bild erzeugen kann. Daher konnten wir das Graustufenbild nicht anzeigen, da es 8 Bit benötigt, um angezeigt zu werden. Infolgedessen wird durch die Implementierung einer anderen Schnittstelle oder die Verwendung einer leistungsstärkeren Karte die Flexibilität bei der Anzeige des Bildes verbessert.


Fazit


Wir konnten unser Wissen und Verständnis für wichtige Konzepte in eingebetteten Systemen wie Zustandsmaschinen, Parallelität von Berechnungen und Hardware-Software-Schnittstellen nutzen, um eine effiziente Kantenerkennungsanwendung zu erstellen, die unsere Ziele erfüllt.


Bestätigung


Dieses Projekt wird von einem Team aus zwei Studenten aufgebaut: Hussein Youness und Hany Hamed im ersten Jahr des Bachelor of Computer Science an der Innopolis University in Russland.


Dieses Projekt ist Teil des Kurses für Computerarchitektur im Herbst 2018 an der Innopolis University .


Source: https://habr.com/ru/post/de431326/


All Articles