Ich bin neu in Python (und habe seit einiger Zeit keine Datei-E / A mehr verwendet). Bitte nehmen Sie Kontakt mit mir auf, wenn ich in irgendetwas, was ich sage, einen Anfängerfehler mache.
Ich habe .bmp-Bilder von jeweils ca. 5 MB. Ich möchte den Durchschnitt von zwei Bildern nehmen und den Durchschnitt in einem anderen Dateiverzeichnis speichern. Dieser Firmen-Laptop ist 8 GB RAM, 64 Bit, Prozessor ist AMD A10-7300 Radeon R6, 10 Rechenkerne 4C + 6G 1,9 GHz
Ich habe genau das getan, aber jetzt möchte mein interner Manager, dass ich den Speichervorgang viel schneller mache (derzeit dauert es ungefähr 2-3 Minuten für 500 Bilder). Ich benutze die Funktion imageResult.save (currentSavePath, "bmp").
Hier ist der Bildspeichercode:
# function for file selection 2
def FileSelect2(self, event):
dirDialog = wx.DirDialog(self, "Choose a directory:", style=wx.DD_DEFAULT_STYLE);
# user canceled file opening
if dirDialog.ShowModal() == wx.ID_CANCEL:
return
# otherwise, proceed loading the file chosen by the user
self.rootDir2 = dirDialog.GetPath()
self.subdirArray2 = [];
for dirName, subdirList, fileList in os.walk(self.rootDir2):
for fname in fileList:
if os.path.splitext(fname)[1] == '.bmp':
self.subdirArray2.append(dirName+'\\'+fname)
self.fileDisplay2.Clear()
self.statusText.SetForegroundColour(wx.BLACK)
self.blocker = False
self.fileDisplay2.AppendText(self.rootDir2)
# function for making sure the directory matches
def CheckIfFilesMatch(self):
if(self.subdirArray1.__len__() != self.subdirArray2.__len__()):
self.statusText.SetValue("please enter same amount of files")
self.blocker = True
self.statusText.SetForegroundColour(wx.RED)
return False
for f in self.subdirArray1:
if f.replace(self.rootDir1,self.rootDir2) not in self.subdirArray2:
self.statusText.SetValue("This file: " + f + " does not correspond to any file in parallel.")
self.blocker = True
self.statusText.SetForegroundColour(wx.RED)
return False
for f in self.subdirArray2:
if f.replace(self.rootDir2,self.rootDir1) not in self.subdirArray1:
self.statusText.SetValue("This file: " + f + " does not correspond to any file in parallel.")
self.blocker = True
self.statusText.SetForegroundColour(wx.RED)
return False
Funktion zum Mitteln von Bildern
def Average(self, event):
self.CheckIfFilesMatch()
if self.blocker:
return
self.count = 0
# save file
saveDialog = wx.DirDialog(self, "Choose a directory(Your files will be saved in same file names under this):", style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT);
# cancel
if saveDialog.ShowModal() == wx.ID_CANCEL:
# update status
self.statusText.SetValue("Did not save")
self.statusText.SetForegroundColour(wx.BLACK)
# ok
return
else:
savePath = saveDialog.GetPath()
# start reading file
for i in self.subdirArray1:
postfix = i.replace(self.rootDir1, "")
print postfix
print i
f = self.rootDir2+postfix
if not os.path.isdir(os.path.dirname(savePath+postfix)):
os.makedirs(os.path.dirname(savePath+postfix))
currentSavePath = savePath+postfix
try:
# update status
self.statusText.SetValue("Processing...")
self.statusText.SetForegroundColour(wx.BLACK)
# try reading the files
print "first path: "+i
print "second path: "+f
self.im1 = Image.open(i)
self.im2 = Image.open(f)
self.count += 1
# convert to matrix
self.mat1 = numpy.array(self.im1)
self.mat2 = numpy.array(self.im2)
# convert to uint16 for addition
self.mat1 = self.mat1.astype('uint16')
self.mat2 = self.mat2.astype('uint16')
# get offset
try:
self.offset = int(self.offsetCtrl.GetValue())
except ValueError:
#throw error
self.statusText.SetValue("Error: please enter integer offset")
self.statusText.SetForegroundColour(wx.RED)
return
# add and convert back to image (with offset)
self.result = (self.mat1 + self.mat2 + self.offset)/2
self.result[self.result > 255] = 255
# convert back to uint 8 for saving
self.result = self.result.astype('uint8')
self.imResult = Image.fromarray(self.result)
# self.imResult = Image.blend(self.im1, self.im2, 1)
self.imResult.save(currentSavePath,"bmp")
# update status
self.statusText.SetValue("Saved image to " + currentSavePath)
self.statusText.SetForegroundColour(wx.BLACK)
except IOError:
# throw error
self.statusText.SetValue("Error: cannot read file : " + i + " or " + f)
self.statusText.SetForegroundColour(wx.RED)
return
Ist 2-3 Minuten normal? Kann es schneller gehen? Sollte ich die Auflösung des endgültigen Bildes verringern?
3 Antworten
Dies ist eher eine Antwort von codeReview. Es scheint, dass Ihr Bildspeicherungsprozess ziemlich schnell ist, wie von Didier beobachtet, daher werde ich nur einige Optimierungen für den anderen Prozess vorschlagen beteiligt ist, die die CheckIfFilesMatch
Methode ist. Dieser Code, der gerade die Komplexität O hat (N 2)
for f in self.subdirArray1:
if f.replace(self.rootDir1,self.rootDir2) not in self.subdirArray2:
self.statusText.SetValue("This file: " + f + " does not correspond to any file in parallel.")
self.blocker = True
self.statusText.SetForegroundColour(wx.RED)
return False
for f in self.subdirArray2:
if f.replace(self.rootDir2,self.rootDir1) not in self.subdirArray1:
self.statusText.SetValue("This file: " + f + " does not correspond to any file in parallel.")
self.blocker = True
self.statusText.SetForegroundColour(wx.RED)
return False
Sie können es zu O (N) machen, indem Sie eine Menge entweder aus self.subdirArray1
oder self.subdirArray2
erstellen. Dann sieht der Code jetzt so aus:
def CheckIfFilesMatch(self):
if(len(self.subdirArray1) != len(self.subdirArray2)):
self.__FileMatchError("please enter same amount of files")
return False
tmp = set(self.subdirArray2)
for f in self.subdirArray1:
frev = f.replace(self.rootDir1,self.rootDir2);
if frev not in tmp:
self.__FileMatchError("This file: " + f + " does not correspond to any file in parallel.")
return False
tmp.discard(frev)
if tmp:
self.__FileMatchError("This file: " + tmp.pop() + " does not correspond to any file in parallel.")
return False
return True
def __FileMatchError(self, txt):
self.statusText.SetValue(txt)
self.blocker = True
self.statusText.SetForegroundColour(wx.RED)
Möglicherweise können Sie die Berechnung mithilfe einer GPU beschleunigen. 2-3 Minuten für 500 Bilder sind nicht allzu seltsam, für große Bildverarbeitungsforschung werden häufig dedizierte Server verwendet.
Beim Speichern ist hier die Festplatte der langsame Faktor. Verwenden Sie zu diesem Zweck einen dedizierten Stapel oder wechseln Sie zu SSD, wenn Sie können.
Sie können die gesamte E / A-Arbeitslast berechnen, die sie darstellt.
Sie haben 500 Bilder mit jeweils 5 MB und müssen zwei davon lesen, um eines zu schreiben. Sie lesen also 500 * 5 * 2 = 5 GB und schreiben 2,5 GB auf die Festplatte.
Nehmen wir an, es dauert 3 Minuten. Dies bedeutet, dass der E / A-Durchsatz im Lesemodus 27,7 MB / s und im Schreibmodus 13,8 MB / s beträgt. Dieses Ergebnis ist für eine klassische Rotationsscheibe nicht so schlecht.
Wenn Sie eine SSD auf diesem Laptop haben, bedeutet dies, dass Sie weit davon entfernt sind, die E / A-Bandbreite zu überlasten, und wahrscheinlich könnten Sie es besser machen. Sie könnten beispielsweise versuchen, den Prozess zu parallelisieren (indem Sie einen Pool von Threads einführen).
Verwandte Fragen
Neue Fragen
python
Python ist eine dynamisch typisierte Mehrzweck-Programmiersprache mit mehreren Paradigmen. Es wurde entwickelt, um schnell zu lernen, zu verstehen, zu verwenden und eine saubere und einheitliche Syntax durchzusetzen. Bitte beachten Sie, dass Python 2 ab dem 01.01.2020 offiziell nicht mehr unterstützt wird. Fügen Sie für versionenspezifische Python-Fragen das Tag [python-2.7] oder [python-3.x] hinzu. Wenn Sie eine Python-Variante (z. B. Jython, PyPy) oder eine Bibliothek (z. B. Pandas und NumPy) verwenden, fügen Sie diese bitte in die Tags ein.