def func(args): """A function to process each image pair.""" # this line is REQUIRED for multiprocessing to work # always use it in your custom function file_a, file_b, counter = args ##################### # Here goes you code ##################### # read images into numpy arrays frame_a = tools.imread(os.path.join(path, file_a)) frame_b = tools.imread(os.path.join(path, file_b)) frame_a = (frame_a * 1024).astype(np.int32) frame_b = (frame_b * 1024).astype(np.int32) # process image pair with extended search area piv algorithm. u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a, frame_b, \ window_size=64, overlap=32, dt=0.02, search_area_size=128, sig2noise_method='peak2peak') u, v, mask = validation.sig2noise_val(u, v, sig2noise, threshold=1.5) u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) # get window centers coordinates x, y = pyprocess.get_coordinates(image_size=frame_a.shape, search_area_size=128, overlap=32) # save to a file tools.save(x, y, u, v, mask, 'test2_%03d.txt' % counter) tools.display_vector_field('test2_%03d.txt' % counter)
def test_display_vector_field(file_a=_file_a, file_b=_file_b, test_file=_test_file): a = imread(file_a) b = imread(file_b) window_size = 32 overlap = 16 search_area_size = 40 u, v, s2n = extended_search_area_piv(a, b, window_size, search_area_size=search_area_size, overlap=overlap, correlation_method='circular', normalized_correlation=False) x, y = get_coordinates(a.shape, search_area_size=search_area_size, overlap=overlap) x, y, u, v = transform_coordinates(x, y, u, v) mask = np.zeros_like(x) mask[-1,1] = 1 # test of invalid vector plot save(x, y, u, v, mask, 'tmp.txt') fig, ax = plt.subplots(figsize=(6, 6)) display_vector_field('tmp.txt', on_img=True, image_name=file_a, ax=ax) decorators.remove_ticks_and_titles(fig) fig.savefig('./tmp.png') res = compare.compare_images('./tmp.png', test_file, 0.001) assert res is None
def PIV(I0, I1, winsize, overlap, dt): """ Normal PIV """ u0, v0, sig2noise = pyprocess.extended_search_area_piv( I0.astype(np.int32), I1.astype(np.int32), window_size=winsize, overlap=overlap, dt=dt, search_area_size=winsize, sig2noise_method='peak2peak', ) # get x, y x, y = pyprocess.get_coordinates(image_size=I0.shape, search_area_size=winsize, overlap=overlap, window_size=winsize) u1, v1, mask_s2n = validation.sig2noise_val( u0, v0, sig2noise, threshold=1.05, ) # replace_outliers u2, v2 = filters.replace_outliers( u1, v1, method='localmean', max_iter=3, kernel_size=3, ) # median filter smoothing u3 = medfilt2d(u2, 3) v3 = medfilt2d(v2, 3) return x, y, u3, v3
def PIV1(I0, I1, winsize, overlap, dt, smooth=True): u0, v0 = pyprocess.extended_search_area_piv(I0.astype(np.int32), I1.astype(np.int32), window_size=winsize, overlap=overlap, dt=dt, search_area_size=winsize) x, y = pyprocess.get_coordinates(image_size=I0.shape, search_area_size=winsize, window_size=winsize, overlap=overlap) if smooth == True: u1 = smoothn(u0)[0] v1 = smoothn(v0)[0] frame_data = pd.DataFrame(data=np.array( [x.flatten(), y.flatten(), u1.flatten(), v1.flatten()]).T, columns=['x', 'y', 'u', 'v']) else: frame_data = pd.DataFrame(data=np.array( [x.flatten(), y.flatten(), u0.flatten(), v0.flatten()]).T, columns=['x', 'y', 'u', 'v']) return frame_data
def doPIV(frame_a_color, frame_b_color, dT=1.0, win_size=64, overlap=32, searchArea=64, apply_clahe=False): frame_a = cv2.cvtColor(frame_a_color, cv2.COLOR_BGR2GRAY) frame_b = cv2.cvtColor(frame_b_color, cv2.COLOR_BGR2GRAY) if (apply_clahe is True): clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(12, 12)) frame_a = clahe.apply(frame_a) frame_b = clahe.apply(frame_b) # u, v, sig2noise = openpiv.process.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size = win_size, overlap = overlap, dt = dT, search_area_size = searchArea, sig2noise_method='peak2peak' ) u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), corr_method='fft', window_size=win_size, overlap=overlap, dt=dT, search_area_size=searchArea, sig2noise_method='peak2peak') x, y = openpiv.process.get_coordinates(image_size=frame_a.shape, window_size=win_size, overlap=overlap) return x, y, u, v, sig2noise
def piv_example(): """ PIV example uses examples/test5 vortex PIV data to show the main principles piv(im1,im2) will create a tmp.vec file with the vector filed in pix/dt (dt=1) from two images, im1,im2 provided as full path filenames (TIF is preferable) """ # if im1 is None and im2 is None: im1 = pkg.resource_filename("openpiv", "examples/test5/frame_a.tif") im2 = pkg.resource_filename("openpiv", "examples/test5/frame_b.tif") frame_a = tools.imread(im1) frame_b = tools.imread(im2) frame_a[0:32, 512 - 32:] = 255 images = [] images.extend([frame_a, frame_b]) fig, ax = plt.subplots() # ims is a list of lists, each row is a list of artists to draw in the # current frame; here we are just animating one artist, the image, in # each frame ims = [] for i in range(2): im = ax.imshow(images[i % 2], animated=True, cmap=plt.cm.gray) ims.append([im]) _ = animation.ArtistAnimation(fig, ims, interval=500, blit=False, repeat_delay=0) plt.show() # import os vel = pyprocess.extended_search_area_piv(frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=32, search_area_size=64, overlap=8) x, y = pyprocess.get_coordinates(image_size=frame_a.shape, search_area_size=64, overlap=8) fig, ax = plt.subplots(1, 2, figsize=(11, 8)) ax[0].imshow(frame_a, cmap=plt.get_cmap("gray"), alpha=0.8) ax[0].quiver(x, y, vel[0], -vel[1], scale=50, color="r") ax[1].quiver(x, y[::-1, :], vel[0], -vel[1], scale=50, color="b") ax[1].set_aspect(1) # ax[1].invert_yaxis() plt.show() return x, y, vel[0], vel[1]
def run_piv( frame_a, frame_b, ): winsize = 64 # pixels, interrogation window size in frame A searchsize = 68 # pixels, search in image B overlap = 32 # pixels, 50% overlap dt = 0.0005 # sec, time interval between pulses u0, v0, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=winsize, overlap=overlap, dt=dt, search_area_size=searchsize, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, search_area_size=searchsize, window_size=winsize, overlap=overlap) u1, v1, mask = validation.sig2noise_val(u0, v0, sig2noise, threshold=1.05) u2, v2 = filters.replace_outliers(u1, v1, method='localmean', max_iter=10, kernel_size=3) x, y, u3, v3 = scaling.uniform(x, y, u2, v2, scaling_factor=41.22) # 41.22 microns/pixel mean_u = np.mean(u3) mean_v = np.mean(v3) deficit_u = u3 - mean_u deficit_v = v3 - mean_v u_prime = np.mean(np.sqrt(0.5 * (deficit_u**2 + deficit_v**2))) u_avg = np.mean(np.sqrt(0.5 * (mean_u**2 + mean_v**2))) turbulence_intensity = u_prime / u_avg #save in the simple ASCII table format fname = "./Tables/" + exp_string + ".txt" # tools.save(x, y, u3, v3, mask, fname) out = np.vstack([m.ravel() for m in [x, y, u3, v3]]) # print(out) # np.savetxt(fname,out.T) with open(fname, "ab") as f: f.write(b"\n") np.savetxt(f, out.T) return turbulence_intensity
def calculate_deformation(im1, im2, window_size=64, overlap=32, std_factor=20): ''' Calculation of deformation field using particle image velocimetry (PIV). Recommendations: window_size should be about 6 time the size of bead. overlap should be no less then half of the window_size. Std_factor should be kept as high as possibel. Make sure to check for to many exclusions caused by this factor e.g. by looking at the mask_std. Side note: returns -v because original v is negative if compared to coordinates of images (y-axis is inverted). :param im1: after iamge :param im2: before image :param window_size: integer, size of interrogation windows for PIV :param overlap: integer, overlap of interrogation windows for PIV :param std_factor: filterng extreme outliers beyond mean (deformation) + std_factor*standard deviation (deforamtion) :return:u,v deformation in x and y direction in pixel of the before and after image x,y psitions of the deformation fiedl in coordinates of the after and before image mask, mask_std mask of filtered values by signal to noise filtering (piv internal) and filtering for extreme outliers ''' # accepting either path to file or image data directly if isinstance(im1, str): frame_a = np.array(openpiv.tools.imread(im1), dtype="int32") elif isinstance(im1, np.ndarray): frame_a = im1 if isinstance(im2, str): frame_b = np.array(openpiv.tools.imread(im2), dtype="int32") elif isinstance(im2, np.ndarray): frame_b = im2 u, v, sig2noise = extended_search_area_piv(frame_a, frame_b, window_size=window_size, overlap=overlap, dt=1, subpixel_method="gaussian", search_area_size=window_size, sig2noise_method='peak2peak') u, v, mask = openpiv.validation.sig2noise_val(u, v, sig2noise, threshold=1.05) def_abs = np.sqrt(u**2 + v**2) m = np.nanmean(def_abs) std = np.nanstd(def_abs) threshold = std * std_factor + m mask_std = def_abs > threshold u[mask_std] = np.nan v[mask_std] = np.nan u, v = openpiv.filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) return (u, -v, mask, mask_std) # return -v because of image inverted axis
def process(args, bga, bgb, reflection): file_a, file_b, counter = args # read images into numpy arrays frame_a = tools.imread(file_a) frame_b = tools.imread(file_b) # removing background and reflections frame_a = frame_a - bga frame_b = frame_b - bgb frame_a[reflection == 255] = 0 frame_b[reflection == 255] = 0 #applying a static mask (taking out the regions where we have walls) yp = [580, 435, 0, 0, 580, 580, 0, 0, 435, 580] xp = [570, 570, 680, 780, 780, 0, 0, 105, 230, 230] pnts = draw.polygon(yp, xp, frame_a.shape) frame_a[pnts] = 0 frame_b[pnts] = 0 # checking the resulting frame #fig, ax = plt.subplots(2,2) #ax[0,0].imshow(frame_a_org, cmap='gray') #ax[0,1].imshow(frame_a, cmap='gray') #ax[1,0].imshow(frame_b_org, cmap='gray') #ax[1,1].imshow(frame_b, cmap='gray') #plt.tight_layout() #plt.show() # main piv processing u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a, frame_b, \ window_size=48, overlap=16, dt=0.001094, search_area_size=64, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, window_size=48, overlap=16) u, v, mask = validation.local_median_val(u, v, 2000, 2000, size=2) u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) u, *_ = smoothn(u, s=1.0) v, *_ = smoothn(v, s=1.0) # saving the results save_file = tools.create_path(file_a, 'Analysis') tools.save(x, y, u, v, mask, save_file + '.dat')
def PIV(image_0, image_1, winsize, searchsize, overlap, frame_rate, scaling_factor): frame_0 = image_0 # [0:600, :] frame_1 = image_1 # [0:600, :] # Processing the images with interrogation area and search area / cross correlation algortihm u, v, sig2noise = pyprocess.extended_search_area_piv( frame_0, frame_1, window_size=winsize, overlap=overlap, dt=dt, search_area_size=searchsize, sig2noise_method='peak2peak') # Compute the coordinates of the centers of the interrogation windows x, y = pyprocess.get_coordinates(image_size=frame_0.shape, window_size=winsize, overlap=overlap) # This function actually sets to NaN all those vector for # which the signal to noise ratio is below 1.3. # mask is a True/False array, where elements corresponding to invalid vectors have been replace by Nan. u, v, mask = validation.sig2noise_val(u, v, sig2noise, threshold=1.5) # Function as described above, removing outliers deviating with more # than twice the standard deviation u, v, mask = remove_outliers(u, v, mask) # Replacing the outliers with interpolation # u, v = filters.replace_outliers(u, # v, # method='nan', # max_iter=50, # kernel_size=3) # Apply an uniform scaling to the flow field to get dimensional units x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=scaling_factor) return x, y, u, v, mask
def ProcessPIV(args, bga, bgb, reflection, stg): # read images into numpy arrays file_a, file_b, counter = args frame_a = tools.imread(file_a) frame_b = tools.imread(file_b) # removing background and reflections if bgb is not None: frame_a = frame_a - bga frame_b = frame_b - bgb frame_a[reflection == 255] = 0 frame_b[reflection == 255] = 0 #plt.imshow(frame_a, cmap='gray') #plt.show() # main piv processing u, v, s2n = pyprocess.extended_search_area_piv( frame_a, frame_b, \ window_size=stg['WS'], overlap=stg['OL'], dt=stg['DT'], search_area_size=stg['SA'], sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, window_size=stg['WS'], overlap=stg['OL']) if stg['BVR'] == 'on': u, v, mask = validation.local_median_val(u, v, stg['MF'][0], stg['MF'][1], size=2) u, v, mask = validation.global_val(u, v, u_thresholds=stg['GF'][0], v_thresholds=stg['GF'][1]) u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) u, *_ = smoothn(u, s=0.5) v, *_ = smoothn(v, s=0.5) x, y, u, v = scaling.uniform(x, y, u, v, stg['SC']) # saving the results save_file = tools.create_path(file_a, 'Analysis') tools.save(x, y, u, v, s2n, save_file + '.dat')
def two_images(image_1, image_2): local_dir = os.path.dirname(os.path.realpath(__file__)) newFile_1 = open('teting1.bmp', 'w+b') newFileByteArray = bytes(image_1) newFile_1.write(newFileByteArray) newFile_1.close() frame_a = tools.imread(local_dir + '/exp1_001_a.bmp') frame_b = tools.imread(local_dir + '/exp1_001_b.bmp') fig, ax = plt.subplots(1, 2, figsize=(10, 8)) ax[0].imshow(frame_a, cmap=plt.cm.gray) ax[1].imshow(frame_b, cmap=plt.cm.gray) winsize = 32 # pixels searchsize = 64 # pixels, search in image B overlap = 12 # pixels dt = 0.02 # sec u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=winsize, overlap=overlap, dt=dt, search_area_size=searchsize, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, window_size=searchsize, overlap=overlap) file_name = 'result.txt' # tools.save(x, y, u, v, np.zeros_like(u), 'exp1_001.txt' ) # no masking, all values are valid tools.save(x, y, u, v, np.zeros_like(u), file_name) # no masking, all values are valid with open(file_name, 'r') as result_file: data = result_file.read().replace('\n', '').replace('\t', ' ') return data
def doPIV(frame_a, frame_b, dT = 1.0, win_size = 64, overlap = 32, searchArea = 64, apply_clahe = False): # Check if image is color or grayscale and convert to grayscale if it is color try: imH, imW, channels = np.shape(frame_a) if(channels > 1): frame_a = cv2.cvtColor(frame_a , cv2.COLOR_BGR2GRAY) frame_b = cv2.cvtColor(frame_b , cv2.COLOR_BGR2GRAY) except: pass if(apply_clahe is True): clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(12,12)) frame_a = clahe.apply(frame_a) frame_b = clahe.apply(frame_b) u, v, sig2noise = pyprocess.extended_search_area_piv(frame_a.astype(np.int32), frame_b.astype(np.int32), window_size = win_size, overlap = overlap, dt = dT, search_area_size = searchArea, sig2noise_method='peak2mean', normalized_correlation=True) x, y = pyprocess.get_coordinates(frame_a.shape, win_size, overlap) return x,y,u,v, sig2noise
def simple_piv(im1, im2, plot=True): """ Simplest PIV run on the pair of images using default settings piv(im1,im2) will create a tmp.vec file with the vector filed in pix/dt (dt=1) from two images, im1,im2 provided as full path filenames (TIF is preferable, whatever imageio can read) """ if isinstance(im1, str): im1 = tools.imread(im1) im2 = tools.imread(im2) u, v, s2n = pyprocess.extended_search_area_piv(im1.astype(np.int32), im2.astype(np.int32), window_size=32, overlap=16, search_area_size=32) x, y = pyprocess.get_coordinates(image_size=im1.shape, search_area_size=32, overlap=16) valid = s2n > np.percentile(s2n, 5) if plot: _, ax = plt.subplots(figsize=(6, 6)) ax.imshow(im1, cmap=plt.get_cmap("gray"), alpha=0.5, origin="upper") ax.quiver(x[valid], y[valid], u[valid], -v[valid], scale=70, color='r', width=.005) plt.show() return x, y, u, v
def process(args): file_a, file_b, counter = args # read images into numpy arrays frame_a = tools.imread(file_a) frame_b = tools.imread(file_b) print(counter + 1) # process image pair with piv algorithm. u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a, frame_b, \ window_size=32, overlap=16, dt=0.0015, search_area_size=32, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, window_size=32, overlap=16) u, v, mask1 = validation.sig2noise_val(u, v, sig2noise, threshold=1.0) u, v, mask2 = validation.global_val(u, v, (-2000, 2000), (-2000, 4000)) u, v, mask3 = validation.local_median_val(u, v, 400, 400, size=2) #u, v, mask4 = validation.global_std(u, v, std_threshold=3) mask = mask1 | mask2 | mask3 #u, v = filters.replace_outliers( u, v, method='localmean', max_iter=10, kernel_size=2) save_file = tools.create_path(file_a, 'Analysis') tools.save(x, y, u, v, mask, save_file + '.dat')
frame_b = im_b[380:1980, 0:1390] plt.imshow(np.c_[frame_a, frame_b], cmap='gray') # Process the original cropped image and see the OpenPIV result: # typical parameters: window_size = 32 #pixels overlap = 16 # pixels search_area_size = 64 # pixels frame_rate = 40 # fps # process again with the masked images, for comparison# process once with the original images u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=window_size, overlap=overlap, dt=1. / frame_rate, search_area_size=search_area_size, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, search_area_size=search_area_size, overlap=overlap) u, v, mask = validation.global_val(u, v, (-300., 300.), (-300., 300.)) u, v, mask = validation.sig2noise_val(u, v, sig2noise, threshold=1.1) u, v = filters.replace_outliers(u, v, method='localmean', max_iter=3, kernel_size=3) x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52) # save to a file
def first_pass(frame_a, frame_b, settings): # window_size, # overlap, # iterations, # correlation_method="circular", # normalized_correlation=False, # subpixel_method="gaussian", # do_sig2noise=False, # sig2noise_method="peak2peak", # sig2noise_mask=2, # settings): """ First pass of the PIV evaluation. This function does the PIV evaluation of the first pass. It returns the coordinates of the interrogation window centres, the displacment u and v for each interrogation window as well as the mask which indicates wether the displacement vector was interpolated or not. Parameters ---------- frame_a : 2d np.ndarray the first image frame_b : 2d np.ndarray the second image window_size : int the size of the interrogation window overlap : int the overlap of the interrogation window, typically it is window_size/2 subpixel_method: string the method used for the subpixel interpolation. one of the following methods to estimate subpixel location of the peak: 'centroid' [replaces default if correlation map is negative], 'gaussian' [default if correlation map is positive], 'parabolic' Returns ------- x : 2d np.array array containg the x coordinates of the interrogation window centres y : 2d np.array array containg the y coordinates of the interrogation window centres u : 2d np.array array containing the u displacement for every interrogation window u : 2d np.array array containing the u displacement for every interrogation window """ # if do_sig2noise is False or iterations != 1: # sig2noise_method = None # this indicates to get out nans u, v, s2n = extended_search_area_piv( frame_a, frame_b, window_size=settings.windowsizes[0], overlap=settings.overlap[0], search_area_size=settings.windowsizes[0], width=settings.sig2noise_mask, subpixel_method=settings.subpixel_method, sig2noise_method=settings.sig2noise_method, correlation_method=settings.correlation_method, normalized_correlation=settings.normalized_correlation) shapes = np.array( get_field_shape(frame_a.shape, settings.windowsizes[0], settings.overlap[0])) u = u.reshape(shapes) v = v.reshape(shapes) s2n = s2n.reshape(shapes) x, y = get_coordinates(frame_a.shape, settings.windowsizes[0], settings.overlap[0]) return x, y, u, v, s2n
def multipass_img_deform( frame_a, frame_b, current_iteration, x_old, y_old, u_old, v_old, settings, mask_coords=[], ): # window_size, # overlap, # iterations, # current_iteration, # x_old, # y_old, # u_old, # v_old, # correlation_method="circular", # normalized_correlation=False, # subpixel_method="gaussian", # deformation_method="symmetric", # sig2noise_method="peak2peak", # sig2noise_threshold=1.0, # sig2noise_mask=2, # interpolation_order=1, """ Multi pass of the PIV evaluation. This function does the PIV evaluation of the second and other passes. It returns the coordinates of the interrogation window centres, the displacement u, v for each interrogation window as well as the signal to noise ratio array (which is full of NaNs if opted out) Parameters ---------- frame_a : 2d np.ndarray the first image frame_b : 2d np.ndarray the second image window_size : tuple of ints the size of the interrogation window overlap : tuple of ints the overlap of the interrogation window, e.g. window_size/2 x_old : 2d np.ndarray the x coordinates of the vector field of the previous pass y_old : 2d np.ndarray the y coordinates of the vector field of the previous pass u_old : 2d np.ndarray the u displacement of the vector field of the previous pass in case of the image mask - u_old and v_old are MaskedArrays v_old : 2d np.ndarray the v displacement of the vector field of the previous pass subpixel_method: string the method used for the subpixel interpolation. one of the following methods to estimate subpixel location of the peak: 'centroid' [replaces default if correlation map is negative], 'gaussian' [default if correlation map is positive], 'parabolic' interpolation_order : int the order of the spline interpolation used for the image deformation mask_coords : list of x,y coordinates (pixels) of the image mask, default is an empty list Returns ------- x : 2d np.array array containg the x coordinates of the interrogation window centres y : 2d np.array array containg the y coordinates of the interrogation window centres u : 2d np.array array containing the horizontal displacement for every interrogation window [pixels] u : 2d np.array array containing the vertical displacement for every interrogation window it returns values in [pixels] s2n : 2D np.array of signal to noise ratio values """ if not isinstance(u_old, np.ma.MaskedArray): raise ValueError('Expected masked array') # calculate the y and y coordinates of the interrogation window centres. # Hence, the # edges must be extracted to provide the sufficient input. x_old and y_old # are the coordinates of the old grid. x_int and y_int are the coordinates # of the new grid window_size = settings.windowsizes[current_iteration] overlap = settings.overlap[current_iteration] x, y = get_coordinates(frame_a.shape, window_size, overlap) # The interpolation function dont like meshgrids as input. # plus the coordinate system for y is now from top to bottom # and RectBivariateSpline wants an increasing set y_old = y_old[:, 0] # y_old = y_old[::-1] x_old = x_old[0, :] y_int = y[:, 0] # y_int = y_int[::-1] x_int = x[0, :] # interpolating the displacements from the old grid onto the new grid # y befor x because of numpy works row major ip = RectBivariateSpline(y_old, x_old, u_old.filled(0.)) u_pre = ip(y_int, x_int) ip2 = RectBivariateSpline(y_old, x_old, v_old.filled(0.)) v_pre = ip2(y_int, x_int) # if settings.show_plot: if settings.show_all_plots: plt.figure() plt.quiver(x_old, y_old, u_old, -1 * v_old, color='b') plt.quiver(x_int, y_int, u_pre, -1 * v_pre, color='r', lw=2) plt.gca().set_aspect(1.) plt.gca().invert_yaxis() plt.title('inside deform, invert') plt.show() # @TKauefer added another method to the windowdeformation, 'symmetric' # splits the onto both frames, takes more effort due to additional # interpolation however should deliver better results old_frame_a = frame_a.copy() old_frame_b = frame_b.copy() # Image deformation has to occur in image coordinates # therefore we need to convert the results of the # previous pass which are stored in the physical units # and so y from the get_coordinates if settings.deformation_method == "symmetric": # this one is doing the image deformation (see above) x_new, y_new, ut, vt = create_deformation_field( frame_a, x, y, u_pre, v_pre) frame_a = scn.map_coordinates(frame_a, ((y_new - vt / 2, x_new - ut / 2)), order=settings.interpolation_order, mode='nearest') frame_b = scn.map_coordinates(frame_b, ((y_new + vt / 2, x_new + ut / 2)), order=settings.interpolation_order, mode='nearest') elif settings.deformation_method == "second image": frame_b = deform_windows( frame_b, x, y, u_pre, -v_pre, interpolation_order=settings.interpolation_order) else: raise Exception("Deformation method is not valid.") # if settings.show_plot: if settings.show_all_plots: if settings.deformation_method == 'symmetric': plt.figure() plt.imshow(frame_a - old_frame_a) plt.show() plt.figure() plt.imshow(frame_b - old_frame_b) plt.show() # if do_sig2noise is True # sig2noise_method = sig2noise_method # else: # sig2noise_method = None # so we use here default circular not normalized correlation: # if we did not want to validate every step, remove the method if settings.sig2noise_validate is False: settings.sig2noise_method = None u, v, s2n = extended_search_area_piv( frame_a, frame_b, window_size=window_size, overlap=overlap, width=settings.sig2noise_mask, subpixel_method=settings.subpixel_method, sig2noise_method=settings.sig2noise_method, correlation_method=settings.correlation_method, normalized_correlation=settings.normalized_correlation, ) shapes = np.array(get_field_shape(frame_a.shape, window_size, overlap)) u = u.reshape(shapes) v = v.reshape(shapes) s2n = s2n.reshape(shapes) u += u_pre v += v_pre # reapply the image mask to the new grid if settings.image_mask: grid_mask = preprocess.prepare_mask_on_grid(x, y, mask_coords) u = np.ma.masked_array(u, mask=grid_mask) v = np.ma.masked_array(v, mask=grid_mask) else: u = np.ma.masked_array(u, np.ma.nomask) v = np.ma.masked_array(v, np.ma.nomask) # validate in the multi-pass by default u, v, mask = validation.typical_validation(u, v, s2n, settings) if np.all(mask): raise ValueError("Something happened in the validation") if not isinstance(u, np.ma.MaskedArray): raise ValueError('not a masked array anymore') if settings.show_all_plots: plt.figure() nans = np.nonzero(mask) plt.quiver(x[~nans], y[~nans], u[~nans], -v[~nans], color='b') plt.quiver(x[nans], y[nans], u[nans], -v[nans], color='r') plt.gca().invert_yaxis() plt.gca().set_aspect(1.) plt.title('After sig2noise, inverted') plt.show() # we have to replace outliers u, v = filters.replace_outliers( u, v, method=settings.filter_method, max_iter=settings.max_filter_iteration, kernel_size=settings.filter_kernel_size, ) # reapply the image mask to the new grid if settings.image_mask: grid_mask = preprocess.prepare_mask_on_grid(x, y, mask_coords) u = np.ma.masked_array(u, mask=grid_mask) v = np.ma.masked_array(v, mask=grid_mask) else: u = np.ma.masked_array(u, np.ma.nomask) v = np.ma.masked_array(v, np.ma.nomask) if settings.show_all_plots: plt.figure() plt.quiver(x, y, u, -v, color='r') plt.quiver(x, y, u_pre, -1 * v_pre, color='b') plt.gca().invert_yaxis() plt.gca().set_aspect(1.) plt.title(' after replaced outliers, red, invert') plt.show() return x, y, u, v, s2n, mask
u, v, mask = validation.sig2noise_val( u, v, sig2noise, threshold = 1.3 ) u, v = filters.replace_outliers( u, v, method='localmean', max_iter=10, kernel_size=2) x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor = 96.52 ) tools.save(x, y, u, v, mask, 'exp1_001.txt' ) tools.display_vector_field('exp1_001.txt', scale=100, width=0.0025) u1, v1, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=24, overlap=12, dt=0.02, search_area_size=64, sig2noise_method='peak2peak' ) x, y = pyprocess.get_coordinates( image_size=frame_a.shape, window_size=24, overlap=12 ) u1, v1, mask = validation.sig2noise_val( u1, v1, sig2noise, threshold = 1.3 ) u1, v1 = filters.replace_outliers( u1, v1, method='localmean', max_iter=10, kernel_size=2) x, y, u1, v1 = scaling.uniform(x, y, u1, v1, scaling_factor = 96.52 ) tools.save(x, y, u1, v1, mask, 'exp1_001_1.txt' ) tools.display_vector_field('exp1_001_1.txt', scale=100, width=0.0025)
u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52) tools.save(x, y, u, v, mask, 'exp1_001.txt') tools.display_vector_field('exp1_001.txt', scale=100, width=0.0025) u1, v1, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=24, overlap=12, dt=0.02, search_area_size=64, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, window_size=24, overlap=12) u1, v1, mask = validation.sig2noise_val(u1, v1, sig2noise, threshold=1.3) u1, v1 = filters.replace_outliers(u1, v1, method='localmean', max_iter=10, kernel_size=2)
def PIV(frame_0, frame_1, winsize, searchsize, overlap, frame_rate, scaling_factor, threshold=1.3, output='fil'): """ Particle Image Velocimetry processing for two sequential images. Input: ------ frame_0 - first frame to indicate potential seeds. frame_1 - second frame to trace seed displacements. winsize - size of the individual (square) grid cells in pixels. searchsize - size of the search area in pixels in which the location with the highest similarity is found. overlap - overlap over the grid cells in pixels. frame_rate - frame rate of the video in frames per second (fps). scaling_factor - amount of pixels per meter. output - after which step the PIV processing is stopped ('raw', 'fil', or 'int'; default: 'fil') """ # determine the timestep between the two sequential frames (1/fps) dt = 1. / frame_rate # estimation of seed displacements in x and y direction # and the corresponding signal-to-noise ratio u, v, sig2noise = pyprocess.extended_search_area_piv( frame_0, frame_1, window_size=winsize, overlap=overlap, dt=dt, search_area_size=searchsize, sig2noise_method='peak2peak') # xy-coordinates of the centre of each grid cell x, y = pyprocess.get_coordinates(image_size=frame_0.shape, window_size=winsize, overlap=overlap) # if ouput is 'fil' or 'int': # filter out grid cells with a low signal-to-noise ratio if output == 'fil' or output == 'int': u, v, mask = validation.sig2noise_val(u, v, sig2noise, threshold=threshold) # if output is 'int' # fill in missing values through interpolation if output == 'int': u, v = filters.replace_outliers(u, v, method='localmean', max_iter=50, kernel_size=3) # scale results based on the pixels per metres x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=scaling_factor) return x, y, u, v, sig2noise
def calc_piv_2_images(frame_a, frame_b, idx, dir_name): ''' Performs Particle Image Velocimetry (PIV) of two images, and saves an image with PIV on it. :param frame_a: first image :param frame_b: consecutive image :param idx: index of the first frame, for saving and ordering the images :param dir_name: directory to save the image to :return: - ''' u0, v0, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=winsize, overlap=overlap, dt=dt, search_area_size=searchsize, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, search_area_size=searchsize, overlap=overlap) u1, v1, mask = validation.sig2noise_val(u0, v0, sig2noise, threshold=1.05) # to see where is a reasonable limit filter out # outliers that are very different from the neighbours u2, v2 = filters.replace_outliers(u1, v1, method='localmean', max_iter=3, kernel_size=3) # convert x,y to mm; convert u,v to mm/sec x, y, u3, v3 = scaling.uniform( x, y, u2, v2, scaling_factor=scaling_factor) # 96.52 microns/pixel # 0,0 shall be bottom left, positive rotation rate is counterclockwise x, y, u3, v3 = tools.transform_coordinates(x, y, u3, v3) fig, ax = plt.subplots() im = np.negative(frame_a) # plot negative of the image for more clarity xmax = np.amax(x) + winsize / (2 * scaling_factor) ymax = np.amax(y) + winsize / (2 * scaling_factor) ax.imshow(im, cmap="Greys_r", extent=[0.0, xmax, 0.0, ymax]) invalid = mask.astype("bool") valid = ~invalid plt.quiver(x[invalid], y[invalid], u3[invalid], v3[invalid], color="r", width=width) plt.quiver(x[valid], y[valid], u3[valid], v3[valid], color="b", width=width) ax.set_aspect(1.) plt.title(r'Velocity Vectors Field (Frame #%d) $(\frac{\mu m}{hour})$' % idx) plt.savefig(dir_name + "/" + "vec_page%d.png" % idx, dpi=200) plt.show() plt.close()
def run_piv( frame_a, frame_b, winsize=16, # pixels, interrogation window size in frame A searchsize=20, # pixels, search in image B overlap=8, # pixels, 50% overlap dt=0.0001, # sec, time interval between pulses image_check=False, show_vertical_profiles=False, figure_export_name='_results.png', text_export_name="_results.txt", scale_factor=1, pixel_density=36.74, arrow_width=0.001, show_result=True, u_bounds=(-100, 100), v_bounds=(-100, 100)): u0, v0, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=winsize, overlap=overlap, dt=dt, search_area_size=searchsize, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, search_area_size=searchsize, overlap=overlap) x, y, u0, v0 = scaling.uniform( x, y, u0, v0, scaling_factor=pixel_density) # no. pixel per distance u0, v0, mask = validation.global_val(u0, v0, u_bounds, v_bounds) u1, v1, mask = validation.sig2noise_val(u0, v0, sig2noise, threshold=1.05) u3, v3 = filters.replace_outliers(u1, v1, method='localmean', max_iter=10, kernel_size=3) #save in the simple ASCII table format if np.std(u3) < 480: tools.save(x, y, u3, v3, sig2noise, mask, text_export_name) if image_check == True: fig, ax = plt.subplots(2, 1, figsize=(24, 12)) ax[0].imshow(frame_a) ax[1].imshow(frame_b) io.imwrite(figure_export_name, frame_a) if show_result == True: fig, ax = plt.subplots(figsize=(24, 12)) tools.display_vector_field( text_export_name, ax=ax, scaling_factor=pixel_density, scale=scale_factor, # scale defines here the arrow length width=arrow_width, # width is the thickness of the arrow on_img=True, # overlay on the image image_name=figure_export_name) fig.savefig(figure_export_name) if show_vertical_profiles: field_shape = pyprocess.get_field_shape(image_size=frame_a.shape, search_area_size=searchsize, overlap=overlap) vertical_profiles(text_export_name, field_shape) print('Std of u3: %.3f' % np.std(u3)) print('Mean of u3: %.3f' % np.mean(u3)) return np.std(u3)
def quick_piv(self, search_dict, index_a=100, index_b=101, folder=None): self.show_piv_param() ns = Namespace(**self.piv_param) if folder == None: img_a, img_b = self.read_two_images(search_dict, index_a=index_a, index_b=index_b) location_path = [ x['path'] for x in self.piv_dict_list if search_dict.items() <= x.items() ] results_path = os.path.join(self.results_path, *location_path) try: os.makedirs(results_path) except FileExistsError: pass else: try: file_a_path = os.path.join(self.path, folder, 'frame_%06d.tiff' % index_a) file_b_path = os.path.join(self.path, folder, 'frame_%06d.tiff' % index_b) img_a = np.array(Image.open(file_a_path)) img_b = np.array(Image.open(file_b_path)) except: return None # crop img_a = img_a[ns.crop[0]:-ns.crop[1] - 1, ns.crop[2]:-ns.crop[3] - 1] img_b = img_b[ns.crop[0]:-ns.crop[1] - 1, ns.crop[2]:-ns.crop[3] - 1] u0, v0, sig2noise = pyprocess.extended_search_area_piv( img_a.astype(np.int32), img_b.astype(np.int32), window_size=ns.winsize, overlap=ns.overlap, dt=ns.dt, search_area_size=ns.searchsize, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=img_a.shape, search_area_size=ns.searchsize, overlap=ns.overlap) x, y, u0, v0 = scaling.uniform( x, y, u0, v0, scaling_factor=ns.pixel_density) # no. pixel per distance u0, v0, mask = validation.global_val( u0, v0, (ns.u_lower_bound, ns.u_upper_bound), (ns.v_lower_bound, ns.v_upper_bound)) u1, v1, mask = validation.sig2noise_val(u0, v0, sig2noise, threshold=1.01) u3, v3 = filters.replace_outliers(u1, v1, method='localmean', max_iter=500, kernel_size=3) #save in the simple ASCII table format tools.save(x, y, u3, v3, sig2noise, mask, os.path.join(results_path, ns.text_export_name)) if ns.image_check == True: fig, ax = plt.subplots(2, 1, figsize=(24, 12)) ax[0].imshow(img_a) ax[1].imshow(img_b) io.imwrite(os.path.join(results_path, ns.figure_export_name), img_a) if ns.show_result == True: fig, ax = plt.subplots(figsize=(24, 12)) tools.display_vector_field( os.path.join(results_path, ns.text_export_name), ax=ax, scaling_factor=ns.pixel_density, scale=ns.scale_factor, # scale defines here the arrow length width=ns.arrow_width, # width is the thickness of the arrow on_img=True, # overlay on the image image_name=os.path.join(results_path, ns.figure_export_name)) fig.savefig(os.path.join(results_path, ns.figure_export_name)) if ns.show_vertical_profiles: field_shape = pyprocess.get_field_shape( image_size=img_a.shape, search_area_size=ns.searchsize, overlap=ns.overlap) vertical_profiles(ns.text_export_name, field_shape) print('Mean of u: %.3f' % np.mean(u3)) print('Std of u: %.3f' % np.std(u3)) print('Mean of v: %.3f' % np.mean(v3)) print('Std of v: %.3f' % np.std(v3)) output = np.array([np.mean(u3), np.std(u3), np.mean(v3), np.std(v3)]) # if np.absolute(np.mean(v3)) < 50: # output = self.quick_piv(search_dict,index_a = index_a + 1, index_b = index_b + 1) return x, y, u3, v3
from openpiv import tools, pyprocess, scaling, validation, filters import numpy as np import os # we can run it from any folder path = os.path.dirname(os.path.abspath(__file__)) frame_a = tools.imread(os.path.join(path, '../test1/exp1_001_a.bmp')) frame_b = tools.imread(os.path.join(path, '../test1/exp1_001_b.bmp')) frame_a = (frame_a * 1024).astype(np.int32) frame_b = (frame_b * 1024).astype(np.int32) u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a, frame_b, \ window_size=32, overlap=16, dt=0.02, search_area_size=64, sig2noise_method='peak2peak' ) print(u, v, sig2noise) x, y = pyprocess.get_coordinates(image_size=frame_a.shape, search_area_size=64, overlap=16) u, v, mask = validation.sig2noise_val(u, v, sig2noise, threshold=1.3) u, v, mask = validation.global_val(u, v, (-1000, 2000), (-1000, 1000)) u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52) tools.save(x, y, u, v, mask, 'test1.vec')
u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52) tools.save(x, y, u, v, mask, 'Y4-S3_Camera000398_a.txt') # %% # Use Python version, pyprocess: u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a.astype(np.int32), frame_b.astype(np.int32), window_size=32, overlap=8, dt=.1, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, window_size=32, overlap=8) u, v, mask = validation.sig2noise_val(u, v, sig2noise, threshold=1.3) u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52) tools.save(x, y, u, v, mask, 'Y4-S3_Camera000398_b.txt')
u, v, mask = validation.sig2noise_val(u, v, sig2noise, threshold=2.5) u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2) x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52) tools.save(x, y, u, v, mask, 'exp1_001_extended.txt') tools.display_vector_field('exp1_001_extended.txt', scale=100, width=0.0025) # %% # %%time u, v, sig2noise = pyprocess.extended_search_area_piv( frame_a, frame_b, corr_method='fft', window_size=24, overlap=12, dt=0.02, sig2noise_method='peak2peak') x, y = pyprocess.get_coordinates(image_size=frame_a.shape, window_size=24, overlap=12) u, v, mask = validation.sig2noise_val(u, v, sig2noise, threshold=2.5) u, v = filters.replace_outliers(u, v, method='localmean', max_iter=10, kernel_size=2.5) x, y, u, v = scaling.uniform(x, y, u, v, scaling_factor=96.52) tools.save(x, y, u, v, mask, 'exp1_001_fft.txt') tools.display_vector_field('exp1_001_fft.txt', scale=100, width=0.0025)