Wie kann ich einen gemeinsam genutzten Speicher in einem benutzerdefinierten Ringpuffer-Datentyp verwalten?Python

Python-Programme
Guest
 Wie kann ich einen gemeinsam genutzten Speicher in einem benutzerdefinierten Ringpuffer-Datentyp verwalten?

Post by Guest »

Ich schreibe ein Programm für die folgende Aufgabe
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()

Zuerst dachte ich, ich könnte die Ringpufferinstanz selbst zu einem gemeinsamen Speicher machen. Ich habe im Internet gesucht und konnte nichts finden. Laut ChatGPT ist es in Python nicht möglich, ein komplexes benutzerdefiniertes Objekt zu einem gemeinsamen Speicher zu machen. Und dann dachte ich, ich könnte die Instanz in einen gemeinsamen Speicher legen, und ChatGPT sagte, das sei auch nicht möglich.
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.

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post