static gdouble calculate_sigma2_2d(GwyDataField *xfield, GwyDataField *yfield) { gdouble xc = gwy_data_field_get_avg(xfield); gdouble yc = gwy_data_field_get_avg(yfield); const gdouble *xdata = gwy_data_field_get_data(xfield); const gdouble *ydata = gwy_data_field_get_data(yfield); gdouble s2 = 0.0; guint n, i; n = gwy_data_field_get_xres(xfield)*gwy_data_field_get_yres(xfield); for (i = 0; i < n; i++) s2 += (xdata[i] - xc)*(xdata[i] - xc) + (ydata[i] - yc)*(ydata[i] - yc); return s2/n; }
/** * gwy_data_field_correlate_iteration: * @state: Correlation iterator. * * Performs one iteration of correlation. * * An iterator can be created with gwy_data_field_correlate_init(). * When iteration ends, either by finishing or being aborted, * gwy_data_field_correlate_finalize() must be called to release allocated * resources. **/ void gwy_data_field_correlate_iteration(GwyComputationState *cstate) { GwyCorrelationState *state = (GwyCorrelationState*)cstate; gint xres, yres, kxres, kyres, k, xoff, yoff; gdouble s, davg, drms; xres = state->data_field->xres; yres = state->data_field->yres; kxres = state->kernel_field->xres; kyres = state->kernel_field->yres; xoff = (kxres - 1)/2; yoff = (kyres - 1)/2; if (state->cs.state == GWY_COMPUTATION_STATE_INIT) { gwy_data_field_fill(state->score, -1); state->kavg = gwy_data_field_get_avg(state->kernel_field); state->krms = gwy_data_field_get_rms(state->kernel_field); state->avg = gwy_data_field_duplicate(state->data_field); state->rms = gwy_data_field_duplicate(state->data_field); calculate_normalization(state->avg, state->rms, kxres, kyres); state->cs.state = GWY_COMPUTATION_STATE_ITERATE; state->cs.fraction = 0.0; state->i = yoff; state->j = xoff; } else if (state->cs.state == GWY_COMPUTATION_STATE_ITERATE) { k = state->i*xres + state->j; davg = state->avg->data[k]; drms = state->rms->data[k]; if (drms && state->krms) { s = gwy_data_field_get_raw_correlation_score(state->data_field, state->kernel_field, state->j - xoff, state->i - yoff, 0, 0, kxres, kyres, davg, state->kavg); state->score->data[k] = s/(drms*state->krms); } else state->score->data[k] = 0.0; state->j++; if (state->j + kxres - xoff > xres) { state->j = xoff; state->i++; if (state->i + kyres - yoff > yres) state->cs.state = GWY_COMPUTATION_STATE_FINISHED; } state->cs.fraction += 1.0/((xres - kxres + 1)*(yres - kyres + 1)); state->cs.fraction = MIN(state->cs.fraction, 1.0); } else if (state->cs.state == GWY_COMPUTATION_STATE_FINISHED) return; gwy_data_field_invalidate(state->score); }
static void dwt(GwyContainer *data, GwyRunType run) { GtkWidget *dialog; GwyDataField *dfield; GwyDataLine *wtcoefs; DWTArgs args; gboolean ok; gint xsize, ysize, newsize, newid, oldid, i; g_return_if_fail(run & DWT_RUN_MODES); gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD, &dfield, GWY_APP_DATA_FIELD_ID, &oldid, 0); g_return_if_fail(dfield); xsize = gwy_data_field_get_xres(dfield); ysize = gwy_data_field_get_yres(dfield); if (xsize != ysize) { dialog = gtk_message_dialog_new (gwy_app_find_window_for_channel(data, oldid), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("%s: Data must be square."), "DWT"); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } for (newsize = 1, i = xsize-1; i; i >>= 1, newsize <<= 1) ; dwt_load_args(gwy_app_settings_get(), &args); if (run == GWY_RUN_INTERACTIVE) { ok = dwt_dialog(&args, xsize, newsize); dwt_save_args(gwy_app_settings_get(), &args); if (!ok) return; } dfield = gwy_data_field_new_resampled(dfield, newsize, newsize, args.interp); gwy_data_field_add(dfield, -gwy_data_field_get_avg(dfield)); wtcoefs = GWY_DATA_LINE(gwy_data_line_new(10, 10, TRUE)); wtcoefs = gwy_dwt_set_coefficients(wtcoefs, args.wavelet); gwy_data_field_dwt(dfield, wtcoefs, 1, 4); newid = gwy_app_data_browser_add_data_field(dfield, data, TRUE); g_object_unref(dfield); gwy_app_set_data_field_title(data, newid, _("DWT")); gwy_app_sync_data_items(data, data, oldid, newid, FALSE, GWY_DATA_ITEM_PALETTE, 0); g_object_unref(wtcoefs); }
static void zero_mean(GwyContainer *data, GwyRunType run) { GwyDataField *dfield; GQuark quark; g_return_if_fail(run & LEVEL_RUN_MODES); gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD_KEY, &quark, GWY_APP_DATA_FIELD, &dfield, 0); g_return_if_fail(dfield && quark); gwy_app_undo_qcheckpoint(data, quark, NULL); gwy_data_field_add(dfield, -gwy_data_field_get_avg(dfield)); gwy_data_field_data_changed(dfield); }
static void dwt_anisotropy(GwyContainer *data, GwyRunType run) { GtkWidget *dialog; GwyDataField *dfield, *mask; GQuark dquark, mquark; GwyDataLine *wtcoefs; DWTAnisotropyArgs args; gboolean ok; gint xsize, ysize, newsize, limit, id, i; g_return_if_fail(run & DWT_ANISOTROPY_RUN_MODES); gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD_KEY, &dquark, GWY_APP_DATA_FIELD, &dfield, GWY_APP_DATA_FIELD_ID, &id, GWY_APP_MASK_FIELD_KEY, &mquark, GWY_APP_MASK_FIELD, &mask, 0); g_return_if_fail(dfield && dquark); xsize = gwy_data_field_get_xres(dfield); ysize = gwy_data_field_get_yres(dfield); if (xsize != ysize) { dialog = gtk_message_dialog_new (gwy_app_find_window_for_channel(data, id), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("%s: Data must be square."), _("DWT Anisotropy")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } dwt_anisotropy_load_args(gwy_app_settings_get(), &args); if (run == GWY_RUN_INTERACTIVE) { ok = dwt_anisotropy_dialog(&args); dwt_anisotropy_save_args(gwy_app_settings_get(), &args); if (!ok) return; } for (newsize = 1, i = xsize-1; i; i >>= 1, newsize <<= 1) ; dfield = gwy_data_field_new_resampled(dfield, newsize, newsize, args.interp); gwy_data_field_add(dfield, -gwy_data_field_get_avg(dfield)); gwy_app_undo_qcheckpoint(data, dquark, mquark, 0); if (!mask) { mask = gwy_data_field_new_alike(dfield, FALSE); gwy_container_set_object(data, mquark, mask); g_object_unref(mask); } gwy_data_field_resample(mask, newsize, newsize, GWY_INTERPOLATION_NONE); wtcoefs = gwy_data_line_new(10, 10, TRUE); wtcoefs = gwy_dwt_set_coefficients(wtcoefs, args.wavelet); /*justo for sure clamp the lowlimit again*/ limit = pow(2, CLAMP(args.lowlimit, 1, 20)); gwy_data_field_dwt_mark_anisotropy(dfield, mask, wtcoefs, args.ratio, limit); gwy_data_field_resample(mask, xsize, ysize, GWY_INTERPOLATION_ROUND); g_object_unref(wtcoefs); g_object_unref(dfield); gwy_data_field_data_changed(mask); gwy_app_channel_log_add_proc(data, id, id); }
static void immerse_do(ImmerseArgs *args) { GwyDataField *resampled, *image, *detail, *result; GwyContainer *data; gint newid; gint kxres, kyres; gint x, y, w, h; gdouble iavg, davg; GQuark quark; data = gwy_app_data_browser_get(args->image.datano); quark = gwy_app_get_data_key_for_id(args->image.id); image = GWY_DATA_FIELD(gwy_container_get_object(data, quark)); data = gwy_app_data_browser_get(args->detail.datano); quark = gwy_app_get_data_key_for_id(args->detail.id); detail = GWY_DATA_FIELD(gwy_container_get_object(data, quark)); davg = gwy_data_field_get_avg(detail); kxres = gwy_data_field_get_xres(detail); kyres = gwy_data_field_get_yres(detail); switch (args->sampling) { case GWY_IMMERSE_SAMPLING_DOWN: result = gwy_data_field_duplicate(image); x = gwy_data_field_rtoj(image, args->xpos); y = gwy_data_field_rtoi(image, args->ypos); w = GWY_ROUND(gwy_data_field_get_xreal(detail) /gwy_data_field_get_xmeasure(image)); h = GWY_ROUND(gwy_data_field_get_yreal(detail) /gwy_data_field_get_ymeasure(image)); w = MAX(w, 1); h = MAX(h, 1); gwy_debug("w: %d, h: %d", w, h); resampled = gwy_data_field_new_resampled(detail, w, h, GWY_INTERPOLATION_LINEAR); if (args->leveling == GWY_IMMERSE_LEVEL_MEAN) { iavg = gwy_data_field_area_get_avg(result, NULL, x, y, w, h); gwy_data_field_add(resampled, iavg - davg); } gwy_data_field_area_copy(resampled, result, 0, 0, w, h, x, y); g_object_unref(resampled); break; case GWY_IMMERSE_SAMPLING_UP: w = GWY_ROUND(gwy_data_field_get_xreal(image) /gwy_data_field_get_xmeasure(detail)); h = GWY_ROUND(gwy_data_field_get_yreal(image) /gwy_data_field_get_ymeasure(detail)); gwy_debug("w: %d, h: %d", w, h); result = gwy_data_field_new_resampled(image, w, h, GWY_INTERPOLATION_LINEAR); x = gwy_data_field_rtoj(result, args->xpos); y = gwy_data_field_rtoi(result, args->ypos); if (args->leveling == GWY_IMMERSE_LEVEL_MEAN) { iavg = gwy_data_field_area_get_avg(result, NULL, x, y, kxres, kyres); gwy_data_field_area_copy(detail, result, 0, 0, kxres, kyres, x, y); gwy_data_field_area_add(result, x, y, kxres, kyres, iavg - davg); } else gwy_data_field_area_copy(detail, result, 0, 0, kxres, kyres, x, y); break; default: g_return_if_reached(); break; } gwy_app_data_browser_get_current(GWY_APP_CONTAINER, &data, 0); newid = gwy_app_data_browser_add_data_field(result, data, TRUE); gwy_app_set_data_field_title(data, newid, _("Immersed detail")); g_object_unref(result); gwy_app_channel_log_add_proc(data, args->image.id, newid); }
/** * gwy_data_field_correlate: * @data_field: A data field. * @kernel_field: Correlation kernel. * @score: Data field to store correlation scores to. * @method: Correlation score calculation method. * * Computes correlation score for all positions in a data field. * * Correlation score is compute for all points in data field @data_field * and full size of correlation kernel @kernel_field. * * The points in @score correspond to centers of kernel. More precisely, the * point ((@kxres-1)/2, (@kyres-1)/2) in @score corresponds to kernel field * top left corner coincident with data field top left corner. Points outside * the area where the kernel field fits into the data field completely are * set to -1 for %GWY_CORRELATION_NORMAL. **/ void gwy_data_field_correlate(GwyDataField *data_field, GwyDataField *kernel_field, GwyDataField *score, GwyCorrelationType method) { gint xres, yres, kxres, kyres, i, j, k, fftxres, fftyres; GwyDataField *data_in_re, *data_out_re, *data_out_im; GwyDataField *kernel_in_re, *kernel_out_re, *kernel_out_im; gdouble norm; g_return_if_fail(data_field != NULL && kernel_field != NULL); xres = data_field->xres; yres = data_field->yres; kxres = kernel_field->xres; kyres = kernel_field->yres; if (kxres <= 0 || kyres <= 0) { g_warning("Correlation kernel has nonpositive size."); return; } switch (method) { case GWY_CORRELATION_NORMAL: gwy_data_field_fill(score, -1); /*correlation request outside kernel */ if (kxres > xres || kyres > yres) { return; } { GwyDataField *avg, *rms; gdouble s, davg, drms, kavg, krms; gint xoff, yoff; /* The number of pixels the correlation kernel extends to the * negative direction */ xoff = (kxres - 1)/2; yoff = (kyres - 1)/2; kavg = gwy_data_field_get_avg(kernel_field); krms = gwy_data_field_get_rms(kernel_field); avg = gwy_data_field_duplicate(data_field); rms = gwy_data_field_duplicate(data_field); calculate_normalization(avg, rms, kxres, kyres); for (i = yoff; i + kyres - yoff <= yres; i++) { for (j = xoff; j + kxres - xoff <= xres; j++) { k = i*xres + j; davg = avg->data[k]; drms = rms->data[k]; if (!krms || !drms) { score->data[k] = 0.0; continue; } s = gwy_data_field_get_raw_correlation_score(data_field, kernel_field, j - xoff, i - yoff, 0, 0, kxres, kyres, davg, kavg); score->data[k] = s/(drms*krms); } } g_object_unref(avg); g_object_unref(rms); } break; case GWY_CORRELATION_FFT: case GWY_CORRELATION_POC: fftxres = gwy_fft_find_nice_size(xres); fftyres = gwy_fft_find_nice_size(yres); data_in_re = gwy_data_field_new_resampled(data_field, fftxres, fftyres, GWY_INTERPOLATION_BILINEAR); kernel_in_re = gwy_data_field_new_alike(data_field, TRUE); gwy_data_field_area_copy(kernel_field, kernel_in_re, 0, 0, kernel_field->xres, kernel_field->yres, kernel_in_re->xres/2 - kernel_field->xres/2, kernel_in_re->yres/2 - kernel_field->yres/2); gwy_data_field_resample(kernel_in_re, fftxres, fftyres, GWY_INTERPOLATION_BILINEAR); gwy_data_field_resample(score, fftxres, fftyres, GWY_INTERPOLATION_NONE); data_out_re = gwy_data_field_new_alike(data_in_re, TRUE); data_out_im = gwy_data_field_new_alike(data_in_re, TRUE); kernel_out_re = gwy_data_field_new_alike(data_in_re, TRUE); kernel_out_im = gwy_data_field_new_alike(data_in_re, TRUE); gwy_data_field_2dfft(data_in_re, NULL, data_out_re, data_out_im, GWY_WINDOWING_NONE, GWY_TRANSFORM_DIRECTION_FORWARD, GWY_INTERPOLATION_BILINEAR, FALSE, FALSE); gwy_data_field_2dfft(kernel_in_re, NULL, kernel_out_re, kernel_out_im, GWY_WINDOWING_NONE, GWY_TRANSFORM_DIRECTION_FORWARD, GWY_INTERPOLATION_BILINEAR, FALSE, FALSE); for (i = 0; i < fftxres*fftyres; i++) { /*NOTE: now we construct new "complex field" from data * and kernel fields, just to save memory*/ data_in_re->data[i] = data_out_re->data[i]*kernel_out_re->data[i] + data_out_im->data[i]*kernel_out_im->data[i]; kernel_in_re->data[i] = -data_out_re->data[i]*kernel_out_im->data[i] + data_out_im->data[i]*kernel_out_re->data[i]; if (method == GWY_CORRELATION_POC) { norm = hypot(data_in_re->data[i], kernel_in_re->data[i]); data_in_re->data[i] /= norm; kernel_in_re->data[i] /= norm; } } gwy_data_field_2dfft(data_in_re, kernel_in_re, score, data_out_im, GWY_WINDOWING_NONE, GWY_TRANSFORM_DIRECTION_BACKWARD, GWY_INTERPOLATION_BILINEAR, FALSE, FALSE); gwy_data_field_2dfft_humanize(score); /*TODO compute it and put to score field*/ g_object_unref(data_in_re); g_object_unref(data_out_re); g_object_unref(data_out_im); g_object_unref(kernel_in_re); g_object_unref(kernel_out_re); g_object_unref(kernel_out_im); break; } gwy_data_field_invalidate(score); }
static void dwt_denoise(GwyContainer *data, GwyRunType run) { GtkWidget *dialog; GwyDataField *dfield; GwyDataLine *wtcoefs; DWTDenoiseArgs args; gboolean ok; gint xsize, ysize, newsize; gint oldid, newid; g_return_if_fail(run & DWT_DENOISE_RUN_MODES); gwy_app_data_browser_get_current(GWY_APP_DATA_FIELD, &dfield, GWY_APP_DATA_FIELD_ID, &oldid, 0); g_return_if_fail(dfield); xsize = gwy_data_field_get_xres(dfield); ysize = gwy_data_field_get_yres(dfield); if (xsize != ysize) { dialog = gtk_message_dialog_new (GTK_WINDOW(gwy_app_data_window_get_current()), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("%s: Data must be square."), _("DWT Denoise")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } dwt_denoise_load_args(gwy_app_settings_get(), &args); if (run == GWY_RUN_INTERACTIVE) { ok = dwt_denoise_dialog(&args); dwt_denoise_save_args(gwy_app_settings_get(), &args); if (!ok) return; } dfield = gwy_data_field_duplicate(dfield); newsize = gwy_fft_find_nice_size(xsize); gwy_data_field_add(dfield, -gwy_data_field_get_avg(dfield)); gwy_data_field_resample(dfield, newsize, newsize, GWY_INTERPOLATION_BILINEAR); wtcoefs = gwy_data_line_new(10, 10, TRUE); wtcoefs = gwy_dwt_set_coefficients(wtcoefs, args.wavelet); gwy_data_field_dwt_denoise(dfield, wtcoefs, TRUE, 20, args.method); if (args.preserve) gwy_data_field_resample(dfield, xsize, ysize, args.interp); newid = gwy_app_data_browser_add_data_field(dfield, data, TRUE); gwy_app_copy_data_items(data, data, oldid, newid, GWY_DATA_ITEM_GRADIENT, GWY_DATA_ITEM_MASK_COLOR, 0); g_object_unref(dfield); gwy_app_set_data_field_title(data, newid, _("DWT denoised")); g_object_unref(wtcoefs); }