Die Aufgabe besteht darin, ein Programm zu schreiben, das zwei Prozesse erstellt:
a) Die ' Der Producer-Prozess liest ein Video-Frame-Bild direkt in einen Shared-Memory-Ringpuffer (d. h. einen Shared-Memory-Puffer, der N Frame-Bilder für ein konfigurierbares N aufnehmen kann – dies kann als Befehlszeilenparameter beibehalten werden).
b) Der 'Consumer-Prozess liest die Frame-Bilder aus dem Ringpuffer und zeigt jeden Frame für eine konfigurierbare Zeitspanne an (z. B. 500 ms – auch ein Programmbefehlszeilenparameter)
c) Der Produzent und der Verbraucher müssen sich synchronisieren, damit
i) Der Verbraucher zeigt ein Bild erst an, nachdem es vollständig produziert wurde (d. h. der gesamte Frame wurde generiert)
ii) Der Verbraucher wartet auf den Produzenten, wenn Das nächste zu verbrauchende Bild ist noch nicht vollständig produziert.\
iii) Der Produzent wartet auf den Konsumenten. Der Ringpuffer hat keinen Platz für das nächste zu produzierende Bild (d. h. der Konsument hat keines der aktuellen Bilder vollständig verbraucht im Ringpuffer)
unten ist mein Code:
Code: Select all
from multiprocessing import Process, Lock, Value
from multiprocessing.shared_memory import SharedMemory
import sys
import numpy as np
import cv2
import time
class RingBufferFullException(Exception):
pass
class RingBufferEmptyException(Exception):
pass
class RingBuffer:
def __init__(self, max_size, single_frame):
self.max_size = Value('i', max_size)
self.shm = SharedMemory(create=True, size=max_size*single_frame.nbytes)
self.queue = np.ndarray(shape=(max_size, *single_frame.shape), dtype=single_frame.dtype, buffer=self.shm.buf)
self.tail = Value('i', -1)
self.head = Value('i', 0)
self.size = Value('i', 0)
self.lock = Lock()
def enqueue(self, item):
with self.lock:
if self.size.value == self.max_size.value:
raise RingBufferFullException('Error: Queue is full')
else:
self.tail.value = (self.tail.value + 1) % self.max_size.value
self.queue[self.tail.value] = item
self.size.value += 1
def dequeue(self):
with self.lock:
if self.size.value == 0:
raise RingBufferEmptyException('Error: Queue is empty')
tmp = self.queue[self.head.value]
self.head.value = (self.head.value + 1) % self.max_size.value
self.size.value -= 1
return tmp
def isFull(self):
return self.size.value == self.max_size.value
def isEmpty(self):
return self.size.value == 0
def display(self):
if self.size.value == 0:
print('Queue is empty')
else:
idx = self.head.value
print('---------------------------------------')
for i in range(self.size.value):
print(self.queue[idx])
idx = (idx + 1) % self.max_size.value
print('---------------------------------------')
def clean(self):
self.shm.close()
self.shm.unlink()
def producer(buf):
cap = cv2.VideoCapture(0)
print(cap.isOpened())
while True:
buf.display()
success, frame = cap.read()
if not success:
print('Failed to capture frame')
continue
try:
buf.enqueue(frame)
except RingBufferFullException:
time.sleep(0.5)
def consumer(buf):
while True:
try:
frame = buf.dequeue()
cv2.imshow('Frame', frame)
cv2.waitKey(100)
except RingBufferEmptyException:
time.sleep(0.2)
cv2.destroyAllWindows()
if __name__ == '__main__':
test = cv2.VideoCapture(0)
if not test.isOpened():
print('Error: Could not open camera.')
sys.exit(1)
success, single_frame = test.read()
if not success:
print('Error: Could not capture initial frame.')
sys.exit(1)
test.release()
buf = RingBuffer(10, single_frame)
test.release()
produce = Process(target=producer, args=(buf,))
consume = Process(target=consumer, args=(buf,))
try:
produce.start()
consume.start()
produce.join()
consume.join()
finally:
buf.clean()
Dann habe ich die Metadaten des Ringpuffers zu einem gemeinsamen Speicher gemacht. Jetzt werden Frames problemlos in die Warteschlange gestellt und aus der Warteschlange entfernt, aber es werden nur schwarze Bilder angezeigt.
Das Hauptproblem besteht darin, dass im CV2-Fenster nur schwarze Bilder angezeigt werden. Die Bilder sind alle schwarz. Wenn ich den aus der Warteschlange entfernten Frame drucke, ist er nur eine Matrix mit nur Nullen. Wenn ich den Puffer innerhalb der Producer- oder Consumer-Funktion drucke, druckt er eine NP-Matrix mit unterschiedlichen Werten. Aber im CV2-Fenster sind es nur schwarze Bilder.
Was mache ich falsch? Jede Hilfe wird geschätzt. Vielen Dank im Voraus.