Example #1
0
	def getTimecodeSync(self, timecode, tcAttrName, attrs, fps, timecodeFps, timecodeMultiplier, offset=0):
		tcSyncTime = None
		if timecode is not None and tcAttrName in attrs and attrs[tcAttrName]:
			tcSyncTime = self.attr('timecode', atLocation=attrs[tcAttrName])
			if tcSyncTime is not None:
				tcSyncValue = Timecode.TCFtoInt(tcSyncTime, fps)
				try:
					diff = Timecode.TCSub(tcSyncTime, timecode, timecodeFps)
					offset += Timecode.TCFtoInt(diff, timecodeFps) * timecodeMultiplier
				except Exception as e:
					self.logger.error('Error calculating timecode difference: %s' % str(e))
					return tcSyncTime, -1
					# import traceback
					# traceback.print_exc()

		return tcSyncTime, offset
Example #2
0
    def initialise(self, interface, attrs):
        directory = self.resolvePath(attrs['directory'])
        if not directory: return False

        prefix = attrs['prefix']
        prefixFilename = self.resolvePath(attrs['prefixFilename'])
        if prefix and not prefixFilename: return

        calibration = attrs['calibration']
        calibrationFilename = self.resolvePath(attrs['calibrationFilename'])
        calibrationLocation = self.resolvePath(attrs['calibrationLocation'])
        if calibration and (not calibrationFilename
                            and not calibrationLocation):
            return False

        movieFilenames = []
        try:
            for file in os.listdir(directory):
                if prefixFilename and not file.startswith(prefixFilename):
                    continue
                if file.endswith('.avi') or file.endswith(
                        '.mov') or file.endswith('mp4'):
                    movieFilenames.append(os.path.join(directory, file))
        except WindowsError as e:
            self.logger.error('Could not find videos: % s' % str(e))

        if not movieFilenames:
            # TODO: Here we'll have to clear the cameras etc.
            return False

        # Windows will produce a wonky order, i.e. 1, 10, 11, .., 2, 3, ..
        # Use natural sorting to rectify
        movieFilenames.sort(key=self.alphaNumKey)

        self.camera_ids = []
        self.camera_names = []
        self.movies = []
        self.mats = []
        vheights = []
        vwidths = []
        timecodes = []
        hasTimecode = False
        useTimecode = attrs['useTimecode'] if 'useTimecode' in attrs else True

        offset = attrs['offset']
        if 'offsets' in attrs and attrs['offsets']:
            offsets = eval(attrs['offsets'])
        else:
            offsets = [offset] * len(movieFilenames)

        for ci, mf in enumerate(movieFilenames):
            self.logger.info('Loading MovieReader: %s' % mf)
            movieData = MovieReader.open_file(mf,
                                              audio=False,
                                              frame_offset=offsets[ci])

            if movieData['vbuffer'] is not None:
                self.movies.append(movieData)

                self.timecodeOffsets.append(0)
                if 'timecode' in movieData and movieData['timecode']:
                    hasTimecode = True
                    timecodes.append(movieData['timecode'])

        # Make sure we have all the cameras before continuing
        if len(self.movies) != len(movieFilenames):
            self.logger.error('Could not load all movies in sequence')
            return

        # Make sure we have as many time codes as movies (if we have any)
        if hasTimecode and len(self.movies) != len(timecodes):
            self.logger.error('Not all movie files have a time code')
            return

        # See if we can get the offsets using the time codes
        if hasTimecode and useTimecode:
            print 'Video timecodes:', timecodes
            fps_all = [round(m['fps']) for m in self.movies]
            print 'FPS:', fps_all
            timecodeValues = [
                Timecode.TCFtoInt(tc, fps)
                for tc, fps in zip(timecodes, fps_all)
            ]
            tcOrderDesc = [
                timecodes.index(tc) for tc in sorted(timecodes, reverse=True)
            ]

            # Set the first offset to 0
            firstTcIndex = tcOrderDesc[0]
            self.timecodeOffsets[firstTcIndex] = 0
            largestTc = timecodes[firstTcIndex]
            offsetStartIndex = 1

            # We can also get the timecode destination from an incoming location, e.g. 2D detections
            if 'timecodeLocation' in attrs and attrs['timecodeLocation']:
                tcSyncTime = interface.attr(
                    'timecode', atLocation=attrs['timecodeLocation'])
                if tcSyncTime is not None:
                    tcSyncValue = Timecode.TCFtoInt(tcSyncTime, fps_all[0])
                    if tcSyncValue < timecodeValues[firstTcIndex]:
                        self.logger.error(
                            'Sync timecode %s is smaller than video timecodes (%s).'
                            % (tcSyncTime, largestTc))
                        return

                    largestTc = tcSyncTime
                    offsetStartIndex = 0

            self.timecode = largestTc
            self.logger.info('Setting timecode to: %s' % (largestTc))

            # Calculate the offset for each camera to get it up to speed with the target timecode
            # TODO: Replace hard coded timecode fps and multiplier
            timecodeFps, timecodeMultiplier = 25., 2.
            for tcInd in tcOrderDesc[offsetStartIndex:]:
                diff = Timecode.TCSub(largestTc, timecodes[tcInd], timecodeFps)
                self.timecodeOffsets[tcInd] = Timecode.TCFtoInt(
                    diff, timecodeFps) * timecodeMultiplier

        if self.timecodeOffsets:
            print 'Video timecode offsets:', self.timecodeOffsets

        self.camera_ids = [
            'Camera %d' % ci for ci in xrange(len(movieFilenames))
        ]
        self.movies = self.movies

        if not calibrationLocation: calibrationLocation = interface.root()
        if calibrationFilename or interface.hasAttr(
                'mats', atLocation=calibrationLocation):
            if calibrationFilename:
                # TODO: Detect filetype, e.g. .cal and .xcp and handle accordingly
                try:
                    self.mats, rawCalData = OptitrackReader.load_CAL(
                        calibrationFilename)
                    if not self.mats: return False
                except IOError as e:
                    self.logger.error('Could not load calibration file: %s' %
                                      str(e))
                    return False
            else:
                self.mats = interface.attr('mats',
                                           atLocation=calibrationLocation)
                if not self.mats:
                    self.logger.error('Could not find calibration mats: %s' %
                                      calibrationLocation)
                    return False

        else:
            from GCore import Calibrate
            for ci, (cid, md) in enumerate(zip(self.camera_ids, self.movies)):
                if md is not None:
                    self.mats.append(
                        Calibrate.makeUninitialisedMat(
                            ci, (md['vheight'], md['vwidth'])))

        for md in self.movies:
            vheights.append(md['vheight'])
            vwidths.append(md['vwidth'])

        Ps = interface.getPsFromMats(self.mats)
        self.attrs = {
            'vheight': vheights,
            'vwidth': vwidths,
            'camera_ids': self.camera_ids,
            'Ps': Ps,
            'mats': self.mats,
            'colour': eval(attrs['colour'])
        }

        if self.camera_names:
            self.attrs['camera_names'] = self.camera_names

        self.initialised = True
        return True