def remove_cell_template(norm, features):
    if features['_fingers_grid']:
        # finger grid
        rh = int(round(features['finger_period_row']))
        cw = int(round(features['finger_period_col']))
        no_fingers = ndimage.uniform_filter(norm, size=(rh, cw))

        features['im_no_fingers'] = no_fingers

        # remove busbars
        no_bbs = no_fingers.copy()
        pixel_ops.InterpolateBBs(no_bbs,
                                 np.array(features['_busbar_cols'], np.int32),
                                 features['busbar_width'] + 6)
        features['im_no_figners_bbs'] = no_bbs

        if False:
            view = ImageViewer(norm)
            ImageViewer(no_fingers)
            ImageViewer(no_bbs)
            view.show()
    else:
        # remove fingers
        f_len = features['finger_period']
        f = np.ones((int(round(f_len)), 1), np.float32) / f_len
        no_lines = ndimage.correlate(norm, f)

        # sharpen
        F_LEN2 = int(round(1.5 * f_len))
        f2 = np.ones((1, F_LEN2), np.float32) / F_LEN2
        filtered = ndimage.correlate(norm, f2)
        filtered[filtered < 0.1] = 1.0
        if False:
            view = ImageViewer(norm)
            ImageViewer(no_lines)
            ImageViewer(filtered)
            view.show()

        edges = norm / filtered
        no_fingers = edges * no_lines
        features['im_no_fingers'] = no_fingers

        if '_busbar_cols' in features:
            # remove busbars
            no_bbs = no_fingers.copy()
            pixel_ops.InterpolateBBs(
                no_bbs, np.array(features['_busbar_cols'], np.int32),
                features['busbar_width'] + 6)
        else:
            no_bbs = no_fingers

        features['im_no_figners_bbs'] = no_bbs

        if False:
            view = ImageViewer(norm)
            ImageViewer(no_fingers)
            ImageViewer(no_bbs)
            view.show()
Exemplo n.º 2
0
def plir(im_sp, im_lp, im_pl, features, spline_plir, spline_plc):
    t_start = timeit.default_timer()

    pixel_ops.ApplyThresholdLT_F32(im_sp, im_sp, 1.0, 1.0)
    pixel_ops.ApplyThresholdLT_F32(im_lp, im_lp, 1.0, 1.0)
    pixel_ops.ApplyThresholdLT_F32(im_pl, im_pl, 1.0, 1.0)
    if im_sp.shape != im_lp.shape:
        print im_sp.shape, im_lp.shape
        assert False
    im_sp = im_sp.astype(np.float64)
    im_lp = im_lp.astype(np.float64)
    im_pl = im_pl.astype(np.float64)

    if False:
        view = ImageViewer(im_sp)
        ImageViewer(im_lp)
        ImageViewer(im_pl)
        view.show()
        sys.exit()

    # vertical registration
    c = np.argmax(im_sp.mean(axis=0))
    profile_sp = im_sp[:, c - 10:c + 11].mean(axis=1)
    profile_lp = im_lp[:, c - 10:c + 11].mean(axis=1)
    shift_v = register(profile_sp, profile_lp, debug=False)
    if False:
        print c, shift_v
        view = ImageViewer(im_lp)
        ImageViewer(im_sp)
        ImageViewer(np.roll(im_sp, shift=shift_v, axis=0))
        view.show()
        sys.exit()
    im_sp = np.roll(im_sp, shift=shift_v, axis=0)

    # compute plir (ratio of LP to SP)
    plir = im_lp / im_sp

    if False:
        t = stats.scoreatpercentile(plir, per=90)
        print plir.min(), t, plir.max()
        plir[plir > t] = t
        view = ImageViewer(im_lp)
        ImageViewer(im_sp)
        ImageViewer(plir)
        view.show()
        sys.exit()

    # Get cropping and rotation parameters (based on short pass)
    vals = im_sp[::2, ::2].flat
    vals = np.sort(vals)
    min_val = vals[int(0.025 * vals.shape[0])]
    max_val = vals[int(0.975 * vals.shape[0])]
    features['norm_range'] = max_val - min_val
    features['norm_lower'] = min_val
    im_normed_temp = (im_sp - min_val) / (max_val - min_val)
    rotated_temp = block_rotate(im_normed_temp, features)
    block_crop(rotated_temp, features)
    rotation = features['crop_rotation']
    x1, x2, y1, y2 = features['_crop_bounds']

    if False:
        cropped_temp = rotated_temp[y1:y2, x1:x2]
        view = ImageViewer(im_sp)
        ImageViewer(rotated_temp)
        ImageViewer(cropped_temp)
        view.show()

    if 'input_param_skip_features' in features and int(
            features['input_param_skip_features']) == 1:
        return True

    # rotate all images
    if abs(rotation) > 0.01:
        h, w = plir.shape
        rot_mat = cv2.getRotationMatrix2D((w // 2, h // 2), rotation, 1.0)
        plir_rotated = cv2.warpAffine(plir,
                                      rot_mat, (w, h),
                                      flags=cv2.INTER_LINEAR,
                                      borderMode=cv2.BORDER_REPLICATE)
        sp_rotated = cv2.warpAffine(im_sp,
                                    rot_mat, (w, h),
                                    flags=cv2.INTER_LINEAR,
                                    borderMode=cv2.BORDER_REPLICATE)
        lp_rotated = cv2.warpAffine(im_lp,
                                    rot_mat, (w, h),
                                    flags=cv2.INTER_LINEAR,
                                    borderMode=cv2.BORDER_REPLICATE)
        h, w = im_pl.shape
        rot_mat = cv2.getRotationMatrix2D((w // 2, h // 2), rotation, 1.0)
        nf_rotated = cv2.warpAffine(im_pl,
                                    rot_mat, (w, h),
                                    flags=cv2.INTER_LINEAR,
                                    borderMode=cv2.BORDER_REPLICATE)
    else:
        plir_rotated = plir
        sp_rotated = im_sp
        lp_rotated = im_lp
        nf_rotated = im_pl

    # find marker location
    features['marker_loc'] = find_marker(sp_rotated[y1:y2, x1:x2])
    nf_to_sp_ratio = nf_rotated.shape[1] / float(sp_rotated.shape[1])
    features['marker_loc'] *= nf_to_sp_ratio

    # crop plir image
    cropped_plir = plir_rotated[y1:y2, x1:x2]
    cropped_plir = np.ascontiguousarray(cropped_plir)
    cropped_sp = sp_rotated[y1:y2, x1:x2]
    cropped_lp = lp_rotated[y1:y2, x1:x2]

    if False:
        _, upper = ip.get_percentile(cropped_plir, 0.005)
        pixel_ops.ClipImageF64(cropped_plir, 0, upper)
        print cropped_plir.min(), cropped_plir.dtype
        view = ImageViewer(plir)
        ImageViewer(cropped_plir)
        ImageViewer(cropped_sp)
        view.show()
        sys.exit()

    # convert plir image to bulk image
    tau_bulk_plir = interpolate.splev(cropped_plir.flatten(),
                                      spline_plir).reshape(cropped_plir.shape)
    _, upper = ip.get_percentile(tau_bulk_plir, 0.0001)
    pixel_ops.ClipImageF64(tau_bulk_plir, 0.1, upper)

    if False:
        ImageViewer(im_sp)
        ImageViewer(im_lp)
        plt.figure()
        plt.imshow(cropped_plir)
        plt.colorbar()
        plt.figure()
        plt.imshow(tau_bulk_plir)
        plt.colorbar()
        plt.show()
        sys.exit()

    # zoom bulk image to make the same size as NF
    if im_pl.shape != im_sp.shape:
        size_ratio_h = im_pl.shape[0] / float(im_sp.shape[0])
        size_ratio_w = im_pl.shape[1] / float(im_sp.shape[1])

        x1 = int(round(x1 * size_ratio_w))
        x2 = int(round(x2 * size_ratio_w))
        y1 = int(round(y1 * size_ratio_h))
        y2 = int(round(y2 * size_ratio_h))

        # correct and crop plir image (using params from short pass)
        cropped_nf = nf_rotated[y1:y2, x1:x2]

        # upsize low res bulk
        tau_bulk_plir = ndimage.zoom(tau_bulk_plir, zoom=2.0, order=1)

        # make sure same size
        height = min(tau_bulk_plir.shape[0], cropped_nf.shape[0])
        width = min(tau_bulk_plir.shape[1], cropped_nf.shape[1])
        tau_bulk_plir = tau_bulk_plir[:height, :width]
        cropped_nf = cropped_nf[:height, :width]
        assert tau_bulk_plir.shape == cropped_nf.shape
    else:
        cropped_nf = nf_rotated[y1:y2, x1:x2]

    if False:
        view = ImageViewer(tau_bulk_plir)
        ImageViewer(cropped_nf)
        view.show()
        sys.exit()

    if parameters.PLIR_INTERPOLATE_MARKER_WIDTH > 0 and features[
            'marker_loc'] > 0:
        # interpolate marker
        print features['marker_loc']
        locs = np.array([int(round(features['marker_loc']))], np.int32)
        cropped_nf = np.ascontiguousarray(cropped_nf, np.float32)
        pixel_ops.InterpolateBBs(cropped_nf, locs,
                                 parameters.PLIR_INTERPOLATE_MARKER_WIDTH)
        tau_bulk_plir = np.ascontiguousarray(tau_bulk_plir, np.float32)
        pixel_ops.InterpolateBBs(tau_bulk_plir, locs,
                                 parameters.PLIR_INTERPOLATE_MARKER_WIDTH)

        if False:
            view = ImageViewer(cropped_nf)
            ImageViewer(tau_bulk_plir)
            view.show()

    # correct for doping and transfer to bulk
    c_vals = fit_c_vals(cropped_nf, tau_bulk_plir, spline_plc)
    doping = ndimage.gaussian_filter1d(c_vals, sigma=2, mode="reflect")

    if False:
        ImageViewer(cropped_nf)
        plt.figure()
        plt.plot(c_vals)
        plt.plot(doping)
        plt.show()

    nf_dope = cropped_nf * np.r_[doping]
    nf_dope[nf_dope > spline_plc[0][-1]] = spline_plc[0][-1]

    tau_bulk_nf = interpolate.splev(nf_dope.flatten(), spline_plc).astype(
        np.float32).reshape(cropped_nf.shape)
    _, upper_p = ip.get_percentile(tau_bulk_nf, 0.0001)
    pixel_ops.ClipImage(tau_bulk_nf, 0.1, upper_p)

    features['_C_vals'] = doping.astype(np.float32)
    features['im_tau_bulk_f32'] = tau_bulk_nf
    features['im_tau_bulk_u8'] = (ip.scale_image(tau_bulk_nf) * 255).astype(
        np.uint8)
    features['im_cropped_nf_u8'] = (ip.scale_image(cropped_nf) * 255).astype(
        np.uint8)
    features['im_cropped_nf_u16'] = np.round(cropped_nf).astype(np.uint16)
    features['im_cropped_sp_u16'] = np.round(cropped_sp).astype(np.uint16)
    features['im_cropped_lp_u16'] = np.round(cropped_lp).astype(np.uint16)

    if False:
        print tau_bulk_nf.min(), tau_bulk_nf.max()
        _, upper_p = ip.get_percentile(tau_bulk_nf, 0.001)
        pixel_ops.ClipImage(tau_bulk_nf, 0.1, upper_p)
        # print interpolate.splev([0.0, 0.0245], spline_plc)
        #ImageViewer(cropped_nf * np.r_[doping])
        #ImageViewer(tau_bulk_nf)

        plt.figure()
        plt.plot(tau_bulk_plir.mean(axis=0))
        plt.plot(tau_bulk_nf.mean(axis=0))

        # plt.figure()
        # plt.hist(tau_bulk_full.flat, bins=100)
        if False:
            plt.figure()
            plt.plot(doping)
            plt.plot(c_vals)
            plt.figure()
            pl = np.mean(cropped_nf, axis=0)
            plt.plot(pl, label="PL")
            plt.legend()
        plt.show()

    # compute runtime
    t_stop = timeit.default_timer()
    features['runtime'] = t_stop - t_start

    return True
def finger_shape(features):
    if 'DEBUG' in features:
        DEBUG = features['DEBUG']
    else:
        DEBUG = False

    # use an image that has been normalised to [0, 1]
    im = features['_cropped_f32'] / features['hist_percentile_99.9']

    if parameters.CELL_BB_MID_POINTS:
        locs = np.round((features['_busbar_cols'][:-1] + features['_busbar_cols'][1:]) / 2.0).astype(np.int32)
        pixel_ops.InterpolateBBs(im, locs, 3)

    im_finger = im[features['_peak_row_nums']]
    # firing = np.zeros_like(im_finger)

    if False:
        view = ImageViewer(im)
        ImageViewer(im_finger)
        plt.figure()
        plt.plot(im_finger.mean(axis=0))
        view.show()
        sys.exit()

    TRAINING_MODE = False
    if TRAINING_MODE:
        import os
        fn = "finger_shape.csv"
        # bb_locs = features['_busbar_cols']
        bb_locs = np.r_[0, features['_busbar_cols'], im.shape[1] - 1]
        with open(fn, 'a') as f:
            def on_click(event):
                tb = plt.get_current_fig_manager().toolbar
                if event.xdata is None: return
                if tb.mode != '':
                    print 'Not in click mode - turn of pan or zoom'
                    return

                if event.button == 1:
                    classification = "good"
                elif event.button == 3:
                    classification = "bad"
                else:
                    return

                y = round(event.ydata)
                x = int(round(event.xdata))
                i = np.searchsorted(bb_locs, x)

                left, right = bb_locs[i - 1], bb_locs[i]
                assert left < x < right
                vals = im_finger[y, left:right]

                if x < im_finger.shape[1] // 2:
                    vals = vals[::-1]

                plt.figure()
                plt.plot(vals)
                plt.show()

                valstr = ','.join(["%0.02f" % (v) for v in vals])

                f.write("%s,%s\n" % (classification, valstr))

            fig = plt.figure()
            fig.canvas.mpl_connect('button_press_event', on_click)
            plt.imshow(im_finger, cmap=plt.cm.gray, interpolation='nearest')
            plt.show()
        return

    if len(features['_busbar_cols']) > 1:
        bb_locs = features['_busbar_cols']
    else:
        # only 1 busbar, so add left and right edges
        bb_locs = np.r_[0, features['_busbar_cols'], im.shape[1] - 1]

    S = 15
    # analyse each finger independently
    peak_broken = []
    peak_fine = []
    finger_rs = []
    finger_maes = []

    if False:
        locs = []
        for bb in range(len(bb_locs) - 1):
            locs.append((bb_locs[bb] + bb_locs[bb + 1]) // 2)
        im_finger2 = im_finger.copy()
        pixel_ops.InterpolateBBs(im_finger2, np.array(locs, np.int32), 4)
        view = ImageViewer(im_finger)
        ImageViewer(im_finger2)
        view.show()
        im_finger = im_finger2

    for bb in range(len(bb_locs) - 1):
        segment = im_finger[:, bb_locs[bb] + S:bb_locs[bb + 1] - S]
        if segment.shape[1] == 0:
            continue
        xs = np.linspace(-1.0, 1.0, num=segment.shape[1])
        for y in range(5, segment.shape[0] - 5):
            # fit a quadratic curve
            bbb = segment[y, :]
            params = np.polyfit(xs, bbb, 2)

            f = np.poly1d(params)
            ys = f(xs)

            # calculate the mean absolute error between the actual pixel values and the fitted parabola
            mae = np.abs(ys - bbb).mean() / bbb.mean()
            sigmoid = expit((mae - 0.02) / 0.001)

            # save curevature & goodness of fit
            finger_rs.append(params[0] * -1)
            finger_maes.append(mae)

            if sigmoid > 0.7:
                peak_broken.append(bbb.max())
            elif sigmoid < 0.3:
                peak_fine.append(bbb.max())

            # if True and bb == 0 and y == 5:
            if False and sigmoid > 0.7:
                print mae, sigmoid
                print bb, y
                im_fin = im_finger.copy()
                im_fin[y - 2, bb_locs[bb] + S:bb_locs[bb + 1] - S] = 0
                im_fin[y + 2, bb_locs[bb] + S:bb_locs[bb + 1] - S] = 0
                ImageViewer(im_fin)
                plt.figure()
                plt.plot(xs, bbb, label="x-profile")
                plt.plot(xs, ys, label="Fitted parabola")
                plt.legend()
                plt.show()

    if len(finger_rs) > 0:
        features['resistance_finger'] = np.median(finger_rs)
        features['resistance_finger_error'] = np.median(finger_maes)
    else:
        features['resistance_finger'] = 0
        features['resistance_finger_error'] = 0

    if len(peak_broken) > 0 or len(peak_fine) > 0:
        range_min = np.array(peak_broken + peak_fine).min()
        range_max = np.array(peak_broken + peak_fine).max()
        range_vals = np.linspace(range_min, range_max, num=100)

        peak_broken = np.array(peak_broken)
        peak_fine = np.array(peak_fine)
        broken_percent = peak_broken.shape[0] * 100 / float(peak_broken.shape[0] + peak_fine.shape[0])
        features['fingers_non_para'] = broken_percent

        # compute distribution of peak vals of bad fingers
        bad_fingers_dist = None
        bad_mode = None
        if len(peak_broken) > 5:
            f_bad_fingers = stats.gaussian_kde(peak_broken)
            bad_fingers_dist = f_bad_fingers(range_vals)
            bad_maxs = np.where((bad_fingers_dist > np.roll(bad_fingers_dist, 1)) &
                                (bad_fingers_dist > np.roll(bad_fingers_dist, -1)) &
                                (bad_fingers_dist > 2.0))[0]
            if len(bad_maxs) > 0:
                bad_mode = range_vals[bad_maxs[np.argmax(bad_fingers_dist[bad_maxs])]]

        # compute distribution of peak vals of good fingers
        good_fingers_dist = None
        good_maxs = []
        good_mode, good_mode_i = None, None
        if len(peak_fine) > 5:
            f_good_fingers = stats.gaussian_kde(peak_fine)
            good_fingers_dist = f_good_fingers(range_vals)
            good_maxs = np.where((good_fingers_dist > np.roll(good_fingers_dist, 1)) &
                                 (good_fingers_dist > np.roll(good_fingers_dist, -1)) &
                                 (good_fingers_dist > 2))[0]

            if len(good_maxs) > 0:
                good_mode_i = good_maxs[np.argmax(good_fingers_dist[good_maxs])]
                good_mode = range_vals[good_mode_i]

        if False:
            ImageViewer(im_finger)
            plt.figure()
            if good_fingers_dist is not None:
                plt.plot(range_vals, good_fingers_dist, 'g')
            if bad_fingers_dist is not None:
                plt.plot(range_vals, bad_fingers_dist, 'b')
            plt.show()
            sys.exit()

        if broken_percent >= 70:
            if DEBUG:
                print "0"
            # lots of broken, use fixed threshold
            threshold = 0.7
        elif broken_percent >= 33 and (good_mode is None or bad_mode < good_mode):
            if DEBUG:
                print "1"
            # significant broken and "non-broken" fingers are brighter than broken ones
            threshold = 0.7
        elif len(good_maxs) >= 2:
            # 2+ peaks in good dist.
            # - perhaps some good fingers are being classified as bad
            if broken_percent < 30 and (bad_mode is None or good_mode < bad_mode):
                if DEBUG:
                    print "2"
                # mostly good and broken fingers brighter
                # - use the highest peak
                i = good_mode_i
                while True:
                    if (good_fingers_dist[i] < 0.5 or i == good_fingers_dist.shape[0] - 1 or
                            (good_fingers_dist[i] < good_fingers_dist[i + 1] and
                                     good_fingers_dist[i] < 3)): break
                    i += 1
                threshold = range_vals[i]
            elif broken_percent < 20 and bad_mode is not None and bad_mode < good_mode:
                if DEBUG:
                    print "2B"
                # mostly good but broken fingers darker
                # - use the highest peak
                threshold = (range_vals[good_maxs[-2]] + range_vals[good_maxs[-1]]) / 2.0
            elif bad_mode is not None:
                if DEBUG:
                    print "3"
                # quite a few bad, or broken fingers darker
                # - use first peak
                i = good_maxs[0]
                while True:
                    if (good_fingers_dist[i] < 0.5 or i == good_fingers_dist.shape[0] - 1 or
                            (good_fingers_dist[i] < good_fingers_dist[i + 1] and
                                     good_fingers_dist[i] < 3)): break
                    i += 1
                threshold = min(range_vals[i], bad_mode - 0.1)
            else:
                threshold = good_mode
        elif (broken_percent <= 33 >= 1 and (bad_mode is None or good_mode < bad_mode) or
                      broken_percent < 10) and len(good_maxs):
            # - majority good fingers, single peak & broken fingers (if they exist) are brighter
            # - base the treshold on the distribution of good finger peaks
            if DEBUG:
                print "4"

            # find main mode in good dist
            i = good_maxs[0]
            while True:
                if (good_fingers_dist[i] < 0.5 or
                            i == good_fingers_dist.shape[0] - 1 or
                        (good_fingers_dist[i] < good_fingers_dist[i + 1] and
                                 good_fingers_dist[i] < 3)):
                    break
                i += 1

            threshold = min(range_vals[good_maxs[-1]] + 0.2, range_vals[i])
        else:
            if broken_percent > 33:
                # roughly 50/50. broken fingers are brighter
                # - use middle between good & bad
                if DEBUG:
                    print "5"
                threshold = (good_mode + bad_mode) / 2.0
            else:
                if DEBUG:
                    print "6"
                # majority good. assume the "bad" ones aren't actually bad
                if good_mode_i is not None:
                    i = good_mode_i
                else:
                    i = np.argmax(good_fingers_dist)
                while True:
                    if (good_fingers_dist[i] < 0.5 or
                                i == good_fingers_dist.shape[0] - 1 or
                            (good_fingers_dist[i] < good_fingers_dist[i + 1] and
                                     good_fingers_dist[i] < 3)):
                        break
                    i += 1

                threshold = range_vals[i]
    else:
        threshold = 1.0

    threshold -= parameters.BRIGHT_AREA_SENSITIVITY

    if False:
        print "Percent broken: ", broken_percent
        print "Threshold:", threshold

        view = ImageViewer(im)
        plt.figure()
        m1, m2 = 0, 0
        if good_fingers_dist is not None:
            plt.plot(range_vals, good_fingers_dist, 'g', label="Not broken")
            m1 = good_fingers_dist.max()
        if bad_fingers_dist is not None:
            plt.plot(range_vals, bad_fingers_dist, 'r', label="Broken")
            m2 = bad_fingers_dist.max()
        plt.vlines(threshold, 0, max(m1, m2))
        plt.legend()
        view.show()

    # highlight areas brighter than threshold
    # features['bright_line_threshold'] = threshold
    if threshold < 1.0:
        bright_lines = (im[features['_peak_row_nums']] - threshold) / (1.0 - threshold)
    else:
        bright_lines = np.zeros_like(im_finger)
    bright_lines *= 0.5
    pixel_ops.ClipImage(bright_lines, 0, 1)

    # don't want to highlight single lines, so apply vertical median filter
    rows_filtered = np.zeros_like(bright_lines)
    pixel_ops.FilterV(bright_lines, rows_filtered)
    rows_filtered[:2, :] = bright_lines[:2, :]
    rows_filtered[-2:, :] = bright_lines[-2:, :]

    if False:
        view = ImageViewer(im_finger)
        ImageViewer(bright_lines)
        ImageViewer(rows_filtered)
        view.show()
        sys.exit()

    bright_lines = rows_filtered

    # create a full size image of bright areas
    bright_area_full = np.zeros_like(im)
    pixel_ops.ExpandFingers(bright_area_full, bright_lines, features['_peak_row_nums'])
    bright_area_full = cv2.GaussianBlur(bright_area_full, sigmaX=3, ksize=(0, 0))
    bright_u8 = (bright_area_full * 255).astype(np.uint8)
    if 'ov_bright_area_u8' in features:
        assert False
        # features['ov_bright_area_u8'] = np.maximum(bright_u8, features['ov_bright_area_u8'])
    else:
        features['ov_bright_area_u8'] = bright_u8
    features['bright_area_strength'] = bright_lines.mean() * 100

    # bright area metrics
    mask_bright = (bright_area_full > 0.1).astype(np.uint8)
    im_pl = features['_cropped_f32']
    brightPL = pixel_ops.MaskMean_F32(im_pl, mask_bright, 1)
    darkPL = pixel_ops.MaskMean_F32(im_pl, mask_bright, 0)
    features['bright_area_mean_PL'] = brightPL
    features['bright_area_fraction'] = mask_bright.mean()
    features['bright_area_PL_intensity_ratio'] = brightPL / max(1, darkPL)

    # firing problems
    # firing_full = np.zeros_like(im)
    # pixel_ops.ExpandFingers(firing_full, firing, features['_peak_row_nums'])


    if False:
        view = ImageViewer(im_finger)
        ImageViewer(bright_area_full)
        # view = ImageViewer(firing_full)
        ImageViewer(features['ov_bright_area_u8'])
        view.show()
        sys.exit()
def dark_areas(features):
    # dark areas (not dark spots)
    im = features['im_norm']
    h, w = im.shape
    row_nums = features['_peak_row_nums']
    cell_mask = features['bl_cropped_u8'][row_nums, :]
    bb_locs = features['_busbar_cols']

    # fill edges & corners
    foreground = im[row_nums].copy()
    edge = features['cell_edge_tb']
    rr, cc = draw.circle_perimeter(features['wafer_middle_y'], features['wafer_middle_x'],
                                   int(round(features['wafer_radius'])) - edge)
    mask = (cc >= 0) & (cc < w) & np.in1d(rr, row_nums)
    lut = np.zeros(h, np.int32)
    lut[row_nums] = np.arange(len(row_nums))
    rr = rr[mask]
    cc = cc[mask]
    rr = np.take(lut, rr)
    pixel_ops.FillCorners(foreground, rr.astype(np.int32), cc.astype(np.int32))
    foreground[:, :edge] = np.c_[foreground[:, edge]]
    foreground[:, -edge:] = np.c_[foreground[:, -edge]]

    # create background
    # 1. make monotonic between edges & BBs
    mono_lr = np.empty_like(foreground)
    mono_rl = np.empty_like(foreground)
    pixel_ops.MakeMonotonicBBs(foreground, mono_lr, bb_locs)
    pixel_ops.MakeMonotonicBBs(np.ascontiguousarray(foreground[:, ::-1]), mono_rl,
                               np.ascontiguousarray(w - bb_locs[::-1]))
    mono_rl = mono_rl[:, ::-1]
    mono = np.minimum(mono_lr, mono_rl)
    background = mono
    da1 = background - foreground

    # fill BBs and flatten
    background2 = background.copy()
    pixel_ops.InterpolateBBs(background2, features['_busbar_cols'], features['busbar_width'])
    cols = background2.mean(axis=0)
    background2 -= np.r_[cols]
    rows = background2.mean(axis=1)
    background2 -= np.c_[rows]

    da2 = -1 * background2
    pixel_ops.ApplyThresholdLT_F32(da2, da2, 0.0, 0.0)

    if False:
        view = ImageViewer(foreground)
        ImageViewer(background)
        ImageViewer(background2)
        ImageViewer(da1)
        ImageViewer(da2)
        ImageViewer(da1 + da2)
        # plt.figure()
        # for x in range(0, background.shape[1], 50):
        #    plt.plot(background[:, x], label="Col %d"%(x))
        # plt.legend()
        view.show()
        sys.exit()

    dark_areas = da1 + da2
    dark_areas -= (0.1 - parameters.DARK_AREA_SENSITIVITY)
    dark_areas[(cell_mask == 1) | (cell_mask == 8)] = 0  # corners
    pixel_ops.ClipImage(dark_areas, 0.0, 1.0)
    dark_areas_full = np.empty_like(im)
    pixel_ops.ExpandFingers(dark_areas_full, dark_areas, features['_peak_row_nums'])

    if False:
        pixel_ops.ApplyThresholdGT_F32(features['im_center_dist_im'], dark_areas_full,
                                       features['wafer_radius'], 0)
        print features['wafer_radius']
        view = ImageViewer(dark_areas)
        ImageViewer(dark_areas_full)
        ImageViewer(features['im_center_dist_im'])
        view.show()

    dark_areas_full = cv2.GaussianBlur(dark_areas_full, ksize=(0, 0), sigmaX=1)

    # metrics
    mask_dark = (dark_areas_full > 0.2).astype(np.uint8)
    features['dark_area_strength'] = dark_areas_full.mean() * 100
    im_pl = features['_cropped_f32']
    darkPL = pixel_ops.MaskMean_F32(im_pl, mask_dark, 1)
    brightPL = pixel_ops.MaskMean_F32(im_pl, mask_dark, 0)
    features['dark_area_mean_PL'] = darkPL
    features['dark_area_fraction'] = mask_dark.mean()
    features['dark_area_PL_intensity_ratio'] = brightPL / max(1, darkPL)

    features['ov_dark_areas_u8'] = (dark_areas_full * 255).astype(np.uint8)

    if False:
        print features['dark_area_fraction'], features['dark_area_strength']
        # plt.figure()
        # plt.plot(cols)
        # plt.plot(cols_mono)
        view = ImageViewer(im)
        ImageViewer(foreground)
        ImageViewer(dark_areas)
        ImageViewer(mask_dark)
        ImageViewer(dark_areas_full)
        view.show()
def feature_extraction(im, features, skip_crop=False):
    t_start = timeit.default_timer()

    # rotation & cropping
    rotated = cropping.correct_cell_rotation(im, features, already_cropped=skip_crop)
    cropped = cropping.crop_cell(rotated, im, features, width=None, already_cropped=skip_crop)

    features['_cropped_f32'] = cropped
    features['im_cropped_u16'] = cropped.astype(np.uint16)
    h, w = cropped.shape

    if False:
        view = ImageViewer(im)
        ImageViewer(rotated)
        ImageViewer(cropped)
        view.show()

    # find fingers, busbars, etc
    cell.cell_structure(cropped, features)

    if False:
        view = ImageViewer(im)
        ImageViewer(cropped)
        ImageViewer(features['bl_cropped_u8'])
        view.show()
        sys.exit()

    # normalise
    ip.histogram_percentiles(cropped, features, center_y=h // 2, center_x=w // 2, radius=features['wafer_radius'])
    cell.normalise(cropped, features)
    norm = features['im_norm']

    if False:
        view = ImageViewer(cropped)
        ImageViewer(norm)
        view.show()
        sys.exit()

    # remove mini busbars
    if parameters.CELL_BB_MID_POINTS:
        locs = np.round((features['_busbar_cols'][:-1] + features['_busbar_cols'][1:]) / 2.0).astype(np.int32)
        norm_no_min = norm.copy()
        pixel_ops.InterpolateBBs(norm_no_min, locs, 3)
        if False:
            print locs
            view = ImageViewer(norm)
            ImageViewer(norm_no_min)
            view.show()
            sys.exit()
        norm = norm_no_min
        features['im_norm'] = norm_no_min

    # full-size cell with no fingers/busbars
    cell.remove_cell_template(norm, features)

    if False:
        view = ImageViewer(norm)
        # ImageViewer(im_peaks)
        ImageViewer(features['im_no_fingers'])
        ImageViewer(features['im_no_figners_bbs'])
        view.show()
        sys.exit()

    if 'input_param_skip_features' not in features or int(features['input_param_skip_features']) != 1:
        # find cell features
        wafer_features(features)
        cell.mono_cracks(features)
        finger_defects(features)
        firing_defects(features)
        finger_shape(features)
        dark_areas(features)
        dark_spots(features)
        if 'input_param_no_post_processing' not in features or int(features['input_param_no_post_processing']) != 1:
            feature_combination(features)

        finger_defect_features(features)

    if False:
        # disable until we can do more tuning with Hunter and Juergen
        # - also should be merged with finger_shape
        emitter_gridline_r(norm, features)

    # undo rotation
    if parameters.ORIGINAL_ORIENTATION and features['cell_rotated']:
        for feature in features.keys():
            if ((feature.startswith('im_') or feature.startswith('mask_') or
                     feature.startswith('map_') or feature.startswith('ov_') or
                     feature.startswith('bl_') or feature.startswith('mk_')) and features[feature].ndim == 2):
                features[feature] = features[feature].T[:, ::-1]

    # compute runtime
    t_stop = timeit.default_timer()
    features['runtime'] = t_stop - t_start