Mercurial > hg > multiomr
view MainMultiOMR.py @ 2:46fb79167a61 tip
Main Code
author | Victor Padilla <victor.padilla.mc@gmail.com> |
---|---|
date | Mon, 04 May 2015 22:56:18 +0200 |
parents | |
children |
line wrap: on
line source
''' @organization: Lancaster University & University of Leeds @version: 1.0 Created on 11/12/2014 @author: Victor Padilla @contact: v.padilla@lancaster.ac.uk The application can be run through command line (without windows interface) using MainMultiOMR library ''' import logging import time import os import gc import sys from subprocess import Popen from music21 import stream from music21 import converter from Process import PipelineAlignment from Process import Voting from Process import SymbolConversion from Process import FullScoreAlignment from Automatism import BatchOMR from Result import ProcessGroundS2 from Result import ExcellData from Functions import FilesFunctions from Functions import MeasureFunctions from Alignment import NWunsch import shutil from Preprocessing import ossia from Preprocessing import movements from Preprocessing import preomr import PythonMagick import PyPDF2 class MainMultiOMR: ''' main functions to run the Big Data Process. They can be called without interface, from another program, for example .... # instance mmOMR=MainMultiOMR() # run the Big Data process once mmOMR.runBigData("C:\\Users\\victor\\Desktop\\data") # run the Big Data waiting for changes mmOMR.runDummyBigData("C:\\Users\\victor\\Desktop\\data") # run the Big Data Ground process once to get the results mmOMR.runBigDataGroung("C:\\Users\\victor\\Desktop\\data") # run the Big Data Ground waiting for changes mmOMR.runDummyBigData("C:\\Users\\victor\\Desktop\\data") ''' def _loadNWunsch(self): ''' Load Needlemann-Wunsch algorith library by default ''' a=["foo00"] b=["foo000"] NWunsch.NWunsch_getSimilarity(a,b) #print "Default NWunsch......" def processPDF2TIFF(self,filename): pdf_im = PyPDF2.PdfFileReader(file(filename, "rb")) npage = pdf_im.getNumPages() print('Converting %d pages.' % npage) intMovement=0 for p in range(npage): im = PythonMagick.Image() im.density('300') print filename im.read(str(filename)+'[' + str(p) +']') strOut=str(filename) + str(p) im.write(strOut+ '.tif') infile=strOut+ '.tif' po = preomr.PreOMR(infile) rv = po.split_movements(strOut+'_A.tif', strOut+'_B.tif') if rv != None: print("new movement was detected at system %d" % (rv,)) arrFile=filename.split("\\") myFile=arrFile.pop() path='\\'.join(arrFile) print "**********************",path if rv==0: intMovement+=1 dirMovement=path+"\\m"+str(intMovement) os.makedirs(dirMovement) shutil.copy(strOut+ '.tif', dirMovement+"\\page_"+str(p)+".tif") else: dirMovement=path+"\\m"+str(intMovement) shutil.copy(strOut+ '_A.tif', dirMovement+"\\page_"+str(p)+".tif") intMovement+=1 dirMovement=path+"\\m"+str(intMovement) os.makedirs(dirMovement) shutil.copy(strOut+ '_B.tif', dirMovement+"\\page_"+str(p)+".tif") else: shutil.copy(strOut+ '.tif', dirMovement+"\\page_"+str(p)+".tif") def processOssia(self,rootDir): ############################################### # @param dirGeneral root movement folder for dirname, dirnames, filenames in os.walk(rootDir): for f in filenames: fname_path = os.path.join(dirname, f) if f.endswith(".tif"): print fname_path ossia.process(fname_path, dirname+"\\_"+f) # rootApp=os.path.dirname(sys.argv[0]) # rootApp=rootApp.replace("\\","/") # cwd="python.exe "+rootApp+"/Preprocessing/ossia.py "+fname_path+" "+fname_path # # print cwd # p = Popen(cwd) # p.wait() # p.communicate() # def processMovement(self,dirGeneral): ''' Process just one movement. The structure should be .... \\movementName\\fullScore\\XML\\(the .xml files) \\parts\\0\\ \\1\\ \\2\\XML\\(the .xml files) the result is \\movementName\\finalScore.xml usage: mmOMR=MainMultiOMR() mmOMR.processMovement("C:\Users\victor\Desktop\data\k458\Process\m2") ''' ff=FilesFunctions() subdirnameParts=ff.SubDirPath(dirGeneral+"\\Parts\\") fsOMRs_files=ff.getFiles(dirGeneral+"\\fullScore\\XML\\") for dirname in subdirnameParts: d=dirname+"/XML/" urlSplit=dirname.split("\\") part=int(urlSplit[-1]) partOMRs_files=ff.getFiles(d) print "---------S2------------" logging.warning("Part:"+str(part)+" "+d) self.setResultS2(d,part,fsOMRs_files,partOMRs_files) print "---------Synchronising scores and parts------------" logging.warning("---------Synchronising scores and parts------------:"+dirGeneral) #fsOMRs=ff.getOMRs(dirGeneral+"\\fullScore\\XML\\") self.__runSynchroScoresAndParts(dirGeneral,fsOMRs_files) ############################################### # @param path folder where the .xml files are # @param idPart part number # @param fsOMRs array with the full score files processed by music21 # @param partOMRs array with the part files processed by music21 def setResultS2(self,path,idPart,fsOMRs,partOMRs): ''' Takes the fullScores (processing the idPart) and parts. It writes the result (result.S2.xml) in the dirname This function process each part independently usage: mmOMR=MainMultiOMR() ff=FilesFunctions() fsOMRs=ff.getOMRs("C:\\Users\\victor\\Desktop\\data\\k458_test\\Process\\m2\\fullScore\\XML") partOMRs=ff.getOMRs("C:\\Users\\victor\\Desktop\\data\\k458_test\\Process\\m2\\parts\\0\\XML") d="C:\\Users\\victor\\Desktop\\data\\k458_test\\Process\\m2\\parts\\0\\XML" mmOMR.setResultS2(d,0,fsOMRs,partOMRs) ''' pa=PipelineAlignment() vote=Voting() sc=SymbolConversion() ff=FilesFunctions() omr_symbolsAlign,betterOmrIds=pa.alignNJ_files(idPart,fsOMRs,partOMRs) #The .txt with the OMRs involved (tree) ff.writeText(path,betterOmrIds) #voting outVote=vote.vote(omr_symbolsAlign) #apply voices if it is needed outVote=sc.setVoices(outVote) #convert to music21 resultS2=sc.convertM21(outVote) mf=MeasureFunctions() #remove blank measures due to the alignment resultS2_clean=mf.filterExtraMeasures(resultS2) resultS2_clean.write("musicxml", path+'/result.S2.xml') ############################################### # @param dirGeneral folder where is the root of the movement # @param fsOMRs array with the full score files processed by music21 def __runSynchroScoresAndParts(self,dirGeneral,fsOMRs_files): ''' Takes the fullScores and part files generated to align the final full score - dirGeneral is the movement URL - fsOMRs is an array with the full scores OMRs processed by music21 ''' ff=FilesFunctions() subdirnameParts=ff.SubDirPath(dirGeneral+"\\parts\\") partsNumber=len(subdirnameParts) fsa=FullScoreAlignment() idCompleteScoreBetter=fsa.getIdBetterOMRFullScore(fsOMRs_files,partsNumber) betterFsOMR=ff.getOMR(fsOMRs_files[idCompleteScoreBetter]) finalScore=fsa.runSynchronisingMeasuresNJ(subdirnameParts,betterFsOMR) betterFsOMR=None finalScore.write("musicxml", dirGeneral+'/finalScore.xml') finalScore=None gc.collect() print "----" ############################################### # @param dirGeneral root movement folder def processMovementGround(self,dirGeneral): ''' Process the result. Just one movement. It takes each OMR file and compare against the ground. The differences are written in .XML and .xls .... \\movementName\\fullScore\\XML\\(the .xml files) \\parts\\0\\ \\1\\ \\2\\XML\\(the .xml files) the file finalScore.xml should be in \\movementName\\finalScore.xml the file ground.xml should be in \\movementName\\ground.xml The final result is written in \\movementName\\parts\\resultGeneral.xlsx \\fullScore_errors.xml usage: mmOMR=MainMultiOMR() mmOMR.processMovementGround("C:\Users\victor\Desktop\data\k458\Process\m2") ''' percentagesArray=[] betterOMRIds=[] ff=FilesFunctions() subdirname=ff.SubDirPath(dirGeneral+"\\parts\\") filesFull=ff.getFiles(dirGeneral+"\\fullScore\\XML\\") ground=ff.getGround(dirGeneral) groundparsed=converter.parse(ground, forceSource=True) finalScore=ff.getFinalScore(dirGeneral) finalScoreparsed=converter.parse(finalScore, forceSource=True) for dirname in subdirname: d=dirname+"/XML/" urlSplit=dirname.split("\\") part=int(urlSplit[-1]) filesPart=ff.getFiles(d) files=filesPart+filesFull print files pg=ProcessGroundS2() ErrorsMatrix=[] percentages=[] OMRs=[] OMRs.append(groundparsed) OMRs.append(finalScoreparsed) percentage,errors,scoreWithErrors= pg.getSimilarity(OMRs,part) ErrorsMatrix.append(errors) percentages.append(percentage) if not os.path.exists(dirname+"\\Result"): os.makedirs(dirname+"\\Result") scoreWithErrors.write("musicxml", dirname+"\\Result\\result.S2.xml") for i in range(len(files)): try: OMRs[1]=ff.getOMR(files[i]) percentage,errors,scoreWithErrors= pg.getSimilarity(OMRs,part) ErrorsMatrix.append(errors) percentages.append(percentage) scoreWithErrors.write("musicxml", dirname+"\\Result\\"+os.path.basename(files[i])) except: print "ERROR OMR READING" ErrorsMatrix.append("ERROR OMR READING") percentages.append(0) f=open(d+"betterOMR.txt","r") betterOMRId=f.readlines() f.close() betterOMRIds.append(betterOMRId) print "betterOMRIds",betterOMRIds ed=ExcellData() files.insert(0,dirname+"\\Result\\result.S2.xml" ) print files ed.saveData(ErrorsMatrix,files,percentages) percentagesArray.append(percentages) ed=ExcellData() ed.saveGlobalData(percentagesArray,dirGeneral,betterOMRIds,files) self.__joinErrorParts(dirGeneral) print "----------- END ------------" ################################################################ # @param rootDir root folder where all the scores to process are def runBigData(self,rootDir): ''' Checks if there is any folder to process If the folder "Process" is written, but the "finalScore.xml" is not, runs the procedure usage mmOMR=MainMultiOMR() d="C:\\Users\\victor\\Desktop\\cach" mmOMR.runBigData(d) ''' ff=FilesFunctions() for outWalk in os.walk(rootDir): dirName=outWalk[0] arrDir=dirName.split("\\") if arrDir[-1]=="Process": movements=ff.SubDirPath(dirName) for movement in movements: print movement if not os.path.isfile(movement+"\\finalScore.xml"): logging.warning("Movement:"+movement+" "+rootDir) self.processMovement(movement) ################################################################ # @param rootDir root folder where all the scores to process are def runLoopBigData(self,rootDir,adaptOMRs=False): ''' Infinity loop for processing data Checks if there is any folder to process If the folder "Process" is written, but the "finalScore.xml" is not, runs the procedure usage mmOMR=MainMultiOMR() d="C:\\Users\\victor\\Desktop\\cach" mmOMR.runLoopBigData(d) ''' batchOMR=BatchOMR() ff=FilesFunctions() for outWalk in os.walk(rootDir): dirName=outWalk[0] subdirList=outWalk[1] if "OMRS" in subdirList: rootScore=dirName omrFinished=True scoreFinished=True for outWalk2 in os.walk(rootScore): dirName2=outWalk2[0] files= ff.getAllImgFiles(dirName2) omrs=ff.getAllXMLFiles(dirName2) if len(files)>0 and len(omrs)<4: omrFinished=False if os.path.exists(rootScore+"\\Process"): movements=ff.SubDirPath(rootScore+"\\Process") for movement in movements: if not os.path.isfile(movement+"\\finalScore.xml"): scoreFinished=False else: scoreFinished=False if omrFinished==True and scoreFinished==False: print "---- CONFIGURE SCORES ---" batchOMR.setupApp(rootScore) print "---- CONFIGURE GROUND ---" batchOMR.setGround(rootScore) if adaptOMRs: print "---- ADAPT OMRs ---" self.runAdaptAllOMRs(rootScore+"\\Process") print "---- RUN BIG DATA ---" self.runBigData(rootScore) print "Waiting for processing..." time.sleep(5) self.runLoopBigData(rootDir,adaptOMRs) ################################################################ # @param rootDir root folder where all the scores to process are def runBigDataGround(self,rootDir): ''' Checks if there is any folder to process to get the result If "resultGeneral.xlsx" is not written and "finalScore.xml" and "ground.xml" are in the movement root dir, launches the process usage mmOMR=MainMultiOMR() d="C:\\Users\\victor\\Desktop\\data" mmOMR.runBigDataGround(d) ''' ff=FilesFunctions() for outWalk in os.walk(rootDir): dirName=outWalk[0] arrDir=dirName.split("\\") if arrDir[-1]=="Process": movements=ff.SubDirPath(dirName) for movement in movements: if not os.path.isfile(movement+"\\parts\\resultGeneral.xlsx"): if os.path.isfile(movement+"\\finalScore.xml") and os.path.isfile(movement+"\\ground.xml") : self.processMovementGround(movement) ################################################################ # @param rootDir root folder where all the scores to process are def runFinalXLS(self,rootDir): ''' Checks if there is any folder to process to get the result If "resultGeneral.xlsx" is not written and "finalScore.xml" and "ground.xml" are in the movement root dir, launches the process usage mmOMR=MainMultiOMR() d="C:\\Users\\victor\\Desktop\\data" mmOMR.runBigDataGround(d) ''' ed=ExcellData() files=0 S2_sum=0 CP_sum=0 PS_sum=0 SE_sum=0 SS_sum=0 ff=FilesFunctions() for outWalk in os.walk(rootDir): dirName=outWalk[0] arrDir=dirName.split("\\") if arrDir[-1]=="Process": movements=ff.SubDirPath(dirName) for movement in movements: if os.path.isfile(movement+"\\parts\\resultGeneral.xlsx"): files=files+1 s2,cp,ps,se,ss=ed.processResultGeneral(movement+"\\parts\\resultGeneral.xlsx") S2_sum=S2_sum+s2 CP_sum=CP_sum+cp PS_sum=PS_sum+ps SE_sum=SE_sum+se SS_sum=SS_sum+ss ed.writeFinalXLS(rootDir,S2_sum/files,CP_sum/files,PS_sum/files,SE_sum/files,SS_sum/files) ################################################################ # @param rootDir root folder where all the scores to process are def runLoopBigDataGround(self,rootDir): ''' Infinity loop for getting the results If "resultGeneral.xlsx" is not written and "finalScore.xml" and "ground.xml" are in the movement root dir, launches the process usage mmOMR=MainMultiOMR() d="C:\\Users\\victor\\Desktop\\data" mmOMR.runLoopBigDataGround(d) ''' self.runBigDataGround(rootDir) print "Waiting for results..." time.sleep(5) self.runLoopBigDataGround(rootDir) ################################################################ # @param dirGeneral root folder of the movement def __joinErrorParts(self,dirGeneral): ''' Joins the different result.S2.xml error in a single file. The output file is "fullScore_errors.xml" The function tries to find the file "parts\\[idMovement]\\Result\\result.S2.xml" in each part ''' ff=FilesFunctions() subdirname=ff.SubDirPath(dirGeneral+"\\parts\\") fullScore=stream.Score() for dirname in subdirname: d=dirname+"\\Result\\" urlSplit=dirname.split("\\") part=int(urlSplit[-1]) f=d+"\\result.S2.xml" omr=converter.parse(f, forceSource=True) part=omr.getElementsByClass(stream.Part)[0] fullScore.append(part) fullScore.write("musicxml", dirGeneral+"\\parts\\fullScore_errors.xml") ############################################### # @param rootDir root folder of the general data def runCompleteProcess(self,rootDir): ''' Instead of working in parallel, this function launches a serial process with the different steps involved 1.- SIKULI AUTOMATISM 2.- SETUP APPLICATION (copying files) 3.- CONVERT GROUND (taking the .krn and convert to ground.xml) 4.- RUN MULTIOMR BIG DATA 5.- RUN GET RESULT BIG DATA usage: mmOMR=MainMultiOMR() d="C:\\Users\\victor\\Desktop\\data" mmOMR.runCompleteProcess(d) ''' batchOMR=BatchOMR() logging.basicConfig(filename=rootDir+'\\BigDataLogs.log',format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') print "-------SIKULI AUTOMATISM----------" logging.warning("---SIKULI AUTOMATISM--- "+rootDir) batchOMR.processAllTiffFiles(rootDir,"ALL") print "-------SETUP APPLICATION----------" logging.warning("---SETUP APPLICATION--- "+rootDir) batchOMR.setupApp(rootDir) print "-------CONVERT GROUND----------" logging.warning("---CONVERT GROUND--- "+rootDir) batchOMR.setGround(rootDir) logging.warning("------RUN MULTIOMR BIG DATA--- "+rootDir) print "-------RUN MULTIOMR BIG DATA----------" self.runBigData(rootDir) print "-------RUN GET RESULT BIG DATA----------" self.runBigDataGround(rootDir) ############################################### # @param filename file to convert def runConvertKrnToMusicXML(self,filename): ''' converts a .krn file to .xml using music21 usage: mmOMR=MainMultiOMR() file="C:\\Users\\victor\\Desktop\\data\\k458\\OMRS\\m2\\k458.krn" mmOMR.runConvertKrnToMusicXML(file) ''' omr=converter.parse(filename) omr.write("musicxml", filename+'.xml') ############################################### # @param filename file to convert def runConvertMidiToMusicXML(self,filename): ''' converts a .mid file to .xml using music21 usage: mmOMR=MainMultiOMR() file="C:\\Users\\victor\\Desktop\\data\\k458\\OMRS\\m2\\k458.mid" mmOMR.runConvertKrnToMusicXML(file) ''' omr=converter.parse(filename) #Reordering the different staffs omrOrdered=stream.Score() numberParts=len(omr.parts) for i in reversed(range(numberParts)): mypart=omr.parts[i] omrOrdered.insert(0,mypart) omrOrdered.write("musicxml", filename+'.xml') ############################################### # @param filename file to convert def runConvertVoicesToChord(self,filename): ''' ''' mf=MeasureFunctions() omr=converter.parse(filename) omr=mf.convertVoicesToChord(omr) omr.show() ############################################### # @param filename file to convert def runConvertBeamsToTriplets(self,filename): ''' ''' mf=MeasureFunctions() omr=converter.parse(filename) omr=mf.convertBeamsToTriplets(omr) # omr.show() omr.write("musicxml", filename+'.xml') def runRemovesEmptyVoices(self,filename): ''' ''' mf=MeasureFunctions() omr=converter.parse(filename) omr=mf.removesEmptyVoices(omr) omr.write("musicxml", filename+'.xml') def runRemovesGaps(self,filename): ''' ''' mf=MeasureFunctions() omr=converter.parse(filename) omr=mf.removesGaps(omr) omr.write("musicxml", filename+'.xml') def runAdaptOMRs(self,dirname): ''' Runs the following process in one directory. 1.-Removing GAPS 2.-Converting voices to chords 3.-Converting triplets 4.-Removing Rest Voices ''' ff=FilesFunctions() mf=MeasureFunctions() files=ff.getFiles(dirname) for f in files: try: print f omr=converter.parse(f) print "--- Removing GAPS---" omr=mf.removesGaps(omr) print "--- Converting voices to chords---" omr=mf.convertVoicesToChord( omr) print "--- Converting triplets---" omr=mf.convertBeamsToTriplets(omr) print "--- Removing Rest Voices---" omr=mf.removeRestVoice(omr) omr.write("musicxml", f) except: pass def runAdaptAllOMRs(self,rootDir): ''' Adapt all the files in one directory tree ''' for outWalk in os.walk(rootDir): dirName=outWalk[0] self.runAdaptOMRs(dirName) ################################################## # @param dirname the directory where the files are def runViewM21(self,dirname): ''' Shows all the .xml files in a folder using music21 to check the differences before and after processing usage: mmOMR=MainMultiOMR() dirname="C:\\Users\\victor\\Desktop\\data\\k458\\OMRS\\m2" mmOMR.runViewM21(dirname) ''' ff=FilesFunctions() mf=MeasureFunctions() files=ff.getFiles(dirname) for f in files: omr=converter.parse(f) omr.show() omr.show('text') ################################################## # @param dirname the directory where the files are def runViewWrongMeasures(self,dirname): ''' Flags and prints the possible wrong measures usage: mmOMR=MainMultiOMR() dirname="C:\\Users\\victor\\Desktop\\data\\k458\\OMRS\\m2" mmOMR.runViewWrongMeasures(dirname) ''' ff=FilesFunctions() mf=MeasureFunctions() path = dirname print("Path:"+path) omr_files=ff.getAllFiles(path) for f in omr_files: omr=converter.parse(f) arrayErrors=mf.flagIncorrectMeasures(omr)[1] for array in arrayErrors: for i in range(len(array)): array[i]=array[i]+1 print print f print "Errors measures duration:"+str(arrayErrors[0]) print "Errors measures estimated:"+str(arrayErrors[1]) print "Errors based on beams:"+str(arrayErrors[2]) print "Errors based on last notes:"+str(arrayErrors[3])