def extractImagesMetadata(self, imagePath, imageIdentifiers):
        """Overrides extractImagesMetadata method making sure to store
        both series and channel indices in the channel code to be reused
        later to extract color information and other metadata.

        The channel code is in the form SERIES-(\d+)_CHANNEL-(\d+).

        Only metadata for the relevant series number is returned!

        @param imagePath Full path to the file to process
        @param imageIdentifiers Array of ImageIdentifier's

        @see constructor.
        """

        # Initialize array of metadata entries
        metaData = []

        # Iterate over all image identifiers
        for id in imageIdentifiers:

            # Extract the info from the image identifier
            ch = int(id.colorChannelIndex)
            plane = int(id.focalPlaneIndex)
            series = int(id.seriesIndex)
            timepoint = int(id.timeSeriesIndex)

            # Make sure to process only the relevant series
            if self._seriesNum != -1 and series != self._seriesNum:
                continue

            # Build the channel code
            channelCode = "SERIES-" + str(series) + "_CHANNEL-" + str(ch)

            # Initialize a new ImageMetadata object
            imageMetadata = ImageMetadata();

            # Fill in all information
            imageMetadata.imageIdentifier = id
            imageMetadata.seriesNumber = series
            imageMetadata.timepoint = timepoint
            imageMetadata.depth = plane
            imageMetadata.channelCode = channelCode
            imageMetadata.tileNumber = 1  # + self._seriesNum
            imageMetadata.well = "IGNORED"

            # Append metadata for current image
            metaData.append(imageMetadata)

        # Log image geometry information
        if self._DEBUG:
            self._logger.info("MICROSCOPYSINGLEDATASETCONFIG::extractImagesMetadata(): " +
                              "Current image: series = " + str(series) +
                              " channel = " + str(ch) +
                              " plane = " + str(plane) +
                              " timepoint = " + str(timepoint) +
                              " channel code = " + str(channelCode))

        # Now return the metaData array
        return metaData
Пример #2
0
    def extractImagesMetadata(self, imagePath, imageIdentifiers):
        """Overrides extractImagesMetadata method making sure to store
        both series and channel indices in the channel code to be reused
        later to extract color information and other metadata.

        The channel code is in the form SERIES-(\d+)_CHANNEL-(\d+).

        Only metadata for the relevant series number is returned!

        @param imagePath Full path to the file to process
        @param imageIdentifiers Array of ImageIdentifier's

        @see constructor.
        """

        # Initialize array of metadata entries
        metaData = []

        # Iterate over all image identifiers
        for id in imageIdentifiers:

            # Extract the info from the image identifier
            ch = int(id.colorChannelIndex)
            plane = int(id.focalPlaneIndex)
            series = int(id.seriesIndex)
            timepoint = int(id.timeSeriesIndex)

            # Make sure to process only the relevant series
            if self._seriesNum != -1 and series != self._seriesNum:
                continue

            # Build the channel code
            channelCode = "SERIES-" + str(series) + "_CHANNEL-" + str(ch)

            # Initialize a new ImageMetadata object
            imageMetadata = ImageMetadata()

            # Fill in all information
            imageMetadata.imageIdentifier = id
            imageMetadata.seriesNumber = series
            imageMetadata.timepoint = timepoint
            imageMetadata.depth = plane
            imageMetadata.channelCode = channelCode
            imageMetadata.tileNumber = 1  # + self._seriesNum
            imageMetadata.well = "IGNORED"

            # Append metadata for current image
            metaData.append(imageMetadata)

        # Log image geometry information
        if self._DEBUG:
            self._logger.info(
                "MICROSCOPYSINGLEDATASETCONFIG::extractImagesMetadata(): " +
                "Current image: series = " + str(series) + " channel = " +
                str(ch) + " plane = " + str(plane) + " timepoint = " +
                str(timepoint) + " channel code = " + str(channelCode))

        # Now return the metaData array
        return metaData
    def extractImagesMetadata(self, imagePath, imageIdentifiers):
        """Overrides extractImageMetadata method making sure to store
        both series and channel indices in the channel code to be reused
        later to extract color information and other metadata.

        The channel code is in the form SERIES-(\d+)_CHANNEL-(\d+).

        Only metadata for the relevant series number is returned!

        @param imagePath Full path to the file to process
        @param imageIdentifiers Array of ImageIdentifier's

        @see constructor.
        """

        # Info
        self._logger.info("Processing file " + str(imagePath) +
                          " with identifiers " + str(imageIdentifiers))

        # Find the file in the csvTable hashmap
        row = self._csvTable[imagePath]
        self._logger.info("File " + imagePath + " was found in the CSV table.")
        self._logger.info("The corresponding row is " + str(row))

        # Coordinates
        position = -1
        tileX = -1
        tileY = -1
        planeNum = -1
        timeNum = -1
        well = ""

        # Get the well
        well = row[4]

        # Test position string
        self._logger.info("Position string is " + str(row[5]))

        # Get the positions from the Position column
        m_pos = self._pattern_pos.match(row[5])
        if m_pos is not None:
            if m_pos.group("position") is not None:
                position = int(m_pos.group("position"))
            if m_pos.group("x") is not None:
                tileX = int(m_pos.group("x"))
            if m_pos.group("y") is not None:
                tileY = int(m_pos.group("y"))
            if m_pos.group("z") is not None:
                planeNum = int(m_pos.group("z"))

        # Try the fallback option
        m_pos_name_fb = self._pattern_pos_name_fb.match(row[6])
        if m_pos_name_fb is not None:
            if m_pos_name_fb.group("pos") is not None:
                pos = m_pos_name_fb.group("pos")
                tileX = int(pos[0:2])
                tileY = int(pos[2:4])

        # Then, get time information
        m_time = self._pattern_time_name.match(row[6])
        if m_time is not None:
            if m_time.group("time") is not None:
                timeNum = int(m_time.group("time"))
        else:
            # Try the fallback option
            m_time_fb = self._pattern_time_name_fb.match(row[6])
            if m_time_fb is not None:
                if m_time_fb.group("time") is not None:
                    timeNum = int(m_time_fb.group("time"))

        # Fallback
        if position == -1:
            position = 1
        if tileX == -1:
            tileX = 1
        if tileY == -1:
            tileY = 1
        if planeNum == -1:
            planeNum = 1
        if timeNum == -1:
            timeNum = 1

        # Channel name
        channelName = self._buildChannelName(row)

        # Build series ID from row (if present, use path information to build a unique id)
        seriesID = "Well_" + well + "_Pos_" + str(position) + "_" + str(tileX) + "_" + str(tileY) + "_Path_" + \
            self._pathInfoAsID(row[6])

        # Find the series number that correspond to seriesID
        series = self._seriesNumFromSeriesID(seriesID)

        # Inform
        if series == -1:
            err = "Series with ID " + seriesID + " could not be found!"
            self._logger.error(err)
            raise (Exception(err))
        else:
            self._logger.info("Series with ID " + seriesID +
                              " corresponds to series number " + str(series))

        # Make sure to process only the relevant series
        if series != self._seriesNum:
            return []

        # Get channel index from channel name
        channel = self._getChannelNumber(self._allSeriesMetadata[series],
                                         channelName)

        # Build the channel code
        channelCode = "SERIES-" + str(series) + "_CHANNEL-" + str(channel)

        if self._DEBUG:
            msg = "Current file = " + imagePath + " has series = " + \
            str(series) + " timepoint = " + str(timeNum) + " plane = " + \
            str(planeNum) + " channel = " + str(channel) + " channelCode = " + \
            str(channelCode)
            self._logger.info(msg)

        # Initialize Metadata array
        Metadata = []

        # Initialize a new ImageMetadata object
        imageMetadata = ImageMetadata()

        # Build a tile number from tileX and tileY
        tileNum = 1000 * tileX + tileY
        if tileNum < 1:
            tileNum = 1
        self._logger.info("Tile number is " + str(tileNum))

        # Fill in all information
        imageMetadata.imageIdentifier = imageIdentifiers.get(0)
        imageMetadata.seriesNumber = series
        imageMetadata.timepoint = timeNum
        imageMetadata.depth = planeNum
        imageMetadata.channelCode = channelCode
        imageMetadata.tileNumber = tileNum
        imageMetadata.well = well

        # Now return the image metadata object in an array
        Metadata.append(imageMetadata)
        return Metadata
    def extractImagesMetadata(self, imagePath, imageIdentifiers):
        """Overrides extractImageMetadata method making sure to store
        both series and channel indices in the channel code to be reused
        later to extract color information and other metadata.

        The channel code is in the form SERIES-(\d+)_CHANNEL-(\d+).

        Only metadata for the relevant series number is returned!

        @param imagePath Full path to the file to process
        @param imageIdentifiers Array of ImageIdentifier's

        @see constructor.
        """

        # Info
        self._logger.info("Processing file " + str(imagePath) +
                          " with identifiers " + str(imageIdentifiers))

        # Extract the relevant information from the file name - the image
        # identifiers in this case do not carry any useful information.
        m = self._pattern.match(imagePath)

        if m is None:
            err = "VISITRONNDCOMPOSITEDATASETCONFIG::extractImageMetadata(): " + \
            "unexpected file name " + str(imagePath)
            self._logger.error(err)
            raise Exception(err)

        # Get the extracted info
        fileinfo = m.groupdict()

        # Get and store the base name
        basename = fileinfo['basename']

        # Extract the series number
        series = self._seriesNumFromFileName(imagePath)
        if series == -1:
            raise Exception("Could not find any series containing file " +
                            imagePath + "!")

        if self._DEBUG:
            self._logger.info("Found file " + imagePath + " in series " +
                              str(series))

        # Make sure to process only the relevant series
        if series != self._seriesNum:
            return []

        # Get current metadata
        currentMetaData = self._allSeriesMetadata[series]

        # Compare the basename extracted from the file name with
        # the one stored in the attributes
        if basename != currentMetaData["basename"]:
            self._logger.error("Basename mismatch: " + basename +
                               "(from filename) vs. " +
                               currentMetaData["basename"] +
                               "(from attributes).")

        # Extract the channel number
        # The channel number in the file name is 1-based
        if fileinfo["channel"] is not None:
            channelNumberFromFile = int(fileinfo['channel']) - 1
            if self._DEBUG:
                self._logger.info("Found channel number " +
                                  str(channelNumberFromFile) +
                                  " in file name.")
        else:
            self._logger.info(
                "Channel number not found: fall back to image identifiers.")
            channelNumberFromFile = -1

        if fileinfo["channelname"] is not None:
            channelName = fileinfo['channelname']
            if self._DEBUG:
                self._logger.info("Found channel name " + channelName +
                                  " in file name.")
        else:
            if channelNumberFromFile != -1:
                keyName = "channelName" + channelNumberFromFile
                if keyName in currentMetadata:
                    channelName = currentMetadata[keyName]
                    self._logger.info("Channel name from metadata: " +
                                      channelName)
                else:
                    self._logger.info(
                        "Channel name not found: falling back to ''.")
                    channelName = ""
            self._logger.info("Channel name not found: falling back to ''.")
            channelName = ""

        # Extract the timepoint
        # The timepoint number in the file (if defined) is 1-based
        if fileinfo["timepoint"] is not None:
            timepointFromFile = int(fileinfo['timepoint']) - 1
            if self._DEBUG:
                self._logger.info("Found timepoint " + str(timepointFromFile) +
                                  " in file name.")
        else:
            timepointFromFile = -1

        # Inform
        if self._DEBUG:
            self._logger.info("Parsing of file " + str(imagePath) + " gives: " + \
                              "basename = " + str(basename) + "; " + \
                              "channelNumber = " + str(channelNumberFromFile) + "; " + \
                              "channelName = " + channelName + "; " + \
                              "seriesNum = " + str(series) + "; " + \
                              "timepoint = " + str(timepointFromFile))

        # Initialize array of metadata entries
        metaData = []

        # Now process the file indentifiers for this file
        # Iterate over all image identifiers
        for id in imageIdentifiers:

            # Extract the relevant info from the image identifier
            plane = id.focalPlaneIndex

            # Fallback
            if channelNumberFromFile == -1:
                channelNumber = int(id.colorChannelIndex)
            else:
                channelNumber = channelNumberFromFile

            if timepointFromFile == -1:
                timepoint = id.timeSeriesIndex
            else:
                timepoint = timepointFromFile

            if self._DEBUG:
                self._logger.info("Image identifiers for image " +
                                  str(imagePath) + ": " + str(id) +
                                  " map to " + "channel = " +
                                  str(id.colorChannelIndex) + "; plane = " +
                                  str(id.focalPlaneIndex) + "; series = " +
                                  str(id.seriesIndex) + "; timepoint = " +
                                  str(id.timeSeriesIndex))
                self._logger.info(
                    "Geometry after integrating image identifiers: " +
                    "channel = " + str(channelNumber) + "; plane = " +
                    str(plane) + "; series = " + str(series) +
                    "; timepoint = " + str(timepoint))

            # Build the channel code
            channelCode = "SERIES-" + str(series) + "_CHANNEL-" + str(
                channelNumber)

            if self._DEBUG:
                self._logger.info(
                    "Adding image to channel with channel code " + channelCode)

            # Attempt to work around a geometry-parsing issue in imageIdentifiers
            expectedNumPlanes = int(currentMetaData["sizeZ"])
            expectedNumTimepoints = int(currentMetaData["sizeT"])
            if (timepoint > (expectedNumTimepoints - 1) and expectedNumPlanes > 1) or \
             (plane > (expectedNumPlanes - 1) and expectedNumTimepoints > 1):
                self._logger.info("Swapping Z and T")
                timepoint, plane = plane, timepoint
                # Update the ImageIdentifier
                id = ImageIdentifier(series, timepoint, plane, channelNumber)

            # Initialize a new ImageMetadata object
            imageMetadata = ImageMetadata()

            # Fill in all information
            imageMetadata.imageIdentifier = id
            imageMetadata.seriesNumber = series
            imageMetadata.timepoint = timepoint
            imageMetadata.depth = plane
            imageMetadata.channelCode = channelCode
            imageMetadata.tileNumber = 1  # + self._seriesNum
            imageMetadata.well = "IGNORED"

            # Append metadata for current image
            metaData.append(imageMetadata)

        # Now return the image metadata object in an array
        return metaData
    def extractImagesMetadata(self, imagePath, imageIdentifiers):
        """Overrides extractImageMetadata method making sure to store
        both series and channel indices in the channel code to be reused
        later to extract color information and other metadata.

        The channel code is in the form SERIES-(\d+)_CHANNEL-(\d+).

        Only metadata for the relevant series number is returned!

        @param imagePath Full path to the file to process
        @param imageIdentifiers Array of ImageIdentifier's

        @see constructor.
        """

        # Info
        self._logger.info("Processing file " + str(imagePath) +
                          " with identifiers " + str(imageIdentifiers))

        # Extract the relevant information from the file name - the image
        # identifiers in this case do not carry any useful information.
        m = self._pattern.match(imagePath)

        if m is None:
            err = "VISITRONNDCOMPOSITEDATASETCONFIG::extractImageMetadata(): " + \
            "unexpected file name " + str(imagePath)
            self._logger.error(err)
            raise Exception(err)

        # Get the extracted info
        fileinfo = m.groupdict()

        # Get and store the base name
        basename = fileinfo['basename']

        # Extract the series number
        series = self._seriesNumFromFileName(imagePath)
        if series == -1:
            raise Exception("Could not find any series containing file " + imagePath + "!")

        if self._DEBUG:
            self._logger.info("Found file " + imagePath + " in series " + str(series))

        # Make sure to process only the relevant series
        if series != self._seriesNum:
            return []

        # Get current metadata
        currentMetaData = self._allSeriesMetadata[series]

        # Compare the basename extracted from the file name with
        # the one stored in the attributes
        if basename != currentMetaData["basename"]:
            self._logger.error("Basename mismatch: " +
                               basename + "(from filename) vs. " +
                               currentMetaData["basename"] +
                               "(from attributes).")

        # Extract the channel number
        # The channel number in the file name is 1-based
        if fileinfo["channel"] is not None:
            channelNumberFromFile = int(fileinfo['channel']) - 1
            if self._DEBUG:
                self._logger.info("Found channel number " + str(channelNumberFromFile) + " in file name.")
        else:
            self._logger.info("Channel number not found: fall back to image identifiers.")
            channelNumberFromFile = -1

        if fileinfo["channelname"] is not None:
            channelName = fileinfo['channelname']
            if self._DEBUG:
                self._logger.info("Found channel name " + channelName + " in file name.")
        else:
            if channelNumberFromFile != -1:
                keyName = "channelName" + channelNumberFromFile
                if keyName in currentMetadata:
                    channelName = currentMetadata[keyName]
                    self._logger.info("Channel name from metadata: " + channelName)
                else:
                    self._logger.info("Channel name not found: falling back to ''.")
                    channelName = ""
            self._logger.info("Channel name not found: falling back to ''.")
            channelName = ""

        # Extract the timepoint
        # The timepoint number in the file (if defined) is 1-based
        if fileinfo["timepoint"] is not None:
            timepointFromFile = int(fileinfo['timepoint']) - 1
            if self._DEBUG:
                self._logger.info("Found timepoint " + str(timepointFromFile) + " in file name.")
        else:
            timepointFromFile = -1

        # Inform
        if self._DEBUG:
            self._logger.info("Parsing of file " + str(imagePath) + " gives: " + \
                              "basename = " + str(basename) + "; " + \
                              "channelNumber = " + str(channelNumberFromFile) + "; " + \
                              "channelName = " + channelName + "; " + \
                              "seriesNum = " + str(series) + "; " + \
                              "timepoint = " + str(timepointFromFile))

        # Initialize array of metadata entries
        metaData = []

        # Now process the file indentifiers for this file
        # Iterate over all image identifiers
        for id in imageIdentifiers:

            # Extract the relevant info from the image identifier
            plane = id.focalPlaneIndex

            # Fallback
            if channelNumberFromFile == -1:
                channelNumber = int(id.colorChannelIndex)
            else:
                channelNumber = channelNumberFromFile

            if timepointFromFile == -1:
                timepoint = id.timeSeriesIndex
            else:
                timepoint = timepointFromFile

            if self._DEBUG:
                self._logger.info("Image identifiers for image " + str(imagePath) +
                                  ": " + str(id) + " map to " +
                                  "channel = " + str(id.colorChannelIndex) +
                                  "; plane = " + str(id.focalPlaneIndex) +
                                  "; series = " + str(id.seriesIndex) +
                                  "; timepoint = " + str(id.timeSeriesIndex))
                self._logger.info("Geometry after integrating image identifiers: " +
                                  "channel = " + str(channelNumber) +
                                  "; plane = " + str(plane) +
                                  "; series = " + str(series) +
                                  "; timepoint = " + str(timepoint))

            # Build the channel code
            channelCode = "SERIES-" + str(series) + "_CHANNEL-" + str(channelNumber)

            if self._DEBUG:
                self._logger.info("Adding image to channel with channel code " + channelCode)

            # Attempt to work around a geometry-parsing issue in imageIdentifiers
            expectedNumPlanes = int(currentMetaData["sizeZ"])
            expectedNumTimepoints = int(currentMetaData["sizeT"])
            if (timepoint > (expectedNumTimepoints - 1) and expectedNumPlanes > 1) or \
             (plane > (expectedNumPlanes - 1) and expectedNumTimepoints > 1):
                self._logger.info("Swapping Z and T")
                timepoint, plane = plane, timepoint
                # Update the ImageIdentifier
                id = ImageIdentifier(series, timepoint, plane, channelNumber)

            # Initialize a new ImageMetadata object
            imageMetadata = ImageMetadata();

            # Fill in all information
            imageMetadata.imageIdentifier = id
            imageMetadata.seriesNumber = series
            imageMetadata.timepoint = timepoint
            imageMetadata.depth = plane
            imageMetadata.channelCode = channelCode
            imageMetadata.tileNumber = 1  # + self._seriesNum
            imageMetadata.well = "IGNORED"

            # Append metadata for current image
            metaData.append(imageMetadata)

        # Now return the image metadata object in an array
        return metaData
Пример #6
0
    def extractImagesMetadata(self, imagePath, imageIdentifiers):
        """Overrides extractImageMetadata method making sure to store
        both series and channel indices in the channel code to be reused
        later to extract color information and other metadata.

        The channel code is in the form SERIES-(\d+)_CHANNEL-(\d+).

        Only metadata for the relevant series number is returned!

        @param imagePath Full path to the file to process
        @param imageIdentifiers Array of ImageIdentifier's

        @see constructor.
        """

        # Extract the relevant information from the file name - the image
        # identifiers in this case do not carry any useful information.
        m = self._pattern.match(imagePath)
        simple_m = self._pattern_simple.match(imagePath)

        # First we try the more complex regex
        if m is not None:

            # Get and store the base name
            basename = m.group("basename")
            if self._basename == "" or self._basename != basename:
                self._basename = basename

            # The series number is not always defined in the file name.
            if m.group("series") is None:
                series = 0
            else:
                series = int(m.group("series"))

            # Make sure to process only the relevant series
            if series != self._seriesNum:
                return []

            # The time index is also not always specified.
            if m.group("timepoint") is None:
                timepoint = 0
            else:
                timepoint = int(m.group("timepoint"))

            # Plane number is always specified
            if m.group("plane") is None:
                plane = 0
            else:
                plane = int(m.group("plane"))

            # Channel number is always specified
            if m.group("channel") is None:
                ch = 0
            else:
                ch = int(m.group("channel"))

        else:

            # Try with the simpler regex
            if simple_m is None:
                err = "MICROSCOPYCOMPOSITEDATASETCONFIG::extractImageMetadata(): " + \
                    "unexpected file name " + str(imagePath)
                self._logger.error(err)
                raise Exception(err)

            # Get and store the base name
            basename = simple_m.group("basename")
            if self._basename == "" or self._basename != basename:
                self._basename = basename

            # Series number
            series = 0

            # Make sure to process only the relevant series
            if series != self._seriesNum:
                return []

            # Timepoint
            timepoint = 0

            # Plane number is always specified
            if simple_m.group("plane") is None:
                plane = 0
            else:
                plane = int(simple_m.group("plane"))

            # Channel number
            ch = 0

        # Build the channel code
        channelCode = "SERIES-" + str(series) + "_CHANNEL-" + str(ch)

        if self._DEBUG:
            msg = "Current file = " + imagePath + " has series = " + \
            str(series) + " timepoint = " + str(timepoint) + " plane = " + \
            str(plane) + " channel = " + str(ch) + "; channelCode = " + \
            str(channelCode)
            self._logger.info(msg)

        # Initialize Metadata array
        Metadata = []

        # Initialize a new ImageMetadata object
        imageMetadata = ImageMetadata()

        # Fill in all information
        imageMetadata.imageIdentifier = imageIdentifiers.get(0)
        imageMetadata.seriesNumber = series
        imageMetadata.timepoint = timepoint
        imageMetadata.depth = plane
        imageMetadata.channelCode = channelCode
        imageMetadata.tileNumber = 1  # + self._seriesNum
        imageMetadata.well = "IGNORED"

        # Now return the image metadata object in an array
        Metadata.append(imageMetadata)
        return Metadata
    def extractImagesMetadata(self, imagePath, imageIdentifiers):
        """Overrides extractImageMetadata method making sure to store
        both series and channel indices in the channel code to be reused
        later to extract color information and other metadata.

        The channel code is in the form SERIES-(\d+)_CHANNEL-(\d+).

        Only metadata for the relevant series number is returned!

        @param imagePath Full path to the file to process
        @param imageIdentifiers Array of ImageIdentifier's

        @see constructor.
        """

        # Info
        self._logger.info("Processing file " + str(imagePath) + " with identifiers " + str(imageIdentifiers))

        # Find the file in the csvTable hashmap
        row = self._csvTable[imagePath]
        self._logger.info("File " + imagePath + " was found in the CSV table.")
        self._logger.info("The corresponding row is " + str(row))

        # Coordinates
        position = -1
        tileX = -1
        tileY = -1
        planeNum = -1
        timeNum = -1
        well = ""

        # Get the well
        well = row[4]

        # Test position string
        self._logger.info("Position string is " + str(row[5]))

        # Get the positions from the Position column
        m_pos = self._pattern_pos.match(row[5])
        if m_pos is not None:
            if m_pos.group("position") is not None:
                position = int(m_pos.group("position"))            
            if m_pos.group("x") is not None:
                tileX = int(m_pos.group("x"))
            if m_pos.group("y") is not None:
                tileY = int(m_pos.group("y"))
            if m_pos.group("z") is not None:
                planeNum = int(m_pos.group("z"))

        # Try the fallback option
        m_pos_name_fb = self._pattern_pos_name_fb.match(row[6])
        if m_pos_name_fb is not None:
            if m_pos_name_fb.group("pos") is not None:
                pos = m_pos_name_fb.group("pos")
                tileX = int(pos[0:2])
                tileY = int(pos[2:4])

        # Then, get time information
        m_time = self._pattern_time_name.match(row[6])
        if m_time is not None:
            if m_time.group("time") is not None:
                timeNum = int(m_time.group("time"))
        else:
            # Try the fallback option
            m_time_fb = self._pattern_time_name_fb.match(row[6])
            if m_time_fb is not None:
                if m_time_fb.group("time") is not None:
                    timeNum = int(m_time_fb.group("time"))

        # Fallback
        if position == -1:
            position = 1
        if tileX == -1:
            tileX = 1
        if tileY == -1:
            tileY = 1
        if planeNum == -1:
            planeNum = 1
        if timeNum == -1:
            timeNum = 1

        # Channel name
        channelName = self._buildChannelName(row)

        # Build series ID from row (if present, use path information to build a unique id)
        seriesID = "Well_" + well + "_Pos_" + str(position) + "_" + str(tileX) + "_" + str(tileY) + "_Path_" + \
            self._pathInfoAsID(row[6])

        # Find the series number that correspond to seriesID
        series = self._seriesNumFromSeriesID(seriesID)

        # Inform
        if series == -1:
            err = "Series with ID " + seriesID + " could not be found!"
            self._logger.error(err)
            raise(Exception(err))
        else:
            self._logger.info("Series with ID " + seriesID + " corresponds to series number " + str(series))

        # Make sure to process only the relevant series
        if series != self._seriesNum:
            return []

        # Get channel index from channel name
        channel = self._getChannelNumber(self._allSeriesMetadata[series], channelName) 

        # Build the channel code
        channelCode = "SERIES-" + str(series) + "_CHANNEL-" + str(channel)

        if self._DEBUG:
            msg = "Current file = " + imagePath + " has series = " + \
            str(series) + " timepoint = " + str(timeNum) + " plane = " + \
            str(planeNum) + " channel = " + str(channel) + " channelCode = " + \
            str(channelCode) 
            self._logger.info(msg)

        # Initialize Metadata array
        Metadata = []

        # Initialize a new ImageMetadata object
        imageMetadata = ImageMetadata()

        # Build a tile number from tileX and tileY
        tileNum = 1000 * tileX + tileY
        if tileNum < 1:
            tileNum = 1
        self._logger.info("Tile number is " + str(tileNum))

        # Fill in all information
        imageMetadata.imageIdentifier = imageIdentifiers.get(0) 
        imageMetadata.seriesNumber = series
        imageMetadata.timepoint = timeNum
        imageMetadata.depth = planeNum
        imageMetadata.channelCode = channelCode
        imageMetadata.tileNumber = tileNum
        imageMetadata.well = well

        # Now return the image metadata object in an array
        Metadata.append(imageMetadata)
        return Metadata
    def extractImagesMetadata(self, imagePath, imageIdentifiers):
        """Overrides extractImageMetadata method making sure to store
        both series and channel indices in the channel code to be reused
        later to extract color information and other metadata.

        The channel code is in the form SERIES-(\d+)_CHANNEL-(\d+).

        Only metadata for the relevant series number is returned!

        @param imagePath Full path to the file to process
        @param imageIdentifiers Array of ImageIdentifier's

        @see constructor.
        """

        # Extract the relevant information from the file name - the image
        # identifiers in this case do not carry any useful information.
        m = self._pattern.match(imagePath)
        simple_m = self._pattern_simple.match(imagePath)

        # First we try the more complex regex
        if m is not None:
            
            # Get and store the base name
            basename = m.group("basename")
            if self._basename == "" or self._basename != basename:
                self._basename = basename

                # The series number is not always defined in the file name.
                # In the regex, the group(2) optionally matches _s{digits};
                # in case group(2) is not None, the actual series number is
                # stored in group(4). 
                if m.group("series") is None:
                    series = 0
                else:
                    series = int("series")

            # Make sure to process only the relevant series
            if series != self._seriesNum:
                return []

            # The time index is also not always specified.
            if m.group("timepoint") is None:
                timepoint = 0
            else:
                timepoint = int(m.group("timepoint"))

            # Plane number is always specified
            if m.group("plane") is None:
                plane = 0
            else:
                plane = int(m.group("plane"))
            
            # Channel number is always specified
            if m.group("channel") is None:
                ch = 0
            else:
                ch = int(m.group(8))
            
        else:
            
            # Try with the simpler regex
            if simple_m is None:
                err = "MICROSCOPYCOMPOSITEDATASETCONFIG::extractImageMetadata(): " + \
                    "unexpected file name " + str(imagePath)
                self._logger.error(err)
                raise Exception(err)

            # Get and store the base name
            basename = simple_m.group("basename")
            if self._basename == "" or self._basename != basename:
                self._basename = basename

            # Series number
            series = 0
            
            # Make sure to process only the relevant series
            if series != self._seriesNum:
                return []

            # Timepoint
            timepoint = 0

            # Plane number is always specified
            if simple_m.group("plane") is None:
                plane = 0
            else:
                plane = int(simple_m.group("plane"))
            
            # Channel number
            ch = 0
            
        # Build the channel code
        channelCode = "SERIES-" + str(series) + "_CHANNEL-" + str(ch)

        if self._DEBUG:
            msg = "Current file = " + imagePath + " has series = " + \
            str(series) + " timepoint = " + str(timepoint) + " plane = " + \
            str(plane) + " channel = " + str(ch) + "; channelCode = " + \
            str(channelCode) 
            self._logger.info(msg)

        # Initialize Metadata array
        Metadata = []

        # Initialize a new ImageMetadata object
        imageMetadata = ImageMetadata();

        # Fill in all information
        imageMetadata.imageIdentifier = imageIdentifiers.get(0) 
        imageMetadata.seriesNumber = series
        imageMetadata.timepoint = timepoint
        imageMetadata.depth = plane
        imageMetadata.channelCode = channelCode
        imageMetadata.tileNumber = 1  # + self._seriesNum
        imageMetadata.well = "IGNORED"

        # Now return the image metadata object in an array
        Metadata.append(imageMetadata)
        return Metadata