Hallo zusammen, ich hab ein kleines Problem mit einer Anwendung in OpenCV bei der ich ein Grauwertbild Pixel für Pixel bearbeiten will. Die Pixel sollen anhand der Kriterien Position und Wert unterschieden werden und entsprechend zu weiß(255) oder schwarz(0) geändert werden. Das ganze habe ich in Python umgesetzt. Hierfür habe ich eine for-Schleife verwendet: Beispiel: for x in range(100): for y in range(100): if(bedingung): image[x,y]= 0 oder 255 Der Code funktioniert, aber braucht sehr viel Zeit. Die Ausführung dauert einige Sekunden, selbst bei kleineren Bildern. Gibt es eine Möglichkeit die einzelnen Pixel auf eine schnellere Weise abzufragen und zu ändern?
Deine Schleife stellt offensichtlich den trivialen Algorithmus für dein Problem dar. Je nach konkreten Problem kann es effizientere Algorithmen geben. Das ist keine Frage der Programmiersprache.
Experte schrieb: > Und was ist 'Bedingung' genau? Da wird überprüft ob der Pixelwert größer als eine Schwelle ist und ob er links oder rechts im Bild ist.
EdB schrieb: > Experte schrieb: >> Und was ist 'Bedingung' genau? > > Da wird überprüft ob der Pixelwert größer als eine Schwelle ist und ob > er links oder rechts im Bild ist. Wenn grundsätzlich alle Pixel einzeln angeschaut werden müssen, führt kein Weg an deinem Algo vorbei, die untere Schranke wäre dann bei O(n), und das macht deine Schleife bereits. (vgl. Sortierung, da muss mindestens jedes Element einmal betrachtet werden, darum kann es keinen Algo besser O(n) theoretisch geben).
Ruf doch einfach die API Funktion dafür auf: https://docs.opencv.org/3.4/d7/d4d/tutorial_py_thresholding.html
EdB schrieb: > for x in range(100): > for y in range(100): Dein Example sehr minimalistisch, aber "for x in range" ist in Python eigentlich immer falsch (okay es gibt ein paar exotische Ausnahmen), Leider kenne ich den Type von Image nicht aber nach ich bin mir ziemlich sicher das man über Image Iterieren kann. Alleine das Kann schon etwas Geschwindigkeit bringen.
Nils schrieb: > Ruf doch einfach die API Funktion dafür auf: > > https://docs.opencv.org/3.4/d7/d4d/tutorial_py_thresholding.html Ich frage aber mehr als nur den Threshold ab
In python benutzt openCV numpy als image container. Deshalb sollte die numpy where function hier hilfreich sein. https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html
1 | np.where(image < 5, 0, 255) |
Die Bedingung kann natürlcih komplizierter sein. Wenn es nur das < ist gibt es dafür explizite openCV Funktionen. Das schaut zwar immer noch jeden Pixel an (muss es ja), macht das aber optimiert.
:
Bearbeitet durch User
Imonbln schrieb: > "for x in range" ist in Python > eigentlich immer falsch Warum das? range(100) erzeugt halt im Speicher eine Liste mit 100 Einträgen. Müsste nicht sein, lieber xrange(), juckt bei heutigen Maschinen aber auch keinen und im Vergleich zum Speicherplatzbedarfs des Bildes ist das eh Kleinkram.
dodadi schrieb: > Warum das? range(100) erzeugt halt im Speicher eine Liste mit 100 > Einträgen. Müsste nicht sein, lieber xrange(), juckt bei heutigen > Maschinen aber auch keinen und im Vergleich zum Speicherplatzbedarfs des > Bildes ist das eh Kleinkram. xrange ist Python2 und seit Anfang des Jahres damit eigentlich im EOL. Was das Iterieren angeht, der Hauptgrund warum es eigentlich immer Falsch ist eine "for x in range" zu schrieben, ist der das man eigentlich jedes Objekt (wo es sinnvol ist) seinen eigenen Iterator mitbringt. meisten Will man ja das nächste Objekt haben und nicht seinen Index kennen, was Python intern nutzen kann zum den Zugriff auf die nächste instance zu Optimieren. Ausserdem geben seit Python3 viele Funktionen lieber ihren Iterator zurück als Speicher für alle Elemente zu verbrauchen z.b map.
EdB schrieb: > Gibt es eine Möglichkeit die einzelnen Pixel auf eine schnellere Weise > abzufragen und zu ändern? Gibt es. Es gibt 2 einfache Lösungen.
Es kann einen Unterschied machen, wie man iteriert:
1 | for x in range(100): |
2 | for y in range(100): |
vs.
1 | for y in range(100): |
2 | for x in range(100): |
Ausprobieren! merciless
Zeig bitte mal etwas mehr Code. - Du kannst aus Python auch C Code aufrufen, falls in dieser Anwendung akzeptabel. Das läuft oft deutlich schneller. Wenn du willst, kannst du auch auf ASM Ebene dann optimieren. Für den C-Fall noch ein paar Tipps: - Wo kommt die Bedingung her? Wird die on-the-fly berechnet? Ggf liegt hier auch ein Problem. - Welche Datentypen verwendest du? Eventuell lassen sich mehrere Werte in einem Schritt abarbeiten (8-bit Pixel in 32-bit Registern) - Loop unrolling mal probiert? Macht ggf hässlichen Code, kann aber schneller werden. Sprünge kosten üblicherweise viel Performance. Für Python wurden schon genügend Optionen genannt
Cyblord -. schrieb: > Das ist keine Frage der Programmiersprache. https://devopsworld.de/1133 Ist es nicht?
M. K. schrieb: > Cyblord -. schrieb: >> Das ist keine Frage der Programmiersprache. > > https://devopsworld.de/1133 > > Ist es nicht? Nein weil die absolute Laufzeit für die Betrachtung eines Algorithmus keine Rolle spielt. Ist dir die Zeit zu lange, dann kannst du immer noch auf einem Supercomputer oder Cluster ausführen. Ein sehr schlechter Algo bleibt sehr schlecht, auch wenn er ein wenig schneller in C als in Python ausgeführt ist. Erst wenn der Algo nachweislich optimal ist, kann man sich über solche Dinge wie Maschine, CPU oder Programmiersprache Gedanken machen.
:
Bearbeitet durch User
Dirk K. schrieb: > Es kann einen Unterschied machen, wie man iteriert:for x in range(100): > for y in range(100): > vs.for y in range(100): > for x in range(100): > Ausprobieren! > > merciless Danke, aber das habe ich bereits getestet. Johannes O. schrieb: > - Wo kommt die Bedingung her? Wird die on-the-fly berechnet? Ggf liegt > hier auch ein Problem Die if-Anfrage wird in der Schleife ausgewertet. Bsp. if img[x,y]>100: img[x,y]=255 Johannes O. schrieb: > - Welche Datentypen verwendest du? Eventuell lassen sich mehrere Werte > in einem Schritt abarbeiten (8-bit Pixel in 32-bit Registern) uint8 Dirk K. schrieb: > In python benutzt openCV numpy als image container. Das habe ich auch bereits gefunden. Laut anderen Beiträgen soll man mit numpy den größten Zeitgewinn erzielen. Allerdings verstehe ich nicht so recht wie man damit arbeitet.
Cyblord -. schrieb: > Ein sehr schlechter Algo bleibt sehr schlecht Ja, da hast Du recht. Aber ein sehr schlechter Algo läuft auf unterscheidlichen Programierspachen immer noch unterschiedlich schnell. Ein sehr schlechter Algo in einer sehr schnellen Sprache geschrieben ist u.U. schneller als ein sehr guter Algo in Python. Also verstehe ich Deinen Ansatz nicht, das die Sprache keine Rolle spielt. Aber lassen wir das nicht zum Schlagabtausch werden. Die laufen nicht so gut zwischen uns. Also, hast Du recht und ich Unrecht und dabei belassen wir das. Das hält mein Ego aus ;-)
100x100 müsste selbst in Python fluppen. Da stimmt was nicht mit dem Zugriff auf ,,image", wird wohl jedesmal neu geladen oder so. Wäre wohl besser ein richtiges array/liste im Pythonstil zu haben, evtl. gibt da eine Funktion die ein solches zurückliefert, welches man dann zwischenspeichert in einer Variable....
> Der Code funktioniert, aber braucht sehr viel Zeit. > Die Ausführung dauert einige Sekunden, selbst bei kleineren Bildern. Wie klein? Ersetze mal image durch ein erstelltes array gleicher Größe und vergleiche. Und poste den code der sich hinter deiner Bedingungsfunktion verbirgt
M. K. schrieb: > Also, hast Du recht und ich Unrecht und dabei belassen wir das. > Das hält mein Ego aus ;-) Putzig. Schlagabtausch? Das wäre so als würde ich nem Hund einen Knochen hinwerfen und er mag ihn nicht. So ein Schlagabtausch wäre das. Und was das mit seinem Ego macht und ich dabei Recht habe, interessiert mich ungefähr ähnlich.
:
Bearbeitet durch User
Hier der gesamte Code: import cv2 import numpy as np import matplotlib.pyplot as plt img = cv2.imread('/home/pi/Desktop/Bilder2/Bild1.png',0) for x in range(img.shape[0]): for y in range(img.shape[1]): if(img[x,y]>180 or y>450): img[x,y]=255 cv2.imshow('Image',img) cv2.waitKey(0) cv2.destroyAllWindows()
Damit dein code schneller ( viel schneller) wird, führt kein Weg an der Benutzung der OpenCV Routinen bzw numpy vorbei. Bedeutet für Dich: Du musst Dich in beides einarbeiten, was nicht so schwer ist und Dir auch bei anderen Aufgabenstellungen helfen wird. Der Code ist langsam, weil alles durch den python Interpreter läuft. Mit OpenCV/numpy würde das in optimierten (C-)Routinen ausgeführt. Ein Full-HD Bild sollte mit Deiner Schwellenwertoperation auf einem aktuellen Rechner deutlich unter 100ms berechnet werden.
Asdf schrieb: > Damit dein code schneller ( viel schneller) wird, führt kein Weg an der > Benutzung der OpenCV Routinen bzw numpy vorbei. Bedeutet für Dich: Du > musst Dich in beides einarbeiten, was nicht so schwer ist und Dir auch > bei anderen Aufgabenstellungen helfen wird. Ok, ich habe schon eine Weile in der Richtung recherchiert aber noch nichts funktionierendes hinbekommen. Weiß jemand wie man numpy für meine Aufgabe anwenden würde?
Cyblord -. schrieb: > Nein weil die absolute Laufzeit für die Betrachtung eines Algorithmus > keine Rolle spielt. Ist dir die Zeit zu lange, dann kannst du immer noch > auf einem Supercomputer oder Cluster ausführen. nicht gleich so dick auftragen je nach Prozessor geht auch erstmal multithreading mittels OpenMP auch unter Open CV https://stackoverflow.com/questions/54466572/how-to-properly-multithread-in-opencv-in-2019
Mike B. schrieb: > je nach Prozessor geht auch erstmal multithreading mittels OpenMP WENN dein Algorithmus parallelisierbar ist. Und selbst dann ist das immer aufwändiger als einfach die große Maschine rauszuholen, wenn das möglich ist. Aber an 1. Stelle steht der Algorithmus selbst. Der ist das wichtigste. Alles andere ist nachgeordnet. Ich bin dagegen auf einen schlechten Algo mit dem Hammer Rechenleistung einzuschlagen.
:
Bearbeitet durch User
Cyblord -. schrieb: > und ich dabei Recht habe Und das ist es ja, worum es geht, nicht wahr? Ich würde ja auf Quarantänekoller bei Dir tippen, aber Du bist ja immer so. Naja, Du must ja mit Dir leben.
Asdf schrieb: > Der Code ist langsam, weil alles durch den python Interpreter läuft. Mit > OpenCV/numpy würde das in optimierten (C-)Routinen ausgeführt. Nein das kann nicht stimmen. Denn Cyblord sagt das das völlig unabhängig von der Sprache ist, und Cyblord hat immer recht, sonst bekommt er Stresspickel, wirft sich auf den Boden und brüllt bis er einen Lutscher bekommt. :-)))
EdB schrieb: > Weiß jemand wie man numpy für meine Aufgabe anwenden würde? ungefähr so
1 | import cv2 |
2 | |
3 | |
4 | img = cv2.imread('/home/pi/Desktop/Bilder2/Bild1.png',0) |
5 | |
6 | img[ img > 180] = 255 # dein img[x,y] > 180 in numpy parallel |
7 | img[ 0:img.shape[0], 450:] = 255 # dein y > 450 in numpy |
8 | |
9 | img[ img <= 180] = 0 # bin nicht sicher ob du das einfach vergessen hast |
10 | |
11 | cv2.imshow('Image',img) |
12 | cv2.waitKey(0) |
13 | cv2.destroyAllWindows() |
EdB schrieb: > for x in range(img.shape[0]): > for y in range(img.shape[1]): > if(img[x,y]>180 or y>450): > img[x,y]=255 Das Ganze in zwei Konstrukte auflösen (je halbe Y-Auflösung). Einmal alle Y-Positionen größer 450 den Wert 255 zuweisen (Vorteil: kein if ) und einmal alle andere mit der Abfrage größer 180 bearbeiten (Vorteil: nur eine Abfrage).
Imonbln schrieb: > ungefähr so > import cv2 > > img = cv2.imread('/home/pi/Desktop/Bilder2/Bild1.png',0) > > img[ img > 180] = 255 # dein img[x,y] > 180 in numpy parallel > img[ 0:img.shape[0], 450:] = 255 # dein y > 450 in numpy > > img[ img <= 180] = 0 # bin nicht sicher ob du das einfach vergessen hast > > cv2.imshow('Image',img) > cv2.waitKey(0) > cv2.destroyAllWindows() Danke erstmal für den Tipp. Das versuch ich mal.
Cyblord -. schrieb: > Mike B. schrieb: >> je nach Prozessor geht auch erstmal multithreading mittels OpenMP > > WENN dein Algorithmus parallelisierbar ist. Und selbst dann ist das > immer aufwändiger als einfach die große Maschine rauszuholen, wenn das > möglich ist. > > Aber an 1. Stelle steht der Algorithmus selbst. Der ist das wichtigste. > Alles andere ist nachgeordnet. Ich bin dagegen auf einen schlechten Algo > mit dem Hammer Rechenleistung einzuschlagen. Sorry aber hier gehts grad um einen Algo der 100x100 Bildpunkte nacheinander aber unabhängig voneinander abcheckt. Leichter parallelisierbar gehts doch kaum noch. bei 8 nutzbaren cores teilt der scheduler die Arbeit in 8 Teile, fertig. Und dass der angegebene Algo für die Aufgabe kaum besser geht wurde schon gesagt. Hängt halt nur von der Hardware ab. Einen singlecore mit Hyperthreading würde auch nicht extra mit multithreading belasten, aber ab 3 nutzbaren cores geht da schon was.
:
Bearbeitet durch User
Imonbln schrieb: > img[ img > 180] = 255 # dein img[x,y] > 180 in numpy parallel > img[ 0:img.shape[0], 450:] = 255 # dein y > 450 in numpy Der Code klappt super und ist schnell... Nur eine Frage: Ist es möglich beide Bedingungen in einem abzufragen? z.B.: Alle Pixel die in der linken Bildhälfte sind und über 180 sind werden zu 255.
EdB schrieb: > Ist es möglich beide Bedingungen in einem abzufragen? Ich bin kein numpy Experte, keine Ahnung ob das geht. Da musst du ins Handbuch gucken.
Cyblord -. schrieb: > Mike B. schrieb: >> je nach Prozessor geht auch erstmal multithreading mittels OpenMP > > WENN dein Algorithmus parallelisierbar ist. Und selbst dann ist das > immer aufwändiger als einfach die große Maschine rauszuholen, wenn das > möglich ist. > > Aber an 1. Stelle steht der Algorithmus selbst. Der ist das wichtigste. > Alles andere ist nachgeordnet. Ich bin dagegen auf einen schlechten Algo > mit dem Hammer Rechenleistung einzuschlagen. Irgendwie widersprechen sich diese beiden Aussagen. Oben schreibst du, man soll doch einfach einen dickeren Rechner nehmen, unten bist du dagegen, das zu tun.
Rolf M. schrieb: > Irgendwie widersprechen sich diese beiden Aussagen. Oben schreibst du, > man soll doch einfach einen dickeren Rechner nehmen, unten bist du > dagegen, das zu tun. Könnte man meinen. Geb ich zu. ;-) Das mit dem dickeren Rechner war auf Geschwindigkeitsprobleme wegen der Programmiersprache bezogen und darauf dass mehr Rechenleistung bis zu einem gewissen Punkt einfacher zu bekommen ist als Parallelisierung. Bezüglich eines schlechten Algo macht aber mehr Rechenleistung nur begrenzt sinn, da hier es hier sehr schnell um extreme Größenänderungen gehen kann. z.B. bei einer Datenbankabfrage mit JOIN kann die Auswahl des Optimierers bezüglich der inneren und äußeren Tabelle einen Unterschied von 1ms bis 1 Million Jahre ausmachen.
:
Bearbeitet durch User
EdB schrieb: > Ist es möglich beide Bedingungen in einem abzufragen? Genau wie in deinem Beispiel ist es normalerweise falsch. Wenn du OR in einer Abfrage hast, werden fast immer beide Bedingungen geprüft (Extremfall - alle Adressen über 450 haben Wert kleiner 180). Wie schon jemand geschrieben hat - Adressen über 450 auf 255 setzen, nur auf Wert über 180 abfragen.
:
Bearbeitet durch User
EdB schrieb: > Der Code funktioniert, aber braucht sehr viel Zeit. Auf welcher Hardware läuft denn Dein Code? C64? Arduino? > Die Ausführung dauert einige Sekunden, selbst bei kleineren Bildern. Sogar auf 'nem RasPi hab ich auf 1000x1000 Pixel erhöhen müssen, damit ich eine Laufzeit von 4-5 Sekunden erreicht hab. Was mach ich bloß falsch.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.