def __init__(self, path, image=None): """Open ROI (.roi) or list of ROIs (.zip) using ijroi modules INPUT: Path to ROI file image: Defines the path to an image associated with the ROIs. Optional. Can be added later""" from read_roi import read_roi_file, read_roi_zip import pims # Import ROI list if path.split('.')[-1] == "zip": self.rois = read_roi_zip(path) # imports a labeled dict elif path.split('.')[-1] == "roi": self.rois = read_roi_file(path) # import single ROI else: # no file extension provided try: self.rois = read_roi_zip(path + '.zip') # imports a labeled dict print('importing list of rois') except FileNotFoundError: # .roi file, not .zip file self.rois = read_roi_file(path + '.roi') # import single ROI print("Opening single ROI...") self.keys = list( self.rois.keys()) # get list of ROI names for referencing in Dict self.attach_image(image) # attach image if specified return
def read_roi(path, roi, subject_roi): roi = read_roi_zip(glob(path + roi + subject_roi + '.zip')[0]) n = len(roi) for i, R in enumerate(roi): x = roi[R]['x'] y = roi[R]['y'] return (n)
def read_rectangular_rois_as_df(rois_path): """ Use the read_roi package to read in the Fiji roi file at rois_path, store information from that roi file in a dataframe, and return the dataframe """ rois_dict = read_roi_zip(rois_path) # Create a dataframe using the crop rois file keys = [key for key in rois_dict.keys()] roi_dfs = [] for key in keys: roi_dict = rois_dict[key] roi_df = pd.DataFrame(roi_dict, index=[key]) roi_dfs.append(roi_df) rois_df = pd.concat(roi_dfs).reset_index(drop=True) # Add position_max so that we can which range of # stack frame positions should use this ROI to find # a cell etc. for index in rois_df.index: if index != np.max(rois_df.index): position_max = rois_df.loc[index + 1, 'position'] - 1 else: position_max = rois_df.loc[index, 'position'] rois_df.loc[index, 'position_max'] = int(position_max) return rois_df
def plot_clusters_in_roi(roi_path, pixel_size, cluster_list, noise=None, save=False, filename=None, show_plot=True, new_figure=True, cluster_marker_size=4): filename, ext = os.path.splitext(roi_path) print(ext) if 'zip' in ext: rois = read_roi_zip(roi_path) else: rois = read_roi_file(roi_path) for roi_id, roi in rois.items(): for k, v in roi.items(): if not isinstance(v, str): roi[k] = float(v) * pixel_size plot_optics_clusters(cluster_list, noise=noise, save=False, filename=None, show_plot=True, new_figure=True, cluster_marker_size=4, roi=roi)
def test_roi2splines(self): # Load test zip. roi = read_roi_zip('ofmc/test/data/Manual_ROIs.zip') # Create splines. spl = rh.roi2splines(roi) self.assertEqual(len(spl), len(roi))
def zip_to_tif(filesource: str, filetarget: str, framesize: tuple = DEFAULT_FRAME_SIZE): """Open a .zip of imagej rois and write them to a tif file Opens imagej rois in \*.zip and writes them to a tif file. Currently does not save the ROI names. Args: filesource(str): File path for ImageJ rois as a zip file filetarget(str): File path to write tif stack of ROIS framesize(tuple, optional): Defaults to DEFAULT_FRAME_SIZE. [description] Returns: None TODO: * imageio tiff writing description seems to break- should write names of ROI as metadata for tiff """ assert isinstance(filesource, str) and filesource.endswith( '.zip' ) and '\\' not in filesource, 'Specify file source as a .zip file as a string using unix style!' assert isinstance(filetarget, str) and filetarget.endswith( '.tif' ) and '\\' not in filetarget, 'Specify file target as a .tif file as a string using unix style!' names, tiffstack = to_stack(read_roi_zip(Path(filesource))) imageio.mimwrite(Path(filetarget), tiffstack.astype(np.uint8)) with open(filetarget + '.names', 'w') as f: f.write(';'.join(names)) return None
def test_plotsplinesderivcolour(self): # Load test zip. roi = read_roi_zip('ofmc/test/data/Manual_ROIs.zip') # Create splines. spl = rh.roi2splines(roi) # Load test image. name = 'ofmc/test/data/DynamicReslice of E2PSB1PMT_10px.tif' img = imageio.imread(name) # Plot image. plt.imshow(img, cmap=cm.gray) # Plot splines. for v in roi: y = roi[v]['y'] # Compute derivative of spline. derivspl = spl[v].derivative() points = np.array([spl[v](y), y]).T.reshape(-1, 1, 2) segments = np.concatenate([points[:-1], points[1:]], axis=1) lc = LineCollection(segments, cmap=cm.coolwarm, norm=plt.Normalize(-2, 2)) lc.set_array(derivspl(y)) lc.set_linewidth(2) plt.gca().add_collection(lc) plt.show()
def __init__(self, path): self.path = path self.raw_rois = read_roi_zip(path) self.region_names = [name for name, data in self.raw_rois.items()] self.rois = [] for r in self.region_names: self.rois.append(ROI(self.raw_rois[r]))
def set_cell_crop_roi_dfs(self, master_cells_df): """ Return a list of DataFrames, one for each cell. The coordinates in each of these DataFrames will be used to crop from the image stacks in set_cropped_cell_stack_list() """ cell_crop_roi_dfs = [] abs_i = 0 for cell_index in master_cells_df.cell_index: # compartment_dir = self.get_compartment_dir(master_cells_df, abs_i) expt_date = int(master_cells_df.date[abs_i]) expt_type = master_cells_df.expt_type[abs_i] cell_rois_fp = f"{compartment_dir}\\{expt_date}_{expt_type}_cell{str(cell_index).zfill(3)}_crop_rois.zip" # cell_rois is an OrderedDict so I split the object up and put it in a dataframe # to get relevant data out of it cell_rois = read_roi_zip(cell_rois_fp) roi_keys = list(cell_rois.keys()) frames = [ cell_rois[roi_key]['position'] - 1 for roi_key in roi_keys ] x_lbs = [cell_rois[roi_key]['left'] for roi_key in roi_keys] x_ubs = [ cell_rois[roi_key]['left'] + cell_rois[roi_key]['width'] for roi_key in roi_keys ] # The y crop boundary settings is a bit weird to me because y increases as you move # down the image, not up. y_ubs = [ cell_rois[roi_key]['top'] + cell_rois[roi_key]['height'] for roi_key in roi_keys ] y_lbs = [cell_rois[roi_key]['top'] for roi_key in roi_keys] width = [cell_rois[roi_key]['width'] for roi_key in roi_keys] height = [cell_rois[roi_key]['height'] for roi_key in roi_keys] cell_rois_df = pd.DataFrame({ 'cell_index': cell_index, 'frame': frames, 'x_lb': x_lbs, 'y_lb': y_lbs, 'x_ub': x_ubs, 'y_ub': y_ubs, 'width': width, 'height': height }) cell_crop_roi_dfs.append(cell_rois_df) abs_i += 1 return cell_crop_roi_dfs
def test_endpoint_error(self): # Load test zip. roi = read_roi_zip('ofmc/test/data/Manual_ROIs.zip') # Create splines. spl = rh.roi2splines(roi) # Load test image. name = 'ofmc/test/data/DynamicReslice of E2PSB1PMT_10px.tif' img = imageio.imread(name) # Create zero velocity field. vel = np.zeros_like(img) m, n = vel.shape # Compute error. err, curve = rh.compute_endpoint_error(vel, roi, spl) # Plot image. plt.imshow(img, cmap=cm.gray) # Plot splines. for v in roi: y = roi[v]['y'] # Compute derivative of spline. derivspl = spl[v].derivative() points = np.array([spl[v](y), y]).T.reshape(-1, 1, 2) segments = np.concatenate([points[:-1], points[1:]], axis=1) lc = LineCollection(segments, cmap=cm.coolwarm, norm=plt.Normalize(-2, 2)) lc.set_array(derivspl(y)) lc.set_linewidth(2) plt.gca().add_collection(lc) # Plot integral curves. y = np.arange(y[0], y[-1] + 1, 1) points = np.array([curve[v], y]).T.reshape(-1, 1, 2) segments = np.concatenate([points[:-1], points[1:]], axis=1) lc = LineCollection(segments, cmap=cm.coolwarm, norm=plt.Normalize(-2, 2)) lc.set_linewidth(2) plt.gca().add_collection(lc) plt.show() # Plot splines. for v in roi: y = roi[v]['y'] y = np.arange(y[0], y[-1] + 1, 1) x = spl[v](y) np.testing.assert_allclose(abs(x[0] - x), err[v])
def tworzenieMaski(ROIS, im, nazwaPliku): im = Image.open(im) ROIS = read_roi_zip(ROIS) #print(len(ROIS)) w, h = im.size maskSum = 0 sumaKrawedzi = 0 iteracja = 0 krawedz = 0 wnetrze = 0 image = 0 images = np.zeros((h,w)) for k in ROIS.values(): x = k.get('x') y = k.get('y') #liczba współrzędnych k-tego ROI n = len(x) #generowanie współrzędnych poligonu i = 0 ListOfCorners = [] for i in range(i,n): ListOfCorners.append((int((y[i])), int((x[i])))) #generowanie masek poligonów poly_path = Path(ListOfCorners) Nx, Ny = np.mgrid[:h, :w] coordinates = np.hstack((Nx.reshape(-1, 1), Ny.reshape(-1, 1))) mask = poly_path.contains_points(coordinates) mask = mask.reshape(h, w) mask = np.array(mask, dtype=bool) mask = 255 * mask mask = np.array(mask, dtype='uint8') er = erozja(mask) dy = dylatacja(mask) krawedz = sumowanieKrawedzi(er,dy) wnetrze = mask - er wnetrze[wnetrze == 255] = 2 krawedz[krawedz == 255] = 1 image = wnetrze + krawedz imageMask = (image != 0) images[imageMask] = image[imageMask] print("\rPostęp: " + str(round(((iteracja+1.0) / len(ROIS)) * 100, 1)), end="%") iteracja += 1 print("\nUkończono przetwarzanie maski, tworzę etykiety i zapisuję do pliku:\n" + "drive/My Drive/Colab Notebooks/Projekt/ROIS/" + nazwaPliku + "_labels.png\n") ImageEtykiety = Image.fromarray(np.uint8(images)) ImageEtykiety.save('drive/My Drive/Colab Notebooks/Projekt/ROIS/' + nazwaPliku + '_labels.png') #print(np.unique(images)) fig = plt.figure() fig.set_size_inches(10, 10) ax1 = fig.add_subplot(1,1,1) ax1.imshow(images*127, cmap='gray') ax1.set_title("MASKA")
def roi_to_arrays(path,image_size): #making roi into numpy arrays with several channels corresponding to the number of rois rois = read_roi_zip(path) coordinates = [[v['x'], v['y']] for k,v in rois.items()] arrays = [] for coor in coordinates: x,y = np.subtract(coor, 1) binary = np.zeros(image_size) binary[x,y] = 1 arrays.append(np.transpose(binary)) return arrays
def readRoiNamesFromPath(path): from read_roi import read_roi_zip import numpy as np import os from apCode import util from apCode.FileTools import findAndSortFilesInDir fn = findAndSortFilesInDir(path, ext='.zip') if len(fn) > 0: ind_best = np.argmax(util.sequenceMatch('RoiSet', fn)) zipName = fn[ind_best] rois = read_roi_zip(os.path.join(path, zipName)) roiNames = np.array(list(rois.keys())) return roiNames
def _load_profiles_from_imagej(self, fn, constant_slice=None, gui=True): """ Read line profiles from Fiji/ImageJ. Parameters ---------- fn : str Filename containing line profiles. constant_slice : int Set slice to a constant value. Useful if ImageJ output is inconsistent. gui: bool flag to update names / send signals to update the gui profile list. """ import zipfile try: import read_roi except (ImportError): raise ImportError( 'Please install the read_roi package (https://pypi.org/project/read-roi/).' ) try: imagej_rois = read_roi.read_roi_zip(fn) except (zipfile.BadZipFile): imagej_rois = read_roi.read_roi_file(fn) for key in imagej_rois.keys(): roi = imagej_rois[key] # Check for a slice val if constant_slice is None: try: slice_val = roi['position'] - 1 except KeyError: slice_val = 0 else: slice_val = constant_slice # x, y transposed in Fiji/ImageJ # Position is 1-indexed in Fiji/ImageJ self.add_line_profile(rois.LineProfile(roi['y1'], roi['x1'], roi['y2'], roi['x2'], slice=slice_val, width=roi['width'], identifier=roi['name'], image_name=self.image_name), update=False) if gui: self.update_names(relabel=True) self._on_list_changed()
def test_plotroi(self): # Load test zip. roi = read_roi_zip('ofmc/test/data/Manual_ROIs.zip') # Load test image. name = 'ofmc/test/data/DynamicReslice of E2PSB1PMT_10px.tif' img = imageio.imread(name) # Plot image. plt.imshow(img, cmap=cm.gray) for v in roi: plt.plot(roi[v]['x'], roi[v]['y'], lw=2) plt.show()
def read_roi(file): try: if get_file_extension(file) == '.zip': roi = read_roi_zip(file) elif get_file_extension(file) == '.roi': roi = read_roi_zip(file) else: print(f'Could not read ROI file for {file}') sys.exit(0) x = [] y = [] for key, value in roi.items(): x.append(int(np.mean(value['x']))) y.append(int(np.mean(value['y']))) success = True return x, y, success except: print(f'Bad ROI file for {file}') success = False return None, None, success
def read_neg_labels(dir_labels, dir_data, type_data=1, if_modify_size=True, if_normalized=True): ''' input: dir_labels: the directory where labels are restored dir_data: the directory where corresponding data are restored type_data: 1(respectively 2) symbols T1 data(respectively T2 data) output: train,test,val data where each element is a ensemble of negative labels in one image ''' train_inds = np.arange(1, 12) val_inds = np.arange(12, 16) train_labels = [] val_labels = [] for root, dirnames, filenames in os.walk(dir_labels): for filename in filenames: ind_brebis = filename[:-6] ind_jour = filename[-5] rois_dict = read_roi_zip(os.path.join(dir_labels, filename)) axis_ens = np.array(rois_dict_to_axis(rois_dict)) type_data = 'T2_TSE_SAG' if type_data == 2 else 'T1_TSE_SAG' dir_a_data = os.path.join( os.path.join(os.path.join(dir_data, 'Brebis' + ind_brebis), ind_jour), type_data) for f_root, _, f_data in os.walk(dir_a_data): im = io.imread(os.path.join(f_root, f_data[0]), as_gray=True) if if_normalized: im = (im - im.mean()) / im.std() break im_rois = np.array(get_rois(im, axis_ens, if_modify_size)) if int(ind_brebis) in train_inds: train_labels.append(im_rois) elif int(ind_brebis) in val_inds: val_labels.append(im_rois) train_labels = np.concatenate(train_labels, axis=0) val_labels = np.concatenate(val_labels, axis=0) return train_labels, val_labels
def synquant_to_pixelmap(filename, size = 1024): from read_roi import read_roi_zip """ This function should take in the output from SynQuant https://www.biorxiv.org/content/10.1101/538769v1 and convert it to a pixelmap Utilizes a package called read_roi to load in the JSON file that is output from SynQuant :param: filename <string> - path to the desired SynQuant output file to be read in and converted to a pixelmap :param: size <int> - value to define the SIZExSIZE area that was fed into the synquant program :return: map <numpy array> - returns a SIZExSIZE numpy array that has 1s in all of the pixel (x,y) locations that came from the output of SynQuant. 0s everywhere else. """ # read in the JSON style SynQuant output file into roi variable roi = read_roi_zip(filename) # initialize blank lists for the x and y coordinates that come from # the SynQuant output xcoord=[] ycoord=[] # loop that goes through all of the synquant output and pulls out the # x and y coordinates and stores them in the respective lists for i in roi.keys(): xcoord=np.append(xcoord,(roi[i]['x'])) ycoord=np.append(ycoord,roi[i]['y']) # convert lists to integer values xcoord=xcoord.astype(int) ycoord=ycoord.astype(int) # initialize SIZExSIZE numpy array of all zeros map = np.zeros((size,size),dtype=int) # loop through the length of the coordinate lists and add each combination # of x and y values to map numpy array for i in range(len(xcoord)): map[xcoord[i]-1,ycoord[i]-1]+=1 return map
def read_roi_position_indices(path): """ Read the .zip or .roi Fiji ROI file at <path> and return the 0 based index for each position in that file (eg position 1 becomes index 0) Return the position indices as a numpy array """ roi_set = read_roi_zip(path) keys = list(roi_set.keys()) # define an array of bud start positions for this cell bud_positions = [] for i in range(0, len(keys)): bud_positions.append(roi_set[keys[i]]['position'] - 1) return np.array(bud_positions)
def __init__(self, path, size=(226, 226), transform=lambda x: x): self.transform = transform with Image.open(path + ".tif") as stack: frames = [] for img in ImageSequence.Iterator(stack): frame = torch.tensor(np.array(img).astype(float)) frames.append(frame.unsqueeze(0)) self.raw_image = torch.cat(frames, dim=0) rois = read_roi_zip(path + ".roi.zip") self.rois = [ torch.tensor(zip(*polygon( roi[1]["x"], roi[1]["y"], shape=(self.raw_image.size(1), self.raw_image.size(2)) )), dtype=torch.long) for roi in rois ]
def marks_from_roizip(roizip): # rois is a dictionary of roi data, key is name of roi rois = read_roi_zip(roizip) # want to get a list/array of x, y, z marks = list() for k, v in rois.items(): x = v['x'][0] y = v['y'][0] z = v['position']['slice'] marks.append([ x, y, z, ]) return np.stack(marks)
def run(self, para=None): ls = read_roi.read_roi_zip(para['path']) img = np.zeros((para['height'], para['width']), dtype=np.int32) for i in ls: current_roi = ls[i] roi_type = current_roi["type"] if roi_type is "freehand": rs, cs = polygon(ls[i]['y'], ls[i]['x'], img.shape) elif roi_type is "oval": rs, cs = ellipse(current_roi["top"]+current_roi["height"]/2, current_roi["left"]+current_roi["width"]/2, current_roi["height"]/2, current_roi["width"]/2) try: ind = int(i) except Exception: ind = int(i.split("-")[-1]) img[rs, cs] = ind self.app.show_img([img], para['name'])
def batch_stats(folder, conditions, use_roi=False): for filename in os.listdir(folder): if filename.endswith('xlsx'): stats_path = os.path.join(folder, filename) basename = os.path.splitext(filename)[0] if use_roi: roi_zip_path = os.path.join(folder, basename + '_roiset.zip') roi_file_path = os.path.join(folder, basename + '_roiset.roi') if os.path.exists(roi_zip_path): rois = read_roi_zip(roi_zip_path) elif os.path.exists(roi_file_path): rois = read_roi_file(roi_file_path) else: raise ValueError(("No ImageJ roi file exists -" "you should put the file in the same" "directory as the data")) stats = [] for roi in rois.keys(): stats.append(import_cluster_stats(stats_path), sheetname=roi) stats_df = pd.concat(stats) else: stats_df = import_cluster_stats(stats_path) fnames = [f for f in listdir(folder) if isfile(join(folder, f))] outpath = os.path.join(folder, 'cluster_statistics_test.xlsx') for condition in conditions: condition_fnames = [ fname for fname in fnames if condition in fname ] cluster_stats = [] for cf in condition_fnames: cluster_stats.append(stats[cf]) cddf = pd.DataFrame(condition_fnames) cddf.columns = ['filename'] csdf = pd.concat(cluster_stats, axis=0) data = pd.concat([cddf, csdf.reset_index(drop=True)], axis=1) statistics.write_stats(stats_path, data, condition)
def test_plotsplines(self): # Load test zip. roi = read_roi_zip('ofmc/test/data/Manual_ROIs.zip') # Create splines. spl = rh.roi2splines(roi) # Load test image. name = 'ofmc/test/data/DynamicReslice of E2PSB1PMT_10px.tif' img = imageio.imread(name) # Plot image. plt.imshow(img, cmap=cm.gray) # Plot splines. for v in roi: xs = np.linspace(max(roi[v]['y'][0], 5), min(roi[v]['y'][-1], 30), 30) plt.plot(spl[v](xs), xs, lw=2) plt.show()
def voronoi(locs_path, roi_path=None, pixel_size=16.0, density_factor=2, min_size=5, show_plot=True, verbose=True): if locs_path.endswith('csv'): # Thunderstorm locs_df = pd.read_csv(locs_path) if roi_path: if roi_path.endswith('zip'): rois = read_roi_zip(roi_path) elif roi_path.endswith('roi'): rois = read_roi_file(roi_path) else: raise ValueError( ("No ImageJ roi file exists -" "you should put the file in the same directory" "as the data and make sure it has the same base" "filename as the localisations.")) else: # use all the localisations but mimic the rois dict data structure dx = locs_df['x [nm]'].max() - locs_df['x [nm]'].min() dy = locs_df['y [nm]'].max() - locs_df['y [nm]'].min() rois = {'image': {'locs': locs_df, 'width': dx, 'height': dy}} for roi_id, roi in rois.items(): vor = build_voronoi(rois[roi_id]['locs'], show_plot=False, verbose=verbose) clusters = voronoi_clustering(vor, density_factor, min_size) if show_plot: plot_voronoi_diagram(clusters['voronoi'], locs_df=clusters['locs']) return clusters else: raise ValueError( "This can only handle data from Thunderstorm at present")
def get_locs_in_rois(ijroi_path, roi_scale, locs): if ijroi_path.endswith('zip'): rois = read_roi_zip(ijroi_path) elif ijroi_path.endswith('roi'): rois = read_roi_file(ijroi_path) else: raise ValueError("No ImageJ roi file exists") for _, roi in rois.items(): for k, v in roi.items(): if not isinstance(v, str): roi[k] = float(v) * roi_scale roi['locs'] = locs[(locs['x'] > roi['left']) & (locs['x'] < roi['left'] + roi['width']) & (locs['y'] > roi['top']) & (locs['y'] < roi['top'] + roi['height'])].reset_index(drop=True) return rois
def read_labels(dir_labels, type_labels, img_height, img_width, tol=0): Y_train_1 = [] Y_train_2 = [] nums = [] for root, dirnames, filenames in os.walk(dir_labels): for filename in filenames: num = filename[0:-4] rois = read_roi_zip(os.path.join(dir_labels, filename)) axis_ens_centre, axis_ens1, axis_ens2 = rois_dict_to_axis(rois) if type_labels == 1: im = make_labels(axis_ens_centre, img_height, img_width, tol) Y_train_1.append(im) if type_labels == 2: im1 = make_labels(axis_ens1, img_height, img_width, tol) im2 = make_labels(axis_ens2, img_height, img_width, tol) im = im1 + im2 Y_train_2.append(im) nums.append(num) Y_train_1 = np.array(Y_train_1) Y_train_2 = np.array(Y_train_2) return Y_train_1, Y_train_2, nums
def roi_to_mask(roi, shape): """ Convert a micromanager roi to a numpy mask. Parameters ---------- roi : str or dict The str to the roi zip folder or an already loaded roi zip. shape : tuple of int The shape of the mask to fill Returns ------- mask : numpy array """ if isinstance(roi, str): roi = read_roi_zip(roi) mask = np.zeros(shape, dtype=bool) for info in roi.values(): if info["type"] == "oval": process_oval(info, mask) return mask
def read_roi_as_df(path): """ Iterate through individual ROIs in the ROI file. Typically a stack of ROIs in time. Each ROI is a dictionary with a key that is the serial number of that ROI and a bunch of values which are also dicts """ roi = read_roi_zip(path) print(path) frame_dfs = [] roi_index = 0 for key, val in roi.items(): print(roi_index) # Cycle through the dictionaries for this ROI # and add the information to a dataframe (roi_df) frame_df = pd.DataFrame(columns=val.keys()) val_types = [type(item) for item in val.values()] print(val['type']) if list in val_types: for k, v in val.items(): # Different dicts in the ROI have different dimensions # that need to be accounted for when population roi_df if type(v) == list and k == 'paths': pass elif type(v) == list and k != 'paths': frame_df[k] = v for k, v in val.items(): if type(v) == int or type(v) == str or type(v) == float: frame_df.loc[:, k] = v frame_df.loc[:, 'roi_index'] = roi_index frame_df.loc[:, 'path'] = path frame_dfs.append(frame_df) roi_index += 1 roi_df = pd.concat(frame_dfs, ignore_index=True) return roi_df
def test_error(self): # Load test zip. roi = read_roi_zip('ofmc/test/data/Manual_ROIs.zip') # Create splines. spl = rh.roi2splines(roi) # Load test image. name = 'ofmc/test/data/DynamicReslice of E2PSB1PMT_10px.tif' img = imageio.imread(name) # Create zero velocity field. vel = np.zeros_like(img) m, n = vel.shape # Compute error. err = rh.compute_error(vel, roi, spl) # Plot splines. for v in roi: y = roi[v]['y'] y = np.arange(y[0], y[-1] + 1, 1) splderiv = spl[v].derivative() np.testing.assert_allclose(abs(splderiv(y) * m / n), err[v])