Пример #1
0
def find_transform(source, target, source_points, target_points):
    y_size, x_size = np.shape(source)
    max_size = max(y_size, x_size)

    threshold = utils.round_up_to_odd(20 * max_size / 2048)
    transform_affine, ransac_affine_failed = ransac_partially_affine(source_points, target_points, 0.99, threshold)
    if ransac_affine_failed:
        threshold = utils.round_up_to_odd(30 * max_size / 2048)
        transform_affine, ransac_affine_failed = ransac_partially_affine(source_points, target_points, 0.90, threshold)

    threshold = utils.round_up_to_odd(20 * max_size / 2048)
    transform_rigid, ransac_rigid_failed = ransac_rigid(source_points, target_points, 0.99, threshold)
    if ransac_rigid_failed:
        threshold = utils.round_up_to_odd(30 * max_size / 2048)
        transform_rigid, ransac_rigid_failed = ransac_rigid(source_points, target_points, 0.90, threshold)

    return transform_affine, transform_rigid, ransac_affine_failed, ransac_rigid_failed
Пример #2
0
def cv_initial_alignment(source, target, echo=True):
    failed = False
    try:
        y_size, x_size = source.shape
        source = (source * 255).astype(np.uint8)
        target = (target * 255).astype(np.uint8)
        max_size = max(y_size, x_size)
        smoothing_size = utils.round_up_to_odd(max_size / 2048 * 31)
        source = cv2.GaussianBlur(source, (smoothing_size, smoothing_size), 0)
        target = cv2.GaussianBlur(target, (smoothing_size, smoothing_size), 0)

        if echo:
            print("SURFN: ")
            print()
        surfn_transform, surfn_score, surfn_failed = calculate_transform(source, target, echo, "surfn")

        if echo:
            print()
            print("SURFE: ")
            print()
        surfe_transform, surfe_score, surfe_failed = calculate_transform(source, target, echo, "surfe")
        
        if echo:
            print()
            print("ORB: ")
            print()
        orb_transform, orb_score, orb_failed = calculate_transform(source, target, echo, "orb")

        if echo:
            print()
            print("SIFT: ")
            print()
        sift_transform, sift_score, sift_failed = calculate_transform(source, target, echo, "sift")

        if echo:
            print("SURFN score:", surfn_score, "SURFN failed: ", surfn_failed)
            print("SURFE score:", surfe_score, "SURFE failed: ", surfe_failed)
            print("ORB score:", orb_score, "ORB failed: ", orb_failed)
            print("SIFT score:", sift_score, "SIFT failed: ", sift_failed)

        scores = np.array([surfn_score, surfe_score, orb_score, sift_score])
        transforms = np.array([surfn_transform, surfe_transform, orb_transform, sift_transform])
        best_id = np.argmax(scores)

        if scores[best_id] == 0:
            failed = True
            transform = np.eye(3)
            u_x, u_y = np.zeros(source.shape), np.zeros(source.shape)
        else:
            failed = False
            transform = transforms[best_id]
            u_x, u_y = utils.rigid_dot(source, np.linalg.inv(transform))
    except:
        failed = True
        transform = np.eye(3)
        u_x, u_y = np.zeros(source.shape), np.zeros(source.shape)

    return u_x, u_y, transform, failed
Пример #3
0
def ORB_calculation(source, target):
    # Magic numbers below
    y_size, x_size = source.shape
    max_size = max(y_size, x_size)
    num_features = 5000
    scale_factor = 1.3
    num_levels = 8
    edge_threshold = 60
    first_level = 0
    wta_k = 3
    patch_size = utils.round_up_to_odd(35 * max_size / 2048)
    fast_threshold = utils.round_up_to_odd(25 * max_size / 2048)
    orb = cv2.ORB_create(num_features, scale_factor, num_levels,
        edge_threshold, first_level, wta_k, cv2.ORB_HARRIS_SCORE,
        patch_size, fast_threshold)
    source_keypoints, source_descriptors = orb.detectAndCompute(source, None)
    target_keypoints, target_descriptors = orb.detectAndCompute(target, None)
    return source_keypoints, source_descriptors, target_keypoints, target_descriptors
Пример #4
0
def threshold_adaptive(ndarray, method, blocksize=5, offset=0):

    # Cast to 16-bit
    #ndarray = convert_array_type(ndarray, 'int16')

    #Inizialize
    method_list = ['Mean', 'Gaussian', 'Sauvola', 'Niblack']

    if method not in method_list:
        raise Exception('Mode has to be amond the following:\n' +
                        str(method_list))

    blocksize = round_up_to_odd(blocksize)

    #For 2D images array needs to be reshaped to run properly through next cycle
    if len(ndarray.shape) < 3:
        converted_image = [img_as_ubyte(ndarray)]
    else:
        converted_image = img_as_ubyte(ndarray)

    #Cycle through image
    outputImage = []
    for i in range(len(converted_image)):

        if method == 'Mean':
            outputImage.append(
                cv2.adaptiveThreshold(converted_image[i], 255,
                                      cv2.ADAPTIVE_THRESH_MEAN_C,
                                      cv2.THRESH_BINARY, blocksize, offset))

        elif method == 'Gaussian':
            outputImage.append(
                cv2.adaptiveThreshold(converted_image[i], 255,
                                      cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                      cv2.THRESH_BINARY, blocksize, offset))
        elif method == 'Sauvola':
            outputImage.append(threshold_sauvola(converted_image[i]))

        elif method == 'Niblack':
            outputImage.append(threshold_niblack(converted_image[i]))

        else:
            raise LookupError('Not a valid method!')

    #Remove singleton dimension (eg. if image was 2D)
    outputImage = np.squeeze(np.array(outputImage) > 0).astype(np.uint8)

    return convert_array_type(outputImage, 'int8')
Пример #5
0
def calc_fixPos(etdata, fix, w=50):
    """
    TODO: dublicate function. Update to use calc_event_data
    """
    data=etdata.data
    ws=round_up_to_odd(w/1000.0*etdata.fs)
    fix_pos=[]
    for f in fix:
        ind_s=f[0]+ws
        ind_s = ind_s if ind_s < f[1] else f[1]
        ind_e=f[1]-ws
        ind_e = ind_e if ind_e > f[0] else f[0]

        posx_s = np.nanmean(data[f[0]:ind_s]['x'])
        posy_s = np.nanmean(data[f[0]:ind_s]['y'])
        posx_e = np.nanmean(data[ind_e:f[1]]['x'])
        posy_e = np.nanmean(data[ind_e:f[1]]['y'])
        fix_pos.append([posx_s, posx_e, posy_s, posy_e])
    return np.array(fix_pos)
Пример #6
0
def calc_event_data(etdata, evt,
                    w = {255:1,
                         0: 1,
                         1: 50,
                         2: 1,
                         3: 1,
                         4: 1,
                         5: 1,
                         6: 1,
                         'vel': 18,
                         'etdq': 200}, ):
    """Calculates event parameters.
    Parameters:
        etdata  --  an instance of ETData
        evt     --  compact event vector
        w       --  dictionary of context to take into account
                    for each event type; in ms
    Returns:
        posx_s      --  onset position, horizontal
        posx_e      --  offset position, horizontal
        posy_s      --  onset position, vertical
        posy_e      --  offset position, vertical
        posx_mean   --  mean postion, horizontal
        posy_mean   --  mean postion, vertical
        posx_med    --  median postion, horizontal
        posy_med    --  median postion, vertical
        pv          --  peak velocity
        pv_index    --  index for peak velocity
        rms         --  precision, 2D rms
        std         --  precision, 2D std
    """

    #init params
    data = etdata.data
    fs = etdata.fs
    e = {k:v for k, v in zip(['s', 'e', 'evt'], evt)}
    ws = w[e['evt']]
    ws = 1 if not(ws > 1) else  round_up_to_odd(ws/1000.0*fs, min_val=3)
    ws_vel = round_up_to_odd(w['vel']/1000.0*fs, min_val=3)
    w_etdq = int(w['etdq']/1000.*fs)

    #calculate velocity using Savitzky-Golay filter
    vel = np.hypot(sg.savgol_filter(data['x'], ws_vel, 2, 1),
                   sg.savgol_filter(data['y'], ws_vel, 2, 1))*fs

    ind_s = e['s']+ws
    ind_s = ind_s if ind_s < e['e'] else e['e']
    ind_e = e['e']-ws
    ind_e = ind_e if ind_e > e['s'] else e['s']

    posx_s = np.nanmean(data[e['s']:ind_s]['x'])
    posy_s = np.nanmean(data[e['s']:ind_s]['y'])
    posx_e = np.nanmean(data[ind_e:e['e']]['x'])
    posy_e = np.nanmean(data[ind_e:e['e']]['y'])

    posx_mean = np.nanmean(data[e['s']:e['e']]['x'])
    posy_mean = np.nanmean(data[e['s']:e['e']]['y'])
    posx_med = np.nanmedian(data[e['s']:e['e']]['x'])
    posy_med = np.nanmedian(data[e['s']:e['e']]['y'])

    pv = np.max(vel[e['s']:e['e']])
    pv_index = e['s']+ np.argmax(vel[e['s']:e['e']])

    if e['e']-e['s']>w_etdq:
        x_ = rolling_window(data[e['s']:e['e']]['x'], w_etdq)
        y_ = rolling_window(data[e['s']:e['e']]['y'], w_etdq)

        std = np.median(np.hypot(np.std(x_, axis=1), np.std(y_, axis=1)))
        rms = np.median(np.hypot(np.sqrt(np.mean(np.diff(x_)**2, axis=1)),
                                 np.sqrt(np.mean(np.diff(y_)**2, axis=1))))
    else:
        std = 0
        rms = 0

    return posx_s, posx_e, posy_s, posy_e, posx_mean, posy_mean, posx_med, posy_med, pv, pv_index, rms, std
Пример #7
0
def extractFeatures(etdata, **kwargs):
    '''Extracts features for IRF
    '''

    #get parameters
    data = etdata.data
    w, w_vel, w_dir = kwargs['w'], kwargs['w_vel'], kwargs['w_dir']

    tic = time.time()

    #find sampling rate
    fs = etdata.fs

    #window size for spatial measures in samples
    ws = round_up_to_odd(w/1000.0*fs+1)

    #window size in samples for velocity calculation
    ws_vel = round_up_to_odd(w_vel/1000.0*fs)

    #window size in samples for direction calculation
    ws_dir = round_up_to_odd(w_dir/1000.0*fs)

    maskInterp = np.zeros(len(data), dtype=np.bool)
    '''Legacy code. Interpolates through missing points.
    if kwargs.has_key('interp') and kwargs['interp']:
        r = np.arange(len(data))
        _mask = np.isnan(data['x']) | np.isnan(data['y'])
        fx = interp.PchipInterpolator(r[~_mask], data[~_mask]['x'],
                                    extrapolate=True)
        fy = interp.PchipInterpolator(r[~_mask], data[~_mask]['y'],
                                    extrapolate=True)
        data['x'][_mask]=fx(r[_mask])
        data['y'][_mask]=fy(r[_mask])
        maskInterp = _mask
    '''

    #prepare data for vectorized processing
    ws_pad=(max((ws, ws_vel, ws_dir))-1)/2
    x_padded = np.pad(data['x'], (ws_pad, ws_pad),
                      'constant', constant_values=np.nan)
    y_padded = np.pad(data['y'], (ws_pad, ws_pad),
                      'constant', constant_values=np.nan)

    ws_dir_pad=(ws_dir-1)/2
    x_padded_dir=np.pad(data['x'], (ws_dir_pad, ws_dir_pad),
                        'constant', constant_values=np.nan)
    y_padded_dir=np.pad(data['y'], (ws_dir_pad, ws_dir_pad),
                        'constant', constant_values=np.nan)

    x_windowed = rolling_window(x_padded, ws)
    y_windowed = rolling_window(y_padded, ws)
    dx_windowed = rolling_window(np.diff(x_padded), ws-1)
    dy_windowed = rolling_window(np.diff(y_padded), ws-1)
    x_windowed_dir = rolling_window(np.diff(x_padded_dir), ws_dir-1)
    y_windowed_dir = rolling_window(np.diff(y_padded_dir), ws_dir-1)

    #%%Extract features
    features=dict()

    #sampling rate
    features['fs'] = np.ones(len(data))*fs

    for d, dd in zip(['x', 'y'], [x_windowed, y_windowed]):
        #difference between positions of preceding and succeding windows,
        #aka tobii feature, together with data quality features and its variants
        means=np.nanmean(dd, axis = 1)
        meds=np.nanmedian(dd, axis = 1)
        features['mean-diff-%s'%d] = np.roll(means, -(ws-1)/2) - \
                                     np.roll(means,  (ws-1)/2)
        features['med-diff-%s'%d] = np.roll(meds, -(ws-1)/2) - \
                                    np.roll(meds,  (ws-1)/2)

        #standard deviation
        features['std-%s'%d] = np.nanstd(dd, axis=1)
        features['std-next-%s'%d] = np.roll(features['std-%s'%d], -(ws-1)/2)
        features['std-prev-%s'%d] = np.roll(features['std-%s'%d],  (ws-1)/2)

    features['mean-diff']= np.hypot(features['mean-diff-x'],
                                    features['mean-diff-y'])
    features['med-diff']= np.hypot(features['med-diff-x'],
                                   features['med-diff-y'])

    features['std'] = np.hypot(features['std-x'], features['std-y'])
    features['std-diff'] = np.hypot(features['std-next-x'], features['std-next-y']) - \
                           np.hypot(features['std-prev-x'], features['std-prev-y'])

    #BCEA
    P = 0.68 #cumulative probability of area under the multivariate normal
    k = np.log(1/(1-P))
    #rho = [np.corrcoef(px, py)[0,1] for px, py in zip(x_windowed, y_windowed)]
    rho = vcorrcoef(x_windowed, y_windowed)
    features['bcea'] = 2 * k * np.pi * \
                       features['std-x'] * features['std-y'] * \
                       np.sqrt(1-np.power(rho,2))
    features['bcea-diff'] = np.roll(features['bcea'], -(ws-1)/2) - \
                            np.roll(features['bcea'], (ws-1)/2)

    #RMS
    features['rms'] = np.hypot(np.sqrt(np.mean(np.square(dx_windowed), axis=1)),
                               np.sqrt(np.mean(np.square(dy_windowed), axis=1)))
    features['rms-diff'] = np.roll(features['rms'], -(ws-1)/2) - \
                           np.roll(features['rms'], (ws-1)/2)

    #disp, aka idt feature
    x_range = np.nanmax(x_windowed, axis=1) - np.nanmin(x_windowed, axis=1)
    y_range = np.nanmax(y_windowed, axis=1) - np.nanmin(y_windowed, axis=1)
    features['disp'] = x_range + y_range

    #velocity and acceleration
    features['vel']=np.hypot(sg.savgol_filter(data['x'], ws_vel, 2, 1),
                             sg.savgol_filter(data['y'], ws_vel, 2, 1))*fs

    features['acc']=np.hypot(sg.savgol_filter(data['x'], ws_vel, 2, 2),
                             sg.savgol_filter(data['y'], ws_vel, 2, 2))*fs**2

    #rayleightest
    angl = np.arctan2(y_windowed_dir, x_windowed_dir)
    features['rayleightest'] = ast.rayleightest(angl, axis=1)

    #i2mc
    if kwargs.has_key('i2mc') and kwargs['i2mc'] is not None:
        features['i2mc'] = kwargs['i2mc']['finalweights'].flatten()
    else:
        features['i2mc'] = np.zeros(len(data))

    #remove padding and nans
    mask_nans = np.any([np.isnan(values) for key, values\
                                         in features.iteritems()], axis=0)
    mask_pad = np.zeros_like(data['x'], dtype=np.bool)
    mask_pad[:ws_pad] = True
    mask_pad[-ws_pad:] = True
    mask = mask_nans | mask_pad | maskInterp
    features={key: values[~mask].astype(np.float32) for key, values \
                                                    in features.iteritems()}

    dtype = np.dtype(zip(features.keys(), itertools.repeat(np.float32)))
    features = np.core.records.fromarrays(features.values(), dtype=dtype)

    #return features
    toc = time.time()
    if kwargs.has_key('print_et') and kwargs['print_et']:
        print 'Feature extraction took %.3f s.'%(toc-tic)
    return features, ~mask
Пример #8
0
def ct_initial_alignment(source, target, echo=True):
    y_size, x_size = source.shape
    source = (source * 255).astype(np.uint8)
    target = (target * 255).astype(np.uint8)
    max_size = max(y_size, x_size)
    smoothing_size = utils.round_up_to_odd(max_size / 2048 * 31)
    source = cv2.GaussianBlur(source, (smoothing_size, smoothing_size), 0)
    target = cv2.GaussianBlur(target, (smoothing_size, smoothing_size), 0)

    ret_source, thresholded_source = fd.threshold_calculation_with_rotation(source)
    ret_target, thresholded_target = fd.threshold_calculation_with_rotation(target)

    xs_m = utils.round_up_to_odd(x_size * 20 / 2048)
    ys_m = utils.round_up_to_odd(y_size * 20 / 2048)

    struct = min([xs_m, ys_m])
    thresholded_source = nd.binary_erosion(thresholded_source, structure=np.ones((struct, struct))).astype(np.uint8)
    thresholded_source = nd.binary_dilation(thresholded_source, structure=np.ones((struct, struct))).astype(np.uint8)                            
    thresholded_target = nd.binary_erosion(thresholded_target, structure=np.ones((struct, struct))).astype(np.uint8)
    thresholded_target = nd.binary_dilation(thresholded_target, structure=np.ones((struct, struct))).astype(np.uint8)

    Ms = cv2.moments(thresholded_source)
    Mt = cv2.moments(thresholded_target)

    cXs = Ms["m10"] / Ms["m00"]
    cYs = Ms["m01"] / Ms["m00"]
    cXt = Mt["m10"] / Mt["m00"]
    cYt = Mt["m01"] / Mt["m00"]

    transform_centroid = np.array([
            [1, 0, (cXt-cXs)],
            [0, 1, (cYt-cYs)],
            [0, 0, 1]])
    u_x_t, u_y_t = utils.rigid_dot(source, np.linalg.inv(transform_centroid))
    failed = True
    angle_step = 2
    initial_dice = utils.dice(thresholded_source, thresholded_target)
    if echo:
        print("Initial dice: ", initial_dice)
    best_dice = initial_dice
    for i in range(0, 360, angle_step):
        if echo:
            print("Current angle: ", i)
        rads = i * np.pi/180
        matrix_1 = np.array([
            [1, 0, cXt],
            [0, 1, cYt],
            [0, 0, 1],
        ])
        matrix_i = np.array([
            [np.cos(rads), -np.sin(rads), 0],
            [np.sin(rads), np.cos(rads), 0],
            [0, 0, 1],
        ])
        matrix_2 = np.array([
            [1, 0, -cXt],
            [0, 1, -cYt],
            [0, 0, 1],
        ])

        matrix = matrix_1 @ matrix_i @ matrix_2
        u_x, u_y = utils.rigid_dot(source, np.linalg.inv(matrix))
        transformed_source = utils.warp_image(source, u_x + u_x_t, u_y + u_y_t)

        ret_transformed_source, thresholded_transformed_source = fd.threshold_calculation_with_threshold_with_rotation(transformed_source, ret_source)
        thresholded_transformed_source = nd.binary_erosion(thresholded_transformed_source, structure=np.ones((struct, struct))).astype(np.uint8)
        thresholded_transformed_source = nd.binary_dilation(thresholded_transformed_source, structure=np.ones((struct, struct))).astype(np.uint8)
        current_dice = utils.dice(thresholded_transformed_source, thresholded_target)
        if echo:
            print("Current dice: ", current_dice)

        if (current_dice > best_dice and current_dice > initial_dice + 0.10 and current_dice > 0.85) or (current_dice > 0.95 and current_dice > best_dice):
            failed = False
            best_dice = current_dice
            transform = matrix.copy()
            if echo:
                print("Current best dice: ", best_dice)

    if failed:
        transform = np.eye(3)

    final_transform = transform @ transform_centroid
    if echo:
        print("Calculated transform: ", final_transform)
    if failed:
        final_transform = np.eye(3)
    u_x, u_y = utils.rigid_dot(source, np.linalg.inv(final_transform))
    return u_x, u_y, final_transform, failed