diff --git a/bin/ffx.py b/bin/ffx.py index d6e4ba2..261ea88 100755 --- a/bin/ffx.py +++ b/bin/ffx.py @@ -19,7 +19,6 @@ from ffx.show_descriptor import ShowDescriptor from ffx.track_type import TrackType from ffx.video_encoder import VideoEncoder from ffx.track_disposition import TrackDisposition -from ffx.nlmeans_controller import NlmeansController from ffx.process import executeProcess from ffx.helper import filterFilename @@ -27,6 +26,12 @@ from ffx.helper import filterFilename from ffx.constants import DEFAULT_QUALITY, DEFAULT_AV1_PRESET from ffx.constants import DEFAULT_STEREO_BANDWIDTH, DEFAULT_AC3_BANDWIDTH, DEFAULT_DTS_BANDWIDTH, DEFAULT_7_1_BANDWIDTH +from ffx.filter.quality_filter import QualityFilter +from ffx.filter.preset_filter import PresetFilter + +from ffx.filter.nlmeans_filter import NlmeansFilter + + VERSION='0.2.2' @@ -277,8 +282,8 @@ def checkUniqueDispositions(context, mediaDescriptor: MediaDescriptor): @click.option('-v', '--video-encoder', type=str, default=FfxController.DEFAULT_VIDEO_ENCODER, help=f"Target video encoder (vp9 or av1)", show_default=True) -@click.option('-q', '--quality', type=str, default=DEFAULT_QUALITY, help=f"Quality settings to be used with VP9 encoder", show_default=True) -@click.option('-p', '--preset', type=str, default=DEFAULT_AV1_PRESET, help=f"Quality preset to be used with AV1 encoder", show_default=True) +@click.option('-q', '--quality', type=str, default="", help=f"Quality settings to be used with VP9 encoder") +@click.option('-p', '--preset', type=str, default="", help=f"Quality preset to be used with AV1 encoder") @click.option('-a', '--stereo-bitrate', type=int, default=DEFAULT_STEREO_BANDWIDTH, help=f"Bitrate in kbit/s to be used to encode stereo audio streams", show_default=True) @click.option('--ac3', type=int, default=DEFAULT_AC3_BANDWIDTH, help=f"Bitrate in kbit/s to be used to encode 5.1 audio streams", show_default=True) @@ -409,14 +414,6 @@ def convert(ctx, context['resource_limits']['cpu_percent'] = cpu - context['denoiser'] = NlmeansController(parameters = denoise, - strength = denoise_strength, - patchSize = denoise_patch_size, - chromaPatchSize = denoise_chroma_patch_size, - researchWindow = denoise_research_window, - chromaResearchWindow = denoise_chroma_research_window, - useHardware = denoise_use_hw) - context['import_subtitles'] = (subtitle_directory and subtitle_prefix) if context['import_subtitles']: context['subtitle_directory'] = subtitle_directory @@ -494,9 +491,13 @@ def convert(ctx, qualityTokens = quality.split(',') q_list = [q for q in qualityTokens if q.isnumeric()] - ctx.obj['logger'].debug(f"Qualities: {q_list}") + presetTokens = preset.split(',') + p_list = [p for p in presetTokens if p.isnumeric()] + ctx.obj['logger'].debug(f"Presets: {p_list}") + + context['bitrates'] = {} context['bitrates']['stereo'] = str(stereo_bitrate) if str(stereo_bitrate).endswith('k') else f"{stereo_bitrate}k" context['bitrates']['ac3'] = str(ac3) if str(ac3).endswith('k') else f"{ac3}k" @@ -519,8 +520,29 @@ def convert(ctx, tc = TmdbController() if context['use_tmdb'] else None - - ctx.obj['logger'].info(f"\nRunning {len(existingSourcePaths) * len(q_list)} jobs") + qualityKwargs = {QualityFilter.QUALITY_KEY: quality} + qf = QualityFilter(**qualityKwargs) + + presetKwargs = {PresetFilter.PRESET_KEY: preset} + PresetFilter(**presetKwargs) + + denoiseKwargs = {} + if denoise_strength: + denoiseKwargs[NlmeansFilter.STRENGTH_KEY] = denoise_strength + if denoise_patch_size: + denoiseKwargs[NlmeansFilter.PATCH_SIZE_KEY] = denoise_patch_size + if denoise_chroma_patch_size: + denoiseKwargs[NlmeansFilter.CHROMA_PATCH_SIZE_KEY] = denoise_chroma_patch_size + if denoise_research_window: + denoiseKwargs[NlmeansFilter.RESEARCH_WINDOW_KEY] = denoise_research_window + if denoise_chroma_research_window: + denoiseKwargs[NlmeansFilter.CHROMA_RESEARCH_WINDOW_KEY] = denoise_chroma_research_window + if denoise != 'none' or denoiseKwargs: + NlmeansFilter(**denoiseKwargs) + + chainYield = list(qf.getChainYield()) + + ctx.obj['logger'].info(f"\nRunning {len(existingSourcePaths) * len(chainYield)} jobs") jobIndex = 0 @@ -650,18 +672,24 @@ def convert(ctx, if 'se' in targetSuffices.keys(): del targetSuffices['se'] - ctx.obj['logger'].debug(f"fileBasename={sourceFileBasename}") - for q in q_list: + for chainIteration in chainYield: + - if len(q_list) > 1: - targetSuffices['q'] = f"q{q}" + ctx.obj['logger'].debug(f"\nchain iteration: {chainIteration}\n") - ctx.obj['logger'].debug(f"\nRunning job {jobIndex} file={sourcePath} q={q}") + # if len(q_list) > 1: + # targetSuffices['q'] = f"q{q}" + + chainVariant = '-'.join([fy['variant'] for fy in chainIteration]) + + ctx.obj['logger'].debug(f"\nRunning job {jobIndex} file={sourcePath} variant={chainVariant}") jobIndex += 1 + continue + ctx.obj['logger'].debug(f"label={label if label else 'Falsy'}") ctx.obj['logger'].debug(f"sourceFileBasename={sourceFileBasename}") @@ -676,9 +704,15 @@ def convert(ctx, if 'se' in targetSuffices.keys(): targetFilenameTokens += [targetSuffices['se']] - if 'q' in targetSuffices.keys(): - targetFilenameTokens += [targetSuffices['q']] + # if 'q' in targetSuffices.keys(): + # targetFilenameTokens += [targetSuffices['q']] + for filterYield in chainIteration: + + # filterIdentifier = filterYield['identifier'] + # filterParameters = filterYield['parameters'] + # filterSuffices = filterYield['suffices'] + targetFilenameTokens += filterYield['suffices'] #TODO #387 # targetFilename = ((f"{sourceFileBasename}_q{q}" if len(q_list) > 1 else sourceFileBasename) @@ -695,8 +729,7 @@ def convert(ctx, targetPath, targetFormat, context['video_encoder'], - q, - preset) + chainIteration) #TODO: click.confirm('Warning! This file is not compliant to the defined source schema! Do you want to continue?', abort=True) diff --git a/bin/ffx/ffx_controller.py b/bin/ffx/ffx_controller.py index 67951d0..ac83590 100644 --- a/bin/ffx/ffx_controller.py +++ b/bin/ffx/ffx_controller.py @@ -13,6 +13,10 @@ from ffx.track_disposition import TrackDisposition from ffx.constants import DEFAULT_QUALITY, DEFAULT_AV1_PRESET from ffx.constants import DEFAULT_CROP_START, DEFAULT_CROP_LENGTH +from ffx.filter.quality_filter import QualityFilter +from ffx.filter.preset_filter import PresetFilter +from ffx.filter.nlmeans_filter import NlmeansFilter + class FfxController(): @@ -44,8 +48,8 @@ class FfxController(): self.__configurationData = self.__context['config'].getData() # Convenience - self.__niceness = self.__context['resource_limits']['niceness'] if 'resource_limits' in self.__context.keys() and 'niceness' in self.__context['resource_limits'].keys() else 99 - self.__cpuPercent = self.__context['resource_limits']['cpu_percent'] if 'resource_limits' in self.__context.keys() and 'cpu_percent' in self.__context['resource_limits'].keys() else 0 + # self.__niceness = self.__context['resource_limits']['niceness'] if 'resource_limits' in self.__context.keys() and 'niceness' in self.__context['resource_limits'].keys() else 99 + # self.__cpuPercent = self.__context['resource_limits']['cpu_percent'] if 'resource_limits' in self.__context.keys() and 'cpu_percent' in self.__context['resource_limits'].keys() else 0 self.__logger = context['logger'] @@ -242,8 +246,19 @@ class FfxController(): targetPath, targetFormat: str = '', videoEncoder: VideoEncoder = VideoEncoder.VP9, - quality: int = DEFAULT_QUALITY, - preset: int = DEFAULT_AV1_PRESET): + chainIteration: list = []): + # quality: int = DEFAULT_QUALITY, + # preset: int = DEFAULT_AV1_PRESET): + + qualityFilters = [fy for fy in chainIteration if fy['identifier'] == 'quality'] + presetFilters = [fy for fy in chainIteration if fy['identifier'] == 'preset'] + denoiseFilters = [fy for fy in chainIteration if fy['identifier'] == 'nlmeans'] + + quality = qualityFilters[0]['parameters']['quality'] if qualityFilters else QualityFilter.DEFAULT_QUALITY + preset = presetFilters[0]['parameters']['preset'] if presetFilters else PresetFilter.DEFAULT_PRESET + + + denoiseTokens = denoiseFilters[0]['tokens'] if denoiseFilters else [] commandTokens = FfxController.COMMAND_TOKENS + ['-i', sourcePath] @@ -257,7 +272,7 @@ class FfxController(): # Optional tokens commandSequence += self.generateMetadataTokens() - commandSequence += self.__context['denoiser'].generateDenoiseTokens() + commandSequence += denoiseTokens commandSequence += (self.generateAudioEncodingTokens() + self.generateAV1Tokens(int(quality), int(preset)) @@ -309,7 +324,7 @@ class FfxController(): # Optional tokens commandSequence2 += self.generateMetadataTokens() - commandSequence2 += self.__context['denoiser'].generateDenoiseTokens() + commandSequence2 += denoiseTokens commandSequence2 += self.generateVP9Pass2Tokens(int(quality)) + self.generateAudioEncodingTokens() diff --git a/bin/ffx/filter/__init__.py b/bin/ffx/filter/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/bin/ffx/filter/filter.py b/bin/ffx/filter/filter.py new file mode 100644 index 0000000..a71c19f --- /dev/null +++ b/bin/ffx/filter/filter.py @@ -0,0 +1,17 @@ +import itertools + + +class Filter(): + + filterChain: list = [] + + def __init__(self, filter): + + self.filterChain.append(filter) + + def getFilterChain(self): + return self.filterChain + + def getChainYield(self): + for fy in itertools.product(*[f.getYield() for f in self.filterChain]): + yield fy diff --git a/bin/ffx/filter/nlmeans_filter.py b/bin/ffx/filter/nlmeans_filter.py new file mode 100644 index 0000000..4bd442d --- /dev/null +++ b/bin/ffx/filter/nlmeans_filter.py @@ -0,0 +1,162 @@ +import itertools + +from .filter import Filter + + +class NlmeansFilter(Filter): + + IDENTIFIER = 'nlmeans' + + DEFAULT_STRENGTH: float = 2.8 + DEFAULT_PATCH_SIZE: int = 13 + DEFAULT_CHROMA_PATCH_SIZE: int = 9 + DEFAULT_RESEARCH_WINDOW: int = 23 + DEFAULT_CHROMA_RESEARCH_WINDOW: int= 17 + + STRENGTH_KEY = 'strength' + PATCH_SIZE_KEY = 'patch_size' + CHROMA_PATCH_SIZE_KEY = 'chroma_patch_size' + RESEARCH_WINDOW_KEY = 'research_window' + CHROMA_RESEARCH_WINDOW_KEY = 'chroma_research_window' + + + def __init__(self, **kwargs): + + self.__useHardware = kwargs.get('use_hardware', False) + + self.__strengthList = [] + strength = kwargs.get(NlmeansFilter.STRENGTH_KEY, '') + if strength: + strengthTokens = strength.split(',') + for st in strengthTokens: + try: + strengthValue = float(st) + except: + raise ValueError('NlmeansFilter: Strength value has to be of type float') + if strengthValue < 1.0 or strengthValue > 30.0: + raise ValueError('NlmeansFilter: Strength value has to be between 1.0 and 30.0') + self.__strengthList.append(strengthValue) + else: + self.__strengthList = [NlmeansFilter.DEFAULT_STRENGTH] + + self.__patchSizeList = [] + patchSize = kwargs.get(NlmeansFilter.PATCH_SIZE_KEY, '') + if patchSize: + patchSizeTokens = patchSize.split(',') + for pst in patchSizeTokens: + try: + patchSizeValue = int(pst) + except: + raise ValueError('NlmeansFilter: Patch size value has to be of type int') + if patchSizeValue < 0 or patchSizeValue > 99: + raise ValueError('NlmeansFilter: Patch size value has to be between 0 and 99') + if patchSizeValue % 2 == 0: + raise ValueError('NlmeansFilter: Patch size value has to an odd number') + self.__patchSizeList.append(patchSizeValue) + else: + self.__patchSizeList = [NlmeansFilter.DEFAULT_PATCH_SIZE] + + self.__chromaPatchSizeList = [] + chromaPatchSize = kwargs.get(NlmeansFilter.CHROMA_PATCH_SIZE_KEY, '') + if chromaPatchSize: + chromaPatchSizeTokens = chromaPatchSize.split(',') + for cpst in chromaPatchSizeTokens: + try: + chromaPatchSizeValue = int(pst) + except: + raise ValueError('NlmeansFilter: Chroma patch size value has to be of type int') + if chromaPatchSizeValue < 0 or chromaPatchSizeValue > 99: + raise ValueError('NlmeansFilter: Chroma patch value has to be between 0 and 99') + if chromaPatchSizeValue % 2 == 0: + raise ValueError('NlmeansFilter: Chroma patch value has to an odd number') + self.__chromaPatchSizeList.append(chromaPatchSizeValue) + else: + self.__chromaPatchSizeList = [NlmeansFilter.DEFAULT_CHROMA_PATCH_SIZE] + + self.__researchWindowList = [] + researchWindow = kwargs.get(NlmeansFilter.RESEARCH_WINDOW_KEY, '') + if researchWindow: + researchWindowTokens = researchWindow.split(',') + for rwt in researchWindowTokens: + try: + researchWindowValue = int(rwt) + except: + raise ValueError('NlmeansFilter: Research window value has to be of type int') + if researchWindowValue < 0 or researchWindowValue > 99: + raise ValueError('NlmeansFilter: Research window value has to be between 0 and 99') + if researchWindowValue % 2 == 0: + raise ValueError('NlmeansFilter: Research window value has to an odd number') + self.__researchWindowList.append(researchWindowValue) + else: + self.__researchWindowList = [NlmeansFilter.DEFAULT_RESEARCH_WINDOW] + + self.__chromaResearchWindowList = [] + chromaResearchWindow = kwargs.get(NlmeansFilter.CHROMA_RESEARCH_WINDOW_KEY, '') + if chromaResearchWindow: + chromaResearchWindowTokens = chromaResearchWindow.split(',') + for crwt in chromaResearchWindowTokens: + try: + chromaResearchWindowValue = int(crwt) + except: + raise ValueError('NlmeansFilter: Chroma research window value has to be of type int') + if chromaResearchWindowValue < 0 or chromaResearchWindowValue > 99: + raise ValueError('NlmeansFilter: Chroma research window value has to be between 0 and 99') + if chromaResearchWindowValue % 2 == 0: + raise ValueError('NlmeansFilter: Chroma research window value has to an odd number') + self.__chromaResearchWindowList.append(chromaResearchWindowValue) + else: + self.__chromaResearchWindowList = [NlmeansFilter.DEFAULT_CHROMA_RESEARCH_WINDOW] + + super().__init__(self) + + + def getPayload(self, iteration): + + strength = iteration[0] + patchSize = iteration[1] + chromaPatchSize = iteration[2] + researchWindow = iteration[3] + chromaResearchWindow = iteration[4] + + suffices = [] + + if len(self.__strengthList) > 1: + suffices += [f"ds{strength}"] + if len(self.__patchSizeList) > 1: + suffices += [f"dp{patchSize}"] + if len(self.__chromaPatchSizeList) > 1: + suffices += [f"dpc{chromaPatchSize}"] + if len(self.__researchWindowList) > 1: + suffices += [f"dr{researchWindow}"] + if len(self.__chromaResearchWindowList) > 1: + suffices += [f"drc{chromaResearchWindow}"] + + filterName = 'nlmeans_opencl' if self.__useHardware else 'nlmeans' + + payload = {'identifier': NlmeansFilter.IDENTIFIER, + 'parameters': { + 'strength': strength, + 'patch_size': patchSize, + 'chroma_patch_size': chromaPatchSize, + 'research_window': researchWindow, + 'chroma_research_window': chromaResearchWindow + }, + 'suffices': suffices, + 'variant': f"DS{strength}-DP{patchSize}-DPC{chromaPatchSize}" + + f"-DR{researchWindow}-DRC{chromaResearchWindow}", + 'tokens': ['-vf', f"{filterName}=s={strength}" + + f":p={patchSize}" + + f":pc={chromaPatchSize}" + + f":r={researchWindow}" + + f":rc={chromaResearchWindow}"]} + + return payload + + + def getYield(self): + for it in itertools.product(self.__strengthList, + self.__patchSizeList, + self.__chromaPatchSizeList, + self.__researchWindowList, + self.__chromaResearchWindowList): + yield self.getPayload(it) diff --git a/bin/ffx/filter/preset_filter.py b/bin/ffx/filter/preset_filter.py new file mode 100644 index 0000000..0905d24 --- /dev/null +++ b/bin/ffx/filter/preset_filter.py @@ -0,0 +1,54 @@ +import itertools + +from .filter import Filter + + +class PresetFilter(Filter): + + IDENTIFIER = 'preset' + + DEFAULT_PRESET = 5 + + PRESET_KEY = 'preset' + + def __init__(self, **kwargs): + + self.__presetsList = [] + presets = str(kwargs.get(PresetFilter.PRESET_KEY, '')) + if presets: + presetTokens = presets.split(',') + for q in presetTokens: + try: + presetValue = int(q) + except: + raise ValueError('PresetFilter: Preset value has to be of type int') + if presetValue < 0 or presetValue > 13: + raise ValueError('PresetFilter: Preset value has to be between 0 and 13') + self.__presetsList.append(presetValue) + else: + self.__presetsList = [PresetFilter.DEFAULT_PRESET] + + super().__init__(self) + + + def getPayload(self, preset): + + suffices = [] + + if len(self.__presetsList) > 1: + suffices += [f"p{preset}"] + + payload = {'identifier': PresetFilter.IDENTIFIER, + 'parameters': { + 'preset': preset + }, + 'suffices': suffices, + 'variant': f"P{preset}", + 'tokens': []} + + return payload + + + def getYield(self): + for q in self.__presetsList: + yield self.getPayload(q) \ No newline at end of file diff --git a/bin/ffx/filter/quality_filter.py b/bin/ffx/filter/quality_filter.py new file mode 100644 index 0000000..fd36542 --- /dev/null +++ b/bin/ffx/filter/quality_filter.py @@ -0,0 +1,54 @@ +import itertools + +from .filter import Filter + + +class QualityFilter(Filter): + + IDENTIFIER = 'quality' + + DEFAULT_QUALITY = 32 + + QUALITY_KEY = 'quality' + + def __init__(self, **kwargs): + + self.__qualitiesList = [] + qualities = kwargs.get(QualityFilter.QUALITY_KEY, '') + if qualities: + qualityTokens = qualities.split(',') + for q in qualityTokens: + try: + qualityValue = int(q) + except: + raise ValueError('QualityFilter: Quality value has to be of type int') + if qualityValue < 0 or qualityValue > 63: + raise ValueError('QualityFilter: Quality value has to be between 0 and 63') + self.__qualitiesList.append(qualityValue) + else: + self.__qualitiesList = [QualityFilter.DEFAULT_QUALITY] + + super().__init__(self) + + + def getPayload(self, quality): + + suffices = [] + + if len(self.__qualitiesList) > 1: + suffices += [f"q{quality}"] + + payload = {'identifier': QualityFilter.IDENTIFIER, + 'parameters': { + 'quality': quality + }, + 'suffices': suffices, + 'variant': f"Q{quality}", + 'tokens': []} + + return payload + + + def getYield(self): + for q in self.__qualitiesList: + yield self.getPayload(q) \ No newline at end of file diff --git a/bin/ffx/filter/scale_filter.py b/bin/ffx/filter/scale_filter.py new file mode 100644 index 0000000..03174ff --- /dev/null +++ b/bin/ffx/filter/scale_filter.py @@ -0,0 +1,6 @@ +from .filter import Filter + +class ScaleFilter(Filter): + + def __init__(self): + super().__init__(self) diff --git a/bin/ffx/helper.py b/bin/ffx/helper.py index 1978dfb..6d16ea9 100644 --- a/bin/ffx/helper.py +++ b/bin/ffx/helper.py @@ -74,5 +74,6 @@ def filterFilename(fileName: str) -> str: fileName = str(fileName).replace(':', ';') fileName = str(fileName).replace('*', '') fileName = str(fileName).replace("'", '') + fileName = str(fileName).replace("?", '#') return fileName.strip() diff --git a/bin/ffx/nlmeans_controller.py b/bin/ffx/nlmeans_controller.py deleted file mode 100644 index 1de91ca..0000000 --- a/bin/ffx/nlmeans_controller.py +++ /dev/null @@ -1,142 +0,0 @@ -class NlmeansController(): - """ - s: double - - Denoising strength (from 1 to 30) (default 1) - Trade-off between noise removal and detail retention. Comparable to gaussian sigma. - - p: int patch size (from 0 to 99) (default 7) - - Catches larger areas reducing broader noise patterns, but costly - - pc: int patch size for chroma planes (from 0 to 99) (default 0) - - r: int research window (from 0 to 99) (default 15) - - Range to search for comparable patches. - Better filtering but costly - - rc: int research window for chroma planes (from 0 to 99) (default 0) - - Good values to denoise film grain that was subobtimally encoded: - strength: float = 2.8 - patchSize: int = 12 - chromaPatchSize: int = 8 - researchWindow: int = 22 - chromaResearchWindow: int= 16 - """ - - DEFAULT_STRENGTH: float = 2.8 - DEFAULT_PATCH_SIZE: int = 13 - DEFAULT_CHROMA_PATCH_SIZE: int = 9 - DEFAULT_RESEARCH_WINDOW: int = 23 - DEFAULT_CHROMA_RESEARCH_WINDOW: int= 17 - - def __init__(self, - parameters: str = "none", - strength: str = "", - patchSize: str = "", - chromaPatchSize: str = "", - researchWindow: str = "", - chromaResearchWindow: str = "", - useHardware: bool = False): - - self.__isActive = (parameters != "none" - or strength - or patchSize - or chromaPatchSize - or researchWindow - or chromaResearchWindow) - self.__useHardware = useHardware - - parameterTokens = parameters.split(',') - - self.__strengthList = [] - if strength: - strengthTokens = strength.split(',') - for st in strengthTokens: - try: - strengthValue = float(st) - except: - raise ValueError('NlmeansController: Strength value has to be of type float') - if strengthValue < 1.0 or strengthValue > 30.0: - raise ValueError('NlmeansController: Strength value has to be between 1.0 and 30.0') - self.__strengthList.append(strengthValue) - else: - self.__strengthList = [NlmeansController.DEFAULT_STRENGTH] - - self.__patchSizeList = [] - if patchSize: - patchSizeTokens = patchSize.split(',') - for pst in patchSizeTokens: - try: - patchSizeValue = int(pst) - except: - raise ValueError('NlmeansController: Patch size value has to be of type int') - if patchSizeValue < 0 or patchSizeValue > 99: - raise ValueError('NlmeansController: Patch size value has to be between 0 and 99') - if patchSizeValue % 2 == 0: - raise ValueError('NlmeansController: Patch size value has to an odd number') - self.__patchSizeList.append(patchSizeValue) - else: - self.__patchSizeList = [NlmeansController.DEFAULT_PATCH_SIZE] - - self.__chromaPatchSizeList = [] - if chromaPatchSize: - chromaPatchSizeTokens = chromaPatchSize.split(',') - for cpst in chromaPatchSizeTokens: - try: - chromaPatchSizeValue = int(pst) - except: - raise ValueError('NlmeansController: Chroma patch size value has to be of type int') - if chromaPatchSizeValue < 0 or chromaPatchSizeValue > 99: - raise ValueError('NlmeansController: Chroma patch value has to be between 0 and 99') - if chromaPatchSizeValue % 2 == 0: - raise ValueError('NlmeansController: Chroma patch value has to an odd number') - self.__chromaPatchSizeList.append(chromaPatchSizeValue) - else: - self.__chromaPatchSizeList = [NlmeansController.DEFAULT_CHROMA_PATCH_SIZE] - - self.__researchWindowList = [] - if researchWindow: - researchWindowTokens = researchWindow.split(',') - for rwt in researchWindowTokens: - try: - researchWindowValue = int(rwt) - except: - raise ValueError('NlmeansController: Research window value has to be of type int') - if researchWindowValue < 0 or researchWindowValue > 99: - raise ValueError('NlmeansController: Research window value has to be between 0 and 99') - if researchWindowValue % 2 == 0: - raise ValueError('NlmeansController: Research window value has to an odd number') - self.__researchWindowList.append(researchWindowValue) - else: - self.__researchWindowList = [NlmeansController.DEFAULT_RESEARCH_WINDOW] - - self.__chromaResearchWindowList = [] - if chromaResearchWindow: - chromaResearchWindowTokens = chromaResearchWindow.split(',') - for crwt in chromaResearchWindowTokens: - try: - chromaResearchWindowValue = int(crwt) - except: - raise ValueError('NlmeansController: Chroma research window value has to be of type int') - if chromaResearchWindowValue < 0 or chromaResearchWindowValue > 99: - raise ValueError('NlmeansController: Chroma research window value has to be between 0 and 99') - if chromaResearchWindowValue % 2 == 0: - raise ValueError('NlmeansController: Chroma research window value has to an odd number') - self.__chromaResearchWindowList.append(chromaResearchWindowValue) - else: - self.__chromaResearchWindowList = [NlmeansController.DEFAULT_CHROMA_RESEARCH_WINDOW] - - def isActive(self): - return self.__isActive - - def generateDenoiseTokens(self): - filterName = 'nlmeans_opencl' if self.__useHardware else 'nlmeans' - return ['-vf', f"{filterName}=s={self.__strengthList[0]}" - + f":p={self.__patchSizeList[0]}" - + f":pc={self.__chromaPatchSizeList[0]}" - + f":r={self.__researchWindowList[0]}" - + f":rc={self.__chromaResearchWindowList[0]}"] if self.__isActive else [] - diff --git a/bin/filtertest.py b/bin/filtertest.py new file mode 100644 index 0000000..f68cf02 --- /dev/null +++ b/bin/filtertest.py @@ -0,0 +1,9 @@ +from ffx.filter.nlmeans_filter import NlmeansFilter +from ffx.filter.quality_filter import QualityFilter + +q = QualityFilter() +#q = QualityFilter('32,34') +# NlmeansFilter(researchWindow='5,7,9', strength='2.0,3.0,4.0') + +for cy in q.getChainYield(): + print(cy)