def get_decile_widths(binary_mask, scale): mask_T = binary_mask.T tip_index = get_index_of_tip(mask_T) shoulder_index = get_index_of_shoulder(mask_T) # print("t", tip_index, "s", shoulder_index) decile = int((shoulder_index - tip_index) / 10) decile_indices = [ i for i in range(tip_index, tip_index + decile * 10, decile) ] + [shoulder_index - 1] decile_widths = [count_white_pixels(mask_T[i]) for i in decile_indices] mm_per_pixel = pixel_to_mm(scale) decile_widths_mm = [round(i * mm_per_pixel, 2) for i in decile_widths] # shoulder to tip, that's why it's reversed here. return decile_widths_mm[::-1]
def get_histogram_data(src, diff_thresh=25): diff_too_big_count = 0 total_count = 0 regr = load("tip-mask-model.joblib") pairs = get_mask_pairs(src) data = [] for pair in pairs: total_count += 1 raw = pair["with-tips"] training = pair["without-tips"] raw_mask = cv2.imread(raw, cv2.IMREAD_GRAYSCALE) training_mask = cv2.imread(training, cv2.IMREAD_GRAYSCALE) attributes = get_attributes_from_filename(raw) scale = attributes.get("Scale", None) mm_per_px = pixel_to_mm(scale) tip_index = tip_mask_ml(raw_mask, regr, mm_per_px) detipped_length = get_length(training_mask) length_diff = round(tip_index[0]) - detipped_length if abs(length_diff) > diff_thresh: diff_too_big_count += 1 raw_length = get_length(raw_mask) print(">>>>>>>>>>>>>>>>") print(f"tip mask diff > {diff_thresh} px", raw) print("with-tip -> without-tip diff: ", raw_length - detipped_length) data.append(length_diff) print( f"diff > {diff_thresh}px in {diff_too_big_count} out of {total_count} cases." ) return data
def tip_mask(src, model, visualize=False): """ mask the tips of the straightened carrots Args: src (str) - absolute path to the binary mask visualize (bool) - only visualize the masking """ # if not dest: dest = src.split(STRAIGHTENED_MASKS_DIR)[0] dest = os.path.join(dest, DETIPPED_MASKS_DIR) if os.path.exists(dest): shutil.rmtree(dest) if not os.path.exists(dest): os.makedirs(dest) for file in os.listdir(src): print(file) src_filepath = os.path.join(src, file) dest_filepath = os.path.join(dest, file) mask = cv2.imread(src_filepath, cv2.IMREAD_GRAYSCALE) attributes = get_attributes_from_filename(src_filepath) scale = attributes.get("Scale", None) mm_per_px = pixel_to_mm(scale) if mask is None: msg = "File %s is empty!" % src_filepath click.secho(msg, fg="red") continue # get index from ml model try: tip_index = tip_mask_ml(mask, model, mm_per_px) except Exception as e: click.secho(file, fg="red") print(e) tip_index = [0] tip_index = int(tip_index[0]) # print(tip_index) # print(mask.shape[1]) tip_index = mask.shape[1] - tip_index # get index based on threshold # tip_index = find_tip_pseudo_dynamic(mask, pure=True) # tip_index_advanced = find_tip_pseudo_dynamic(mask, pure=False) # if tip_index_advanced > 0: # crop_index = tip_index_advanced # else: # crop_index = tip_index crop_index = tip_index if visualize: # paint only tip = mark_start_of_tail(mask.copy(), tip_index, [0, 0, 255]) # tip = mark_start_of_tail(tip, tip_index_advanced, [0, 255, 0]) # print(dest) write_file(tip, dest, file) continue else: # crop + buffer + wirte mask = mask[:, crop_index:] black_col = np.zeros((mask.shape[0], 10), dtype=np.uint8) mask = np.hstack([black_col, mask]) # another round of contour reduction to remove dangling white pixels mask = reduce_to_contour(mask, minimize=False) cv2.imwrite(dest_filepath, mask) old_tip_index = get_index_of_tip(mask.T) tip_length = crop_index - old_tip_index if tip_length < 0: tip_length = 0 tip_biomass = get_biomass(mask[:, old_tip_index:crop_index]) new_filepath = append_or_change_filename(dest_filepath, "TipLength", None, tip_length) append_or_change_filename(new_filepath, "TipBiomass", None, tip_biomass)
def run(src): start = timeit.default_timer() pairs = get_mask_pairs(src) # pixel müssen vergleichbar sein. data = [] for pair in pairs: raw = pair["with-tips"] training = pair["without-tips"] # print(raw) attributes = get_attributes_from_filename(raw) scale = attributes.get("Scale", None) mm_per_px = pixel_to_mm(scale) # print(mm_per_px) raw_mask = cv2.imread(raw, cv2.IMREAD_GRAYSCALE) training_mask = cv2.imread(training, cv2.IMREAD_GRAYSCALE) # reverse, so the thick end is at 0 width_array = get_width_array_mm(raw_mask, mm_per_px)[::-1] # print(width_array) normalized_width_array = normalize_width_array(width_array) # length of raw carrot # raw_length = get_length(raw_mask) # print("length", raw_length) # length of detipped carrot detipped_length = get_length(training_mask) # print("detipped length", detipped_length) # difference in length # length_diff = raw_length - detipped_length # white_index_raw = get_index_first_white_pixel(raw_mask) # tip_index = white_index_raw + length_diff # because the widths are reversed tip_index = detipped_length data.append( {"tip_index": tip_index, "normalized_widths": normalized_width_array} ) # resampling sagt Gilles... equalized_data = equalize_lengths(data) X = [d["normalized_widths"] for d in equalized_data] y = [d["tip_index"] for d in equalized_data] X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0) # linreg = LinearRegression().fit(X_train, y_train) # print('R-squared score (training): {:.3f}' # .format(linreg.score(X_train, y_train))) # print('R-squared score (test): {:.3f}' # .format(linreg.score(X_test, y_test))) regr = RandomForestRegressor(max_depth=5, random_state=0, n_estimators=10) regr.fit(X_train, y_train) print("score", regr.score(X_test, y_test)) # regr.predict([[feature1, feature2]]) dump(regr, "tip-mask-model.joblib") print("model dumped") stop = timeit.default_timer() print(f"training: {stop - start}")
def convert_surface_to_mm2(scale, surface_px): mm_per_pixel = pixel_to_mm(scale) mm2_per_pixel = mm_per_pixel**2 surface_mm2 = mm2_per_pixel * surface_px return round(surface_mm2, 4)
def convert_length_to_mm(scale, length_px): mm_per_pixel = pixel_to_mm(scale) length_mm = length_px * mm_per_pixel return round(length_mm, 4)