def make_window(self): self.update_config() x_tile = self.config['xtile'] y_tile = self.config['ytile'] x_off = self.config['xoff'] y_off = self.config['yoff'] fade = self.config['fade'] # adjust config to suit actual window in_data = self.in_frame.as_numpy(dtype=numpy.float32) if in_data.shape[1] != y_tile: y_off = y_off * in_data.shape[1] // y_tile y_tile = in_data.shape[1] if in_data.shape[2] != x_tile: x_off = x_off * in_data.shape[2] // x_tile x_tile = in_data.shape[2] out_frame = Frame() out_frame.initialise(self.in_frame) audit = out_frame.metadata.get('audit') audit += 'data = InverseWindow(data)\n' audit += ' size: %d x %d, offset: %d x %d\n' % ( y_tile, x_tile, y_off, x_off) audit += ' fade: %s\n' % fade out_frame.metadata.set('audit', audit) result = numpy.empty(in_data.shape, dtype=numpy.float32) x_overlap = x_tile - x_off y_overlap = y_tile - y_off for y in range(y_tile): y0 = y while y0 >= y_off: y0 -= y_off for x in range(x_tile): x0 = x while x0 >= x_off: x0 -= x_off # get window value of this and neighbouring tiles centre = in_data[0, y, x, 0] neighbours = [] for j in range(y0, y_tile, y_off): for i in range(x0, x_tile, x_off): if j == y and i == x: continue neighbours.append(in_data[0, j, i, 0]) if not neighbours: result[0, y, x, 0] = 1.0 / max(centre, 0.000001) elif fade == 'minsnr': result[0, y, x, 0] = centre / ( (centre ** 2) + sum(map(lambda x: x ** 2, neighbours))) elif fade == 'linear': result[0, y, x, 0] = 1.0 / (centre + sum(neighbours)) else: biggest = max(neighbours) if centre > biggest: result[0, y, x, 0] = 1.0 / max(centre, 0.000001) elif centre < biggest: result[0, y, x, 0] = 0.0 else: result[0, y, x, 0] = 0.5 / max(centre, 0.000001) out_frame.data = result self.send('inv_window', out_frame)
def __init__(self, config={}, **kwds): super(ModulateUV, self).__init__(config=config, **kwds) cell = numpy.empty([4, 8, 4, 2], dtype=numpy.float32) # phase is in "quarter cycles" phase = 2.5 # integer part of start is arbitrary v_axis_switch = 1 for z in range(cell.shape[0]): for f in range(2): for y in range(f, cell.shape[1], 2): phase = phase % 4 for x in range(cell.shape[2]): cell[z, y, x, 0] = math.sin(phase * math.pi / 2.0) cell[z, y, x, 1] = math.cos(phase * math.pi / 2.0) * v_axis_switch # 4 fsc sampling, so fsc advances by 1/4 cycle per sample phase += 1 # "quarter line offset" retards by 1/4 cycle per field line phase -= 1 v_axis_switch *= -1 # 313 lines in 1st field, 312 lines in 2nd if f == 0: remainder = 313 - (cell.shape[1] // 2) else: remainder = 312 - (cell.shape[1] // 2) phase -= remainder if remainder % 2: v_axis_switch *= -1 # "25 Hz offset" adds 1/2 cycle per field period phase += 2 cell_frame = Frame() cell_frame.data = cell cell_frame.type = 'cell' audit = cell_frame.metadata.get('audit') audit += 'data = PAL subcarrier modulation cell\n' cell_frame.metadata.set('audit', audit) self.cell(cell_frame)
def Window2D(name, x_tile, y_tile, sym, function_1D, x_params={}, y_params={}): if x_tile == 1: x_win = numpy.array([1.0], dtype=numpy.float32) elif sym: x_win = function_1D(x_tile, **x_params) else: x_win = function_1D(x_tile + 1, **x_params)[:-1] if y_tile == 1: y_win = numpy.array([1.0], dtype=numpy.float32) elif sym: y_win = function_1D(y_tile, **y_params) else: y_win = function_1D(y_tile + 1, **y_params)[:-1] x_win = x_win.reshape((1, 1, -1, 1)) y_win = y_win.reshape((1, -1, 1, 1)) out_frame = Frame() out_frame.data = x_win * y_win out_frame.type = 'win' audit = out_frame.metadata.get('audit') audit += 'data = %sWindow()\n' % name audit += ' size: %d x %d\n' % (y_tile, x_tile) audit += ' symmetric: %s\n' % (str(sym)) extras = [] for key, value in x_params.items(): extras.append('%s: %s' % (key, str(value))) if extras: audit += ' horiz params: %s\n' % (', '.join(extras)) extras = [] for key, value in y_params.items(): extras.append('%s: %s' % (key, str(value))) if extras: audit += ' vert params: %s\n' % (', '.join(extras)) out_frame.metadata.set('audit', audit) return out_frame
def HHIPreFilter(config={}): """HHI pre-interlace filter. A widely used prefilter to prevent line twitter when converting sequential images to interlace. Coefficients taken from: 'Specification of a Generic Format Converter', S. Pigeon, L. Vandendorpe, L. Cuvelier and B. Maison, CEC RACE/HAMLET Deliverable no R2110/WP2/DS/S/006/b1, September 1995. http://www.stephanepigeon.com/Docs/deliv2.pdf """ fil = numpy.array( [-4, 8, 25, -123, 230, 728, 230, -123, 25, 8, -4], dtype=numpy.float32).reshape((-1, 1, 1)) / numpy.float32(1000) resize = Resize(config=config) out_frame = Frame() out_frame.data = fil out_frame.type = 'fil' audit = out_frame.metadata.get('audit') audit += 'data = HHI pre-interlace filter\n' out_frame.metadata.set('audit', audit) resize.filter(out_frame) return resize
def Window2D(name, x_tile, y_tile, function_1D, x_params={}, y_params={}): if x_tile == 1: x_win = numpy.array([1.0], dtype=numpy.float32) else: x_win = function_1D(x_tile, **x_params) if y_tile == 1: y_win = numpy.array([1.0], dtype=numpy.float32) else: y_win = function_1D(y_tile, **y_params) result = numpy.empty([1, y_win.shape[0], x_win.shape[0], 1], dtype=numpy.float32) for y in range(result.shape[1]): for x in range(result.shape[2]): result[0, y, x, 0] = x_win[x] * y_win[y] out_frame = Frame() out_frame.data = result out_frame.type = 'win' audit = out_frame.metadata.get('audit') audit += 'data = %sWindow()\n' % name audit += ' size: %d x %d\n' % (y_tile, x_tile) extras = [] for key, value in x_params.items(): extras.append('%s: %s' % (key, str(value))) if extras: audit += ' horiz params: %s\n' % (', '.join(extras)) extras = [] for key, value in y_params.items(): extras.append('%s: %s' % (key, str(value))) if extras: audit += ' vert params: %s\n' % (', '.join(extras)) out_frame.metadata.set('audit', audit) return out_frame
def GaussianFilterCore(x_sigma=0.0, y_sigma=0.0): """Gaussian filter generator core. Alternative to the :py:class:`GaussianFilter` component that can be used to make a non-reconfigurable resizer:: resize = Resize() resize.filter(GaussianFilterCore(x_sigma=1.5)) ... start(..., resize, ...) ... :keyword float x_sigma: Horizontal standard deviation parameter. :keyword float y_sigma: Vertical standard deviation parameter. :return: A :py:class:`~pyctools.core.frame.Frame` object containing the filter. """ def filter_1D(sigma): alpha = 1.0 / (2.0 * (max(sigma, 0.0001) ** 2.0)) coefs = [] coef = 1.0 while coef > 0.0001: coefs.append(coef) coef = math.exp(-(alpha * (float(len(coefs) ** 2)))) fil_dim = len(coefs) - 1 result = numpy.zeros(1 + (fil_dim * 2), dtype=numpy.float32) for n, coef in enumerate(coefs): result[fil_dim - n] = coef result[fil_dim + n] = coef # normalise result result /= result.sum() return result x_sigma = max(x_sigma, 0.0) y_sigma = max(y_sigma, 0.0) x_fil = filter_1D(x_sigma) y_fil = filter_1D(y_sigma) result = numpy.empty( [y_fil.shape[0], x_fil.shape[0], 1], dtype=numpy.float32) for y in range(y_fil.shape[0]): for x in range(x_fil.shape[0]): result[y, x, 0] = x_fil[x] * y_fil[y] out_frame = Frame() out_frame.data = result out_frame.type = 'fil' audit = out_frame.metadata.get('audit') audit += 'data = GaussianFilter()\n' if x_sigma != 0.0: audit += ' x_sigma: %g\n' % (x_sigma) if y_sigma != 0.0: audit += ' y_sigma: %g\n' % (y_sigma) out_frame.metadata.set('audit', audit) return out_frame
def process_frame(self): self.update_config() x_tile = self.config['xtile'] y_tile = self.config['ytile'] x_off = self.config['xoff'] y_off = self.config['yoff'] fade = self.config['fade'] in_frame = self.input_buffer['input'].get() self.window(in_frame) out_frame = Frame() out_frame.initialise(in_frame) audit = out_frame.metadata.get('audit') audit += 'data = InverseWindow(data)\n' audit += ' size: %d x %d, offset: %d x %d\n' % (y_tile, x_tile, y_off, x_off) audit += ' fade: %s\n' % fade out_frame.metadata.set('audit', audit) in_data = in_frame.as_numpy(dtype=numpy.float32) result = numpy.empty(in_data.shape, dtype=numpy.float32) x_overlap = x_tile - x_off y_overlap = y_tile - y_off for y in range(y_tile): y0 = y while y0 >= y_off: y0 -= y_off for x in range(x_tile): x0 = x while x0 >= x_off: x0 -= x_off # get window value of this and neighbouring tiles centre = in_data[0, y, x, 0] neighbours = [] for j in range(y0, y_tile, y_off): for i in range(x0, x_tile, x_off): if j == y and i == x: continue neighbours.append(in_data[0, j, i, 0]) if not neighbours: result[0, y, x, 0] = 1.0 / max(centre, 0.000001) elif fade == 'minsnr': result[0, y, x, 0] = centre / ( (centre**2) + sum(map(lambda x: x**2, neighbours))) elif fade == 'linear': result[0, y, x, 0] = 1.0 / (centre + sum(neighbours)) else: biggest = max(neighbours) if centre > biggest: result[0, y, x, 0] = 1.0 / max(centre, 0.000001) elif centre < biggest: result[0, y, x, 0] = 0.0 else: result[0, y, x, 0] = 0.5 / max(centre, 0.000001) out_frame.data = result self.inv_window(out_frame)
def __init__(self, config={}, **kwds): super(CtoUV, self).__init__(config=config, **kwds) mat = Frame() mat.data = numpy.array( [[2.02 / 0.886], [1.14 / 0.701]], dtype=numpy.float32) mat.type = 'mat' audit = mat.metadata.get('audit') audit += 'data = PAL -> CbCr matrix\n' audit += ' values: %s\n' % (str(mat.data)) mat.metadata.set('audit', audit) self.matrix(mat)
def __init__(self, config={}, **kwds): super(CtoUV, self).__init__(config=config, **kwds) mat = Frame() mat.data = numpy.array([[2.02 / 0.886], [1.14 / 0.701]], dtype=numpy.float32) mat.type = 'mat' audit = mat.metadata.get('audit') audit += 'data = PAL -> CbCr matrix\n' audit += ' values: %s\n' % (str(mat.data)) mat.metadata.set('audit', audit) self.matrix(mat)
def __init__(self, config={}, **kwds): super(UVtoC, self).__init__(config=config, **kwds) mat = Frame() mat.data = numpy.array( [[2.0 * 0.886 / 2.02, 2.0 * 0.701 / 1.14]], dtype=numpy.float32) mat.type = 'mat' audit = mat.metadata.get('audit') audit += 'data = Modulated CbCr -> PAL chroma matrix\n' audit += ' values: %s\n' % (str(mat.data)) mat.metadata.set('audit', audit) self.matrix(mat)
def make_window(self): self.update_config() x_tile = self.config['xtile'] y_tile = self.config['ytile'] sym = self.config['sym'] combine2D = self.config['combine2D'] function = self.config['function'] alpha = self.config['alpha'] function_1D, has_alpha = self.functions[function] if combine2D == 'square' or x_tile == 1 or y_tile == 1: if x_tile == 1: x_win = numpy.array([1.0]) elif sym: x_win = function_1D(x_tile, alpha) else: x_win = function_1D(x_tile + 1, alpha)[:-1] if y_tile == 1: y_win = numpy.array([1.0]) elif sym: y_win = function_1D(y_tile, alpha) else: y_win = function_1D(y_tile + 1, alpha)[:-1] x_win = x_win.reshape((1, 1, -1, 1)) y_win = y_win.reshape((1, -1, 1, 1)) window = x_win * y_win else: xc, yc = x_tile // 2, y_tile // 2 if sym: xc, yc = xc - 0.5, yc - 0.5 func_win = numpy.zeros((2049,), dtype=pt_float) func_win[0:1025] = function_1D(2049, alpha)[1024:] window = numpy.empty((1, y_tile, x_tile, 1), dtype=pt_float) for y in range(y_tile): for x in range(x_tile): window[0, y, x, 0] = math.sqrt((((x - xc) / x_tile) ** 2) + (((y - yc) / y_tile) ** 2)) if combine2D == 'round2': window /= math.sqrt(2.0) window = numpy.interp( window, numpy.linspace(0, 1.0, func_win.shape[0]), func_win) out_frame = Frame() out_frame.data = window.astype(pt_float) out_frame.type = 'win' audit = out_frame.metadata.get('audit') audit += 'data = %sWindow()\n' % function audit += ' size: %d x %d\n' % (y_tile, x_tile) audit += ' symmetric: %s\n' % str(sym) if has_alpha: audit += ' alpha: %g\n' % alpha out_frame.metadata.set('audit', audit) self.send('output', out_frame)
def GaussianFilterCore(x_sigma=0.0, y_sigma=0.0): """ :keyword float x_sigma: Horizontal standard deviation parameter. :keyword float y_sigma: Vertical standard deviation parameter. :return: A :py:class:`~pyctools.core.frame.Frame` object containing the filter. """ def filter_1D(sigma): alpha = 1.0 / (2.0 * (max(sigma, 0.0001)**2.0)) coefs = [] coef = 1.0 while coef > 0.0001: coefs.append(coef) coef = math.exp(-(alpha * (float(len(coefs)**2)))) fil_dim = len(coefs) - 1 result = numpy.zeros(1 + (fil_dim * 2), dtype=numpy.float32) for n, coef in enumerate(coefs): result[fil_dim - n] = coef result[fil_dim + n] = coef # normalise result result /= result.sum() return result x_sigma = max(x_sigma, 0.0) y_sigma = max(y_sigma, 0.0) x_fil = filter_1D(x_sigma) y_fil = filter_1D(y_sigma) result = numpy.empty([y_fil.shape[0], x_fil.shape[0], 1], dtype=numpy.float32) for y in range(y_fil.shape[0]): for x in range(x_fil.shape[0]): result[y, x, 0] = x_fil[x] * y_fil[y] out_frame = Frame() out_frame.data = result out_frame.type = 'fil' audit = out_frame.metadata.get('audit') audit += 'data = GaussianFilter()\n' if x_sigma != 0.0: audit += ' x_sigma: %g\n' % (x_sigma) if y_sigma != 0.0: audit += ' y_sigma: %g\n' % (y_sigma) out_frame.metadata.set('audit', audit) return out_frame
def __init__(self, config={}, **kwds): super(FTFilterUV_2Dthresh, self).__init__(xtile=32, ytile=16, mode='2Dthresh', config=config, **kwds) threshold = Frame() threshold.data = numpy.array( [[6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6]], dtype=numpy.float32) / numpy.float32(10.0) threshold.type = 'thresh' audit = threshold.metadata.get('audit') audit += 'data = transform PAL decoder thresholds\n' threshold.metadata.set('audit', audit) self.threshold(threshold)
def on_start(self): # read file self.update_config() path = self.config['path'] out_frame = Frame() image = cv2.imread(path, cv2.IMREAD_UNCHANGED) # scale data if image.dtype == numpy.uint8: pass elif image.dtype == numpy.uint16: image = image.astype(numpy.float32) / numpy.float32(2 ** 8) else: self.logger.error('Cannot handle %s data type', str(image.dtype)) self.stop() return # rearrange components if image.shape[2] == 4: # RGBA image B = image[:, :, 0] G = image[:, :, 1] R = image[:, :, 2] A = image[:, :, 3] image = numpy.dstack((R, G, B, A)) out_frame.type = 'RGBA' elif image.shape[2] == 3: # RGB image B = image[:, :, 0] G = image[:, :, 1] R = image[:, :, 2] image = numpy.dstack((R, G, B)) out_frame.type = 'RGB' elif image.shape[2] == 1: out_frame.type = 'Y' else: out_frame.type = '???' # send output frame out_frame.data = image out_frame.frame_no = 0 out_frame.metadata.from_file(path) audit = out_frame.metadata.get('audit') audit += 'data = {}\n'.format(path) out_frame.metadata.set('audit', audit) self.send('output', out_frame) # shut down pipeline self.stop()
def __init__(self, config={}, **kwds): super(FTFilterUV_2Dthresh, self).__init__( xtile=32, ytile=16, mode='2Dthresh', config=config, **kwds) threshold = Frame() threshold.data = numpy.array( [[6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6], [6, 6, 6, 6, 6]], dtype=numpy.float32) / numpy.float32(10.0) threshold.type = 'thresh' audit = threshold.metadata.get('audit') audit += 'data = transform PAL decoder thresholds\n' threshold.metadata.set('audit', audit) self.threshold(threshold)
def gen_process(self): # wait for self.output to be connected while self.output.__self__ == self: yield 1 time.sleep(0.01) # read file self.update_config() path = self.config['path'] out_frame = Frame() image = PIL.Image.open(path) # send output frame out_frame.data = image out_frame.type = image.mode out_frame.frame_no = 0 out_frame.metadata.from_file(path) audit = out_frame.metadata.get('audit') audit += 'data = %s\n' % path out_frame.metadata.set('audit', audit) self.output(out_frame) # shut down pipeline self.output(None) self.stop()
def on_set_config(self): super(ModulateUV, self).on_set_config() self.update_config() # phase is in "quarter cycles" phase = float(self.config['sc_phase']) + 0.5 v_axis_switch = int(self.config['VAS_phase']) cell = numpy.empty([4, 8, 4, 2], dtype=numpy.float32) for z in range(cell.shape[0]): for f in range(2): for y in range(f, cell.shape[1], 2): phase = phase % 4 for x in range(cell.shape[2]): cell[z, y, x, 0] = math.sin(phase * math.pi / 2.0) cell[z, y, x, 1] = math.cos( phase * math.pi / 2.0) * v_axis_switch # 4 fsc sampling, so fsc advances by 1/4 cycle per sample phase += 1 # "quarter line offset" retards by 1/4 cycle per field line phase -= 1 v_axis_switch *= -1 # 313 lines in 1st field, 312 lines in 2nd if f == 0: remainder = 313 - (cell.shape[1] // 2) else: remainder = 312 - (cell.shape[1] // 2) phase -= remainder if remainder % 2: v_axis_switch *= -1 # "25 Hz offset" adds 1/2 cycle per field period phase += 2 cell_frame = Frame() cell_frame.data = cell cell_frame.type = 'cell' audit = cell_frame.metadata.get('audit') audit += 'data = PAL subcarrier modulation cell\n' cell_frame.metadata.set('audit', audit) self.cell(cell_frame)
def on_start(self): # read file self.update_config() path = self.config['path'] with Raw(filename=path) as raw: raw.options.auto_brightness = False raw.options.rotation = 0 raw.options.use_camera_profile = self.config['use_camera_profile'] raw.options.brightness = self.config['brightness'] raw.options.highlight_mode = getattr( highlight_modes, self.config['highlight_mode']) raw.options.chromatic_aberration = ( self.config['red_scale'], self.config['blue_scale']) if self.config['crop']: w, h = Metadata().from_file(path).image_size() x = (raw.metadata.width - w) // 2 y = (raw.metadata.height - h) // 2 raw.options.cropbox = x, y, w, h raw.options.gamma = getattr(gamma_curves, self.config['gamma']) raw.options.colorspace = getattr( colorspaces, self.config['colourspace']) raw.options.interpolation = getattr( interpolation, self.config['interpolation']) raw.options.bps = (8, 16)[self.config['16bit']] noise_threshold = self.config['noise_threshold'] if noise_threshold != 0: raw.options.noise_threshold = noise_threshold wb = { 'auto' : self.config['wb_auto'], 'camera' : self.config['wb_camera'], } if self.config['wb_greybox']: wb['greybox'] = eval('(' + self.config['wb_greybox'] + ')') if self.config['wb_rgbg']: wb['rgbg'] = eval('(' + self.config['wb_rgbg'] + ')') raw.options.white_balance = WhiteBalance(**wb) data = raw.to_buffer() if self.config['16bit']: image = numpy.frombuffer(data, dtype=numpy.uint16) clip_count = numpy.count_nonzero( numpy.greater_equal(image, (2 ** 16) - 1)) image = image.astype(pt_float) / pt_float(256.0) else: image = numpy.frombuffer(data, dtype=numpy.uint8) clip_count = numpy.count_nonzero( numpy.greater_equal(image, (2 ** 8) - 1)) if clip_count > 0: print('Pixels at clipping limit:', clip_count) image = image.reshape((raw.metadata.height, raw.metadata.width, 3)) out_frame = Frame() # send output frame out_frame.data = image out_frame.type = 'RGB' out_frame.frame_no = 0 out_frame.metadata.from_file(path) audit = out_frame.metadata.get('audit') audit += 'data = %s\n' % path out_frame.metadata.set('audit', audit) self.send('output', out_frame) # shut down pipeline self.stop()
def FilterGeneratorCore(x_up=1, x_down=1, x_ap=1, x_cut=100, y_up=1, y_down=1, y_ap=1, y_cut=100): """ :keyword int x_up: Horizontal up-conversion factor. :keyword int x_down: Horizontal down-conversion factor. :keyword int x_ap: Horizontal filter aperture. :keyword int x_cut: Horizontal cut frequency adjustment. :keyword int y_up: Vertical up-conversion factor. :keyword int y_down: Vertical down-conversion factor. :keyword int y_ap: Vertical filter aperture. :keyword int y_cut: Vertical cut frequency adjustment. :return: A :py:class:`~pyctools.core.frame.Frame` object containing the filter. """ def filter_1D(up, down, ap, cut_adj): nyquist_freq = float(min(up, down)) / float(2 * up * down) cut_adj = float(cut_adj) / 100.0 coefs = [] n = 1 while True: theta_1 = float(n) * math.pi * 2.0 * nyquist_freq theta_2 = theta_1 * 2.0 / float(ap) if theta_2 >= math.pi: break theta_1 *= cut_adj coef = math.sin(theta_1) / theta_1 win = 0.5 * (1.0 + math.cos(theta_2)) coef = coef * win if abs(coef) < 1.0e-16: coef = 0.0 coefs.append(coef) n += 1 fil_dim = len(coefs) result = numpy.ones(1 + (fil_dim * 2), dtype=numpy.float32) n = 1 for coef in coefs: result[fil_dim - n] = coef result[fil_dim + n] = coef n += 1 # normalise gain of each phase phases = (up * down) // min(up, down) for n in range(phases): result[n::phases] /= result[n::phases].sum() result /= float(phases) return result x_up = max(x_up, 1) x_down = max(x_down, 1) x_ap = max(x_ap, 1) x_cut = max(x_cut, 1) y_up = max(y_up, 1) y_down = max(y_down, 1) y_ap = max(y_ap, 1) y_cut = max(y_cut, 1) x_fil = filter_1D(x_up, x_down, x_ap, x_cut) y_fil = filter_1D(y_up, y_down, y_ap, y_cut) result = numpy.empty([y_fil.shape[0], x_fil.shape[0], 1], dtype=numpy.float32) for y in range(y_fil.shape[0]): for x in range(x_fil.shape[0]): result[y, x, 0] = x_fil[x] * y_fil[y] out_frame = Frame() out_frame.data = result out_frame.type = 'fil' audit = out_frame.metadata.get('audit') audit += 'data = FilterGenerator()\n' if x_up != 1 or x_down != 1 or x_ap != 1: audit += ' x_up: %d, x_down: %d, x_ap: %d, x_cut: %d%%\n' % ( x_up, x_down, x_ap, x_cut) if y_up != 1 or y_down != 1 or y_ap != 1: audit += ' y_up: %d, y_down: %d, y_ap: %d, y_cut: %d%%\n' % ( y_up, y_down, y_ap, y_cut) out_frame.metadata.set('audit', audit) return out_frame
def FilterGeneratorCore(x_up=1, x_down=1, x_ap=1, x_cut=100, y_up=1, y_down=1, y_ap=1, y_cut=100): """Classic filter generator core. Alternative to the :py:class:`FilterGenerator` component that can be used to make a non-reconfigurable resizer:: resize = Resize(xup=2) resize.filter(FilterGeneratorCore(xup=2, xaperture=16)) ... start(..., resize, ...) ... :keyword int x_up: Horizontal up-conversion factor. :keyword int x_down: Horizontal down-conversion factor. :keyword int x_ap: Horizontal filter aperture. :keyword int x_cut: Horizontal cut frequency adjustment. :keyword int y_up: Vertical up-conversion factor. :keyword int y_down: Vertical down-conversion factor. :keyword int y_ap: Vertical filter aperture. :keyword int y_cut: Vertical cut frequency adjustment. :return: A :py:class:`~pyctools.core.frame.Frame` object containing the filter. """ def filter_1D(up, down, ap, cut_adj): nyquist_freq = float(min(up, down)) / float(2 * up * down) cut_adj = float(cut_adj) / 100.0 coefs = [] n = 1 while True: theta_1 = float(n) * math.pi * 2.0 * nyquist_freq theta_2 = theta_1 * 2.0 / float(ap) if theta_2 >= math.pi: break theta_1 *= cut_adj coef = math.sin(theta_1) / theta_1 win = 0.5 * (1.0 + math.cos(theta_2)) coef = coef * win if abs(coef) < 1.0e-16: coef = 0.0 coefs.append(coef) n += 1 fil_dim = len(coefs) result = numpy.ones(1 + (fil_dim * 2), dtype=numpy.float32) n = 1 for coef in coefs: result[fil_dim - n] = coef result[fil_dim + n] = coef n += 1 # normalise gain of each phase phases = (up * down) // min(up, down) for n in range(phases): result[n::phases] /= result[n::phases].sum() result /= float(phases) return result x_up = max(x_up, 1) x_down = max(x_down, 1) x_ap = max(x_ap, 1) x_cut = max(x_cut, 1) y_up = max(y_up, 1) y_down = max(y_down, 1) y_ap = max(y_ap, 1) y_cut = max(y_cut, 1) x_fil = filter_1D(x_up, x_down, x_ap, x_cut) y_fil = filter_1D(y_up, y_down, y_ap, y_cut) result = numpy.empty( [y_fil.shape[0], x_fil.shape[0], 1], dtype=numpy.float32) for y in range(y_fil.shape[0]): for x in range(x_fil.shape[0]): result[y, x, 0] = x_fil[x] * y_fil[y] out_frame = Frame() out_frame.data = result out_frame.type = 'fil' audit = out_frame.metadata.get('audit') audit += 'data = FilterGenerator()\n' if x_up != 1 or x_down != 1 or x_ap != 1: audit += ' x_up: %d, x_down: %d, x_ap: %d, x_cut: %d%%\n' % ( x_up, x_down, x_ap, x_cut) if y_up != 1 or y_down != 1 or y_ap != 1: audit += ' y_up: %d, y_down: %d, y_ap: %d, y_cut: %d%%\n' % ( y_up, y_down, y_ap, y_cut) out_frame.metadata.set('audit', audit) return out_frame