Files
es-praktikum/Milestone6/milestone_6_template.cpp
2024-12-09 14:48:49 +01:00

204 lines
7.4 KiB
C++

#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include "opencv2/opencv.hpp"
#include <iostream>
#include <thread>
#include "gip.h"
// **********************************************************************
//
// Frame-Interrupt Thread der HDMI-Ausgabe des IPs ZYNQ-BASE-HDMI
//
// Alle 60 Frames (und damit jede Sekunde) wird die Farbe einer
// der RGB-LEDs auf dem Zybo-Board geändert
//
// **********************************************************************
void blinkRGBLED()
{
int fdZynqBase = open ("/dev/uio0", O_RDWR);
PGIP_ZYNQ_BASE zynqBase= (PGIP_ZYNQ_BASE) mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fdZynqBase, 0);
int i = 0;
int col = 0;
int pending;
int reenable=1;
// Initialisierung:
// Interrupts freigeben, INT-Status loeschen und Interrupt-verarbeitung im UIO-Treiber aktivieren
zynqBase->InterruptStatus = 0;
zynqBase->InterruptEnable = 1;
write(fdZynqBase,&reenable,4);
// Hier die eigentliche ISR:
// INTs zaehlen und alle 60 INTs die Farbe einer der RGB-LEDs aendern
while(1) {
read(fdZynqBase,&pending,4);
write(fdZynqBase,&reenable,4);
zynqBase->InterruptStatus = 0;
i++;
if (i==60) {
i=0;
zynqBase->Board_IO &= 0x00FFFFFF;
zynqBase->Board_IO |= 1<<(24+col);
col = (col+1)%3;
}
}
}
// **********************************************************************
//
// Thread zur Demonstration des Verhaltens eines Video-Streaming-IPs
// mit Ausgabe der Input- und Output-Bilder ueber OpenCV-Fenster
//
// Bei CIF-Aufloesung (352x288) wird annaehernd Echtzeit erreicht
// Bei Verwendung hoeherer Aufloesungen ist die Ausgabe, bedingt durch OpenCV, deutlich verlangsamt
//
// **********************************************************************
int videoDemo()
{
int currFrame = 0; // Zaehler fuer aktuell verwendetes Bild
int videoNum = 6; // Auswahl der Videosequenz - aus den nachfolgend aufgefuehrten
const std::string videoFiles[9] = {
"/home/user/Videos/testseq/MobileCalendar",
"/home/user/Videos/testseq/Football",
"/home/user/Videos/testseq/acht_cam_",
"/home/user/Videos/testseq/acht_bev_",
"/home/user/Videos/testseq/BetesPasBetes_CIF",
"/home/user/Videos/testseq/Football_CIF",
"/home/user/Videos/testseq/MobileCalendar_CIF",
"/home/user/Videos/testseq/FlowerGarden_CIF",
"/home/user/Videos/testseq/LePoint_CIF",
};
std::string fn = videoFiles[videoNum]+std::to_string(currFrame++)+".jpg"; // Filename
cv::Mat imgJpg = cv::imread(fn,cv::IMREAD_GRAYSCALE); // Erstes Bild lesen
char c = 0;
int pending;
int reenable=1;
// Memory-Mapping durchfuehren
int fdPrivateMemory = open ("/dev/uio16", O_RDWR);
uint8_t* privMem = (uint8_t*) mmap(NULL, 0x8000000, PROT_READ|PROT_WRITE, MAP_SHARED, fdPrivateMemory, 0); // Request 128 MB
int fdMm2vs = open ("/dev/uio1", O_RDWR);
PGIP_AXI_2D_MM2VS mmvs= (PGIP_AXI_2D_MM2VS) mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fdMm2vs, 0);
int fdFilter = open ("/dev/uio2", O_RDWR);
int32_t* filter = (int32_t*) mmap(NULL, 0x1000, PROT_READ|PROT_WRITE, MAP_SHARED, fdFilter, 0);
// Falls MMVS bereits aktiv ist, sollte er zunächst alle laufenden Requests zuende abarbeiten
// Schaltet man zunaechst die Zufuehrung von Daten (MM2VS) ab, können auch die Streaming-FIFOs leerlaufen
mmvs->MM2VS_Control = 0;
usleep(100000);
mmvs->VS2MM_Control = 0;
usleep(100000);
if (!imgJpg.empty()) { // Konnte das 1. Bild erfolgreich gelesen werden?
// Falls nein, brauchen wir gar nicht weitermachen und beenden den Thread
cv::Mat imgGrayIn(imgJpg.size(),CV_8UC1,&privMem[0]); // Speicher fuer Eingangsbild einer OpenCV-Mat zuordnen
cv::Mat imgGrayOut(imgJpg.size(),CV_8UC1,&privMem[0x400000]); // dto. fuer Ausgangsbild
mmvs->InterruptEnable = (1<<1); // VS2MM INT freigeben
write(fdMm2vs,&reenable,4);
mmvs->MM2VS_StartAddress = 0x30000000; // Adressierungsparameter fuer Eingangsbild setzen
mmvs->MM2VS_HorizontalBytes = imgJpg.cols;
mmvs->MM2VS_Stride=imgJpg.cols;
mmvs->MM2VS_VerticalLines=imgJpg.rows;
mmvs->MM2VS_Control |= (0x0<<12); // ARCACHE
mmvs->VS2MM_StartAddress = 0x30400000; // Adressierungsparameter fuer Ausgangsbild setzen
mmvs->VS2MM_HorizontalBytes = imgJpg.cols;
mmvs->VS2MM_Stride=imgJpg.cols;
mmvs->VS2MM_VerticalLines=imgJpg.rows;
mmvs->VS2MM_InterruptLine = 1;
mmvs->VS2MM_Control |= (0x0<<12); // AWCACHE
mmvs->VS2MM_Control |= (1<<1); // Synchronize with Start of Frame (e.g. TUSER=1)
mmvs->InterruptStatus = 0; // INT Status im MMVS loeschen
mmvs->VS2MM_Control |= (1<<0); // Start VS2MM
mmvs->MM2VS_Control |= (1<<0); // Start MM2VS
// Filter Coefficients
filter[0]= -1;
filter[1]= -2;
filter[2]= -1;
filter[3]= 0;
filter[4]= 0;
filter[5]= 0;
filter[6]= 1;
filter[7]= 2;
filter[8]= 1;
filter[9]= 0;
//
// Schleife durch alle Bilder der Videodateien (Abbruch mit ESC-Taste)
//
while(c!=27) { // Press ESC on keyboard to exit
fn = videoFiles[videoNum]+std::to_string(currFrame++)+".jpg";
imgJpg = cv::imread(fn,cv::IMREAD_GRAYSCALE);
if (imgJpg.empty()) {
currFrame = 0;
} else {
memcpy(imgGrayIn.data,imgJpg.data,imgJpg.cols*imgJpg.rows);
read(fdMm2vs,&pending,4); // Auf VS2MM INT warten
write(fdMm2vs,&reenable,4); // INT wieder aktivieren
mmvs->InterruptStatus = 0;
cv::imshow( "In", imgGrayIn ); // Display input image
cv::imshow( "Out", imgGrayOut); // Display output image
//fn = videoFiles[videoNum]+std::to_string(currFrame)+"_out.jpg";
//cv::imwrite(fn,imgGrayOut);
c=(char)cv::waitKey(1); // Press ESC on keyboard to exit
}
}
cv::destroyAllWindows(); // Close all OpenCV windows
}
// Memory-Streaming ausschalten (wir wollen schliesslich nicht unnoetig die anderen Komponenten ausbremsen)
mmvs->MM2VS_Control = 0;
usleep(100000);
mmvs->VS2MM_Control = 0;
usleep(100000);
return 0;
}
// **********************************************************************
//
// main()
//
// **********************************************************************
int main(int argc, char** argv)
{
std::thread t1(blinkRGBLED); // Threads anlegen
std::thread t2(videoDemo);
//t1.join(); // Der Blink-Thread wird nie beendet, also brauchen wir darauf auch nicht warten
t2.join(); // Wenn der OpenCV-Thread beendet wird, sind wir fertig
return 0;
}