class ScaleNoteSheetPreprocessor(IPreprocessingUnit):
    def __init__(self,
                 averageHeight,
                 targetLineHeight=100,
                 interpolation=cv2.INTER_CUBIC,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("Preprocessing_Component_Logger")
        self.__logger.info("Starting __init__()",
                           "ScaleNoteSheetPreprocessor:__init__")

        self.__averageHeight = averageHeight
        self.__targetLineHeight = targetLineHeight
        self.__interpolation = interpolation
        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finished __init__()",
                           "ScaleNoteSheetPreprocessor:__init__")

    def preProcess(self, mat):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!

        Example
        -------
        >>> ScaleNoteSheetPreprocessor.preProcess(mat)

        """
        self.__logger.info("Starting preProcess()",
                           "ScaleNoteSheetPreprocessor:preProcess")

        # Berechnung der neuen Bildgroesse
        currentImageHeight = mat.shape[0]
        currentImageWidth = mat.shape[1]
        newImageHeight = int(currentImageHeight / (-self.__averageHeight) *
                             self.__targetLineHeight)
        newImageWidth = int(currentImageWidth / (-self.__averageHeight) *
                            self.__targetLineHeight)

        # Fuehrt eine Skalierung auf die angegeben Groesse aus
        resizeMat = cv2.resize(mat, (newImageWidth, newImageHeight),
                               interpolation=self.__interpolation)

        # Binarisieren des Bildes, da durch die Skalierung und das damit
        # stattfindende Interpolieren zwischen Schwarz und Weiß verschiedene Graustufen entstehen
        _, resultMat = cv2.threshold(resizeMat, 127, 255, cv2.THRESH_BINARY)

        # Anzeigen des Ergebnisses Note
        if (self.__showImagesInWindow):
            cv2.imshow("ScaleNoteSheetPreprocessor", resultMat)
            cv2.waitKey(0)

        self.__logger.info("Finished preProcess() with following Image: ",
                           "ScaleNoteSheetPreprocessor:preProcess", resultMat)

        return resultMat
class GaussianBlurNoiseFilterPreprocessor(IPreprocessingUnit):
    def __init__(self,
                 ksize,
                 sigmaX,
                 sigmaY=0,
                 borderType=cv2.BORDER_DEFAULT,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("Preprocessing_Component_Logger")
        self.__logger.info("Starting __init__()",
                           "GaussianBlurNoiseFilterPreprocessor:__init__")

        self.__ksize = ksize
        self.__sigmaX = sigmaX
        self.__sigmaY = sigmaY
        self.__borderType = borderType
        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finished __init__()",
                           "GaussianBlurNoiseFilterPreprocessor:__init__")

    def preProcess(self, mat):
        """
        Führt den Rauschfilter gaussian blur auf eine Bildmatrix aus.

        Parameters
        ----------
        mat : Mat
        Die Matrix auf welche der Rauschfilter gaussian blur ausgeführt werden soll.

        Returns
        -------
        gaussianBlurMat : Mat
        Die Ergebniss-Matrix auf die der Rauschfilter gaussian blur ausgeführt wurde.

        Example
        -------
        >>> gaussianBlurNoiseFilterPreprocessor.preProcess()

        """
        self.__logger.info("Starting preProcess()",
                           "GaussianBlurNoiseFilterPreprocessor:preProcess")
        gaussianBlurMat = cv2.GaussianBlur(src=mat,
                                           ksize=self.__ksize,
                                           sigmaX=self.__sigmaX,
                                           sigmaY=self.__sigmaY,
                                           borderType=self.__borderType)

        # Anzeigen des Ergebnisses Note
        if (self.__showImagesInWindow):
            cv2.imshow("GaussianBlurNoiseFilterPreprocessor", gaussianBlurMat)
            cv2.waitKey(0)

        self.__logger.info("Finished preProcess() with following Image: ",
                           "GaussianBlurNoiseFilterPreprocessor:preProcess",
                           gaussianBlurMat)
        return gaussianBlurMat
예제 #3
0
class BitwiseNotPreprocessor(IPreprocessingUnit):
    def __init__(self, showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("Preprocessing_Component_Logger")
        self.__logger.info("Starting __init__()",
                           "BitwiseNotPreprocessor:__init__")

        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finished __init__()",
                           "BitwiseNotPreprocessor:__init__")

    def preProcess(self, mat):
        """
        Führt eine Inversierung (bit-weises not) auf eine Bildmatrix aus.

        Parameters
        ----------
        mat : Mat
        Die Matrix auf welche die Operation ausgeführt werden soll.

        Returns
        -------
        bitwiseNot : Mat
        Die Ergebniss-Matrix auf die die Operation ausgeführt wurde.

        Example
        -------
        >>> bitwiseNotPreprocessor.preProcess()
        """
        self.__logger.info("Starting preProcess()",
                           "BitwiseNotPreprocessor:preProcess")

        bitwiseNot = cv2.bitwise_not(mat)

        # Anzeigen des Ergebnisses Note
        if (self.__showImagesInWindow):
            cv2.imshow("BitwiseNotPreprocessor", bitwiseNot)
            cv2.waitKey(0)

        self.__logger.info("Finished preProcess() with following Image: ",
                           "GaussianBlurNoiseFilterPreprocessor:preProcess",
                           bitwiseNot)
        return bitwiseNot
예제 #4
0
class Preprocessor(IPreprocessingUnit):
    def __init__(self, orderedPreprocessingUnits):
        """
        Constructor, initialisiert Membervariablen

        Parameters
        ----------
        orderedPreprocessingUnits: list
        Eine geordnete Liste von PreprrcessingUnits in Ausführungsreihenfolge.
        """
        self.__logger = State().getLogger("Preprocessing_Component_Logger")
        self.__logger.info("Starting __init__()", "Preprocessor:__init__()")

        self.__orderedPrePorcessingUnits = orderedPreprocessingUnits

        self.__logger.info("Finished __init__()", "Preprocessor:__init__()")

    def preProcess(self, mat):
        """
        Führt die entpsrechene Preprocessing-Schritte auf eine Bildmatrix aus.

        Parameters
        ----------
        imgMatrix : Mat
        Die Matrix auf welcher die Preprocessing-Schritte ausgeführt werden soll

        Returns
        -------
        imgMatrix : Mat
        Die Ergebniss-Matrix auf welcher alle Preprocessing-Schritte ausgeführt wurde.

        Example
        -------
        >>> preprocessor.preProcess(mat)
        """
        self.__logger.info("Starting preProcess()", "Preprocessor:preProcess")

        currentMat = mat

        for unit in self.__orderedPrePorcessingUnits:
            newMat = unit.preProcess(currentMat)
            currentMat = newMat

        self.__logger.info("Finished preProcess()", "Preprocessor:preProcess")
        return currentMat
예제 #5
0
class ConfigInput(IConfigInput):
    def __init__(self, configPath):
        """
        Constructor, initialisiert Membervariablen

        Parameters
        ----------
        configPath : string
        Path to config file.

        Example
        -------
        >>> ConfigInput("/path/to/config")
        """
        self.__logger = State().getLogger("ConfigInput_Component_Logger")
        self.__logger.info(
            "Starting __init__() with ConfigPath: " + configPath,
            "Input:__init__")
        self.__configParser = JsonParser(configPath)
        self.__logger.info(
            "Finished __init__() with ConfigPath: " + configPath,
            "Input:__init__")

    def execute(self):
        """
        Führt den entsprechenden Einlesevorgang über einen Parser durch und erstellt die Config.

        Parameters
        ----------

        Returns
        -------
        config : Config
        Die erstellte Konfiguration.

        Example
        -------
        >>> configInput.execute()
        """
        self.__logger.info("Starting execute()", "Input:execute")

        config = self.__configParser.parse()

        self.__logger.info("Finished execute()", "Input:execute")
        return config
예제 #6
0
class PipeConstructor(IPipeConstructor):
    def __init__(self, config):
        """
        Constructor, initialisiert Membervariablen

        :param Config : config Die Konfiguration.
        :example:
            PipeConstructor(config)
        """
        self.__logger = State().getLogger("PipeController_Component_Logger")
        self.__logger.info("Starting __init__()", "PipeConstructor:__init__")
        self.__config = config
        self.__logger.info("Finished __init__()", "PipeConstructor:__init__")

    def constructPipe(self):
        """
        Konstruiert die Pipe für die Klassifizierung und gibt diese zurück.

        :return: successful : boolean
        :return: pipe : dictionary Die Pipe als <name,object> Paar.
        :example:
            pipeConstructor.constructPipe()
        """
        self.__logger.info("Starting to constructPipe()",
                           "PipeConstructor:constructPipe")
        pipe = {
            "Input":
            Input(self.__config.getConfigForComponent("Input")),
            "Preprocessing":
            Preprocessing(
                self.__config.getConfigForComponent("Preprocessing")),
            "DetectionCore":
            DetectionCore(
                self.__config.getConfigForComponent("DetectionCore")),
            "Postprocessing":
            Postprocessing(
                self.__config.getConfigForComponent("Postprocessing")),
            "Output":
            Output(self.__config.getConfigForComponent("Output"))
        }
        self.__logger.info("Finished to constructPipe()",
                           "PipeConstructor:constructPipe")
        return pipe
예제 #7
0
class PipeController(IPipeController):
    def __init__(self, configFilePath):
        """
        Constructor, initialisiert Membervariablen

        :param configFilePath : string Pfad zum Configurations-File
        :example:
            PipeController("my/path/to/a/config/File")
        """
        print("PipeController: Starting __init__()")

        self.__configFilePath = configFilePath
        self.__config = 0
        self.__controllerConfig = 0
        self.__pipe = 0
        self.__pipeConstructor = 0
        self.__configInput = 0
        self.__state = 0

        print("PipeController: Finished __init__()")

    def init(self):
        """
        Baut mithilfe eines PipeContructors, die Pipe zur Klassifizierung auf.

        :return: successful : boolean Initialisierung erfolgreich?
        :example:
            pipeController.init()
        """
        print("PipeController: Starting init() components with Config" +
              self.__configFilePath)
        """Hier kann der ConfigInput mit einer anderen Realisierung des IConfigInput ausgetauscht werden."""
        self.__configInput = ConfigInput(self.__configFilePath)
        self.__config = self.__configInput.execute()
        self.__controllerConfig = self.__config.getConfigForComponent(
            "PipeController")
        """Todo: Check if Config ok """
        """Hier kann der ConfigInput mit einer anderen Realisierung des IConfigInput ausgetauscht werden."""
        self.__state = State()
        self.__state.init(self.__config.getConfigForComponent("State"))
        self.__logger = State().getLogger("PipeController_Component_Logger")
        """Todo: Check if init ok """
        """Hier kann der PipeConstructor mit einer anderen Realisierung des IPipeConstructors ausgetauscht werden."""
        self.__pipeConstructor = PipeConstructor(self.__config)
        self.__pipe = self.__pipeConstructor.constructPipe()
        """Todo: Check if pipe ok """

        self.__logger.info(
            "Finished init() components with Config-Path: " +
            self.__configFilePath, "PipeController:init")
        return True

    def execute(self):
        """
        Führt die Befehle über die Pipe aus und steuert diese.

        :return: successful : boolean War die Klassifizierung erfolgreich?
        :example:
            pipeController.execute()
        """
        self.__logger.info("Starting execute()", "PipeController:execute")

        if self.__controllerConfig["executeBuildTraindata"]:
            outPutOk = self.executeBuildTraindata()

        if self.__controllerConfig["executeTrain"]:
            outPutOk = self.executeTrain()

        if self.__controllerConfig["executeClassification"]:
            outPutOk = self.executeClassification()

        self.__logger.info("Finished execute()", "PipeController:execute")
        return outPutOk

    def executeClassification(self):
        """
        Führt die Klassifizierung über die Pipe aus und steuert diese.

        :return: successful : boolean War die Klassifizierung erfolgreich?
        :example:
            pipeController.executeClassification()
        """
        self.__logger.info("Starting executeClassification()",
                           "PipeController:executeClassification")

        inputMat = self.__pipe["Input"].execute()
        preprocessingMats = self.__pipe["Preprocessing"].execute(inputMat)
        classification = self.__pipe["DetectionCore"].execute(
            preprocessingMats)
        postProcessedClassification = self.__pipe["Postprocessing"].execute(
            classification)
        outPutOk = self.__pipe["Output"].execute(postProcessedClassification)

        self.__logger.info("Finished executeClassification()",
                           "PipeController:executeClassification")
        return outPutOk

    def executeBuildTraindata(self):
        """
        Erstellt ein Trainingsdatenset über die Pipe und speichert diese.

        :return: successful : boolean War der Aufbau erfolgreich?
        :example:
            pipeController.executeBuildTraindata()
        """
        self.__logger.info("Starting executeBuildTraindate()",
                           "PipeController:executeBuildTraindate")

        while True:
            inputMat, lable = self.__pipe["Input"].readNextImgXMLPair()
            if inputMat is None:
                break
            if lable is not None:
                preprocessingMats = self.__pipe["Preprocessing"].execute(
                    inputMat)
                trainMats = self.__pipe["DetectionCore"].buildNextTraindata(
                    preprocessingMats)
                self.__pipe["Output"].writeNextTraindata(trainMats, lable)
        self.__logger.info("Finished executeBuildTraindate()",
                           "PipeController:executeBuildTraindate")
        return True

    def executeTrain(self):
        """
        Führt das Training der Classifier im DetectionCore über die Pipe aus.
        :return: successful : boolean War dir Aufbau erfolgreich?
        :example:
            pipeController.executeTrain()
        """
        self.__logger.info("Starting executeTrain()",
                           "PipeController:executeTrain")

        inputMatArray, lableArray = self.__pipe["Input"].readNoteTrainData()

        self.__pipe["DetectionCore"].executeTrain(inputMatArray, lableArray)

        self.__logger.info("Finished executeTrain()",
                           "PipeController:executeTrain")
        return True
예제 #8
0
class ImageFiller:

    def __init__(self,
                 fillRows=True,
                 fillColumns=True,
                 targetNumberOfRows=110,
                 targetNumberOfColumns=32,
                 appendRowsTop=False,
                 appendColumnsRight=True,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "ImageFiller:__init__")

        self.__fillRows = fillRows
        self.__fillColumns = fillColumns
        self.__targetNumberOfRows = targetNumberOfRows
        self.__targetNumberOfColumns = targetNumberOfColumns
        self.__appendRowsTop = appendRowsTop
        self.__appendColumnsRight = appendColumnsRight
        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finsihed __init__()", "ImageFiller:__init__")

    def coreProcess(self, mats):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger.info("Starting coreProcess()", "ImageFiller:coreProcess")

        # Erstelle eine Liste mit i leeren Listen.
        # Jede leere Liste i wird fuer einen Matrix-Typen angelegt
        newMats = []
        for i in range(0, len(mats)):
            newMats.append([])

        # Iteriere ueber jeden Matrix-Typen
        for i in range(0, len(mats)):

            # Iteriere ueber jedes Objekt der Matrix-Typen-Liste
            for matObject in mats[i]:

                # Speichere die Matrix als neues Objekt ab
                newMatObject = matObject.copy()

                # Zwischenspeichern der Zeilen und Spaltenanzahl
                rows, columns = newMatObject.shape

                # Wenn die Anzahl der Zeilen angepasst werden sollen ...
                if(self.__fillRows):

                    # dann ueberpruefe, ob die urspruengliche Matrix
                    # zu wenig Zeilen besitzt.
                    if(rows < self.__targetNumberOfRows):

                        # Berechne die Anzahl der zusaetzlich benoetigten Zeilen.
                        numberOfAdditionalRows = self.__targetNumberOfRows - rows

                        # Erstellen der Zeilen die zusaetzlich hinzugefuegt werden sollen
                        additionalRows = np.full((numberOfAdditionalRows, columns), 255, dtype=newMatObject.dtype)

                        # Fuege die zusaetzlichen Zeilen oben an, wenn True
                        if(self.__appendRowsTop):
                            newMatObject = np.append(additionalRows, newMatObject, axis=0)

                        # ansonsten fuege die Zeilen unten an.
                        else:
                            newMatObject = np.append(newMatObject, additionalRows, axis=0)

                    # Wenn nicht, dann ueberpruefe, ob die urspruengliche
                    # Matrix zu viele Zeilen besitzt.
                    elif(self.__targetNumberOfRows < rows):

                        # Loesche die Zeilen von der obersten Zeile beginnend
                        # nach unten, wenn True
                        if(self.__appendRowsTop):

                            # Berechne von oben her die Indices der zu loeschenden Zeilen
                            # und loesche diese Zeilen
                            indicesToDeleteRows = range(0, rows - self.__targetNumberOfRows)
                            newMatObject = np.delete(newMatObject, indicesToDeleteRows, axis=0)

                        # ansonsten loesche die Zeilen von der
                        # untersten Zeile beginnend nach oben.
                        else:
                            # Berechne von unten her die Indices der zu loeschenden Zeilen
                            # und loesche diese Zeilen
                            indicesToDeleteRows = range(self.__targetNumberOfRows, rows)
                            newMatObject = np.delete(newMatObject, indicesToDeleteRows, axis=0)


                # Aktualisieren der Zeilen und Spaltengroesse
                rows, columns = newMatObject.shape

                # Wenn die Anzahl der Spalten angepasst werden sollen ...
                if (self.__fillColumns):

                    # dann ueberpruefe, ob die urspruengliche Matrix
                    # zu wenig Spalten besitzt.
                    if (columns < self.__targetNumberOfColumns):

                        # Berechne die Anzahl der zusaetzlich benoetigten Spalten.
                        numberOfAdditionalColumns = self.__targetNumberOfColumns - columns

                        # Erstellen der Spalten die zusaetzlich hinzugefuegt werden sollen.
                        additionalColumns = np.full((rows, numberOfAdditionalColumns), 255, dtype=newMatObject.dtype)

                        # Fuege die zusaetzlichen Spalten rechts an, wenn True
                        if(self.__appendColumnsRight):
                            newMatObject = np.append(newMatObject, additionalColumns, axis=1)

                        # ansonsten fuege die Spalten links an.
                        else:
                            newMatObject = np.append(additionalColumns, newMatObject, axis=1)

                    # Wenn nicht, dann ueberpruefe, ob die urspruengliche
                    # Matrix zu viele Spalten besitzt.
                    elif (self.__targetNumberOfColumns < columns):

                        # Loesche die Spalten von der rechtesten Spalte beginnend
                        # nach links, wenn True
                        if(self.__appendColumnsRight):

                            # Berechne von rechts her die Indices der zu loeschenden Spalten
                            # und loesche diese Spalten
                            indicesToDeleteColumns = range(self.__targetNumberOfColumns, columns)
                            newMatObject = np.delete(newMatObject, indicesToDeleteColumns, axis=1)

                        # ansonsten loesche die Spalten von der linkesten Spalte beginnend
                        # nach rechts.
                        else:
                            # Berechne von links her die Indices der zu loeschenden Spalten
                            # und loesche diese Spalten
                            indicesToDeleteColumns = range(0, columns - self.__targetNumberOfColumns)
                            newMatObject = np.delete(newMatObject, indicesToDeleteColumns, axis=1)

                # Fuege die Matrix der
                newMats[i].append(newMatObject)

                # Anzeigen des Mat-Objektes dem Zeilen bzw. Spalten
                # abgezogen bzw. hinzugefuegt wurden.
                if (self.__showImagesInWindow):
                    cv2.imshow("ImageFiller_Object", newMatObject)
                    cv2.waitKey(0)

        # Abspeichern aller Noten von jedem Matrix-Typ
        for matType in newMats:
            for note in matType:
                self.__logger.info("Filled following Object: ", "ImageFiller:coreProcess", note)

        self.__logger.info("Finished coreProcess()", "ImageFiller:coreProcess")

        return mats
예제 #9
0
class MusicXmlOutput(ISheetMusicOutput):
    def __init__(self, outputPath=None, fillwithrests=True):
        if (outputPath == None):
            self.__outputPath = "output_musicxml.xml"
        else:
            self.__outputPath = outputPath

        self.compare_lenght = 0.0
        self.__fillwithrests = fillwithrests
        self.__logger = State().getLogger("Output_Component_Logger")
        #MUSS DANN GELÖSCHT WERDEN
        #self.__outputPath = "output_mxml.xml"

    #pass

    def write(self, sheetMusic):
        """
        Interface Methode: Jeder SheetMusicOutput muss diese realisieren.
        Führt den entsprechenden Ausgabevorgang durch und erstellt ausgebene Datau.

        Parameters
        ----------
        sheetMusic: SheetMusic

        Returns
        -------
        successful : boolean
        War die Ausgabe erfolgreich?
        """

        ########Erstelle Test-SheetMusic
        #self.create_testdata()

        ########Ausgabe Test-SheetMusic
        #self.print_ausgabe_sheetMusic()

        #Übernehme eingehendes sheetMusic
        self.sheetMusic = sheetMusic

        # Öffnet neues XML-Dokument und füllt den Header der Datei
        temp = minidom.DOMImplementation()
        doctype = temp.createDocumentType(
            'score-partwise', "-//Recordare//DTD MusicXML 3.0 Partwise//EN",
            "http://www.musicxml.org/dtds/partwise.dtd")
        self.__doc = temp.createDocument(None, 'score-partwise', doctype)

        #Erstellt root-Element der XML-Datei
        root = self.__doc.documentElement

        #Schreibt Headerinformationen in das root-Element
        self.write_header(root)

        #Schreibt die part-list in das root-Element
        self.write_part_list(root)

        # Schreibt den erzeugten stream in das Xml-Dokument
        xml_str = self.__doc.toprettyxml(indent="  ")
        with open(self.__outputPath, "w") as f:
            #with open("output_mxml.xml", "w") as f:

            f.write(xml_str)

        return None

#################################################################################
#Schreiben von Standard-Header mit Seitenformatierung etc.

    def write_header(self, input_root):
        """
        <work>
            <work-title>Title</work-title>
        </work>
        <identification>
            <encoding>
                <software>Score Scanner 1.0</software>
                <encoding-date>2017-12-13</encoding-date>
            </encoding>
        </identification>
        <defaults>
            <scaling>
                <millimeters>7.05556</millimeters>
                <tenths>40</tenths>
            </scaling>
            <page-layout>
                <page-height>1683.78</page-height>
                <page-width>1190.55</page-width>
                <page-margins type="even">
                    <left-margin>56.6929</left-margin>
                    <right-margin>56.6929</right-margin>
                    <top-margin>56.6929</top-margin>
                    <bottom-margin>113.386</bottom-margin>
                </page-margins>
                <page-margins type="odd">
                    <left-margin>56.6929</left-margin>
                    <right-margin>56.6929</right-margin>
                    <top-margin>56.6929</top-margin>
                    <bottom-margin>113.386</bottom-margin>
                </page-margins>
            </page-layout>
        </defaults>

        :param input_root:
        Das root-Element der XML-Datei
        :return:
        """

        work = self.__doc.createElement('work')
        work_title = self.__doc.createElement('work-title')
        work_title_text = self.__doc.createTextNode(
            'ScoreScan 1.0 SheetMusic MusicXML')
        work_title.appendChild(work_title_text)
        work.appendChild(work_title)
        input_root.appendChild(work)

        identification = self.__doc.createElement('identification')
        encoding = self.__doc.createElement('encoding')
        identification.appendChild(encoding)
        software = self.__doc.createElement('software')

        software_text = self.__doc.createTextNode('Score Scanner 1.0')
        software.appendChild(software_text)
        encoding.appendChild(software)
        input_root.appendChild(identification)

        import datetime as dt
        encoding_date = self.__doc.createElement('encoding-date')
        encoding_date_text = self.__doc.createTextNode(str(dt.date.today()))
        encoding_date.appendChild(encoding_date_text)
        encoding.appendChild(encoding_date)

        defaults = self.__doc.createElement('defaults')
        scaling = self.__doc.createElement('scaling')
        defaults.appendChild(scaling)
        millimeters = self.__doc.createElement('millimeters')
        millimeters_text = self.__doc.createTextNode('7.05556')
        millimeters.appendChild(millimeters_text)
        scaling.appendChild(millimeters)
        tenths = self.__doc.createElement('tenths')
        tenths_text = self.__doc.createTextNode('40')
        tenths.appendChild(tenths_text)
        scaling.appendChild(tenths)
        input_root.appendChild(defaults)

        page_layout = self.__doc.createElement('page-layout')
        defaults.appendChild(page_layout)
        page_height = self.__doc.createElement('page-height')
        page_height_text = self.__doc.createTextNode('1683.78')
        page_height.appendChild(page_height_text)
        page_layout.appendChild(page_height)

        page_width = self.__doc.createElement('page-width')
        page_width_text = self.__doc.createTextNode('1190.55')
        page_width.appendChild(page_width_text)
        page_layout.appendChild(page_width)

        page_margins = self.__doc.createElement('page-margins')
        page_margins.setAttribute('type', 'even')
        page_layout.appendChild(page_margins)

        left_margin = self.__doc.createElement('left-margin')
        left_margin_text = self.__doc.createTextNode('56.6929')
        left_margin.appendChild(left_margin_text)
        page_margins.appendChild(left_margin)

        right_margin = self.__doc.createElement('right-margin')
        right_margin_text = self.__doc.createTextNode('56.6929')
        right_margin.appendChild(right_margin_text)
        page_margins.appendChild(right_margin)

        top_margin = self.__doc.createElement('top-margin')
        top_margin_text = self.__doc.createTextNode('56.6929')
        top_margin.appendChild(top_margin_text)
        page_margins.appendChild(top_margin)

        bottom_margin = self.__doc.createElement('bottom-margin')
        bottom_margin_text = self.__doc.createTextNode('113.386')
        bottom_margin.appendChild(bottom_margin_text)
        page_margins.appendChild(bottom_margin)

        page_margins_2 = self.__doc.createElement('page-margins')
        page_margins_2.setAttribute('type', 'odd')
        left_margin_2 = self.__doc.createElement('left-margin')
        left_margin_2_text = self.__doc.createTextNode('56.6929')
        left_margin_2.appendChild(left_margin_2_text)
        page_margins_2.appendChild(left_margin_2)
        right_margin_2 = self.__doc.createElement('right-margin')
        right_margin_2_text = self.__doc.createTextNode('56.6929')
        right_margin_2.appendChild(right_margin_2_text)
        page_margins_2.appendChild(right_margin_2)
        top_margin_2 = self.__doc.createElement('top-margin')
        top_margin_2_text = self.__doc.createTextNode('56.6929')
        top_margin_2.appendChild(top_margin_2_text)
        page_margins_2.appendChild(top_margin_2)
        bottom_margin_2 = self.__doc.createElement('bottom-margin')
        bottom_margin_2_text = self.__doc.createTextNode('113.386')
        bottom_margin_2.appendChild(bottom_margin_2_text)
        page_margins_2.appendChild(bottom_margin_2)
        page_layout.appendChild(page_margins_2)

    #Schreiben der part-list in MusicXML
    def write_part_list(self, input_root):
        """Gibt die part-list wieder und ruft hierfür für jeden Part die f_newpart() Funktion auf
          <part-list>
            ...
          </part-list>
          ...

        :param input_root:
        Das root-Element der XML-Datei
        :return:
        """

        part_list = self.__doc.createElement('part-list')
        input_root.appendChild(part_list)

        self.write_newpart(part_list, 'P1')
        #self.write_newpart(part_list, 'P2')

        self.write_part(input_root,
                        self.sheetMusic.sheetMusicClassificationUnits, 'P1')
        #write_part(root, list2, 'P2')

    #Schreiben eines parts innerhalb der part-list in MusicXML
    def write_newpart(self, input_part_list, input_part_id):
        """Erstellt innerhalb des "part-list" Elements einen neuen Part
            <score-part id="P1">
              <part-name>Music</part-name>
            </score-part>

        :param input_part_list:
        Das XML Part-list-Element in das die zu erzeugenden Elemente geschrieben werden sollen.
        :param input_part_id:
        Die ID der Stimme
        :return:
        """

        score_part = self.__doc.createElement('score-part')
        score_part.setAttribute('id', str(input_part_id))
        input_part_list.appendChild(score_part)

        part_name = self.__doc.createElement('part-name')
        part_name_text = self.__doc.createTextNode('Music')
        part_name.appendChild(part_name_text)
        score_part.appendChild(part_name)

    #Schreiben einer Stimme in MusicXML
    def write_part(self, input_root, input_list, input_part_id):
        """Gibt den eigentlichen Part wieder, wobei ein Part eine einzelne "Stimme" ist
        <part id="P1">
        ...
        </part>

        :param input_root:
        Das root-Element der XML-Datei
        :param input_list:
        Die Liste mit den Takten von sheetMusic
        :param input_part_id:
        Die ID der Stimme
        :return:
        """

        part = self.__doc.createElement('part')
        part.setAttribute('id', str(input_part_id))
        counter = 0
        #Startet für jeden Takt die write_measure Funktion
        while (counter < (len(input_list))):
            self.write_measure(part, input_list[counter], counter)
            counter += 1
            input_root.appendChild(part)

    #Schreiben eines Taktes in MusicXML
    def write_measure(self, input_part, input_tact, input_measure_counter):
        """Gibt den jeweiligen Takt wieder
           <measure number="1">
           ...
           </measure>

        :param input_part:
        Das XML Part-Element in das die zu erzeugenden Elemente geschrieben werden sollen.
        :param input_tact:
        Der Takt der in XML geschrieben werden soll.
        :param input_measure_counter:
        Die ID des Taktes
        :return:
        """
        """ """
        measure = self.__doc.createElement('measure')
        measure.setAttribute('number', str(input_measure_counter + 1))
        counter = 0
        #if measure_counter == 0:
        #self.write_clef(measure, list1)
        #Durchläuft die Liste tactElements und startet die jeweilige write Funktion

        ausgabe = 0.0
        while counter < len(input_tact.tactElements):
            if (type(input_tact.tactElements[counter]) == Chord):
                ausgabe += self.write_chord(measure,
                                            input_tact.tactElements[counter])

            elif (type(input_tact.tactElements[counter]) == Clef):
                self.write_clef(measure, input_tact.tactElements[counter])
            elif (type(input_tact.tactElements[counter]) == KeySignatur):
                self.write_key_signatur(measure,
                                        input_tact.tactElements[counter])
            elif (type(input_tact.tactElements[counter]) == TimeSignature):
                self.write_timeSignature(measure,
                                         input_tact.tactElements[counter])

                #schreibt Vergleichstaktlänge zur überprüfung
                self.compare_lenght = input_tact.tactElements[counter].beats * (
                    4 / input_tact.tactElements[counter].beatType)
            elif (type(input_tact.tactElements[counter]) == Rest):
                self.write_rest(measure, input_tact.tactElements[counter])
            counter += 1
            input_part.appendChild(measure)
        #if (input_measure_counter == 0):
        #TODO: bei korrekter erkennung der Taktangabe -1 entfernen
        #self.compare_lenght = (ausgabe-1.0)
        #outputmessage = str("Takt Nr.: ", (input_measure_counter + 1), " ist ", ausgabe, " lang")
        #self.__logger.info("Takt Nr.: " + str(input_measure_counter + 1) + " ist " + str(ausgabe) + " lang", "Output:MusicXML execute")
        #überprüfung der taktlänge mit solltaktlänge
        if ((self.compare_lenght != ausgabe) & (self.compare_lenght != 0.0)):

            if ((self.compare_lenght > ausgabe) & self.__fillwithrests):
                #test_rest = Rest()
                test_rest = input_tact.creatRest(
                    input_measure_counter, (len(input_tact.tactElements) + 1))
                test_rest.duration = (self.compare_lenght - ausgabe)

                #füllen mit pausen bei zu kurzen takten
                self.write_rest(measure, test_rest)
                self.__logger.info(
                    "Takt Nr.: " + str(input_measure_counter + 1) +
                    " hat Abweichung!  (Soll:" + str(self.compare_lenght) +
                    "/Ist:" + str(ausgabe) +
                    ") und wurde mit Pause aufgefüllt",
                    "Output:MusicXML execute")

            else:
                self.__logger.info(
                    "Takt Nr.: " + str(input_measure_counter + 1) +
                    " hat Abweichung!  (Soll:" + str(self.compare_lenght) +
                    "/Ist:" + str(ausgabe), "Output:MusicXML execute")
        #print("Takt Nr.: ", (input_measure_counter+1), " ist ", ausgabe, " Lang")

    #Schreiben eines Schlüssels in MusicXML
    def write_clef(self, input_measure, input_clef):
        """Gibt einen Notenschllüssel
        z.B. Violinschlüssel
             <attributes>
                <clef>
                  <sign>G</sign>
                  <line>2</line>
                </clef>
              </attributes>

        :param input_measure:
        Das XML Element in das geschrieben werden soll
        :param input_clef:
        Das Clef Element, das erzeugt werden soll
        :return:
        """

        attributes = self.__doc.createElement('attributes')
        input_measure.appendChild(attributes)

        #divisions = self.__doc.createElement('divisions')
        #divisions_text = self.__doc.createTextNode('1')
        #divisions.appendChild(divisions_text)
        #attributes.appendChild(divisions)

        clef = self.__doc.createElement('clef')
        attributes.appendChild(clef)

        sign = self.__doc.createElement('sign')
        sign_text = self.__doc.createTextNode(input_clef.sign)
        sign.appendChild(sign_text)
        clef.appendChild(sign)

        line = self.__doc.createElement('line')
        line_text = self.__doc.createTextNode(str(input_clef.line))
        line.appendChild(line_text)
        clef.appendChild(line)

    #Schreiben einer Note in MusicXML
    def write_chord(self, input_measure, input_list):
        """Gibt ein einzelnes Chord-Element wieder, dass in der Regel eine Note enthält
        z.B. ein C in der vierten Oktave mit länge einer Viertel Note
              <note>
                <pitch>
                  <step>C</step>
                  <alter>0.0</alter>
                  <octave>4</octave>
                </pitch>
                <duration>1</duration>
                <type>quarter</type>
              </note>

        :param input_measure:
        Das XML Element in das geschrieben werden soll
        :param input_list:
        Die Liste des Chord-Elements, welches die Note Elemente enthält
        :return:
        """

        min_chord_duration = 0.0
        counter = 0
        #Durchläuft jede Note der Liste des Chord-Elements
        while counter < len(input_list.chordElements):
            note = self.__doc.createElement('note')
            input_measure.appendChild(note)

            if counter >= 1:
                chord = self.__doc.createElement('chord')
                note.appendChild(chord)

            pitch = self.__doc.createElement('pitch')
            note.appendChild(pitch)

            step = self.__doc.createElement('step')
            step_text = self.__doc.createTextNode(
                str(input_list.chordElements[counter].pitch["step"]))
            step.appendChild(step_text)
            pitch.appendChild(step)

            alter = self.__doc.createElement('alter')
            alter_text = self.__doc.createTextNode(
                str(input_list.chordElements[counter].pitch["alter"]))
            alter.appendChild(alter_text)
            pitch.appendChild(alter)

            octave = self.__doc.createElement('octave')
            octave_text = self.__doc.createTextNode(
                str(input_list.chordElements[counter].pitch["octave"]))
            octave.appendChild(octave_text)
            pitch.appendChild(octave)

            temp_float = 0.0
            duration = self.__doc.createElement('duration')

            if (input_list.chordElements[counter].duration == "0.0"):
                # Liest aus .type   -> .duration
                if input_list.chordElements[counter].type == 'quarter':
                    duration_text = self.__doc.createTextNode(str(1.0))
                    temp_float = 1.0
                elif input_list.chordElements[counter].type == 'half':
                    duration_text = self.__doc.createTextNode(str(2.0))
                    temp_float = 2.0
                elif input_list.chordElements[counter].type == 'whole':
                    duration_text = self.__doc.createTextNode(str(4.0))
                    temp_float = 4.0
                elif input_list.chordElements[counter].type == 'eighth':
                    duration_text = self.__doc.createTextNode(str(0.5))
                    temp_float = 0.5
                elif input_list.chordElements[counter].type == '16th':
                    duration_text = self.__doc.createTextNode(str(0.25))
                    temp_float = 0.25
                elif input_list.chordElements[counter].type == '32nd':
                    duration_text = self.__doc.createTextNode(str(0.125))
                    temp_float = 0.125
                elif input_list.chordElements[counter].type == '64th':
                    duration_text = self.__doc.createTextNode(str(0.0625))
                    temp_float = 0.0625
                elif input_list.chordElements[counter].type == '128th':
                    duration_text = self.__doc.createTextNode(str(0.03125))
                    temp_float = 0.03125
            else:
                duration_text = self.__doc.createTextNode(
                    str(input_list.chordElements[counter].duration))
                temp_float = float(input_list.chordElements[counter].duration)

            duration.appendChild(duration_text)
            note.appendChild(duration)

            type = self.__doc.createElement('type')

            if input_list.chordElements[counter].type != "":
                type_text = self.__doc.createTextNode(
                    input_list.chordElements[counter].type)

            # Liest aus .duration   -> .type
            elif input_list.chordElements[counter].duration == 1.0:
                type_text = self.__doc.createTextNode('quarter')
            elif input_list.chordElements[counter].duration == 2.0:
                type_text = self.__doc.createTextNode('half')
            elif input_list.chordElements[counter].duration == 4.0:
                type_text = self.__doc.createTextNode('whole')
            elif input_list.chordElements[counter].duration == 0.5:
                type_text = self.__doc.createTextNode('eighth')
            elif input_list.chordElements[counter].duration == 0.25:
                type_text = self.__doc.createTextNode('16th')
            elif input_list.chordElements[counter].duration == 0.125:
                type_text = self.__doc.createTextNode('32nd')
            elif input_list.chordElements[counter].duration == 0.0625:
                type_text = self.__doc.createTextNode('64th')
            elif input_list.chordElements[counter].duration == 0.03125:
                type_text = self.__doc.createTextNode('128th')

            type.appendChild(type_text)
            note.appendChild(type)

            if ((min_chord_duration == 0.0)
                    or (min_chord_duration >
                        input_list.chordElements[counter].duration)):
                #if (float(input_list.chordElements[counter].duration) == 0.0):
                min_chord_duration = temp_float
            #else:
            #    min_chord_duration = float(input_list.chordElements[counter].duration)

            counter += 1
        return float(min_chord_duration)

    #Schreiben eines KeySignature in MusicXML
    def write_key_signatur(self, input_measure, input_key_signature):
        """ Erzeugt ein KeySignature Element in XML.
            Also die Vorzeichen der jeweiligen Tonart, z.B. fifths = 0  --> C-Dur
           <attributes>
                <key>
                    <fifths>0</fifths>
                </key>
            </attributes>

        :param input_measure:
        Das XML Element in das geschrieben werden soll
        :param input_key_signature:
        Das KeySignature Element von sheetMusic, zu dem ein jeweiliges XML Element erzeugt werden soll
        :return:
        """
        attributes = self.__doc.createElement('attributes')
        input_measure.appendChild(attributes)

        key = self.__doc.createElement('key')
        attributes.appendChild(key)

        fifths = self.__doc.createElement('fifths')
        fifths_text = self.__doc.createTextNode(str(
            input_key_signature.fifths))
        fifths.appendChild(fifths_text)
        key.appendChild(fifths)

    #Schreiben einer TimeSignature in MusicXML
    def write_timeSignature(self, input_measure, input_timesignature):
        """Schreibt das XML TimeSignature Element, welches den Taktart angiebt, z.B. 4/4 Takt mit beats = 4 und beat-type = 4
             <attributes>
                    <time>
                        <beats>4</beats>
                        <beat-type>4</beat-type>
                    </time>
                </attributes>

        :param input_measure:
        Das XML Element in das geschrieben werden soll
        :param input_timesignature:
        Das TimeSignature Element aus sheetMusic, zu dem das jeweilige XML Gegenstück erzeugt werden soll
        :return:
        """
        """"""
        attributes = self.__doc.createElement('attributes')
        input_measure.appendChild(attributes)

        time = self.__doc.createElement('time')
        attributes.appendChild(time)

        beats = self.__doc.createElement('beats')
        beats_text = self.__doc.createTextNode(str(input_timesignature.beats))
        beats.appendChild(beats_text)
        time.appendChild(beats)

        beat_type = self.__doc.createElement('beat-type')
        beat_type_text = self.__doc.createTextNode(
            str(input_timesignature.beatType))
        beat_type.appendChild(beat_type_text)
        time.appendChild(beat_type)

    #Schreiben einer Pause in MusicXML
    def write_rest(self, input_measure, input_rest):
        """Schreibt eine Pause in XML
            <note>
                </rest>
                <duration>2.0</duration>
            </note>

        :param input_measure:
        Das XML Element in das geschrieben werden soll
        :param input_rest:
        Das Rest Element von sheetMusic, zu dem ein XML Element erzeugt werden soll
        :return:
        """
        note = self.__doc.createElement('note')
        input_measure.appendChild(note)

        rest = self.__doc.createElement('rest')
        note.appendChild(rest)

        duration = self.__doc.createElement('duration')
        duration_text = self.__doc.createTextNode(str(input_rest.duration))
        duration.appendChild(duration_text)
        note.appendChild(duration)

        type = self.__doc.createElement('type')
        # Liest aus .duration   -> .type
        if input_rest.duration == 1.0:
            type_text = self.__doc.createTextNode('quarter')
        elif input_rest.duration == 2.0:
            type_text = self.__doc.createTextNode('half')
        elif input_rest.duration == 4.0:
            type_text = self.__doc.createTextNode('whole')
        elif input_rest.duration == 0.5:
            type_text = self.__doc.createTextNode('eighth')
        elif input_rest.duration == 0.25:
            type_text = self.__doc.createTextNode('16th')
        elif input_rest.duration == 0.125:
            type_text = self.__doc.createTextNode('32nd')
        elif input_rest.duration == 0.0625:
            type_text = self.__doc.createTextNode('64th')
        elif input_rest.duration == 0.03125:
            type_text = self.__doc.createTextNode('128th')
        else:
            type_text = self.__doc.createTextNode('half')

        type.appendChild(type_text)
        note.appendChild(type)

################################################################################
#Print Ausgabe

    def print_ausgabe_sheetMusic(self):
        print("\n")
        self.ausgabe_takt_element(
            0, 0, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            0, 1, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            0, 2, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            0, 3, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            1, 0, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            1, 1, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            2, 0, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            2, 1, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            2, 2, self.sheetMusic.sheetMusicClassificationUnits)
        self.ausgabe_takt_element(
            2, 3, self.sheetMusic.sheetMusicClassificationUnits)

    #Print Ausgabe eines Elements eines Taktes
    def ausgabe_takt_element(self, number_takt, number_element, liste):
        print(
            "Ausgabe erstes TaktElement(Chord) : \t", liste[number_takt].
            tactElements[number_element].chordElements[0].pitch["step"])
        #print("Ausgabe erstes TaktElement(Chord) : \t", liste[number_takt].tactElements[number_element].chordElements[0].pitch["octave"])
        print(
            "Ausgabe erstes TaktElement(Chord) : \t", liste[number_takt].
            tactElements[number_element].chordElements[0].duration)
#################################################################################
#Funktionen um TestSheetMusic zu erstellen

    def create_testdata(self):
        # TEST_ERSTELLUNG alle meine Entchen
        self.sheetMusic = SheetMusic()

        # Erster Takt
        test_tact = Tact()

        test_tact.addChord(self.testing_add_Note("C", 4, 1.0, 0.0))
        test_tact.addChord(self.testing_add_Note("D", 4, 1.0, 0.0))
        test_tact.addChord(self.testing_add_Note("E", 4, 1.0, 0.0))
        test_tact.addChord(self.testing_add_Note("F", 4, 1.0, 0.0))
        test_tact.tactNumber = 1
        self.sheetMusic.addTact(test_tact)

        # Zweiter Takt
        test_tact_2 = Tact()
        test_clef = Clef()
        test_tact_2.addClef(test_clef)

        test_keysignatur = KeySignatur()
        test_keysignatur.fifths = 3
        test_tact_2.addKeySignatur(test_keysignatur)

        test_tact_2.addChord(self.testing_add_Note("G", 4, 2.0, 0.0))
        test_tact_2.addChord(self.testing_add_Note("G", 4, 2.0, 0.0))
        test_tact_2.tactNumber = 2
        self.sheetMusic.addTact(test_tact_2)

        # Dritter Takt
        test_tact_3 = Tact()
        test_tact_3.addChord(self.testing_add_Note("A", 4, 1.0, 0.0))
        test_tact_3.addChord(self.testing_add_Note("A", 4, 1.0, 0.0))
        test_tact_3.addChord(self.testing_add_Note("A", 4, 1.0, 0.0))
        test_tact_3.addChord(self.testing_add_Note("A", 4, 1.0, 0.0))
        test_tact_3.tactNumber = 3
        self.sheetMusic.addTact(test_tact_3)

        # Dritter Takt
        test_tact_4 = Tact()
        test_tact_4.addChord(self.testing_add_Note("A", 4, 1.0, 0.0))
        test_tact_4.addChord(
            self.testing_add_chord("A", 4, 1.0, 0.0, "C", 5, 1.0, 0.0))
        test_rest = Rest()
        test_rest.duration = 2
        test_tact_4.addRest(test_rest)
        test_tact_4.tactNumber = 4
        self.sheetMusic.addTact(test_tact_4)

        testliste = []
        testliste.append(test_tact)
        testliste.append(test_tact_2)
        testliste.append(test_tact_3)
        testliste.append(test_tact_4)
        #print(len(testliste))
        #print("testliste ist :", type(testliste))

    #Hinzufügen einer Note zum TestSheetMusic
    def testing_add_Note(self, pitch, octave, duration, semitones):
        """Gibt die entsprechende Note als ein Chord-Element zurück"""
        test_chord = Chord()
        test_note = Note()
        test_note.duration = duration
        test_note.pitch["step"] = pitch
        test_note.pitch["octave"] = octave
        test_note.pitch["alter"] = semitones
        test_chord.addNote(test_note)
        return test_chord

    #Hinzufügen eines Chord-Elements mit zwei Noten zum TestSheetMusic
    def testing_add_chord(self, pitch, octave, duration, semitones, pitch2,
                          octave2, duration2, semitones2):
        """Gibt die entsprechende Note als ein Chord-Element zurück"""
        test_chord = Chord()
        test_note = Note()
        test_note.duration = duration
        test_note.pitch["step"] = pitch
        test_note.pitch["octave"] = octave
        test_note.pitch["alter"] = semitones
        test_chord.addNote(test_note)
        test_note_2 = Note()
        test_note_2.duration = duration2
        test_note_2.pitch["step"] = pitch2
        test_note_2.pitch["octave"] = octave2
        test_note_2.pitch["alter"] = semitones2
        test_chord.addNote(test_note_2)
        return test_chord
예제 #10
0
class HorizontalLineRemoveDetector(IDetector):
    def __init__(self,
                 indexOfProcessMat=0,
                 anchorPoint=(-1, -1),
                 kernelWidth=1,
                 kernelHeight=3,
                 morphOfKernel=cv2.MORPH_RECT,
                 showImagesInWindow=True):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()",
                           "HorizontalLineRemoveDetector:__init__")
        self.__indexOfProcessMat = indexOfProcessMat
        self.__anchorPoint = anchorPoint
        self.__kernelWidth = kernelWidth
        self.__kernelHeight = kernelHeight
        self.__morphOfKernel = morphOfKernel
        self.__logger.info("Starting __init__()",
                           "HorizontalLineRemoveDetector:__init__")
        self.__showImagesInWindow = showImagesInWindow

    def detect(self, mats):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger.info("Starting detect()",
                           "HorizontalLineRemoveDetector:detect")

        # Auswahl der Matrix, die vom Detektor bearbeitet werden soll
        mat = mats[self.__indexOfProcessMat]

        # Erstelle eine Kopie der zu bearbeitenden Matrix
        vertical = mat.copy()
        if (self.__showImagesInWindow):
            cv2.imshow("Input_HorizontalLineRemoveDetector", vertical)
            cv2.waitKey(0)

        # Es wird ein verticaler Kernel erstellt,
        # d. h. viele Zeilen und wenig Spalten
        verticalStructure = cv2.getStructuringElement(
            self.__morphOfKernel, (self.__kernelWidth, self.__kernelHeight))

        # Beim Erodieren wird fuer jede Kernelposition der kleinste Wert zurueckgegeben
        # Auf diese Weise werden Features wie horizontale Linien zerstoert, da eine langer
        # vertikaler Kernel verwendet wird und invertiertes Bild erwartet wird.
        # Es werden also flache Objekte verworfen.
        vertical = cv2.erode(vertical, verticalStructure, self.__anchorPoint)
        self.__logger.info("Vertical_erode:",
                           "HorizontalLineRemoveDetector:detect", vertical)
        if (self.__showImagesInWindow):
            cv2.imshow("Input_HorizontalLineRemoveDetector", vertical)
            cv2.waitKey(0)

        # Beim Delatieren wird fuer jede Kernelposition der groesste Wert zurueckgegeben
        # Auf diese Weise werden die beim Erodieren flach gedrueckte Objekte wieder ausgedeht,
        # da der selbe Kernel verwendet und das selbe invertierte Bild erwartet wird.
        # Es werden also flache Objekte nach unten und oben ausgedeht.
        vertical = cv2.dilate(vertical, verticalStructure, self.__anchorPoint)
        if (self.__showImagesInWindow):
            cv2.imshow("Input_HorizontalLineRemoveDetector", vertical)
            cv2.waitKey(0)
        self.__logger.info("Vertical_dialte:",
                           "HorizontalLineRemoveDetector:detect", vertical)

        # Da der Linienentferner ein invertiertes Bild erwartet,
        # muss dieses nach der Verarbeitung wieder zurueck invertiert werden
        vertical = cv2.bitwise_not(vertical)

        # Ueberschreibe die Urspruengliche Input Matrix
        # mit der Ergebnis Matrix
        mats[self.__indexOfProcessMat] = vertical

        self.__logger.info("Finished detect() with following image:",
                           "HorizontalLineRemoveDetector:detect", vertical)

        return mats
예제 #11
0
class TimeTemplateClassifier(ATempalteMatcher):
    """
    Klasse zur Klassifizierung von Rythmusangaben in einem Takt.
    Erkennt 2/4, 3/4, 4/4, 5/4, 6/4, 3/8, 6/8, 9/8, 12/8.
    """
    def __init__(self, config):
        """
        Konstruktor der BeatTemplateClassifier Klasse.

        Initialisiert alle Membervariablen.

        :param config:          Die Config für diesen TemplateMatcher
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")

        self.__templateFolder = config["templateFolder"]
        self.__templateMethod = config["templateMethod"]
        self.__removeIfFound = config["removeIfFound"]

        self.__timeTemplates = []
        self.__timeTemplates.append(self.__loadTemplate(2, 4))
        self.__timeTemplates.append(self.__loadTemplate(3, 4))
        self.__timeTemplates.append(self.__loadTemplate(4, 4))
        self.__timeTemplates.append(self.__loadTemplate(5, 4))
        self.__timeTemplates.append(self.__loadTemplate(6, 4))
        self.__timeTemplates.append(self.__loadTemplate(3, 8))
        self.__timeTemplates.append(self.__loadTemplate(6, 8))
        self.__timeTemplates.append(self.__loadTemplate(9, 8))
        self.__timeTemplates.append(self.__loadTemplate(12, 8))

        self.__timeRatio = 47 / 97
        self.__timeThreshold = 0.57  # max: 0.70 min: 0.44 mid: 0.57

        for template in self.__timeTemplates:
            self.__logger.info(
                "Loaded Time Signature " + str(template[1]) + "/" +
                str(template[2]) + " Template",
                "TimeTemplateClassifier::__init__", template[0])

    def classify(self, classUnit, matArray):
        """
        Interface Methode: Jeder TempalteMatcher muss diese realisieren.
        Führt die Klassifizierung auf ein Array von Bildmatrizen anhand TemplateMatching aus und gibt die
        erkannten Objekte zurück.

        Parameters
        ----------
        classUnit : Die Klassifikation als Out-Parameter
        matArray : Die Bildmatrizen auf welche die Klassifizierung ausgeführt werden soll.

        Returns
        -------
        [True] wenn Taktangabe erkannt wurde, [False] falls nicht
        """
        maxMatch = -1
        maxLoc = (0, 0)

        for i in range(0, len(self.__timeTemplates)):
            match, loc = self.__hasTime(matArray, self.__timeTemplates[i][0],
                                        self.__timeRatio, self.__timeThreshold)
            if match > classUnit.recognitionPercentage:
                classUnit.recognitionPercentage = match
                classUnit.beats = self.__timeTemplates[i][1]
                classUnit.beatType = self.__timeTemplates[i][2]
                maxMatch = i
                maxLoc = loc

        if maxMatch == -1:
            return False

        self.__logger.info(
            "Time Signature found " + str(classUnit.beats) + "/" +
            str(classUnit.beatType) + " " +
            str(classUnit.recognitionPercentage),
            "TimeTemplateClassifier::classify", matArray[0])

        if self.__removeIfFound:
            self._removeHit(matArray, self.__timeTemplates[maxMatch][0],
                            self.__timeRatio, maxLoc)

        return True

    def __hasTime(self, mats, template, templateMatRatio, threshold):
        """
        Führt den eigentlichen Templatematch aus.

        :param mats:                Takt als Bildmatrix ([0] ohne Linien, [1] mit Linien, [2] nur skaliert).
        :param template:            Template, welches zum Templatematching verwendet wird.
        :param templateMatRatio:    Höhenverhältnis von Template zum Bildausschnitt.
        :param threshold:           Grenzwert, welcher erreicht werden muss, damit das Template als gefunden gilt.
        :return:                    Maximal erreichten Matchwert.

        """
        # Template auf Bildgröße skalieren
        resizedTemplate = ATempalteMatcher._resizeTemplate(
            self, mats[0], template, templateMatRatio)

        if (mats[0].shape[1] >= resizedTemplate.shape[1]):
            # Templatematching mit Bild OHNE Linen
            matchNoLine = cv2.matchTemplate(mats[0], resizedTemplate,
                                            self.__templateMethod)

            # Templatematching mit Bild MIT Linen
            matchLine = cv2.matchTemplate(mats[1], resizedTemplate,
                                          self.__templateMethod)

            # Templatematching mit nur skaliertem Bild
            matchSkal = cv2.matchTemplate(mats[2], resizedTemplate,
                                          self.__templateMethod)

            # Verwende das Maximum von beiden Matches
            match = cv2.max(matchLine, matchNoLine, matchSkal)

            # Hole den maximalen Wert und die zugehörige Position
            __, maxVal, __, maxLoc = cv2.minMaxLoc(match)

            # Wenn Threshold erreicht wurde
            if maxVal >= threshold:
                return maxVal, maxLoc

        return 0, (0, 0)

    def __loadTemplate(self, beat, beatType):
        return [
            cv2.imread(
                self.__templateFolder + "beat_" + str(beat) + "_" +
                str(beatType) + ".jpg", 0), beat, beatType
        ]
예제 #12
0
class Input(IInput):
    def __init__(self, config):
        """
        Konstruktor
        :param config:
        """
        self.__logger = State().getLogger("Input_Component_Logger")
        self.__logger.info("Starting __init__()", "Input:__init__")

        self.__matParser = None
        self.__lableParser = None

        self.__matXMLPairCounter = 0
        self.__matFileNamesForTestDataCreation = 0
        self.__xmlFileNamesForTestDataCreation = 0

        self.__createTraindataPdfDir = config["pathToCreateTrainDataFolder"]
        self.__createTraindataXmlDir = config[
            "pathToCreateTrainDataLabelFolder"]
        self.__traindataDir = config["pathToTrainDataFolder"]
        self.__pathToFileToClassify = config["pathToClassifiactionImage"]
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_basic_1.pdf"
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_basic_10.pdf"
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_basic_15.pdf"
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_basic_rest_9.pdf"
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_middle_5.pdf"
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_middle_7.pdf"
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_elements.pdf"
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_basic_38.pdf"
        # self.__pathToFileToClassify = "./Input_Component\\Input\\clear_basic_41.pdf"

        self.__logger.info("Finished __init__()", "Input:__init__")

    def execute(self):
        """
        Führt den entsprechenden Einlesevorgang über einen Parser durch und erstellt die Bildmatrix.
        :return: mat Die Matrix des eingelesenen Bildes
        """
        self.__logger.info("Starting execute()", "Input:execute")

        filename, file_extension = os.path.splitext(
            self.__pathToFileToClassify)
        if file_extension == ".pdf":
            self.__logger.info("File is detected as PDF.", "Input:execute")
            self.__matParser = PdfToMatParser(self.__pathToFileToClassify)
        else:
            self.__logger.info("File looks like an image-datatype.",
                               "Input:execute")
            self.__matParser = PngToMatParser(self.__pathToFileToClassify)

        mat = self.__matParser.parseToMat()

        self.__logger.info("Readed following Image:", "Input:execute", mat)
        self.__logger.info("Finished execute()", "Input:execute")
        return mat

    def readNextImgXMLPair(self):
        """
        Führt den entsprechenden Einlesevorgang für die nächsten Files im Ordner
        über einen Parser durch und erstellt die Bildmatrix sowie das Lable.
        :return: mat Die Matrix des eingelesenen Bildes.
        :return: lable Das Lable zur Bildmatrix.
        """
        self.__logger.info("Starting readNextImgXMLPair()",
                           "Input:readNextImgXMLPair")

        # Falls es der erste Schritt ist, Filenamen einlesen
        if not self.__matXMLPairCounter:
            self.__matFileNamesForTestDataCreation = glob.glob(
                self.__createTraindataPdfDir + "*.pdf")
            self.__xmlFileNamesForTestDataCreation = glob.glob(
                self.__createTraindataXmlDir + "*.xml")
            self.__logger.info(
                "Found following files to create testdata:" +
                str(self.__matFileNamesForTestDataCreation) +
                str(self.__xmlFileNamesForTestDataCreation),
                "Input:readNextImgXMLPair")

        # Falls es der letzte Schritt ist, Counter zurücksetzen
        if (self.__matXMLPairCounter >= self.__matFileNamesForTestDataCreation.__len__()) \
                or (self.__matXMLPairCounter > self.__xmlFileNamesForTestDataCreation.__len__()):
            self.__logger.debug(
                "Max Filecount reached: reset matXMLPairCounter to 0",
                "Input:readNextImgXMLPair")
            self.__matXMLPairCounter = 0
            return None, None

        # Lese Mat und Lable und erhöhe Counter
        self.__matParser = PdfToMatParser(
            self.__matFileNamesForTestDataCreation[self.__matXMLPairCounter])
        # test with png:
        # self.__matParser = PngToMatParser(self.__pathToFileToClassify)
        self.__lableParser = XmlToLableParser(
            self.__xmlFileNamesForTestDataCreation[self.__matXMLPairCounter])
        mat = self.__matParser.parseToMat()
        lable = self.__lableParser.parseToLable()

        self.__matXMLPairCounter = self.__matXMLPairCounter + 1

        self.__logger.info("Finished readNextImgXMLPair()",
                           "Input:readNextImgXMLPair")
        return mat, lable

    def readNoteTrainData(self):
        """
        Führt den entsprechenden Einlesevorgang für einen Ordner über einen Parser durch und gibt die
        Notentrainingsdaten mit ihrem Label zurück.
        :return: matArray Die MAtrizen des eingelesenen Bildes.
        :return: lableArray Die Lable zu den Bildmatrizen.
        """
        self.__logger.info("Starting readNoteTrainData()",
                           "Input:readNoteTrainData")

        # Reading Filenames from traindata dir
        fileNames = glob.glob(self.__traindataDir + "*.png")

        matArray = []
        lableArray = []

        # For each Testdate Parse Mat and Lable
        for fileName in fileNames:
            # Prepare LableString for Parser
            name = fileName.split("\\")[-1]
            name = name.split(".")[0]
            lableArray = lableArray + FilenameToLableParser(
                name).parseToLable()
            matArray.append(PngToMatParser(fileName).parseToMat())
        self.__logger.info("Finished readNoteTrainData()",
                           "Input:readNoteTrainData")
        return matArray, lableArray
예제 #13
0
class NoteDetector(IDetector):
    def __init__(self,
                 indexOfProcessMat=0,
                 minNoteWidth_WithStem=15,
                 maxNoteWidth_WithStem=8,
                 minNoteHeight_WithStem=30,
                 maxNoteHeight_WithStem=80,
                 minNoteWidth_WithoutStem=8,
                 maxNoteWidth_WithoutStem=30,
                 minNoteHeight_WithoutStem=8,
                 maxNoteHeight_WithoutStem=23,
                 noteImageWidth=20,
                 findCountersMode=cv2.RETR_LIST,
                 findCountersMethode=cv2.CHAIN_APPROX_NONE,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "NoteDetector:__init__")

        self.__indexOfProcessMat = indexOfProcessMat
        self.__minNoteWidth_WithStem = minNoteWidth_WithStem
        self.__maxNoteWidth_WithStem = maxNoteWidth_WithStem
        self.__minNoteHeight_WithStem = minNoteHeight_WithStem
        self.__maxNoteHeight_WithStem = maxNoteHeight_WithStem
        self.__minNoteWidth_WithoutStem = minNoteWidth_WithoutStem
        self.__maxNoteWidth_WithoutStem = maxNoteWidth_WithoutStem
        self.__minNoteHeight_WithoutStem = minNoteHeight_WithoutStem
        self.__maxNoteHeight_WithoutStem = maxNoteHeight_WithoutStem
        self.__noteImageWidth = noteImageWidth
        self.__findCountersMode = findCountersMode
        self.__findCountersMethode = findCountersMethode
        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finsihed __init__()", "NoteDetector:__init__")

    def detect(self, mats):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger.info("Starting detect()", "NoteDetector:detect")

        # Variablen zum Zeichnen
        lineThickness = 1
        rectangleColorGreen = (0, 255, 0)
        rectangleColorRed = (0, 0, 255)

        # Merke die Anzahl von Noten pro Takt
        noteCountPerTact = []

        # Erstelle eine Liste mit i leeren Listen.
        # Jede leere Liste i wird fuer einen Matrix-Typen angelegt
        noteMats = []
        for i in range(0, len(mats)):
            noteMats.append([])

        # Speichern der Liste, die die Takte ohne Notenlinien enthaelt
        matsOfTactsWithoutLines = mats[self.__indexOfProcessMat]

        # Itteriere ueber jeden Takt ohne Notenlinien
        for j in range(0, len(matsOfTactsWithoutLines)):

            # Setz die Notecount für diesen Takt initial auf 0
            noteCountPerTact.append(0)

            # Extrahiere den j-ten Takt
            tactWithoutLines = matsOfTactsWithoutLines[j]

            # Anlegen einer Koordinatenliste, die die x-Koordianten
            # der Noten enthaelt.
            xCoordinates = []

            if (self.__showImagesInWindow):
                cv2.imshow("NoteDetector_Tact", tactWithoutLines)
                cv2.waitKey(0)

            # Abholung der Breite und Höhe einer Notenzeile
            xRight = tactWithoutLines.shape[1]
            yBottom = tactWithoutLines.shape[0]

            # Erstellen einer weißen Zeile
            additionalRow = np.full((1, xRight),
                                    255,
                                    dtype=tactWithoutLines.dtype)

            # Die Methode findContours findet keine Objekte, die sich in der ersten oder/und letzten Zeile
            # oder/und in der ersten oder/und letzten Zeile befinden.
            # Daher werden diese für die findCountours Methode temporäre auf den Wert 255 (weiß) gesetzt.
            tactWithoutLines[0, :] = additionalRow
            tactWithoutLines[yBottom - 1, :] = additionalRow

            # Erodiere horizontal um Loecher in unausgefuellte Noten zu zerstoeren
            tactWithoutLines_erode_dilate = cv2.erode(tactWithoutLines,
                                                      np.ones((1, 9)))
            if (self.__showImagesInWindow):
                cv2.imshow("NoteDetector_Tact", tactWithoutLines_erode_dilate)
                cv2.waitKey(0)

            # Dilatiere auf die urspruengliche Groesse zurueck
            tactWithoutLines_erode_dilate = cv2.dilate(
                tactWithoutLines_erode_dilate, np.ones((1, 9)))
            if (self.__showImagesInWindow):
                cv2.imshow("NoteDetector_Tact", tactWithoutLines_erode_dilate)
                cv2.waitKey(0)

            # Dilatiere vertical um Verbindungen zwischen verbundene Noten zu zerstoeren
            tactWithoutLines_erode_dilate = cv2.dilate(
                tactWithoutLines_erode_dilate, np.ones((9, 1)))
            if (self.__showImagesInWindow):
                cv2.imshow("NoteDetector_Tact", tactWithoutLines_erode_dilate)
                cv2.waitKey(0)

            # Erodiere auf die urstpruengliche Groesse zurueck
            tactWithoutLines_erode_dilate = cv2.erode(
                tactWithoutLines_erode_dilate, np.ones((9, 1)))
            if (self.__showImagesInWindow):
                cv2.imshow("NoteDetector_Tact", tactWithoutLines_erode_dilate)
                cv2.waitKey(0)

            # An dieser Stelle trennen sich manchmal der Notenkopf und der Notenhals voneinander.
            # Mit diesem Erode werden sie wieder zusammengefügt.
            tactWithoutLines_erode_dilate = cv2.erode(
                tactWithoutLines_erode_dilate, np.ones((1, 4)))
            if (self.__showImagesInWindow):
                cv2.imshow("NoteDetector_Tact", tactWithoutLines_erode_dilate)
                cv2.waitKey(0)

            # Finde alle Konturen im Takt
            _, contours, _ = cv2.findContours(
                image=tactWithoutLines_erode_dilate,
                mode=self.__findCountersMode,
                method=self.__findCountersMethode)

            # Erstelle eine Darstellungsbild indem die
            # gefundenen Elemente eingezeichnet werden
            imgShowTact = cv2.cvtColor(tactWithoutLines, cv2.COLOR_GRAY2RGB)

            # Iteriere ueber allen gefundenen Elemente eines Taktes
            for i in range(0, len(contours)):

                # Erstelle aus einem Konturelement ein Rechteck
                # und speichere die benoetigten parameter
                x, y, w, h = cv2.boundingRect(contours[i])

                # Der Rahmen der gefundenen Elemente muss eine Mindesthoehe
                # und eine Minimal- und Mintestbreite besitzen
                if (((self.__minNoteWidth_WithStem < w
                      and w < self.__maxNoteWidth_WithStem) and
                     (self.__minNoteHeight_WithStem < h
                      and h < self.__maxNoteHeight_WithStem))
                        or ((self.__minNoteWidth_WithoutStem < w
                             and w < self.__maxNoteWidth_WithoutStem) and
                            (self.__minNoteHeight_WithoutStem < h
                             and h < self.__maxNoteHeight_WithoutStem))):

                    # Zeichnen der Rechtecke um die gefundenen Noten
                    cv2.rectangle(img=imgShowTact,
                                  pt1=(x, y),
                                  pt2=(x + w, y + h),
                                  color=rectangleColorGreen,
                                  thickness=lineThickness)

                    # Fuege die Rahmen-Koordinaten der gefundenen Noten der Liste hinzu
                    xCoordinates.append([x, x + w])

                    #Erhöhe die Notenanzahl dieses Taktes um eins
                    noteCountPerTact[j] += 1
                else:
                    # Zeichnen der Rechtecke um die restlichen gefundenen Elemente
                    cv2.rectangle(img=imgShowTact,
                                  pt1=(x, y),
                                  pt2=(x + w, y + h),
                                  color=rectangleColorRed,
                                  thickness=lineThickness)

            # Anzeigen der Notenzeilen indem die gefunden Taktstriche
            # gruen und alle anderen Elemente rot umrahmt sind.
            if (self.__showImagesInWindow):
                cv2.imshow("NoteDetector_NoteRow", imgShowTact)
                cv2.waitKey(0)

            # self.__logger.info("Detect following rectangle: ", "NoteDetector:detect", tactWithoutLines)

            # Sortieren der gefundenen Elemente von links nach rechts
            xCoordinates.sort(key=itemgetter(0))

            # Ueberpruefe alle gefundenen Noten auf ihre Mindestbreite
            for i in range(0, len(xCoordinates)):

                # Extrahieren der rechten Koordinate einer gefunden Note
                x0 = xCoordinates[i][0]
                # Extrahieren der linken Koordinate einer gefunden Note
                x1 = xCoordinates[i][1]

                # Berechnung des Zentrums der Note bzgl. x-Koordinate
                center = int((x0 + x1) * 0.5)

                # Berechnung der neuen x-Koordinaten, um die Sollgroesse zu erhalten
                x0 = center - int(self.__noteImageWidth * 0.5)
                x1 = center + int(self.__noteImageWidth * 0.5) + (
                    (self.__noteImageWidth) % 2)

                # Gehe jeden eingegangene Matrix-Typen des j-ten Taktes durch
                for k in range(0, len(mats)):

                    # Extrahiere den j-ten Takt aus der Liste des k-ten Matrix-Typen
                    tact = mats[k][j]

                    # Ueberpruefe ob die linke x-Koordinate
                    # außerhalb des linken Randes ragt
                    if (x0 < 0):

                        # Berechnen der Anzahl der zusaetzlich benoetigten Spalten
                        numberOfAdditionalColumns = abs(x0)

                        # Erstellen einer Kopie der ersten Spalte
                        firstColumn = tact[:, 0]

                        # Erstellen der Spalten die am Anfang hinzugefuegt werden sollen,
                        # indem die erste Spalte des Taktes mehrfach kopiert wird.
                        additionalColumns = np.repeat(
                            firstColumn[:, np.newaxis],
                            repeats=numberOfAdditionalColumns,
                            axis=1)

                        # Setze die zusaetzlichen Spalten vor den Takt
                        tact = np.append(additionalColumns, tact, axis=1)

                        # Erweitere die x-Koordinaten um die Anzahl
                        # der zusaetzlich hinzugefuegten Spalten
                        x0 += numberOfAdditionalColumns
                        x1 += numberOfAdditionalColumns

                    # Extrahiere die Anzahl der Spalten des aktuellen Taktes
                    numberOfColumnsOfTact = tact.shape[1]

                    # Ueberpruefe ob die rechte x-Koordinate
                    # außerhalb des rechten Randes ragt
                    if (numberOfColumnsOfTact < x1):

                        # Berechnen der Anzahl der zusaetzlich benoetigten Spalten
                        numberOfAdditionalColumns = abs(x1 -
                                                        numberOfColumnsOfTact)

                        # Erstellen einer Kopie der letzten Spalte
                        lastColumn = tact[:, numberOfColumnsOfTact - 1]

                        # Erstellen der Spalten die am Ende zusaetzlich hinzugefuegt werden sollen,
                        # indem die letzte Spalte des Taktes mehrfach kopiert wird.
                        additionalColumns = np.repeat(
                            lastColumn[:, np.newaxis],
                            repeats=numberOfAdditionalColumns,
                            axis=1)

                        # Setze die zusaetzlichen Spalten hinter den Takt
                        tact = np.append(tact, additionalColumns, axis=1)

                    # Extrahieren einer Note mit den x-Koordinaten x0 und x1
                    # aus dem j-ten Takt des k-ten Matrix-Typen
                    note = tact[:, x0:x1]

                    # Fuege die Note der k-ten Liste des k-ten Matrix-Typen an
                    noteMats[k].append(note)

                    # Anzeigen der hinzugefuegten Note
                    if (self.__showImagesInWindow):
                        cv2.imshow("NoteDetector_Note", note)
                        cv2.waitKey(0)

        # Abspeichern aller Noten von jedem Matrix-Typ
        for matType in noteMats:
            for note in matType:
                self.__logger.info("Detect following Note: ",
                                   "NoteDetector:detect", note)

        self.__logger.info("Finished detect()", "NoteDetector:detect")

        return noteMats, noteCountPerTact
예제 #14
0
class ClefDetector(IDetector):
    def __init__(self,
                 delimitWidthMax=30,
                 delimitWidthMin=20,
                 delimitHeightMin=20,
                 templateThreshold=0.55,
                 templateMethod=cv2.TM_CCOEFF_NORMED,
                 findCountersMode=cv2.RETR_LIST,
                 findCountersMethode=cv2.CHAIN_APPROX_NONE):
        """
        Konstruktor für den ClefDetector.

        :param delimitWidthMax:     Maximale Breite eines Notenschlüssels.
        :param delimitWidthMin:     Minimale Breite eines Notenschlüssels.
        :param delimitHeightMin:    Minimale Höhe eines Notenschlüssels.
        :param templateThreshold:   Der Wert den das Template-Matching mindestens erreichen muss, damit ein Bildauschnitt als der jeweilige Notenschlüssel erkannt wird
        :param templateMethod:      Methode des Template-Matchers
        :param findCountersMode:    Modus des Konturfindungs-Algorithmus
        :param findCountersMethode: Methode des Konturfindungs-Algorithmus
        """

        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "ClefDetector:__init__")

        self.__delimitWidthMax = delimitWidthMax
        self.__delimitWidthMin = delimitWidthMin
        self.__delimitHeightMin = delimitHeightMin
        self.__templateThreshold = templateThreshold
        self.__templateMethod = templateMethod
        self.__findCountersMode = findCountersMode
        self.__findCountersMethode = findCountersMethode

        self.__logger.info("Finished __init__()", "ClefDetector:__init__")

    def detect(self, matArray):
        """
        Detection Funktion. Geerbt von IDetector.

        :param matArray:        Liste von Bilder, welche die Takte enthalten
        :return:                Liste alles gefundenen Notenschlüssel mit und ohne Notenlinien
        """
        self.__logger.info("Starting detect()", "ClefDetector:detect")

        # Initialierung der Taktlisten:
        # 1. List ohne und die 2. Liste mit Notenlinien
        clefMatsNoLines = []
        clefMatsLines = []

        # Variablen zum Zeichnen
        lineThickness = 1
        rectangleColor = (0, 255, 0)

        for j in range(0, len(matArray[0])):
            mat = matArray[0][j].copy()  # Takt ohne Linien
            matLine = matArray[1][j].copy()

            xCoordinates = []
            xCoordinates.append([0, 0])

            self.__logger.debug("Starting detect Clefs for image",
                                "ClefDetector:detect", mat)

            # Finde alle Konturen im Takt
            _, contours, _ = cv2.findContours(
                image=mat,
                mode=self.__findCountersMode,
                method=self.__findCountersMethode)

            found = False
            for i in range(0, len(contours)):
                # Erstelle aus einem Konturelement ein Rechteck
                # und speichere die benoetigten parameter
                x, y, w, h = cv2.boundingRect(contours[i])

                if (self.__delimitWidthMin <= w and w < self.__delimitWidthMax
                        and h >= self.__delimitHeightMin):
                    found = True

                    # Falls es sich um einen Violinschlüssel handelt, im Bild markieren und koordinaten merken
                    if self.__isViolin(mat[:, x:x + w]):
                        xCoordinates.append([x, x + w])

                        cv2.rectangle(img=mat,
                                      pt1=(x, y),
                                      pt2=(x + w, y + h),
                                      color=rectangleColor,
                                      thickness=lineThickness)

                    # TODO an dieser Stelle die gefundenen prüfen ob vll ein Bassschlüssel

            if found:
                self.__logger.info("Detect following rectangle: ",
                                   "ClefDetector:detect", mat)

            # Sortieren der gefundenen Elemente von links nach rechts
            xCoordinates.sort(key=itemgetter(0))

            # Ueberpruefe alle gefundenen Noten auf ihre Mindestbreite
            for i in range(1, len(xCoordinates)):
                x0 = xCoordinates[i][0]
                x1 = xCoordinates[i][1]
                clefMatsNoLines.append(mat[:, x0:x1])
                clefMatsLines.append(matArray[1][j][:, x0:x1])

        for i in range(0, len(clefMatsNoLines)):
            self.__logger.info("Detected following clef: ",
                               "ClefDetector:detect", clefMatsNoLines[i])

        self.__logger.info("Finished detect()", "ClefDetector:detect")

        return clefMatsNoLines, clefMatsLines

    def __isViolin(self, image):
        """
        Funktion, welche feststellt ob es sich bei einem gegebenen Bildauschnitt um einen Violinschlüssel handelt oder nicht.

        :param image: Bildauschnitt, welcher untersucht wird.
        :return: [True] wenn ein Violinschlüssel, [False] falls nicht.
        """

        # Lade Template als Graustufenbild
        #template = cv2.cvtColor(cv2.imread("DetectionCore_Component/Detector/templates/clef_violin.jpg"), cv2.COLOR_BGR2GRAY)
        template = cv2.imread(
            "DetectionCore_Component/Detector/templates/clef_violin.jpg", 0)

        # Wenn Bild kleiner als Template ist, brich ab mit False
        if image.shape[0] >= template.shape[0] and image.shape[
                1] >= template.shape[1]:
            match = cv2.matchTemplate(image, template, self.__templateMethod)
        else:
            self.__logger.warning("Template to small",
                                  "ClefDetector:__isViolin")
            return False

        # Wenn einer der Werte im Match größer als der vordefinierte Threshold ist, handelt es sich um einen Violinschlüssel
        if (match >= self.__templateThreshold).any():
            return True
        else:
            return False
예제 #15
0
class TactDetector(IDetector):
    def __init__(self,
                 indexOfProcessMat=0,
                 tactLineWidthMax=8,
                 tactLineHeightMin=40,
                 minWidthOfTactLine=10,
                 findCountersMode=cv2.RETR_LIST,
                 findCountersMethode=cv2.CHAIN_APPROX_NONE,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "TactDetector:__init__")

        self.__indexOfProcessMat = indexOfProcessMat
        self.__tactLineWidthMax = tactLineWidthMax
        self.__tactLineHeightMin = tactLineHeightMin
        self.__minWidthOfTactLine = minWidthOfTactLine
        self.__findCountersMode = findCountersMode
        self.__findCountersMethode = findCountersMethode
        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finished __init__()", "TactDetector:__init__")

    def detect(self, mats):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger.info("Starting detect()", "TactDetector:detect")

        # Variablen zum Zeichnen
        lineThickness = 1
        rectangleColorGreen = (0, 255, 0)
        rectangleColorRed = (0, 0, 255)

        # Erstelle eine Liste mit i leeren Listen.
        # Jede leere Liste i wird fuer einen Matrix-Typen angelegt
        tactMats = []
        for i in range(0, len(mats)):
            tactMats.append([])

        # Extrahier die Liste der Notenzeilen,
        # deren Notenlinien entfernt wurde
        matsOfNoteRowsWithoutLines = mats[self.__indexOfProcessMat]

        # Iteriere ueber alle Notenzeilen
        for j in range(0, len(matsOfNoteRowsWithoutLines)):

            # Extrahiere die j-te Notenzeile
            matNoteRow = matsOfNoteRowsWithoutLines[j]

            # Anlegen einer Koordinatenliste, die die x-Koordianten
            # der Taktstriche enthaelt.
            xCoordinates = []

            # Fuege die erste Pixelspalte des Bildes der Notenzeile
            # zu den Koordinaten hinzu, um den Anfang als ersten Takt erkennen zu koennen,
            # da der Zeilenanfang of keinen Taktstrich enthaelt
            xCoordinates.append([0, 0])

            # Verbreitern der Elemente in der Notenzeile
            anchorPoint = (-1, -1)
            kernelWidth = 3
            kernelHeight = 1
            morphOfKernel = cv2.MORPH_RECT
            verticalStructure = cv2.getStructuringElement(
                morphOfKernel, (kernelWidth, kernelHeight))
            matNoteRow_eroded = cv2.erode(matNoteRow, verticalStructure,
                                          anchorPoint)

            # Anzeigen des Notenblattes indem die gefunden Notenzeilen
            # und Notenlinien farblich markiert sind.
            if (self.__showImagesInWindow):
                cv2.imshow("TactDetector_NoteRow", matNoteRow_eroded)
                cv2.waitKey(0)

            # Finde alle Konturen in der Notenzeile
            _, contours, _ = cv2.findContours(
                image=matNoteRow_eroded,
                mode=self.__findCountersMode,
                method=self.__findCountersMethode)

            # Erstelle eine Darstellungsbild indem die
            # gefundenen Elemente eingezeichnet werden
            imgShowNoteRow = cv2.cvtColor(matNoteRow, cv2.COLOR_GRAY2RGB)

            # Iteriere ueber alle gefundenen Elemente der Notenzeile
            for i in range(0, len(contours)):

                # Erstelle aus einem Konturelement ein Rechteck
                # und speichere die benoetigten parameter
                x, y, w, h = cv2.boundingRect(points=contours[i])

                # Der Rahmen der gefundenen Elemente muss eine Maximalbreite
                # und eine Mindesthoehe besitzen um als Takt klassifiziert zu werden
                if (w < self.__tactLineWidthMax) and (self.__tactLineHeightMin
                                                      < h):

                    # Zeichnen der Rechtecke um die gefundenen Taktstriche
                    cv2.rectangle(img=imgShowNoteRow,
                                  pt1=(x, y),
                                  pt2=(x + w, y + h),
                                  color=rectangleColorGreen,
                                  thickness=lineThickness)

                    # Fuege die Rahmen-Koordinaten der gefundenen Taktstriche zu der Liste hinzu
                    xCoordinates.append([x, x + w])

                else:
                    # Zeichnen der Rechtecke um die restlichen gefundenen Elemente
                    cv2.rectangle(img=imgShowNoteRow,
                                  pt1=(x, y),
                                  pt2=(x + w, y + h),
                                  color=rectangleColorRed,
                                  thickness=lineThickness)

            # Fuege die letzte Pixelspalte des Bildes der Notenzeile
            # zu den Koordinaten hinzu, um das Ende als letzten Takt erkennen zu koennen,
            # da das Zeilenende of keinen Taktstrich enthaelt
            xCoordinates.append([matNoteRow.shape[1], matNoteRow.shape[1]])

            # Anzeigen der Notenzeilen indem die gefunden Taktstriche
            # gruen und alle anderen Elemente rot umrahmt sind.
            if (self.__showImagesInWindow):
                cv2.imshow("TactDetector_NoteRow", imgShowNoteRow)
                cv2.waitKey(0)

            # Sortieren der gefundenen Elemente von links nach rechts
            xCoordinates.sort(key=itemgetter(0))

            # Ueberpruefe alle gefundenen Takte auf ihre Mindestbreite mit Hilfe der Koordinaten
            # Iteriere hierzu ueber die Koordinaten
            for i in range(0, len(xCoordinates) - 1):

                # Extrahieren der rechten Koordinate eines gefunden Taktstriches
                x0 = xCoordinates[i][1]

                # Extrahieren der linken Koordinate des darauffolgenden Taktstriches
                x1 = xCoordinates[i + 1][0]

                # Der Inhalt zwischen den Koordinatn x0 und x1 ist ein Tak
                newMatWithoutLines = matNoteRow[:, x0:x1]

                # Finde alle Konturen in der Notenzeile
                _, contours, _ = cv2.findContours(
                    image=newMatWithoutLines,
                    mode=self.__findCountersMode,
                    method=self.__findCountersMethode)

                # Speichern der Anzahl der Elemente
                numberOfElementsInTact = len(contours)

                # Falls der gefundene Takt breit genug ist und mindestens zwei Elemente besitzt,
                # dann ist es ein Takt. Der gesamte Takt an sich ist auch ein Element,
                # daher muss der Takt mindestens zwei Elemente besitzen.
                if (self.__minWidthOfTactLine <
                        x1 - x0) and (2 <= numberOfElementsInTact):

                    for k in range(0, len(mats)):
                        # Gehe jeden eingegangene Matrix-Typen der j-ten Zeile durch
                        # Extrahieren eines Taktes mit den x-Koordinaten x0 und x1
                        # aus j-ten Notenzeile des k-ten Matrix-Typen
                        tact = mats[k][j][:, x0:x1]

                        # Fuege den Takt der k-ten Liste des k-ten Matrix-Typen an
                        tactMats[k].append(tact)

                        # Anzeigen des hinzugefuegten Taktes
                        if (self.__showImagesInWindow):
                            cv2.imshow("TactDetector_Tact", tact)
                            cv2.waitKey(0)

        # Abspeichern aller Takte von jedem Matrix-Typ
        for matType in tactMats:
            for tact in matType:
                self.__logger.info("Detecting Tact:", "TactDetector:detect",
                                   tact)

        self.__logger.info("Finished detect()", "TactDetector:detect")

        return tactMats
예제 #16
0
class ObjectCentering:
    def __init__(self,
                 indexOfProcessMat=0,
                 targetNumberOfRows=110,
                 targetNumberOfColumns=32,
                 useDeletingVerticalSpaces=True,
                 useDeletingHorizontalSpaces=True,
                 findCountersMode=cv2.RETR_LIST,
                 findCountersMethode=cv2.CHAIN_APPROX_NONE,
                 colorOfBorder=0,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "ObjectCentering:__init__")

        self.__indexOfProcessMat = indexOfProcessMat
        self.__targetNumberOfRows = targetNumberOfRows
        self.__targetNumberOfColumns = targetNumberOfColumns
        self.__useDeletingVerticalSpaces = useDeletingVerticalSpaces
        self.__useDeletingHorizontalSpaces = useDeletingHorizontalSpaces
        self.__findCountersMode = findCountersMode
        self.__findCountersMethode = findCountersMethode
        self.__colorOfBorder = colorOfBorder
        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finsihed __init__()", "ObjectCentering:__init__")

    def coreProcess(self, mats):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger.info("Starting coreProcess()",
                           "ObjectCentering:coreProcess")

        # Variablen zum Zeichnen
        lineThickness = 1
        rectangleColorGreen = (0, 255, 0)
        rectangleColorRed = (0, 0, 255)

        # Erstelle eine Liste mit i leeren Listen.
        # Jede leere Liste i wird fuer einen Matrix-Typen angelegt
        newMats = []
        for i in range(0, len(mats)):
            newMats.append([])

        # Speichern der Liste, die die Objekte ohne Notenlinien enthaelt
        matsOfObjectsWithoutLines = mats[self.__indexOfProcessMat]

        # Iteriere ueber jeden Matrix-Typen
        for i in range(0, len(matsOfObjectsWithoutLines)):

            # Extrahiere die i-te Objekt-Matrix
            matObject = matsOfObjectsWithoutLines[i]

            # Abholung der Breite und Höhe einer Notenzeile
            xRight = matObject.shape[1]
            yBottom = matObject.shape[0]

            # Erstellen einer weißen Spalte
            additionalColumn = np.full((yBottom), 255, dtype=matObject.dtype)

            # Die Methode findContours findet keine Objekte, die sich in der ersten oder/und letzten Zeile
            # oder/und in der ersten oder/und letzten Zeile befinden.
            # Daher werden diese für die findCountours Methode temporäre auf den Wert 255 (weiß) gesetzt.
            matObject[:, 0] = additionalColumn
            matObject[:, xRight - 1] = additionalColumn

            # Finde alle Konturen (Elemente) in der Objekt-Matrix
            _, contours, _ = cv2.findContours(
                image=matObject,
                mode=self.__findCountersMode,
                method=self.__findCountersMethode)

            # Erstelle eine Darstellungsbild indem die
            # gefundenen Elemente eingezeichnet werden
            imgShowObject = cv2.cvtColor(matObject, cv2.COLOR_GRAY2RGB)

            # Finde das kleinste Rechteck, welches alle Elemente binhaltet.
            # Hierzu werden die Minimalwerte zu Beginn mit den hoechst moeglichen
            # Werten initialisiert und umbekehrt.
            minX = matObject.shape[1]
            minY = matObject.shape[0]
            maxX = 0
            maxY = 0

            # Entferne das letzte Element.
            # Das letzte Element ist die Kontur, welche das gesamte Feld einschliesst.
            contours.pop()

            # Iteriere ueber alle gefundenen Elemente des Matrix-Objektes
            for j in range(0, len(contours)):

                # Erstelle aus einem Konturelement ein Rechteck
                # und speichere die benoetigten Parameter
                xLeft, yTop, w, h = cv2.boundingRect(points=contours[j])
                xRight = xLeft + w
                yBottom = yTop + h

                # Zeichnen der Rechtecke um die gefundenen Elemente
                cv2.rectangle(img=imgShowObject,
                              pt1=(xLeft, yTop),
                              pt2=(xRight, yBottom),
                              color=rectangleColorRed,
                              thickness=lineThickness)

                # Ueberpruefe, ob das aktuelle Rechteck, das gefundene Element beinhaltet,
                # wenn nicht, dann passe die Koordinaten des alles umschließenden Rechtecks an.
                if xLeft < minX:
                    minX = xLeft

                if yTop < minY:
                    minY = yTop

                if maxX < xRight:
                    maxX = xRight

                if maxY < yBottom:
                    maxY = yBottom

            # Zeichnen des kleinst moeglichen Rechtecks,
            # welches alle gefundenen Elemente beinhaltet.
            cv2.rectangle(img=imgShowObject,
                          pt1=(minX, minY),
                          pt2=(maxX, maxY),
                          color=rectangleColorGreen,
                          thickness=lineThickness)

            # Anzeigen des Bildes in dem die gefundenen
            # Rechtecke eingezeichnet werden.
            if (self.__showImagesInWindow):
                cv2.imshow("ObjectCentering_FoundedContours", imgShowObject)
                cv2.waitKey(0)

            # Initialisiere die Werte der zu herausnehmenden Teilmatrix auf die gesamte Bildgroesse.
            xLeft = 0
            xRight = matObject.shape[1]
            yTop = 0
            yBottom = matObject.shape[0]

            # Falls ueber und unter den gefundenen Elementen die urspruenglichen Bildzeilen
            # zerstoert werden sollen, muessen die y-Koordinaten der zu herausnehmenden Teilmatrix
            # auf die y-Werte des Rahmens gesetzt werden.
            if (self.__useDeletingVerticalSpaces):
                yTop = minY
                yBottom = maxY

            # Falls neben den gefundenen Elementen die urspruenglichen Bildspalten
            # zerstoert werden sollen, muessen die x-Koordinaten der zu herausnehmenden Teilmatrix
            # auf die x-Werte des Rahmens gesetzt werden.
            if (self.__useDeletingHorizontalSpaces):
                xLeft = minX
                xRight = maxX

            # Schneide aus allen Eingangslisten, welche jeweils einen anderen Bildtypen enthaelt
            # die Teilmatrix mit den gefundenen Objekten aus und fuege sie in eine neue groessen-normierte Matrix ein.
            # Itteriere hierzu ueber alle Listen.
            for k in range(0, len(mats)):

                # Erstelle eine neue leere Matrix, in der die neue Matrix eingefuegt werden soll.
                newMatObject = np.full(
                    (self.__targetNumberOfRows, self.__targetNumberOfColumns),
                    fill_value=self.__colorOfBorder,
                    dtype=matObject.dtype)

                # Schneide aus der urspruenglichen Matrix, die Teilmatrix aus,
                # die alle enthaltenen Objekte enthaelt.
                newCroppedMatObject = mats[k][i][yTop:yBottom, xLeft:xRight]

                # Anzeige der ausgeschnittenen Teilmatrix
                if (self.__showImagesInWindow):
                    cv2.imshow("ObjectCentering_CropedMatrix",
                               newCroppedMatObject)
                    cv2.waitKey(0)

                # Speichern der Zeilen- und Spaltenzahl der Teilmatrix
                # und der Matrix in der diese eingefuegt werden soll.
                shapeCroppedMatObject_rows = newCroppedMatObject.shape[0]
                shapeCroppedMatObject_columns = newCroppedMatObject.shape[1]
                shapeNewMatObject_rows = newMatObject.shape[0]
                shapeNewMatObject_columns = newMatObject.shape[1]

                # Berechnung der Koordinaten in der die Teilmatrix in die neue Matrix eingefuegt werden soll.
                xLeft_insertion = int((shapeNewMatObject_columns / 2) -
                                      (shapeCroppedMatObject_columns / 2))
                xRight_insertion = int((shapeNewMatObject_columns / 2) +
                                       (shapeCroppedMatObject_columns / 2))
                yTop_insertion = int((shapeNewMatObject_rows / 2) -
                                     (shapeCroppedMatObject_rows / 2))
                yBottom_insertion = int((shapeNewMatObject_rows / 2) +
                                        (shapeCroppedMatObject_rows / 2))

                # Fuege die Teilmatrix in die Mitte der neuen Matrix hinzu,
                # um fuer alle Matrizen die selbe Groesse zu erhalten.
                newMatObject[
                    yTop_insertion:yBottom_insertion,
                    xLeft_insertion:xRight_insertion] = newCroppedMatObject

                # Fuege die Matrix der k-ten Liste hinzu
                newMats[k].append(newMatObject)

                # Anzeige der Ergebnismatrix mit der normierten Groesse
                if (self.__showImagesInWindow):
                    cv2.imshow("ObjectCentering_ResultMatrix", newMatObject)
                    cv2.waitKey(0)

        # Abspeichern aller Objekte von jedem Matrix-Typ
        for matType in newMats:
            for object in matType:
                self.__logger.info("Centered/Resized following Object: ",
                                   "ObjectCentering:coreProcess", object)

        self.__logger.info("Finished coreProcess()",
                           "ObjectCentering:coreProcess")

        return mats
예제 #17
0
class ImageResizer:
    def __init__(self,
                 targetNumberOfRows=110,
                 targetNumberOfColumns=32,
                 interpolation=cv2.INTER_LINEAR,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "ImageResizer:__init__")

        self.__targetNumberOfRows = targetNumberOfRows
        self.__targetNumberOfColumns = targetNumberOfColumns
        self.__interpolation = interpolation
        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finsihed __init__()", "ImageResizer:__init__")

    def coreProcess(self, mats):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger.info("Starting coreProcess()",
                           "ImageResizer:coreProcess")

        # Erstelle eine Liste mit i leeren Listen.
        # Jede leere Liste i wird fuer einen Matrix-Typen angelegt
        newMats = []
        for i in range(0, len(mats)):
            newMats.append([])

        # Iteriere ueber jeden Matrix-Typen
        for i in range(0, len(mats)):

            # Iteriere ueber jedes Objekt der Matrix-Typen-Liste
            for matObject in mats[i]:

                # Skaliere das Mat-Objekt mit der angegeben Interpolations-Methode
                newMatObject = cv2.resize(src=matObject,
                                          dsize=(self.__targetNumberOfColumns,
                                                 self.__targetNumberOfRows),
                                          interpolation=self.__interpolation)

                # Fuege die Matrix der
                newMats[i].append(newMatObject)

                # Anzeigen des Mat-Objektes dem Zeilen bzw. Spalten
                # abgezogen bzw. hinzugefuegt wurden.
                if (self.__showImagesInWindow):
                    cv2.imshow(
                        "ImageFiller_Object: " + str(newMatObject.shape),
                        newMatObject)
                    cv2.waitKey(0)

        # Abspeichern aller Noten von jedem Matrix-Typ
        for matType in newMats:
            for note in matType:
                self.__logger.info(
                    "Resized following Object to:  " + str(note.shape),
                    "ImageResizer:coreProcess", note)

        self.__logger.info("Finished coreProcess()",
                           "ImageResizer:coreProcess")

        return newMats
class NoteHeightBlobClassifier(IClassifier):
    def __init__(self,
                 indexOfProcessMatWithoutLines=0,
                 indexOfProcessMatWithLines=1,
                 maxGradeOfLinesInPx=2,
                 marginTop=0.5,
                 marginBottom=0.5,
                 cannyThreshold1=50,
                 cannyThreshold2=150,
                 cannyApertureSize=3,
                 houghLinesRho=1,
                 houghLinesTheta=np.pi / 180,
                 houghLinesThreshold=5,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()",
                           "NoteHeightBlobClassifier:__init__")

        self.__indexOfProcessMatWithoutLines = indexOfProcessMatWithoutLines
        self.__indexOfProcessMatWithLines = indexOfProcessMatWithLines
        self.__firstLineHeight = 0
        self.__stepHeight = 0
        self.__maxGradeOfLinesInPx = maxGradeOfLinesInPx
        self.__marginTop = marginTop
        self.__marginBottom = marginBottom
        self.__cannyThreshold1 = cannyThreshold1
        self.__cannyThreshold2 = cannyThreshold2
        self.__cannyApertureSize = cannyApertureSize
        self.__houghLinesRho = houghLinesRho
        self.__houghLinesTheta = houghLinesTheta
        self.__houghLinesThreshold = houghLinesThreshold
        self.__showImagesInWindow = showImagesInWindow

        self.__logger.info("Finsihed __init__()",
                           "NoteHeightBlobClassifier:__init__")

    def classify(self, matArray):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger.info("Starting classify()",
                           "NoteHeightBlobClassifier:classify")

        # Iterate about every note
        for i in range(0, len(matArray[self.__indexOfProcessMatWithoutLines])):

            imageWithLines = matArray[self.__indexOfProcessMatWithLines][i]

            cv2.imshow("Mit Linien", imageWithLines)

            # Apply edge detector canny
            edges = cv2.Canny(imageWithLines,
                              threshold1=self.__cannyThreshold1,
                              threshold2=self.__cannyThreshold2,
                              apertureSize=self.__cannyApertureSize)

            # Apply hough line detection
            lines = cv2.HoughLines(edges,
                                   rho=self.__houghLinesRho,
                                   theta=self.__houghLinesTheta,
                                   threshold=self.__houghLinesThreshold)

            # Extract array of hough line coordinates
            lines_coordinates = []
            for x in range(0, len(lines)):
                for rho, theta in lines[x]:

                    # Calculation of line coordinates
                    a = np.cos(theta)
                    b = np.sin(theta)
                    y0 = b * rho
                    y1 = int(y0 + 1000 * (a))
                    y2 = int(y0 - 1000 * (a))

                    # Extract horizontal lines
                    if (abs(y1 - y2) <= self.__maxGradeOfLinesInPx):
                        lines_coordinates.append([y1, y2])

                        print([y1, y2])

            # Sort coordinates of hough line
            lines_coordinates.sort(key=itemgetter(0))

            #
            yPositionFirsLine = (
                ((lines_coordinates[0][0] + lines_coordinates[0][1]) / 2) +
                ((lines_coordinates[1][0] + lines_coordinates[1][1]) / 2)) / 2
            yPositionLastLine = (
                ((lines_coordinates[len(lines_coordinates) - 1][0] +
                  lines_coordinates[len(lines_coordinates) - 1][1]) / 2) +
                ((lines_coordinates[len(lines_coordinates) - 2][0] +
                  lines_coordinates[len(lines_coordinates) - 2][1]) / 2)) / 2

            # Berechne die Anzahl der Pixel von einer Notenhoehe zur naechsten Notenhoehe
            numberOfLines = 5
            noteStep = (yPositionFirsLine +
                        yPositionLastLine) / (numberOfLines - 1) / 2

            # Draw hough lines to image
            showMat = cv2.cvtColor(
                src=matArray[self.__indexOfProcessMatWithoutLines][i],
                code=cv2.COLOR_GRAY2BGR)

            # Create array for mats and line groups
            noteLineCoordinates = []
            line_groupe = []
            lineThickness = 1
            lineColor = (0, 255, 0)

            for j in range(0, len(lines_coordinates) - 1):
                """
                Get line coordinates of line
                """
                line = lines_coordinates[j]
                """
                Draw line
                """
                cv2.line(showMat, (0, line[0]),
                         (showMat.shape[1] - 1, line[1]), lineColor,
                         lineThickness)

            # Read image
            imageWithoutLines = matArray[
                self.__indexOfProcessMatWithoutLines][i]
            imageWithoutLines = 255 - imageWithoutLines
            #cv2.waitKey(0)
            cv2.imshow("Test1", imageWithoutLines)
            #cv2.waitKey(0)
            imageWithoutLines = 255 - cv2.dilate(
                imageWithoutLines, np.ones((1, 10)), iterations=1)
            cv2.imshow("Test2", imageWithoutLines)
            imageWithoutLines = cv2.dilate(imageWithoutLines,
                                           np.ones((1, 16)),
                                           iterations=1)
            cv2.imshow("Test3", imageWithoutLines)
            cv2.waitKey(0)

            # Setup SimpleBlobDetector parameters.
            params = cv2.SimpleBlobDetector_Params()

            # Change thresholds
            # params.minThreshold = 0
            # params.maxThreshold = 255

            # Filter by Area.
            params.filterByArea = True
            params.minArea = 20
            # params.maxArea = 500000

            # Filter by Color
            # params.filterByColor = True
            # params.blobColor = 0

            # Filter by Circularity
            # params.filterByCircularity = False
            # params.minCircularity = 0.0

            # Filter by Convexity
            params.filterByConvexity = False
            # params.minConvexity = 0.87

            # Filter by Inertia
            # params.filterByInertia = False
            # params.minInertiaRatio = 0.01

            # Create a detector with the parameters
            detector = cv2.SimpleBlobDetector_create(params)

            # Detect blobs.
            keypoints = detector.detect(imageWithoutLines)

            if (not (len(keypoints) < 1)):

                # Draw detected blobs as red circles.
                # cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS ensures
                # the size of the circle corresponds to the size of blob

                im_with_keypoints = cv2.drawKeypoints(
                    imageWithoutLines, keypoints, np.array([]), (0, 0, 255),
                    cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

                print("Row", imageWithoutLines.shape[0])
                print("Column", imageWithoutLines.shape[1])
                for point in keypoints:
                    print("x=", point.pt[0], "y=", point.pt[1])
                    cv2.circle(showMat, (int(point.pt[0]), int(point.pt[1])),
                               1, (0, 255, 255), 3)

                difference = yPositionFirsLine - keypoints[0].pt[1]

                note_nr = round(difference / noteStep * 2, 0)

                txt = ""
                if (note_nr == 0):
                    txt = "f''" + str(note_nr)
                elif (note_nr == -1):
                    txt = "e''" + str(note_nr)
                elif (note_nr == -2):
                    txt = "d''" + str(note_nr)
                elif (note_nr == -3):
                    txt = "c''" + str(note_nr)
                elif (note_nr == -4):
                    txt = "h'" + str(note_nr)
                elif (note_nr == -5):
                    txt = "a'" + str(note_nr)
                elif (note_nr == -6):
                    txt = "g'" + str(note_nr)
                elif (note_nr == -7):
                    txt = "f'" + str(note_nr)
                elif (note_nr == -8):
                    txt = "e'" + str(note_nr)
                elif (note_nr == -9):
                    txt = "d'" + str(note_nr)
                else:
                    txt = "-" + str(note_nr)

                #cv2.addText(showMat, str(note_nr), (5, 5), font, 4, (243, 127, 53), 2, cv2.LINE_AA)
                cv2.putText(showMat, txt, (0, 75), cv2.FONT_HERSHEY_SIMPLEX,
                            0.35, 255)

                # Show blobs
                cv2.imshow("Keypoints", im_with_keypoints)
                cv2.imshow("ShowMat", showMat)
                cv2.waitKey(0)
예제 #19
0
class KeyDetector(IDetector):
    def __init__(self,
                 templateThreshold=0.75,
                 templateMethod=cv2.TM_CCOEFF_NORMED,
                 findCountersMode=cv2.RETR_LIST,
                 findCountersMethode=cv2.CHAIN_APPROX_NONE):
        """
        Konstruktor für den KeyDetector.

        :param templateThreshold:   Der Wert den das Template-Matching mindestens erreichen muss, damit ein Bildauschnitt als der jeweilige Key erkannt wird
        :param templateMethod:      Methode des Template-Matchers
        :param findCountersMode:    Modus des Konturfindungs-Algorithmus
        :param findCountersMethode: Methode des Konturfindungs-Algorithmus
        """

        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "KeyDetector:__init__")

        self.__templateThreshold = templateThreshold
        self.__templateMethod = templateMethod
        self.__findCountersMode = findCountersMode
        self.__findCountersMethode = findCountersMethode

        self.__logger.info("Finished __init__()", "KeyDetector:__init__")

    def detect(self, matArray):
        """
        Detection Funktion. Geerbt von IDetector.

        :param matArray:        Liste von Bilder, welche die Takte enthalten
        :return:                Liste alles gefundenen Keys mit und ohne Notenlinien
        """
        self.__logger.info("Starting detect()", "KeyDetector:detect")

        # Initialierung der Taktlisten:
        # 1. List ohne und die 2. Liste mit Notenlinien
        clefMatsNoLines = []
        clefMatsLines = []

        # Variablen zum Zeichnen
        lineThickness = 1
        rectangleColor = (0, 255, 0)

        for j in range(0, len(matArray[0])):
            mat = matArray[0][j].copy()  # Takt ohne Linien
            matLine = matArray[1][j].copy()  # Takt mit Linien

            self.__logger.debug("Starting detect Keys for image",
                                "KeyDetector:detect", mat)

            found = False
            template = cv2.imread(
                "DetectionCore_Component/Detector/templates/key_b.jpg", 0)
            w, h = template.shape[::-1]

            res = cv2.matchTemplate(mat, template, cv2.TM_CCOEFF_NORMED)
            loc = np.where(res >= self.__templateThreshold)

            for pt in zip(*loc[::-1]):
                found = True
                cv2.rectangle(mat, pt, (pt[0] + w, pt[1] + h), rectangleColor,
                              lineThickness)
                cv2.rectangle(matLine, pt, (pt[0] + w, pt[1] + h),
                              rectangleColor, lineThickness)
                clefMatsNoLines.append(mat[:, pt[0]:pt[0] + w])
                clefMatsLines.append(matLine[:, pt[0]:pt[0] + w])

            if found:
                self.__logger.info("Detect following rectangle: ",
                                   "KeyDetector:detect", mat)

        for i in range(0, len(clefMatsNoLines)):
            self.__logger.info("Detected following clef: ",
                               "KeyDetector:detect", clefMatsNoLines[i])

        self.__logger.info("Finished detect()", "KeyDetector:detect")

        return clefMatsNoLines, clefMatsLines
예제 #20
0
class ClefTemplateClassifier(ATempalteMatcher):
    """
    Klasse zur Klassifizierung von Notenschlüsseln in einem Takt.
    Erkennt Violin-, Bass- und Altschlüssel.

    Höhe der Schlüssel wird nicht erkannt!!!!!
    """
    def __init__(self, config):
        """
        Konstruktor der ClefTemplateClassifier Klasse.

        Initialisiert alle Membervariablen.

        :param config:          Die Config für diesen TemplateMatcher
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")

        self.__templateFolder = config["templateFolder"]
        self.__templateMethod = config["templateMethod"]
        self.__removeIfFound = config["removeIfFound"]

        self.__clefTemplates = []
        self.__clefRatios = []
        self.__clefThresholds = []

        # Violin
        self.__clefTemplates.append(self.__loadTemplate("G", 2))
        self.__clefRatios.append(83 / 97)
        self.__clefThresholds.append(0.52)  # max: 0.77  min: 0.27  mid: 0.52

        # Bass
        self.__clefTemplates.append(self.__loadTemplate("F", 4))
        self.__clefRatios.append(36 / 97)
        self.__clefThresholds.append(0.64)  # max: 0.76  min: 0.52  mid: 0.64

        # Alt
        self.__clefTemplates.append(self.__loadTemplate("C", 3))
        self.__clefRatios.append(50 / 97)
        self.__clefThresholds.append(0.535)  # max: 0.58  min: 0.49  mid: 0.535

        for template in self.__clefTemplates:
            self.__logger.info(
                "Loaded Clef " + template[1] + str(template[2]) + " Template",
                "ClefTemplateClassifier::__init__", template[0])

    def classify(self, classUnit, matArray):
        """
        Interface Methode: Jeder TempalteMatcher muss diese realisieren.
        Führt die Klassifizierung auf ein Array von Bildmatrizen anhand TemplateMatching aus und gibt die
        erkannten Objekte zurück.

        Parameters
        ----------
        classUnit : Die Klassifikation als Out-Parameter
        matArray : Die Bildmatrizen auf welche die Klassifizierung ausgeführt werden soll.

        Returns
        -------
        [True] wenn Notenschlüssel erkannt wurde, [False] falls nicht
        """
        maxMatch = -1
        maxLoc = (0, 0)

        for i in range(0, len(self.__clefTemplates)):
            match, loc = self.__hasClef(matArray, self.__clefTemplates[i][0],
                                        self.__clefRatios[i],
                                        self.__clefThresholds[i])
            if match > classUnit.recognitionPercentage:
                classUnit.recognitionPercentage = match
                classUnit.sign = self.__clefTemplates[i][1]
                classUnit.line = self.__clefTemplates[i][2]
                maxMatch = i
                maxLoc = loc

        if maxMatch == -1:
            return False

        self.__logger.info(
            "Clef found " + classUnit.sign + str(classUnit.line) + " " +
            str(classUnit.recognitionPercentage),
            "ClefTemplateClassifier::classify", matArray[0])

        if self.__removeIfFound:
            self._removeHit(matArray, self.__clefTemplates[maxMatch][0],
                            self.__clefRatios[maxMatch], maxLoc)

        return True

    def __hasClef(self, mats, template, templateMatRatio, threshold):
        """
        Führt den eigentlichen Templatematch aus.

        :param mats:                Takt als Bildmatrix ([0] ohne Linien, [1] mit Linien, [2] nur skaliert).
        :param template:            Template, welches zum Templatematching verwendet wird.
        :param templateMatRatio:    Höhenverhältnis von Template zum Bildausschnitt.
        :param threshold:           Grenzwert, welcher erreicht werden muss, damit das Template als gefunden gilt.
        :return:                    [True] wenn Threshold erreicht, [False] wenn nicht.
        """
        # Template auf Bildgröße skalieren
        resizedTemplate = ATempalteMatcher._resizeTemplate(
            self, mats[0], template, templateMatRatio)

        if (mats[0].shape[1] >= resizedTemplate.shape[1]):
            # Templatematching mit Bild OHNE Linen
            matchNoLine = cv2.matchTemplate(mats[0], resizedTemplate,
                                            self.__templateMethod)

            # Templatematching mit Bild MIT Linen
            matchLine = cv2.matchTemplate(mats[1], resizedTemplate,
                                          self.__templateMethod)

            # Templatematching mit nur skaliertem Bild
            matchSkal = cv2.matchTemplate(mats[2], resizedTemplate,
                                          self.__templateMethod)

            # Verwende das Maximum von allen Matches
            match = cv2.max(matchLine, matchNoLine, matchSkal)

            # Hole den maximalen Wert und die zugehörige Position
            __, maxVal, __, maxLoc = cv2.minMaxLoc(match)

            # Wenn Threshold erreicht wurde
            if maxVal >= threshold:
                return maxVal, maxLoc

        return 0, (0, 0)

    def __loadTemplate(self, sign, line):
        return [
            cv2.imread(
                self.__templateFolder + "clef_" + sign + "_" + str(line) +
                ".jpg", 0), sign, line
        ]
예제 #21
0
class CnnNoteClassifier(IClassifier):
    def __init__(self,
                 modelDir,
                 gdLearnRateForTypeModel,
                 gdLearnRateForHightModel,
                 trainSteps,
                 evalInterval,
                 evalDataSize,
                 testDataSize,
                 trainTypeModel=True,
                 trainHightModel=True):
        """
        Constructor, initialisiert Membervariablen.

        :param modelDir : string Pfad unter welchem die trainierten CnnModelle gespeichert werden.
        :example:
            CnnNoteClassifier("my/path/to/a/model/Dir")
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__noteTypeCnn = CnnModelSuit(
            cnnNotetypeModel, predictionToNotetypeClassificationFn,
            modelDir + "/noteTypeModel", gdLearnRateForTypeModel)
        self.__noteHightCnn = CnnModelSuit(
            cnnNoteHightModel, predictionToNoteHightClassificationFn,
            modelDir + "/noteHightModel", gdLearnRateForHightModel)

        self.__gdLearnRateForTypeModel = gdLearnRateForTypeModel
        self.__gdLearnRateForHightModel = gdLearnRateForHightModel

        self.__trainSteps = trainSteps
        self.__evalInterval = evalInterval

        self.__evalDataSize = evalDataSize
        self.__testDataSize = testDataSize

        self.__trainTypeModel = trainTypeModel
        self.__trainHightModel = trainHightModel

    def classify(self, inputDataWithLines, inputDataWithoutLines):
        """
        Bereitet die Inputdaten für das neuronale Netz vor und klassifiziert mit diesem den Input zu einer Note.

        :param inputDataWithLines : Eine Mat welche ein Bild einer Note mit Linien enthält.
        :param inputDataWithoutLines : Eine Mat welche ein Bild einer Note ohne Linien enthält.
        :return: note : Note() Die Klassifizierung einer Musiknote.
        :example:
            cnnNoteClassifier.classify(myInputDataWithLines, myInputDataWithoutLines)
        """

        #Converting the Input
        cnnNoteTypeInput = []
        cnnNoteHightInput = []
        for i in range(0, len(inputDataWithLines)):
            cnnNoteTypeInput.append(inputDataWithoutLines[i].ravel())
            cnnNoteHightInput.append(inputDataWithLines[i].ravel())

        cnnNoteTypeInput, _ = self.convDataForNet(cnnNoteTypeInput)
        cnnNoteHightInput, _ = self.convDataForNet(cnnNoteHightInput)

        #Classify the Input
        noteTypes = self.__noteTypeCnn.classify(cnnNoteTypeInput)
        noteSteps, noteOctaves = self.__noteHightCnn.classify(
            cnnNoteHightInput)

        #Converting the Classification into internal representation
        notens = []
        for i in range(0, len(noteTypes)):
            # One of i ClassinifcationUnit to classify
            note = Note()
            note.type = noteTypes[i]
            note.pitch["step"] = noteSteps[i]
            note.pitch["octave"] = noteOctaves[i]
            notens.append(note)
            self.__logger.info(
                "Classified following notetype: " + str(note.type) +
                " step: " + str(note.pitch["step"]) + " octave: " +
                str(note.pitch["octave"]), "CnnNoteClassifier:classify",
                inputDataWithLines[i])
            #cv2.imshow(note.type, inputDataWithLines[i])
            #cv2.waitKey()

        return notens

    def train(self, inputTrainData, inputTrainLabels):
        """
        Bereitet die Inputdaten für das neuronale Netz vor und trainiert dieses mit den Daten.
        Führt alle n Schritte eine Evaluation auf dem Netz durch.

        :param inputTrainData : Eine Array von Mat welche ein Bild einer Note mit und daneben eins ohne Linien enthält.
        :param inputTrainLabels : Eine Array von Labels für die Bilder von inputTrainData (Gleiche Länge gleiche Sortierung)
        :example:
            cnnNoteClassifier.train(myInputTrainData, myInputTrainaLables)
        """

        self.__logger.info("Starting train()", "CnnNoteClassifier:train")

        #Inputs for the Cnns to train
        noteTypeTrainData = []
        noteTypeTrainLable = []
        noteHightTrainData = []
        noteHightTrainLable = []

        #Converting the Input
        for i in range(0, len(inputTrainData)):
            noteTypeTrainData.append(inputTrainData[i][0:96, 28:57].ravel())
            noteHightTrainData.append(inputTrainData[i][0:96, 0:28].ravel())
            noteTypeTrainLable.append(
                noteTypeToInt(inputTrainLabels[i]["type"]))
            noteHightTrainLable.append(
                noteHightToInt(inputTrainLabels[i]["step"],
                               inputTrainLabels[i]["octave"]))

        noteTypeTrainData, noteTypeTrainLable = self.convDataForNet(
            noteTypeTrainData, noteTypeTrainLable)
        noteHightTrainData, noteHightTrainLable = self.convDataForNet(
            noteHightTrainData, noteHightTrainLable)

        #Shuffel the Input via Permutation. This is an inital shuffel neeedet to split the data into train, eval, test
        #The Train Shuffel will be made after each step in the train Methode of CnnModelSuit
        p = np.random.permutation(len(noteTypeTrainData))
        noteTypeTrainData = noteTypeTrainData[p]
        noteTypeTrainLable = noteTypeTrainLable[p]
        noteHightTrainData = noteHightTrainData[p]
        noteHightTrainLable = noteHightTrainLable[p]

        #Training the model
        noTrainDataSize = self.__evalDataSize + self.__testDataSize

        if self.__trainTypeModel:
            #Train the model for NoteType
            for i in range(0, self.__trainSteps, self.__evalInterval):
                self.__noteTypeCnn.train(
                    noteTypeTrainData[0:-noTrainDataSize],
                    noteTypeTrainLable[0:-noTrainDataSize],
                    self.__evalInterval)
                self.__noteTypeCnn.eval(
                    noteTypeTrainData[-noTrainDataSize:-self.__testDataSize],
                    noteTypeTrainLable[-noTrainDataSize:-self.__testDataSize])
            #Testing the model
            self.__noteTypeCnn.eval(noteTypeTrainData[-self.__testDataSize:],
                                    noteTypeTrainLable[-self.__testDataSize:])

        if self.__trainHightModel:
            #Train the model for NoteHight
            for i in range(0, self.__trainSteps, self.__evalInterval):
                self.__noteHightCnn.train(
                    noteHightTrainData[0:-noTrainDataSize],
                    noteHightTrainLable[0:-noTrainDataSize],
                    self.__evalInterval)
                self.__noteHightCnn.eval(
                    noteHightTrainData[-noTrainDataSize:-self.__testDataSize],
                    noteHightTrainLable[-noTrainDataSize:-self.__testDataSize])
            #Testing the model
            self.__noteHightCnn.eval(
                noteHightTrainData[-self.__testDataSize:],
                noteHightTrainLable[-self.__testDataSize:])

        self.__logger.info("Finished train()", "CnnNoteClassifier:train")

    def convDataForNet(self, inputData, lables=None):
        """
        Convertiert die Inputdaten und Lables für das neuronale Netz.

        :param inputData : Eine Array von Mats welche ein Bild einer Note enthält.
        :param lables : Eine Array von Labels für die Bilder von inputData (Gleiche Länge gleiche Sortierung)
        :example:
            cnnNoteClassifier.convDataForNet(myInpuData, mLables)
        """
        #Converting the Input into one Image - each row represents a note
        inputData = np.row_stack(inputData)
        inputData = inputData.astype(np.float32)
        inputData = inputData / 255

        if lables:
            lables = np.array(lables)
            # print(lables)
            # print(type(lables))
            # print(lables.shape)
        # print(inputData)
        # print(type(inputData))
        # print(inputData.shape)
        return inputData, lables
예제 #22
0
class SheetMusicTemplateClassifier(IFullClassifier):
    def __init__(self, config):
        """
        Constructor, initialisiert Membervariablen.

        :param config:          Die Config für den SheetMusicClassifier
        """

        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()",
                           "SheetMusicTemplateClassifier:__init__")
        self.__config = config

        lineRemoveConfig = self.__config["HorizontalLineRemoveDetector"]
        self.__horizontalLineRemoveDetector = HorizontalLineRemoveDetector \
            (indexOfProcessMat=lineRemoveConfig["indexOfProcessMat"],
             anchorPoint=(lineRemoveConfig["anchorPointX"], lineRemoveConfig["anchorPointY"]),
             kernelWidth=lineRemoveConfig["kernelWidth"],
             kernelHeight=lineRemoveConfig["kernelHeight"],
             morphOfKernel=getattr(cv2, lineRemoveConfig["morphOfKernel"]),
             showImagesInWindow=lineRemoveConfig["showImagesInWindow"])

        lineDetectorConfig = self.__config["NoteLineDetector"]
        self.__noteLineDetector = NoteLineDetector \
            (indexOfProcessMat=lineDetectorConfig["indexOfProcessMat"],
             maxGradeOfLinesInPx=lineDetectorConfig["maxGradeOfLinesInPx"],
             minDistanceToNextNoteRow=lineDetectorConfig["minDistanceToNextNoteRow"],
             marginTop=lineDetectorConfig["marginTop"],
             marginBottom=lineDetectorConfig["marginBottom"],
             cannyThreshold1=lineDetectorConfig["cannyThreshold1"],
             cannyThreshold2=lineDetectorConfig["cannyThreshold2"],
             cannyApertureSize=lineDetectorConfig["cannyApertureSize"],
             houghLinesRho=lineDetectorConfig["houghLinesRho"],
             houghLinesTheta=np.pi / 180 * lineDetectorConfig["houghLinesThetaInDegree"],
             houghLinesThreshold=lineDetectorConfig["houghLinesThreshold"],
             showImagesInWindow=lineDetectorConfig["showImagesInWindow"])

        tactDetectorConfig = self.__config["TactDetector"]
        self.__tactDetector = TactDetector \
            (indexOfProcessMat=tactDetectorConfig["indexOfProcessMat"],
             tactLineWidthMax=tactDetectorConfig["tactLineWidthMax"],
             tactLineHeightMin=tactDetectorConfig["tactLineHeightMin"],
             minWidthOfTactLine=tactDetectorConfig["minWidthOfTactLine"],
             findCountersMode=getattr(cv2, tactDetectorConfig["findCountersMode"]),
             findCountersMethode=getattr(cv2, tactDetectorConfig["findCountersMethode"]),
             showImagesInWindow=tactDetectorConfig["showImagesInWindow"])

        self.__clefClassifier = ClefTemplateClassifier(
            self.__config["ClefTemplateClassifier"])

        self.__timeClassifier = TimeTemplateClassifier(
            self.__config["TimeTemplateClassifier"])

        self.__keyClassifier = KeyTemplateClassifier(
            self.__config["KeyTemplateClassifier"])

        noteDetectorConfig = self.__config["NoteDetector"]
        self.__noteDetector = NoteDetector \
            (indexOfProcessMat=noteDetectorConfig["indexOfProcessMat"],
             minNoteWidth_WithStem=noteDetectorConfig["minNoteWidth_WithStem"],
             maxNoteWidth_WithStem=noteDetectorConfig["maxNoteWidth_WithStem"],
             minNoteHeight_WithStem=noteDetectorConfig["minNoteHeight_WithStem"],
             maxNoteHeight_WithStem=noteDetectorConfig["maxNoteHeight_WithStem"],
             minNoteWidth_WithoutStem=noteDetectorConfig["minNoteWidth_WithoutStem"],
             maxNoteWidth_WithoutStem=noteDetectorConfig["maxNoteWidth_WithoutStem"],
             minNoteHeight_WithoutStem=noteDetectorConfig["minNoteHeight_WithoutStem"],
             maxNoteHeight_WithoutStem=noteDetectorConfig["maxNoteHeight_WithoutStem"],
             noteImageWidth=noteDetectorConfig["noteImageWidth"],
             findCountersMode=getattr(cv2, noteDetectorConfig["findCountersMode"]),
             findCountersMethode=getattr(cv2, noteDetectorConfig["findCountersMethode"]),
             showImagesInWindow=noteDetectorConfig["showImagesInWindow"])

        # NoteHeightBlobClassifier wird nicht mehr benoetigt, da die
        # Notenhoehe von einem CNN klassifiziert wird.
        """
        noteDetectorConfig = self.__config["NoteDetector"]
        self.__noteHeightBlobClassifier = NoteHeightBlobClassifier \
            (indexOfProcessMatWithoutLines=noteDetectorConfig["indexOfProcessMatWithoutLines"],
             indexOfProcessMatWithLines=noteDetectorConfig["indexOfProcessMatWithLines"],
             maxGradeOfLinesInPx=noteDetectorConfig["maxGradeOfLinesInPx"],
             marginTop=noteDetectorConfig["marginTop"],
             marginBottom=noteDetectorConfig["marginBottom"],
             cannyThreshold1=noteDetectorConfig["cannyThreshold1"],
             cannyThreshold2=noteDetectorConfig["cannyThreshold2"],
             cannyApertureSize=noteDetectorConfig["cannyApertureSize"],
             houghLinesRho=noteDetectorConfig["houghLinesRho"],
             houghLinesTheta=np.pi / 180 * noteDetectorConfig["houghLinesThetaInDegree"],
             houghLinesThreshold=noteDetectorConfig["houghLinesThreshold"],
             showImagesInWindow=noteDetectorConfig["showImagesInWindow"])
        """

        fillerConfig = self.__config["ImageFiller"]
        self.__imageFiller = ImageFiller \
            (fillRows=fillerConfig["fillRows"],
             fillColumns=fillerConfig["fillColumns"],
             targetNumberOfRows=fillerConfig["targetNumberOfRows"],
             targetNumberOfColumns=fillerConfig["targetNumberOfColumns"],
             appendRowsTop=fillerConfig["appendRowsTop"],
             appendColumnsRight=fillerConfig["appendColumnsRight"],
             showImagesInWindow=fillerConfig["showImagesInWindow"])

        centeringConfig = self.__config["ObjectCentering"]
        self.__objectCentering = ObjectCentering \
            (indexOfProcessMat=centeringConfig["indexOfProcessMat"],
             targetNumberOfRows=centeringConfig["targetNumberOfRows"],
             targetNumberOfColumns=centeringConfig["targetNumberOfColumns"],
             useDeletingVerticalSpaces=centeringConfig["useDeletingVerticalSpaces"],
             useDeletingHorizontalSpaces=centeringConfig["useDeletingHorizontalSpaces"],
             findCountersMode=getattr(cv2, centeringConfig["findCountersMode"]),
             findCountersMethode=getattr(cv2, centeringConfig["findCountersMethode"]),
             colorOfBorder=centeringConfig["colorOfBorder"],
             showImagesInWindow=centeringConfig["showImagesInWindow"])

        resizerConfig = self.__config["ImageResizer"]
        self.__imageResizerForCnn = ImageResizer \
            (targetNumberOfRows=resizerConfig["targetNumberOfRows"],
             targetNumberOfColumns=resizerConfig["targetNumberOfColumns"],
             interpolation=getattr(cv2, resizerConfig["interpolation"]),
             showImagesInWindow=resizerConfig["showImagesInWindow"])

        dirname, _ = os.path.split(os.path.abspath(__file__))
        cnnConfig = self.__config["CnnNoteClassifier"]
        self.__cnnNoteClassifier = CnnNoteClassifier \
            (modelDir=dirname + cnnConfig["modelDir"],
             gdLearnRateForTypeModel=cnnConfig["gdLearnRateForTypeModel"],
             gdLearnRateForHightModel=cnnConfig["gdLearnRateForHightModel"],
             trainSteps=cnnConfig["trainSteps"],
             evalInterval=cnnConfig["evalInterval"],
             evalDataSize=cnnConfig["evalDataSize"],
             testDataSize=cnnConfig["testDataSize"],
             trainTypeModel = cnnConfig["trainTypeModel"],
             trainHightModel = cnnConfig["trainHightModel"])

        self.__logger.info("Finished __init__()",
                           "SheetMusicTemplateClassifier:__init__")

    def executeClassification(self, mat):
        """
        Führt die Klassifizierung auf einer Bildmatrix aus und gibt die erkannte IClassification zurück.

        Parameters
        ----------
        mat : Die Bildmatrix auf welche die Klassifizierung ausgeführt werden soll.

        Returns
        -------
        classification : IClassification
        Aus dem Eingabematrix erkannte IClassification (z.B. Note, Slur, Rest).

        Example
        -------
        >>> sheetMusicTemplateClassifier.executeClassification(mat)
        """
        self.__logger.info(
            "Starting executeClassification()",
            "SheetMusicTemplateClassifier:executeClassification")
        classification = SheetMusic()

        noteLinesWithoutHLines = self.__horizontalLineRemoveDetector.detect(
            mat)
        noteLines = self.__noteLineDetector.detect(noteLinesWithoutHLines)
        tacts = self.__tactDetector.detect(noteLines)

        # --- Takt Klassifikation ---
        elementCounter = 1
        lastClefLine = 0
        lastClefSign = ""

        # Führt für jeden erkannten Takt aus
        for i in range(0, len(tacts[0])):
            # self.__logger.debug("Analyzing Tact", image = tacts[0][i])

            tactInternalCounter = 1
            tactClassification = classification.creatTact(
                i + 1, elementCounter)  # Neuer Takt
            elementCounter += 1

            # ----- Clef -----
            clefClassification = tactClassification.creatClef(
                tactInternalCounter, elementCounter)

            if self.__clefClassifier.classify(
                    clefClassification,
                [tacts[0][i], tacts[1][i], tacts[2][i]]):
                if (clefClassification.sign != lastClefSign
                        or clefClassification.line != lastClefLine):
                    tactClassification.addClef(
                        clefClassification
                    )  # Füge Notenschlüssel zu Takt hinzu
                    elementCounter += 1
                    tactInternalCounter += 1
                    lastClefSign = clefClassification.sign
                    lastClefLine = clefClassification.line

            # ----- KeySignature -----
            keyClassification = tactClassification.creatKeySignature(
                tactInternalCounter, elementCounter)

            if self.__keyClassifier.classify(
                    keyClassification,
                [tacts[0][i], tacts[1][i], tacts[2][i]]):
                tactClassification.addKeySignatur(
                    keyClassification)  # Füge Tonhöheangabe zu Takt hinzu
                elementCounter += 1
                tactInternalCounter += 1

            # ----- Time -----
            timeClassification = tactClassification.creatTimeSignature(
                tactInternalCounter, elementCounter)

            if self.__timeClassifier.classify(
                    timeClassification,
                [tacts[0][i], tacts[1][i], tacts[2][i]]):
                tactClassification.addTimeSignatur(
                    timeClassification)  # Füge Rythmus zu Takt hinzu
                elementCounter += 1
                tactInternalCounter += 1

            classification.addTact(
                tactClassification)  # Füge Takt zur Klassifikation hinzu
        # --- Takt Klassifikation ---

        notes, noteCountPerTact = self.__noteDetector.detect(tacts)
        self.__logger.debug(
            "Return from noteDetector 0",
            "SheetMusicTemplateClassifier::executeClassification",
            notes[0][0])  # Ohne Linien
        self.__logger.debug(
            "Return from noteDetector 1",
            "SheetMusicTemplateClassifier::executeClassification",
            notes[1][0])  # Mit Linien

        filledNotes = self.__imageFiller.coreProcess(notes)
        centeredNotes = self.__objectCentering.coreProcess(filledNotes)
        cnnNotes = self.__imageResizerForCnn.coreProcess(centeredNotes)

        # notesHeight = self.__noteHeightBlobClassifier.classify(notes)
        # self.__logger.debug("Return from noteHeightBlobClassifier 0", "SheetMusicTemplateClassifier::executeClassification", notesHeight[0][0]) # Ohne Linien
        # self.__logger.debug("Return from noteHeightBlobClassifier 1", "SheetMusicTemplateClassifier::executeClassification", notesHeight[1][0]) # Mit Linien

        # ----- Classify Notes -----

        notes = self.__cnnNoteClassifier.classify(cnnNotes[0], cnnNotes[1])

        # Fülle die Takte mit den erkannten Noten und nutze zur Vermeidung von Fehlerfortpflanzung noteCountPerTact
        noteIndex = 0
        for t in range(0, len(noteCountPerTact)):
            for n in range(0, noteCountPerTact[t]):
                chord = classification.tacts[t].creatChord(
                    classification.tacts[t].tactNumber, n)
                note = chord.creatNote(classification.tacts[t].tactNumber, n,
                                       chord.chordInternalNumber)
                note.pitch = notes[noteIndex].pitch
                note.type = notes[noteIndex].type
                chord.addNote(note)
                classification.tacts[t].addChord(chord)
                noteIndex += 1
                self.__logger.debug(
                    ("Tact " + str(t) + " added Note on pos " + str(n) +
                     " type: " + note.type + " pitch: " + str(note.pitch)),
                    "SheetMusicTemplateClassifier:executeClassification")

        self.__logger.info(
            "Finished executeClassification()",
            "SheetMusicTemplateClassifier:executeClassification")
        return classification

    def buildTraindata(self, mat):
        """
        Interface Methode: Jeder FullClassifier muss diese realisieren.
        Erstellt Trainingdaten für das Trainieren seiner Classifier

        :param Bildmatrix : mat Die Bildmatrix aus welcher die Trainingdaten erstellt werden soll.
        :return: trainData : matArray Aus dem Eingabematrix erstellte Trainingdaten.
        """
        self.__logger.info("Starting buildTraindata()",
                           "SheetMusicTemplateClassifier:buildTraindata")

        noteLinesWithoutHLines = self.__horizontalLineRemoveDetector.detect(
            mat)
        noteLines = self.__noteLineDetector.detect(noteLinesWithoutHLines)
        tacts = self.__tactDetector.detect(noteLines)
        notes, _ = self.__noteDetector.detect(tacts)

        self.__logger.debug("Return from noteDetector 0",
                            "SheetMusicTemplateClassifier::buildTraindata",
                            notes[0][0])  # Ohne Linien
        self.__logger.debug("Return from noteDetector 1",
                            "SheetMusicTemplateClassifier::buildTraindata",
                            notes[1][0])  # Mit Linien

        filledNotes = self.__imageFiller.coreProcess(notes)
        centeredNotes = self.__objectCentering.coreProcess(filledNotes)
        cnnNotes = self.__imageResizerForCnn.coreProcess(centeredNotes)

        self.__logger.info("Finished executeClassification()",
                           "SheetMusicTemplateClassifier:buildTraindata")
        return cnnNotes

    def train(self, inputMatArray, lableArray):
        """
        Trainiert alle trainierbaren Classifier mit den gegebenen Trainingsdaten

        :param Bildmatrizen: inputMatArray Die Bildmatrizen für das Training.
        :param Lable: lableArray Die Lable zu den Bildmatrizen für das Training.
        :return: successful : boolean War das Training erfolgreich?
        """
        self.__logger.info("Started train()",
                           "SheetMusicTemplateClassifier:train")

        self.__cnnNoteClassifier.train(inputMatArray, lableArray)

        self.__logger.info("Finished train()",
                           "SheetMusicTemplateClassifier:train")
예제 #23
0
class CnnModelSuit:
    def __init__(self,
                 cnnModelFn,
                 preditcionToClassificationFn,
                 modelDir="/tmp/cnn_model",
                 learnRate=0.001):
        """
        Constructor, initialisiert Membervariablen.

        :param cnnModelFn : function Ein CnnModel mit den Methoden train, predict, evaluate.
        :param predictedClassesToClassificationFn : function Eine Funktion um die Klassifizierung der cnnModelFn zu interpretieren,
        :param modelDir : string Pfad unter welchem das trainierte CnnModel gespeichert wird.
        :example:
            CnnModelSuit(cnnNotetypeModel, predictedClassesToNotetypeClassificationFn, "my/path/to/a/model/Dir")
        """
        # Set model params
        modelParams = {"learning_rate": learnRate}

        #Setting up the Loggers
        tf.logging.set_verbosity(tf.logging.INFO)
        self.__logger = State().getLogger("DetectionCore_Component_Logger")

        #The Function to interprete the Classification Vector
        self.preditcionToClassificationFn = preditcionToClassificationFn

        #The Cnn to be trained and to classify the inputs
        self.__cnnClassifier = tf.estimator.Estimator(model_fn=cnnModelFn,
                                                      model_dir=modelDir,
                                                      params=modelParams)

        # Set up logging for predictions
        # Log the values in the "Softmax" tensor with label "probabilities"
        self.__tensorsToLog = {"probabilities": "softmax_tensor"}
        self.__loggingHook = tf.train.LoggingTensorHook(
            tensors=self.__tensorsToLog, every_n_iter=50)

    def classify(self, inputData):
        """
        Bereitet die Inputdaten für das neuronale Netz vor und klassifiziert mit diesem den Input.

        :param inputData : Eine Mat welche den zu klassifizierenden Input enthält.
        :return: predictedClass : Die Klassifizierung welche durch die predictedClassesToClassificationFn bestimmt wird.
        :example:
            cnnModelSuit.classify(myInputData)
        """
        self.__logger.info("Starting classify()", "CnnModelSuit:classify")

        #Classify Input with the trained model
        predictInputFn = tf.estimator.inputs.numpy_input_fn(x={"x": inputData},
                                                            num_epochs=1,
                                                            shuffle=False)

        predictions = list(
            self.__cnnClassifier.predict(input_fn=predictInputFn))

        self.__logger.info("Finished classify()", "CnnModelSuit:classify")

        return self.preditcionToClassificationFn(predictions)

    def train(self, trainData, trainLabels, steps):
        """
        Bereitet die Inputdaten für das neuronale Netz vor und trainiert dieses mit den Daten.

        :param trainData : Eine Array von Mats welche traineirt werden sollen.
        :param trainLabels : Eine Array von Labels für die Mats von trainData (Gleiche Länge gleiche Sortierung)
        :param steps : Anzahl der Trainingsschritte
        :example:
            cnnNoteClassifier.train(myTrainData, myInputTrainLables)
        """
        self.__logger.info("Starting train()", "CnnModelSuit:train")

        #Train the model
        trainInputFn = tf.estimator.inputs.numpy_input_fn(x={"x": trainData},
                                                          y=trainLabels,
                                                          batch_size=100,
                                                          num_epochs=None,
                                                          shuffle=True)

        self.__cnnClassifier.train(input_fn=trainInputFn,
                                   steps=steps,
                                   hooks=[self.__loggingHook])

        self.__logger.info("Finished train()", "CnnModelSuit:train")

    def eval(self, evalData, evalLabels):
        """
        Bereitet die Inputdaten für das neuronale Netz vor und evaluiert dieses mit den Daten.

        :param evalData : Eine Array von Mats mit welchen evaluiert werden sollen.
        :param evalLabels : Eine Array von Labels für die Mats von evalData (Gleiche Länge gleiche Sortierung)
        :example:
            cnnNoteClassifier.eval(myEvalData, myEvalLabels)
        """
        self.__logger.info("Starting eval()", "CnnModelSuit:eval")

        #Evaluate the model and print results
        evalInputFn = tf.estimator.inputs.numpy_input_fn(x={"x": evalData},
                                                         y=evalLabels,
                                                         num_epochs=1,
                                                         shuffle=False)
        evalResults = self.__cnnClassifier.evaluate(input_fn=evalInputFn)

        self.__logger.info("Finished eval()", "CnnModelSuit:eval")
예제 #24
0
class NoteLineDetector(IDetector):
    def __init__(self,
                 indexOfProcessMat=0,
                 maxGradeOfLinesInPx=2,
                 minDistanceToNextNoteRow=20,
                 marginTop=0.5,
                 marginBottom=0.5,
                 cannyThreshold1=50,
                 cannyThreshold2=150,
                 cannyApertureSize=3,
                 houghLinesRho=1,
                 houghLinesTheta=np.pi / 180,
                 houghLinesThreshold=200,
                 showImagesInWindow=False):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "NoteLineDetector:__init__")
        self.__indexOfProcessMat = indexOfProcessMat
        self.__maxGradeOfLinesInPx = maxGradeOfLinesInPx
        self.__minDistanceToNextNoteRow = minDistanceToNextNoteRow
        self.__marginTop = marginTop
        self.__marginBottom = marginBottom
        self.__cannyThreshold1 = cannyThreshold1
        self.__cannyThreshold2 = cannyThreshold2
        self.__cannyApertureSize = cannyApertureSize
        self.__houghLinesRho = houghLinesRho
        self.__houghLinesTheta = houghLinesTheta
        self.__houghLinesThreshold = houghLinesThreshold
        self.__showImagesInWindow = showImagesInWindow
        self.__logger.info("Finished __init__()", "NoteLineDetector:__init__")

    def detect(self, mats):
        """
        To-Do:
        Bitte Kommentar bzw. Dokumentaion erstellen!
        """
        self.__logger.info("Starting detect()", "NoteLineDetector:detect")
        mat = mats[self.__indexOfProcessMat]

        # Anwendung des Canny Filters um als Kantendetektor,
        # um über den HoughLines Detektor Kanten zu detektieren
        edges = cv2.Canny(mat,
                          threshold1=self.__cannyThreshold1,
                          threshold2=self.__cannyThreshold2,
                          apertureSize=self.__cannyApertureSize)

        self.__logger.info("Detected following Canny-Edges",
                           "NoteLineDetector:detect", edges)

        # Verwendung des HoughLines Detektors um Notenlinien zu detektieren
        lines = cv2.HoughLines(edges,
                               rho=self.__houghLinesRho,
                               theta=self.__houghLinesTheta,
                               threshold=self.__houghLinesThreshold)

        # Gehe alle Linien durch, um aus rho und theta
        # die Linienkoordinaten zu berechnen
        lines_coordinates = []
        for x in range(0, len(lines)):
            for rho, theta in lines[x]:

                # Berechnung der Linienkoordinaten
                # Die X Koordinaten gehen über die komplette Seite,
                # daher 0 und mat.shape[1]
                a = np.cos(theta)
                b = np.sin(theta)
                x0 = a * rho
                y0 = b * rho
                x1 = int(x0 + 0 * (-b))
                y1 = int(y0 + 1000 * (a))
                x2 = int(x0 - mat.shape[1] * (-b))
                y2 = int(y0 - 1000 * (a))

                # Speichere die Koordinaten in eine Liste, wenn
                # eine definierte Steigung nicht überschritten wird
                if (abs(y1 - y2) <= self.__maxGradeOfLinesInPx):
                    lines_coordinates.append([x1, y1, x2, y2])

        # Sortieren die Linien von oben nach unten
        lines_coordinates.sort(key=itemgetter(1))

        # Erstelle eine Matrix, welche als Ausgabe verwendete wird
        # auf welcher die Linien farbig gezeichnet werden koennen
        showMat = cv2.cvtColor(src=mat, code=cv2.COLOR_GRAY2BGR)

        # Die noteLineCoordinates ist ein Array, welches spaeter
        # die Rechteckkoordinaten der Notenzeilen enthaelt,
        # um diese als eigenstaendige Matrizen extrahieren zu koennen.
        # Eine Liniengruppe definiert Linien die zur selben Zeile gehoeren
        noteLineCoordinates = []
        line_groupe = []
        lineThickness = 2
        lineColor = (0, 255, 0)
        rectangleColor = (255, 255, 0)

        # Gehe allen Notenlinien durch
        for i in range(0, len(lines_coordinates) - 1):

            # Erhalte die Koordinaten einer Linie und Speichere sie in einer Liniengruppe
            line_coordinates = lines_coordinates[i]
            line_groupe.append(line_coordinates)

            # Zeichne die Linie auf die Debug-Matrix
            cv2.line(showMat, (line_coordinates[0], line_coordinates[1]),
                     (line_coordinates[2], line_coordinates[3]), lineColor,
                     lineThickness)

            # Falls der Abstand zwischen zwei Notenzinien gering genug ist,
            # dann ist die Linie ein Teil einer Liniengruppe und somit Teil einer Notenzeile
            if (not (abs(line_coordinates[1] - lines_coordinates[i + 1][1]) <
                     self.__minDistanceToNextNoteRow)):

                # Berechne einen Rahmen zu der aktuellen Notenzeile
                marginTop = int(
                    abs(line_groupe[0][1] -
                        line_groupe[len(line_groupe) - 1][1]) *
                    self.__marginTop)
                marginBorder = int(
                    abs(line_groupe[0][1] -
                        line_groupe[len(line_groupe) - 1][1]) *
                    self.__marginBottom)

                coordinateTop = line_groupe[0][1] - marginTop
                coordinateBottom = line_groupe[len(line_groupe) -
                                               1][1] + marginBorder

                # Zeichne einen Rahmen um die aktuelle Notenzeile
                cv2.rectangle(img=showMat,
                              pt1=(0, coordinateTop),
                              pt2=(mat.shape[1], coordinateBottom),
                              color=rectangleColor,
                              thickness=lineThickness)

                # Speichern der Koordinaten der Notenzeile
                noteLineCoordinates.append(
                    [coordinateTop, coordinateBottom, 0, mat.shape[1]])

                # Loesche den Inhalt, um Platz fuer eine neue Liniengruppe zu sorgen
                line_groupe.clear()

        else:
            # Erhalte die Koordinaten einer Linie und Speichere sie in einer Liniengruppe
            line_coordinates = lines_coordinates[len(lines_coordinates) - 1]
            line_groupe.append(line_coordinates)

            # Zeichne die Linie auf die Debug-Matrix
            cv2.line(showMat, (line_coordinates[0], line_coordinates[1]),
                     (line_coordinates[2], line_coordinates[3]), lineColor,
                     lineThickness)

            # Berechne einen Rahmen zu der aktuellen Notenzeile
            marginTop = int(
                abs(line_groupe[0][1] - line_groupe[len(line_groupe) - 1][1]) *
                self.__marginTop)
            marginBorder = int(
                abs(line_groupe[0][1] - line_groupe[len(line_groupe) - 1][1]) *
                self.__marginBottom)

            coordinateTop = line_groupe[0][1] - marginTop
            coordinateBottom = line_groupe[len(line_groupe) -
                                           1][1] + marginBorder

            # Zeichne einen Rahmen um die aktuelle Notenzeile
            cv2.rectangle(img=showMat,
                          pt1=(0, coordinateTop),
                          pt2=(mat.shape[1], coordinateBottom),
                          color=rectangleColor,
                          thickness=lineThickness)
            self.__logger.info("Detected following Line:",
                               "NoteLineDetector:detect", showMat)

            # Speichern der Koordinaten der Notenzeile
            noteLineCoordinates.append(
                [coordinateTop, coordinateBottom, 0, mat.shape[1]])

            # Loesche den Inhalt, um Platz fuer eine neue Liniengruppe zu sorgen
            line_groupe.clear()

        # Anzeigen des Notenblattes indem die gefunden Notenzeilen
        # und Notenlinien farblich markiert sind.
        if (self.__showImagesInWindow):
            cv2.imshow("NoteLineDetector_MusicSheet", showMat)
            cv2.waitKey(0)

        # Extrahierung und Abspeichern der Notenzeilen
        # aus allen eingegeben Matrizen (Notenblaetter).
        noteLinesMats = []
        for mat_Bla in mats:
            noteRows = []
            for line_coordinates in noteLineCoordinates:
                if (line_coordinates[0] != line_coordinates[1]):
                    noteRow = mat_Bla[line_coordinates[0]:line_coordinates[1],
                                      line_coordinates[2]:line_coordinates[3]]
                    noteRows.append(noteRow)
                    if (self.__showImagesInWindow):
                        cv2.imshow("NoteLineDetector_NoteRow", noteRow)
                        cv2.waitKey(0)
                        # noteRow = np.zeros(noteRow.shape)
            noteLinesMats.append(noteRows)

        # Abspeichern der Notenzeilen aller Matrizen
        for i in range(0, len(noteLinesMats[0])):
            for j in range(0, len(noteLinesMats)):
                self.__logger.info("Detected following Notelines:",
                                   "NoteLineDetector:detect",
                                   noteLinesMats[j][i])

        return noteLinesMats
예제 #25
0
class DetectionCore(IDetectionCore):
    def __init__(self, config):
        """
        Constructor, initialisiert Membervariablen

        :param Config: config Die Konfiguration.
        :example:
            DetectionCore(config)
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")
        self.__logger.info("Starting __init__()", "DetectionCore:__init__")

        self.__fullClassifier = SheetMusicTemplateClassifier(
            config["SheetMusicClassifier"])
        """
        Todo:     
        self.__classificationCombiner = some ClassificationCombiner
        Mehr fullClassifier können hier erstellt werden
        """
        self.__logger.info("Finished __init__()", "DetectionCore:__init__")

    def execute(self, mat):
        """
        Führt die Klassifiezierung auf die BildMatrix aus und gibt die Klassifiezierung zurück.

        :param Bildmatrix: mat Die Bildmatrix auf welcher die Klassifiezierung stattfinden soll.
        :return: IClassification : classification Die Klassifizierung
        :example:
            detectionCore.execute(mat)
        """
        self.__logger.info("Starting execute()", "DetectionCore:execute")

        classification = self.__fullClassifier.executeClassification(mat)
        """
        Todo: 
        Dann könnten noch weitere fullClassifier klassifizieren und ein Combiner die Klassifizierungen bewerten 
        und kombinieren.
        """

        self.__logger.info("Finished execute()", "DetectionCore:execute")
        return classification

    def buildNextTraindata(self, mat):
        """
        Interface Methode: Jeder DetectionCore muss diese realisieren.
        Erstellt Trainingsdaten und fügt diese einem Ordner hinzu.

        :param Bildmatrix: mat Die Bildmatrix aus welcher die Trainingsdaten erstell werden sollen.
        :return: nextTrainData : Trainingsdaten zu gegebenem Bild und Lable.
        """
        self.__logger.info("Starting buildNextTraindata()",
                           "DetectionCore:buildNextTraindata")
        trainDataArray = self.__fullClassifier.buildTraindata(mat)
        self.__logger.info("Finished buildNextTraindata()",
                           "DetectionCore:buildNextTraindata")
        return trainDataArray

    def executeTrain(self, inputMatArray, lableArray):
        """
        Trainiert alle FullClassifier und deren Classifier mit den gegebenen Trainingsdaten

        :param Bildmatrizen: inputMatArray Die Bildmatrizen für das Training.
        :param Lable: lableArray Die Lable zu den Bildmatrizen für das Training.
        :return: successful : boolean War das Training erfolgreich?
        """
        self.__logger.info("Starting executeTrain()",
                           "DetectionCore:executeTrain")
        self.__fullClassifier.train(inputMatArray, lableArray)
        self.__logger.info("Finished executeTrain()",
                           "DetectionCore:executeTrain")
        return True
예제 #26
0
class Preprocessing(IPreprocessing):

    def __init__(self, config):
        """
        Constructor, initialisiert Membervariablen

        Parameters
        ----------
        config : Config
        Die Konfiguration.

        Example
        -------
        >>> Preprocessing(config)
        """
        self.__logger = State().getLogger("Preprocessing_Component_Logger")
        self.__logger.info("Starting __init__()", "Preprocessing:__init__()")
        self.__config = config

        # Erstelle eine Liste von Preprozessoreinheiten,
        # die eine Matrix bearbeiten
        ordererPreporcessingUnitList = []

        noiseFilterConfig = self.__config["GaussianBlurNoiseFilterPreprocessor"]
        self.__gaussianBlurNoiseFilterPreprocessor = GaussianBlurNoiseFilterPreprocessor \
                                (ksize=(noiseFilterConfig["ksizeWidth"], noiseFilterConfig["ksizeHeight"]),
                                 sigmaX=noiseFilterConfig["sigmaX"],
                                 showImagesInWindow=noiseFilterConfig["showImagesInWindow"])
        ordererPreporcessingUnitList.append(self.__gaussianBlurNoiseFilterPreprocessor)

        binarizationConfig1 = self.__config["AdaptiveThresholdBinarizationPreprocessor_FirstPreprocessor"]
        self.__adaptiveThresholdBinarizationPreProcessor1 = AdaptiveThresholdBinarizationPreprocessor \
                                (maxValue=binarizationConfig1["maxValue"],
                                 adaptiveMethode=getattr(cv2, binarizationConfig1["adaptiveMethode"]),
                                 thresholdType=getattr(cv2, binarizationConfig1["thresholdType"]),
                                 blockSize=binarizationConfig1["blockSize"],
                                 C=binarizationConfig1["C"],
                                 showImagesInWindow=binarizationConfig1["showImagesInWindow"])
        ordererPreporcessingUnitList.append(self.__adaptiveThresholdBinarizationPreProcessor1)

        # Erstelle einen Preprozessor, der die unterschiedelichen Preprozessoreinheiten
        # der ersten Liste nacheineander auf eine Matrix ausfuehrt
        self.__preProcessor1 = Preprocessor(ordererPreporcessingUnitList)

        # Erstelle eine weitere Liste mit anderen Preprozessoreinheiten,
        # die eine Matrix bearbeiten
        ordererPreporcessingUnitList2 = []

        bitwiseNotConfig = self.__config["BitwiseNotPreprocessor"]
        self.__bitwiseNotPreprocessor = BitwiseNotPreprocessor \
                                (showImagesInWindow=bitwiseNotConfig["showImagesInWindow"])
        ordererPreporcessingUnitList2.append(self.__bitwiseNotPreprocessor)

        binarizationConfig2 = self.__config["AdaptiveThresholdBinarizationPreprocessor_SecondPreprocessor"]
        self.__adaptiveThresholdBinarizationPreProcessor2 = AdaptiveThresholdBinarizationPreprocessor \
                                (maxValue=binarizationConfig2["maxValue"],
                                 adaptiveMethode=getattr(cv2, binarizationConfig2["adaptiveMethode"]),
                                 thresholdType=getattr(cv2, binarizationConfig2["thresholdType"]),
                                 blockSize=binarizationConfig2["blockSize"],
                                 C=binarizationConfig2["C"],
                                 showImagesInWindow=binarizationConfig2["showImagesInWindow"])
        ordererPreporcessingUnitList2.append(self.__adaptiveThresholdBinarizationPreProcessor2)

        # Erstelle einen Preprozessor, der die unterschiedelichen Preprozessoreinheiten
        # der zweiten Liste nacheineander auf eine Matrix ausfuehrt
        self.__preProcessor2 = Preprocessor(ordererPreporcessingUnitList2)

        self.__logger.info("Finished __init__()", "Preprocessing:__init__()")

    def execute(self, mat):
        """
        Führt Preprocessingschritte auf die BildMatrix aus und gibt die bearbeitet Matrix zurück.

        Parameters
        ----------
        mat : Die Bildmatrix auf welche Preprocessingschritte angewendet werden sollen.

        Returns
        -------
        imgMatrix : mat
        Die "preprocesste" Matrix.

        Example
        -------
        >>> preprocessing.execute()
        """
        self.__logger.info("Starting execute", "Preprocessing:execute")

        # Ausfuehren der Preprozessoren
        preprocessedMat1 = self.__preProcessor1.preProcess(mat)
        preprocessedMat2 = self.__preProcessor2.preProcess(mat)

        # Erstelle einen Calculator, der einen Skalierungsfaktor
        # fuer die Notenblattskalierung berechnet
        scaleCalculatorConfig = self.__config["NoteSheetScaleConstCalculator"]
        self.__noteSheetScaleConstCalculator = NoteSheetScaleConstCalculator \
                                (maxGradeOfLinesInPx=scaleCalculatorConfig["maxGradeOfLinesInPx"],
                                 marginTop=scaleCalculatorConfig["marginTop"],
                                 marginBottom=scaleCalculatorConfig["marginBottom"],
                                 cannyThreshold1=scaleCalculatorConfig["cannyThreshold1"],
                                 cannyThreshold2=scaleCalculatorConfig["cannyThreshold2"],
                                 cannyApertureSize=scaleCalculatorConfig["cannyApertureSize"],
                                 houghLinesRho=scaleCalculatorConfig["houghLinesRho"],
                                 houghLinesTheta=np.pi / 180 * scaleCalculatorConfig["houghLinesThetaInDegree"],
                                 houghLinesThreshold=scaleCalculatorConfig["houghLinesThreshold"],
                                 minDistanceToNextNoteRow=scaleCalculatorConfig["minDistanceToNextNoteRow"],
                                 minHeightOfNoteRow=scaleCalculatorConfig["minHeightOfNoteRow"],
                                 showImagesInWindow=scaleCalculatorConfig["showImagesInWindow"])

        # Ausfuehren der Konstantenberechnung auf eine Matrix (Notenblatt)
        averageHeight = self.__noteSheetScaleConstCalculator.preProcess(preprocessedMat1)

        # Initialisierung eines Preprozessors mit der aktuellen Durchschnitthoehe der Zeilen und der Zielhoehe
        sheetScalerConfig = self.__config["ScaleNoteSheetPreprocessor"]
        self.__scaleNoteSheetPreprocessor = ScaleNoteSheetPreprocessor \
                                (averageHeight=averageHeight,
                                 targetLineHeight=sheetScalerConfig["targetLineHeight"],
                                 interpolation=getattr(cv2, sheetScalerConfig["interpolation"]))

        # Skalieren der im Preprozessor bearbeiteten Matrizen
        preprocessedMat1 = self.__scaleNoteSheetPreprocessor.preProcess(preprocessedMat1)
        preprocessedMat2 = self.__scaleNoteSheetPreprocessor.preProcess(preprocessedMat2)
        preprocessedMat3 = self.__scaleNoteSheetPreprocessor.preProcess(mat)

        self.__logger.info("Finished execute", "Preprocessing:execute")

        return [preprocessedMat1, preprocessedMat2, preprocessedMat3]

		
		
예제 #27
0
class KeyTemplateClassifier(ATempalteMatcher):
    """
    Klasse zur Klassifizierung von Tonhöhen in einem Takt.
    Erkennt b un #.
    """
    def __init__(self, config):
        """
        Konstruktor der KeyTemplateClassifier Klasse.

        Initialisiert alle Membervariablen.

        :param config:          Die Config für diesen TemplateMatcher
        """
        self.__logger = State().getLogger("DetectionCore_Component_Logger")

        self.__templateFolder = config["templateFolder"]
        self.__templateMethod = config["templateMethod"]

        self.__bTemplate = self.__loadTemplate(-1)
        self.__bRatio = 29 / 97
        self.__bThreshold = 0.61  # Max: 0.65  Min: 0.57  Mid: 0.61

        self.__CrossTemplate = self.__loadTemplate(1)
        self.__CrossRatio = 36 / 97
        self.__CrossThreshold = 0.635  # Max: 0.68  Min: 0.59  Mid: 0.635

        self.__logger.info(
            "Loaded Key " + str(self.__bTemplate[1]) + " Template",
            "KeyTemplateClassifier::__init__", self.__bTemplate[0])

        self.__logger.info(
            "Loaded Key " + str(self.__CrossTemplate[1]) + " Template",
            "KeyTemplateClassifier::__init__", self.__CrossTemplate[0])

    def classify(self, clasUnit, matArray):
        """
        Interface Methode: Jeder TempalteMatcher muss diese realisieren.
        Führt die Klassifizierung auf ein Array von Bildmatrizen anhand TemplateMatching aus und gibt die
        erkannten Objekte zurück.

        Parameters
        ----------
        classUnit : Die Klassifikation als Out-Parameter
        matArray : Die Bildmatrizen auf welche die Klassifizierung ausgeführt werden soll.

        Returns
        -------
        [True] wenn Notenschlüssel erkannt wurde, [False] falls nicht
        """

        # b Vorzeichen
        match, count = self.__hasKey(matArray, self.__bTemplate[0],
                                     self.__bRatio, self.__bThreshold)

        if match > clasUnit.recognitionPercentage:
            clasUnit.recognitionPercentage = match
            clasUnit.fifths = self.__bTemplate[1] * count

        # Kreuz Vorzeichen
        match, count = self.__hasKey(matArray, self.__CrossTemplate[0],
                                     self.__CrossRatio, self.__CrossThreshold)

        if match > clasUnit.recognitionPercentage:
            clasUnit.recognitionPercentage = match
            clasUnit.fifths = self.__CrossTemplate[1] * count

        if clasUnit.recognitionPercentage == 0:
            return False

        self.__logger.info(
            "Key found " + str(clasUnit.fifths) + " " +
            str(clasUnit.recognitionPercentage),
            "KeyTemplateClassifier::classify", matArray[0])

        return True

    def __hasKey(self, mats, template, templateMatRatio, threshold):
        """
        Führt den eigentlichen Templatematch aus.

        :param mats:                Takt als Bildmatrix ([0] ohne Linien, [1] mit Linien, [2] nur skaliert).
        :param template:            Template, welches zum Templatematching verwendet wird.
        :param templateMatRatio:    Höhenverhältnis von Template zum Bildausschnitt.
        :param threshold:           Grenzwert, welcher erreicht werden muss, damit das Template als gefunden gilt.
        :return:                    [True] wenn Threshold erreicht, [False] wenn nicht.
        """
        # Template auf Bildgröße skalieren
        resizedTemplate = ATempalteMatcher._resizeTemplate(
            self, mats[0], template, templateMatRatio)

        if (mats[0].shape[1] >= resizedTemplate.shape[1]):
            # Templatematching mit Bild OHNE Linen
            matchNoLine = cv2.matchTemplate(mats[0], resizedTemplate,
                                            self.__templateMethod)

            # Templatematching mit Bild MIT Linen
            matchLine = cv2.matchTemplate(mats[1], resizedTemplate,
                                          self.__templateMethod)

            # Templatematching mit nur skaliertem Bild
            matchSkal = cv2.matchTemplate(mats[2], resizedTemplate,
                                          self.__templateMethod)

            # Verwende das Maximum von beiden Matches
            match = cv2.max(matchLine, matchNoLine, matchSkal)

            # Erzeuge ein binarisiertes Bild anhand eines Thresholds
            __, bin = cv2.threshold(match, threshold, 255, cv2.THRESH_BINARY)

            # Zähle die Konturen im Binarisierten Bild
            im2, contours, hierarchy = cv2.findContours(
                np.uint8(bin), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

            # Wenn Threshold mindestens einmal erreicht wurde
            if (bin > 0).any():
                return match.max(), len(contours)

        return 0, 0

    def __loadTemplate(self, fiths):
        return [
            cv2.imread(self.__templateFolder + "key_" + str(fiths) + ".jpg",
                       0), fiths
        ]