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?

2
OneRaynyDay 10 Aug. 2015 im 22:01

3 Antworten

Beste Antwort

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)
1
Community 23 Mai 2017 im 11:44

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.

1
zxvn 10 Aug. 2015 im 21:44

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).

2
Didier Spezia 10 Aug. 2015 im 19:24