def make(self): comps = {} for name, component in self.components.items(): comps[name] = eval(component['class'])() cnf = comps[name].get_config() for key, value in eval(component['config']).items(): cnf[key] = value comps[name].set_config(cnf) return Compound(linkages=self.linkages, **comps)
def make(self): comps = {} for name, component in self.components.items(): comps[name] = eval( component['class'])(config=eval(component['config'])) return Compound(linkages=self.linkages, **comps)
def main(): logging.basicConfig(level=logging.INFO) parser = argparse.ArgumentParser() parser.add_argument('-a', '--audit', action='store_true', help='show processing audit trail') parser.add_argument('-g', '--gamma', action='store_true', help='plot gamma correction curve') parser.add_argument('--histogram', action='store_true', help='plot histogram of output') parser.add_argument('-l', '--linear', action='store_true', help='save "linear light" (not gamma corrected) image') parser.add_argument('--astro', action='store_true', help='set defaults for astrophotography') parser.add_argument('-e', '--exposure', default=0, type=float, metavar='x', help='adjust exposure by x stops') parser.add_argument('-o', '--offset', default=1.7, type=float, metavar='x', help='offset black level by x') parser.add_argument('-c', '--colour', default=1.07, type=float, metavar='x', help='multiply colour by x') parser.add_argument('-f', '--filter_colour', default=0, type=float, metavar='x', help='set colour smoothing radius to x') parser.add_argument('-n', '--noise', default=0, type=float, metavar='x', help='set wavelet denoising threshold to x') parser.add_argument('-r', '--reorient', action='store_true', help='rotate/reflect image data') parser.add_argument('-s', '--sharpen', nargs=3, type=float, metavar=('a', 'r', 't'), help='sharpen with amount a, radius r, threshold t') parser.add_argument('file', nargs='+', help='raw files to be processed') args = parser.parse_args() if args.gamma or args.histogram: from PyQt5 import QtCore, QtWidgets QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_X11InitThreads) app = QtWidgets.QApplication(sys.argv) app.lastWindowClosed.connect(app.quit) if args.gamma: from pyctools.components.io.plotdata import PlotData if args.histogram: from pyctools.components.qt.showhistogram import ShowHistogram for in_file in args.file: if not os.path.exists(in_file): continue print(in_file) in_file = os.path.abspath(in_file) base, ext = os.path.splitext(in_file) if ext != '.CR2': print('Skip non raw') continue out_file = base + 'p.jpg' if os.path.exists(out_file): print('Skip existing', os.path.basename(out_file)) continue md = GExiv2.Metadata() md.open_path(in_file) lens = md.get_tag_string('Exif.Photo.LensModel') aperture = md.get_fnumber() focal_length = md.get_focal_length() iso = md.get_iso_speed() if '10-18' in lens: lens = 'Canon_10_18' elif '18-55' in lens: lens = 'Canon_18_55' elif '18-200' in lens: lens = 'Sigma_18_200' elif '70-300' in lens: lens = 'Sigma_70_300' elif '50' in lens: lens = 'Samyang_500' aperture = 6.3 focal_length = 500 else: print('Skip lens', lens) continue ca_params = get_chromatic_aberration_params(lens, focal_length) comps = { 'reader': RawImageFileReader2(path=in_file, highlight_mode='Blend', demosaic_algorithm='DCB', dcb_iterations=0, dcb_enhance=False, fbdd_noise_reduction='Off', **ca_params), 'rgbtoyuv': RGBtoYUV(matrix='709'), 'sharpen': UnsharpMask(amount=0.3, radius=2.5, threshold=1.0), 'yuvtorgb': YUVtoRGB(matrix='709'), 'gamma': GammaCorrect(gamma='hybrid_log', scale=5, black=args.offset, white=100.0 / (2**args.exposure)), 'quantise': ErrorFeedbackQuantise(), 'writer': ImageFileWriterPIL(path=out_file, options='"quality":95', set_thumbnail=True), } if iso >= 3200: comps['reader'].set_config({ 'fbdd_noise_reduction': 'Full', 'noise_thr': 400 }) elif iso >= 1600: comps['reader'].set_config({ 'fbdd_noise_reduction': 'Full', 'noise_thr': 200 }) elif iso >= 400: comps['reader'].set_config({ 'fbdd_noise_reduction': 'Full', 'noise_thr': 100 }) if args.astro: comps['reader'].set_config({ 'fbdd_noise_reduction': 'Full', 'noise_thr': 300, # force daylight white balance 'use_camera_wb': False, 'user_wb': '2123,1024,1531,1024', }) if args.noise: comps['reader'].set_config({'noise_thr': args.noise}) if lens == 'Samyang_500': comps['sharpen'].set_config({'amount': 0.5}) linkages = { ('reader', 'output'): [('rgbtoyuv', 'input')], ('rgbtoyuv', 'output_Y'): [('sharpen', 'input')], ('rgbtoyuv', 'output_UV'): [('yuvtorgb', 'input_UV')], ('sharpen', 'output'): [('yuvtorgb', 'input_Y')], ('yuvtorgb', 'output'): [('gamma', 'input')], ('gamma', 'output'): [('quantise', 'input')], ('quantise', 'output'): [('writer', 'input'), ('self', 'output')], } if args.reorient: comps['reorient'] = Reorient(orientation='auto') linkages[('reorient', 'output')] = linkages[('reader', 'output')] linkages[('reader', 'output')] = [('reorient', 'input')] vignette_params = get_vignette_params(lens, aperture, focal_length) if vignette_params: comps['vignette'] = VignetteCorrector(**vignette_params) linkages[('vignette', 'output')] = linkages[('reader', 'output')] linkages[('reader', 'output')] = [('vignette', 'input')] if args.gamma: comps['plot'] = PlotData() linkages[('gamma', 'function')] = [('plot', 'input')] if args.histogram: comps['histogram'] = ShowHistogram() linkages[('gamma', 'output')].append(('histogram', 'input')) if args.linear: from pyctools.components.io.imagefilecv import ImageFileWriterCV comps['lin_writer'] = ImageFileWriterCV(path=base + 'l.tiff') comps['lin_writer'].set_config({'16bit': True}) linkages[('yuvtorgb', 'output')].append(('lin_writer', 'input')) if args.colour != 1.0: comps['colour'] = Arithmetic( func='data * pt_float({})'.format(args.colour)) linkages[('colour', 'output')] = linkages[('rgbtoyuv', 'output_UV')] linkages[('rgbtoyuv', 'output_UV')] = [('colour', 'input')] if args.filter_colour > 0: comps['filter'] = UnsharpMask(amount=-1, radius=args.filter_colour, denoise=False) linkages[('filter', 'output')] = linkages[('rgbtoyuv', 'output_UV')] linkages[('rgbtoyuv', 'output_UV')] = [('filter', 'input')] if args.sharpen: a, r, t = args.sharpen comps['sharpen2'] = UnsharpMask(amount=a, radius=r, threshold=t, denoise=True) linkages[('sharpen2', 'output')] = linkages[('yuvtorgb', 'output')] linkages[('yuvtorgb', 'output')] = [('sharpen2', 'input')] graph = Compound(linkages=linkages, **comps) graph.start() if args.gamma or args.histogram: app.exec_() else: try: graph.join(end_comps=True) except KeyboardInterrupt: pass graph.stop() graph.join() if os.path.exists(out_file): # set modified timestamp md = GExiv2.Metadata() md.open_path(out_file) now = datetime.now() tz_offset = (now - datetime.utcnow()).total_seconds() / 60 tz_offset = int(round(tz_offset / 15, 0) * 15) if tz_offset < 0: sign = '-' tz_offset = -tz_offset else: sign = '+' md.set_tag_string('Exif.Image.DateTime', now.strftime('%Y:%m:%d %H:%M:%S')) md.clear_tag('Exif.Photo.SubSecTime') md.set_tag_string( 'Xmp.xmp.ModifyDate', now.strftime('%Y-%m-%dT%H:%M:%S') + sign + '{:02d}:{:02d}'.format(tz_offset // 60, tz_offset % 60)) # set audit trail audit = md.get_tag_string('Xmp.pyctools.audit') audit += '{} = process_raw({})\n'.format( os.path.basename(out_file), os.path.basename(in_file)) params = [] for key, value in vars(args).items(): if key not in ('audit', 'file', 'gamma', 'histogram'): params.append('{}: {}'.format(key, value)) if params: audit += ' ' + ', '.join(params) + '\n' md.set_tag_string('Xmp.pyctools.audit', audit) md.save_file(out_file) if args.audit: print(audit)