def coarse_to_fine(I0, I1, solver, downscale=2, nlevel=10, min_size=16, dtype='float32'): """Generic coarse to fine solver. Parameters ---------- I0 : ndarray The first gray scale image of the sequence. I1 : ndarray The second gray scale image of the sequence. solver : callable The solver applyed at each pyramid level. downscale : float The pyramid downscale factor. nlevel : int The maximum number of pyramid levels. min_size : int The minimum size for any dimension of the pyramid levels. dtype : dtype Output data type. Returns ------- flow : ndarray The estimated optical flow components for each axis. """ if I0.shape != I1.shape: raise ValueError("Input images should have the same shape") if np.dtype(dtype).char not in 'efdg': raise ValueError("Only floating point data type are valid" " for optical flow") pyramid = list(zip(get_pyramid(convert(I0, dtype), downscale, nlevel, min_size), get_pyramid(convert(I1, dtype), downscale, nlevel, min_size))) # Initialization to 0 at coarsest level. flow = np.zeros((pyramid[0][0].ndim, ) + pyramid[0][0].shape, dtype=dtype) flow = solver(pyramid[0][0], pyramid[0][1], flow) for J0, J1 in pyramid[1:]: flow = solver(J0, J1, resize_flow(flow, J0.shape)) return flow
def test_range_extra_dtypes(): """Test code paths that are not skipped by `test_range`""" # Add non-standard data types that are allowed by the `convert` function. dtype_range_extra = dtype_range.copy() dtype_range_extra.update({ np.int32: (-2147483648, 2147483647), np.uint32: (0, 4294967295) }) dtype_pairs = [(np.uint8, np.uint32), (np.int8, np.uint32), (np.int8, np.int32), (np.int32, np.int8), (np.float64, np.float32), (np.int32, np.float32)] for dtype_in, dt in dtype_pairs: imin, imax = dtype_range_extra[dtype_in] x = np.linspace(imin, imax, 10).astype(dtype_in) with expected_warnings(['precision loss|sign loss|\A\Z']): y = convert(x, dt) omin, omax = dtype_range_extra[dt] yield (_verify_range, "From %s to %s" % (np.dtype(dtype_in), np.dtype(dt)), y, omin, omax, np.dtype(dt))
def add_noise(self, mean=0, var=0.01): img = np.multiply(self.img, 1. / 255, dtype=np.float64) noise = np.random.normal(mean, var ** 0.5, img.shape) img = convert(img, np.floating) out = img + noise return out
def test_range_extra_dtypes(): """Test code paths that are not skipped by `test_range`""" # Add non-standard data types that are allowed by the `convert` function. dtype_range_extra = dtype_range.copy() dtype_range_extra.update({np.int32: (-2147483648, 2147483647), np.uint32: (0, 4294967295)}) dtype_pairs = [(np.uint8, np.uint32), (np.int8, np.uint32), (np.int8, np.int32), (np.int32, np.int8), (np.float64, np.float32), (np.int32, np.float32)] for dtype_in, dt in dtype_pairs: imin, imax = dtype_range_extra[dtype_in] x = np.linspace(imin, imax, 10).astype(dtype_in) with expected_warnings(['precision loss|sign loss|\A\Z']): y = convert(x, dt) omin, omax = dtype_range_extra[dt] yield (_verify_range, "From %s to %s" % (np.dtype(dtype_in), np.dtype(dt)), y, omin, omax, np.dtype(dt))
def transform_from_corners(im): """ Allow the user to click on the sudoku grid corners, and then crop and warp it to get a squared grid """ # Mark corners (1. Top left, 2. Bottom left, 3. Bottom right, 4. Top right) pl.figure() pl.title( "Click on corners (1. Top left, 2. Bottom left, 3. Bottom right, 4. Top right)" ) pl.imshow(im) pl.gray() x = pl.ginput(4) # Wait on user input clicks pl.close() # Top left, top right, bottom right, bottom left fp = np.array([np.array([p[0], p[1]]) for p in x]) dim = 1000 # New size for the croped grid tp = np.array([[0, 0], [0, dim], [dim, dim], [dim, 0]]) # Compute projective transform, and apply it through warping tform = tf.ProjectiveTransform() tform.estimate(tp, fp) output_shape = (dim, dim) # TOD.O: use scikit-image warp function to apply the transformation #warped = None warped = tf.warp(im, tform, output_shape=output_shape) # Convert result in the right format [0, 255] im = convert(warped, np.uint8) return im
def add_noise(p_img): p_img = np.multiply(p_img, 1.0 / 255, dtype=np.float64) mean, var = 0, 0.01 noise = np.random.normal(mean, var**0.5, p_img.shape) p_img = convert(p_img, np.floating) out = p_img + noise return out
def transform(self, image): result = gray2rgb(image) if self.keep_dtype: result = dtype.convert(result, image.dtype) return result
def test_subclass_conversion(): """Check subclass conversion behavior""" x = np.array([-1, 1]) for dtype in float_dtype_list: x = x.astype(dtype) y = convert(x, np.floating) assert y.dtype == x.dtype
def transform(self, image: np.ndarray): if len(image.shape) != 3: raise ValueError("image.shape != 3 in {!r}".format(self)) result = rgb2gray(image) if self.keep_dtype: result = dtype.convert(result, image.dtype) return result
def test_range_extra_dtypes(dtype_in, dt): """Test code paths that are not skipped by `test_range`""" imin, imax = dtype_range_extra[dtype_in] x = np.linspace(imin, imax, 10).astype(dtype_in) y = convert(x, dt) omin, omax = dtype_range_extra[dt] _verify_range("From %s to %s" % (np.dtype(dtype_in), np.dtype(dt)), y, omin, omax, np.dtype(dt))
def test_float_conversion_dtype(): """Test any convertion from a float dtype to an other.""" x = np.array([-1, 1]) # Test all combinations of dtypes convertions dtype_combin = np.array(np.meshgrid(float_dtype_list, float_dtype_list)).T.reshape(-1, 2) for dtype_in, dtype_out in dtype_combin: x = x.astype(dtype_in) y = convert(x, dtype_out) assert y.dtype == np.dtype(dtype_out)
def imread(record, dtype=None): """Load an image from a WARC record. Parameters ---------- record : WARC Record """ im = _imread.imread_from_blob(record.payload.read()) if dtype is not None: im = convert(im, dtype) return im
def test_range_extra_dtypes(dtype_in, dt): """Test code paths that are not skipped by `test_range`""" imin, imax = dtype_range_extra[dtype_in] x = np.linspace(imin, imax, 10).astype(dtype_in) with expected_warnings(['precision loss|sign loss|\A\Z']): y = convert(x, dt) omin, omax = dtype_range_extra[dt] _verify_range("From %s to %s" % (np.dtype(dtype_in), np.dtype(dt)), y, omin, omax, np.dtype(dt))
def imread(fname, dtype=None): """Load an image from file. Parameters ---------- fname : str Name of input file """ im = _imread.imread(fname) if dtype is not None: im = convert(im, dtype) return im
def find_centroids(img, bkg=None, threshold=None, min_size=0): if bkg is None: bkg = gaussian(img, 10) bkg.astype(np.uint16) img = convert(img-bkg,np.uint8) #<- This changes the execution speed ~5-fold if threshold is None: threshold = mh.otsu(img) # mask = img>threshold # labels = np.array(mh.label(img>threshold)[0]) labels = label(img>threshold) # <- This is faster props = regionprops(labels, img, cache=True) # <- Cache True is faster # num_pixels = [p['filled_area'] for p in props] centroids = [p['centroid'] for p in props if p['filled_area']>=min_size] return centroids
def test_float_conversion_dtype_warns(): """Test that convert issues a warning when called""" from skimage.util.dtype import convert x = np.array([-1, 1]) # Test all combinations of dtypes conversions dtype_combin = np.array(np.meshgrid(float_dtype_list, float_dtype_list)).T.reshape(-1, 2) for dtype_in, dtype_out in dtype_combin: x = x.astype(dtype_in) with expected_warnings(["The use of this function is discouraged"]): y = convert(x, dtype_out) assert y.dtype == np.dtype(dtype_out)
def next_frame(self): hdr = self.fd.readline() if hdr == b"": return [] if hdr[0:5] != b"FRAME": raise Exception("Invalid Y4M Frame") raw_y = self.fd.read(self.width * self.height) raw_u = self.fd.read(self.halfwidth * self.halfheight) raw_v = self.fd.read(self.halfwidth * self.halfheight) y = convert( np.frombuffer(raw_y, dtype='uint8').reshape(self.height, self.width), np.float32) u = resize( convert( np.frombuffer(raw_u, dtype='uint8').reshape(self.halfheight, self.halfwidth), np.float32), (self.height, self.width), 0, 'reflect') v = resize( convert( np.frombuffer(raw_v, dtype='uint8').reshape(self.halfheight, self.halfwidth), np.float32), (self.height, self.width), 0, 'reflect') yuv = np.array([y, u, v]) from skimage.color import yuv2rgb rgb = yuv2rgb(yuv.transpose(1, 2, 0)).transpose(2, 0, 1) #transform = np.array([[1, 0, 1.139883], [1, -0.39464233, -0.580621850], [1, 2.03206, 0]], dtype=np.float32) #rgb = yuv.transpose(1, 2, 0).dot(transform).transpose(2, 0, 1) return rgb
def setup(self, dtype_in, N, order): with warnings.catch_warnings(): warnings.filterwarnings("ignore", "Possible precision loss") self.image = convert(np.random.random((N, N)), dtype=dtype_in) self.tform = SimilarityTransform(scale=1, rotation=np.pi / 10, translation=(0, 4)) self.tform.params = self.tform.params.astype('float32') self.order = order if 'dtype' in inspect.signature(warp).parameters: self.warp = functools.partial(warp, dtype=self.image.dtype) else: # Keep a call to functools to have the same number of python # function calls self.warp = functools.partial(warp)
def hsv_value(image_filter, image, *args, **kwargs): """Return color image by applying `image_filter` on HSV-value of `image`. Note that this function is intended for use with `adapt_rgb`. Parameters ---------- image_filter : function Function that filters a gray-scale image. image : array Input image. Note that RGBA images are treated as RGB. """ # Slice the first three channels so that we remove any alpha channels. hsv = color.rgb2hsv(image[:, :, :3]) value = hsv[:, :, 2].copy() value = image_filter(value, *args, **kwargs) hsv[:, :, 2] = convert(value, hsv.dtype) return color.hsv2rgb(hsv)
def apply_C_filter(image, dll, c_function, filter_size, mode='constant', cval=0): """ Apply a C function based filter on image Parameters ---------- image : 2D array Input image. dll: str or a ctypes dll object If str: A dll name (including full path if not on the default search path). c_function: str or int If str: The name of the variable in the dll pointing to the function. If int: A Function pointer. filter_size : (2,) array Filter shape. mode : str Padding mode. cval : a scalar Padding fill value (applicable is mode == 'const') Returns ------- output : array A 2D array of the same dtype and shape as the input array. """ # A temporary confinment to float32 image = convert(image, np.float32) if type(dll) is str: dll = ctypes.cdll.LoadLibrary(dll) if type(c_function) is str: # pfcn = ctypes.c_voidp.in_dll(dll, c_function).value pfcn = ctypes.cast(getattr(dll, c_function), ctypes.c_void_p).value #pfcn = getattr(dll, c_function) else: pfcn = c_function #pfcn = ctypes.cast(pfcn, ctypes.pointer) # Prepare paded data padded = fiter.gen_filter_matrix(image, filter_size, mode=mode, cval=cval) output = np.empty_like(image) padded.filter_with_C_callback_float(pfcn, output) return output
def resize_image(img, new_width, new_height): """Resize image to a ``new_width`` and ``new_height``. Args: img (np.array): An image. new_width (int): New width. new_height (int): New height. Returns: np.array: A resized image. Examples: >>> img = Image.open('share/Lenna.png') >>> img_resized = resize_image(img, 256, 256) >>> img_resized.shape (256, 256, 3) """ img_new = resize(img, (int(new_width), int(new_height)), anti_aliasing=True) return convert(img_new, dtype=img.dtype)
def image_data(itype, dtype): """Return test image array.""" if itype in ('rgb', 'view'): data = DATA[..., [0, 2, 4]] elif itype == 'rgba': data = DATA[..., [0, 2, 4, -1]] elif itype == 'cmyk': data = DATA[..., [0, 2, 4, 6]] elif itype == 'cmyka': data = DATA[..., [0, 2, 4, 6, -1]] elif itype == 'gray': data = DATA[..., 0:1] elif itype == 'graya': data = DATA[..., [0, -1]] elif itype == 'rrggbbaa': data = numpy.moveaxis(DATA[..., [0, 2, 4, -1]], -1, 0) elif itype == 'rrggbb': data = numpy.moveaxis(DATA[..., [0, 2, 4]], -1, 0) elif itype == 'channels': data = DATA[..., :-1] elif itype == 'channelsa': data = DATA[..., :] elif itype == 'line': data = DATA[0:1, :, 0:1] else: raise ValueError('itype not found') # TODO: replace skimage convert with dtype codec data = convert(data.copy(), dtype) if dtype == 'uint16': # 12-bit data //= 16 if itype == 'view': shape = data.shape temp = numpy.empty((shape[0] + 5, shape[1] + 5, shape[2]), dtype) temp[2:2 + shape[0], 3:3 + shape[1], :] = data data = temp[2:2 + shape[0], 3:3 + shape[1], :] return data
def __new__(cls, array: ndarray, dtype: Optional[Type[Union[np.float64, np.float32, np.float16]]] = None, copy: bool = True, meta: Optional[dict] = None, band_info: Optional[BandInfo] = None, ndim_exp: Optional[int] = None): """Create a SpectralArray from a numpy ndarray and metadata. Args: array: Input data array as numpy ndarray. dtype: Target datatype. Only numpy floats allowed: np.float16, np.float32, np.float64. Default: np.float32 copy: By default, a copy of the input array is forced. If 'False', will try to only use a view of the input array. This might not work in some cases and also depends on the Python interpreter. meta: Meta data dictionary. band_info: :class:`BandInfo` object holding the the spectral band properties. ndim_exp: Number of dimension expected of the array. This is used by inherited classes. Raises: DimensionError(ndim_exp, array.ndim) If number of dimensions of input array does not match the specified ndim_exp option. Returns: SpectralArray """ # Check input types if not isinstance(array, np.ndarray): raise ValueError("SpectralArray expects a numpy array.") # Check number of dimension if ndim_exp is not None and ndim_exp != array.ndim: raise DimensionError(exp=ndim_exp, found=array.ndim) if not (meta is None or isinstance(meta, dict)): raise ValueError("SpectralArray expects meta data to be a dict.") if not (band_info is None or isinstance(band_info, BandInfo)): raise ValueError( "SpectralArray expects BandInfo or None instance.") # Check data size if array.size == 0: raise ValueError( f"Invalid array size. Must have at least one axis.") # Convert dtype to fit standard, this might force a copy if not array.dtype == dtype and dtype is not None: logger.warning(f"Converting type from {array.dtype} to {dtype}.") logger.warning(f"Range will be mapped to (0, 1).") if not copy: logger.warning("Dtype conversion without copying is not " "possible. Ignoring 'copy' option.") # Set default dtype if dtype is None: dtype = np.float32 if dtype in [np.float16, np.float32, np.float64]: conv_data = convert(array, dtype=dtype, force_copy=copy) else: raise ValueError(f"The passed dtype '{dtype}' is invalid. " "Only numpy float types are allowed.") # Get object ob = conv_data.view(cls) # Get number of color channels from last axis ob._numChannels = ob.shape[-1] # Check that BandInfo is compatible with data ob._bandInfo = band_info if ob._bandInfo is not None \ and not ob._numChannels == ob._bandInfo.num_channels: raise ValueError( f"The numbers of channels of the band info object " f"and the numbers of channels of the given data " f"does not match. Found " f"{ob._bandInfo.num_channels} and " f"{ob._numChannels} respectively.") # Set metadata ob._meta = meta if meta is not None else {} return ob
def match_template(image, template, pad_input=False): """Match a template to an image using normalized correlation. The output is an array with values between -1.0 and 1.0, which correspond to the probability that the template is found at that position. Parameters ---------- image : array_like Image to process. template : array_like Template to locate. pad_input : bool If True, pad `image` with image mean so that output is the same size as the image, and output values correspond to the template center. Otherwise, the output is an array with shape `(M - m + 1, N - n + 1)` for an `(M, N)` image and an `(m, n)` template, and matches correspond to origin (top-left corner) of the template. Returns ------- output : ndarray Correlation results between -1.0 and 1.0. For an `(M, N)` image and an `(m, n)` template, the `output` is `(M - m + 1, N - n + 1)` when `pad_input = False` and `(M, N)` when `pad_input = True`. Examples -------- >>> template = np.zeros((3, 3)) >>> template[1, 1] = 1 >>> print template [[ 0. 0. 0.] [ 0. 1. 0.] [ 0. 0. 0.]] >>> image = np.zeros((6, 6)) >>> image[1, 1] = 1 >>> image[4, 4] = -1 >>> print image [[ 0. 0. 0. 0. 0. 0.] [ 0. 1. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. 0. 0.] [ 0. 0. 0. 0. -1. 0.] [ 0. 0. 0. 0. 0. 0.]] >>> result = match_template(image, template) >>> print np.round(result, 3) [[ 1. -0.125 0. 0. ] [-0.125 -0.125 0. 0. ] [ 0. 0. 0.125 0.125] [ 0. 0. 0.125 -1. ]] >>> result = match_template(image, template, pad_input=True) >>> print np.round(result, 3) [[-0.125 -0.125 -0.125 0. 0. 0. ] [-0.125 1. -0.125 0. 0. 0. ] [-0.125 -0.125 -0.125 0. 0. 0. ] [ 0. 0. 0. 0.125 0.125 0.125] [ 0. 0. 0. 0.125 -1. 0.125] [ 0. 0. 0. 0.125 0.125 0.125]] """ if np.any(np.less(image.shape, template.shape)): raise ValueError("Image must be larger than template.") image = convert(image, np.float32) template = convert(template, np.float32) if pad_input: pad_size = tuple(np.array(image.shape) + np.array(template.shape) - 1) pad_image = np.mean(image) * np.ones(pad_size, dtype=np.float32) h, w = image.shape i0, j0 = template.shape i0 /= 2 j0 /= 2 pad_image[i0:i0+h, j0:j0+w] = image image = pad_image result = _template.match_template(image, template) return result