/** * 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); }
void gwy_data_field_crosscorrelate_set_weights(GwyComputationState *state, GwyWindowingType type) { GwyCrossCorrelationState *cstate = (GwyCrossCorrelationState*)state; g_return_if_fail(cstate->cs.state == GWY_COMPUTATION_STATE_INIT); gwy_data_field_fill(cstate->weights, 1); gwy_fft_window_data_field(cstate->weights, GWY_ORIENTATION_HORIZONTAL, type); gwy_fft_window_data_field(cstate->weights, GWY_ORIENTATION_VERTICAL, type); }
/** * gwy_data_field_crosscorrelate_init: * @data_field1: A data field. * @data_field2: A data field. * @x_dist: A data field to store x-distances to, or %NULL. * @y_dist: A data field to store y-distances to, or %NULL. * @score: Data field to store correlation scores to, or %NULL. * @search_width: Search area width. * @search_height: Search area height. * @window_width: Correlation window width. * @window_height: Correlation window height. * * Initializes a cross-correlation iterator. * * This iterator reports its state as #GwyComputationStateType. * * Returns: A new cross-correlation iterator. **/ GwyComputationState* gwy_data_field_crosscorrelate_init(GwyDataField *data_field1, GwyDataField *data_field2, GwyDataField *x_dist, GwyDataField *y_dist, GwyDataField *score, gint search_width, gint search_height, gint window_width, gint window_height) { GwyCrossCorrelationState *state; g_return_val_if_fail(GWY_IS_DATA_FIELD(data_field1), NULL); g_return_val_if_fail(GWY_IS_DATA_FIELD(data_field2), NULL); g_return_val_if_fail(data_field1->xres == data_field2->xres && data_field1->yres == data_field2->yres, NULL); g_return_val_if_fail(!x_dist || GWY_IS_DATA_FIELD(x_dist), NULL); g_return_val_if_fail(!y_dist || GWY_IS_DATA_FIELD(y_dist), NULL); g_return_val_if_fail(!score || GWY_IS_DATA_FIELD(score), NULL); state = g_new0(GwyCrossCorrelationState, 1); state->cs.state = GWY_COMPUTATION_STATE_INIT; state->cs.fraction = 0.0; state->data_field1 = g_object_ref(data_field1); state->data_field2 = g_object_ref(data_field2); if (x_dist) state->x_dist = g_object_ref(x_dist); if (y_dist) state->y_dist = g_object_ref(y_dist); if (score) state->score = g_object_ref(score); state->search_width = search_width; state->search_height = search_height; state->window_width = window_width; state->window_height = window_height; state->weights = gwy_data_field_new(window_width, window_height, window_width, window_height, 1); gwy_data_field_fill(state->weights, 1); return (GwyComputationState*)state; }
static void rotate_datafield(GwyDataField *dfield, RotateArgs *args) { gint xres, yres, xborder, yborder; gdouble xreal, yreal, phi, min; GwyDataField *df; if (!args->expand) { gwy_data_field_rotate(dfield, args->angle, args->interp); return; } xres = gwy_data_field_get_xres(dfield); yres = gwy_data_field_get_yres(dfield); xreal = gwy_data_field_get_xreal(dfield); yreal = gwy_data_field_get_yreal(dfield); min = gwy_data_field_get_min(dfield); phi = args->angle; xborder = fabs(xres/2.0 * cos(phi)) + fabs(yres/2.0 * sin(phi)); xborder -= xres/2; yborder = fabs(yres/2.0 * cos(phi)) + fabs(xres/2.0 * sin(phi)); yborder -= yres/2; df = gwy_data_field_new(xres + fabs(2*xborder), yres + fabs(2*yborder), 1.0, 1.0, FALSE); gwy_data_field_fill(df, min); gwy_data_field_area_copy(dfield, df, 0, 0, xres, yres, fabs(xborder), fabs(yborder)); gwy_data_field_rotate(df, args->angle, args->interp); gwy_data_field_resample(dfield, xres + 2*xborder, yres + 2*yborder, GWY_INTERPOLATION_NONE); if (xborder <= 0) gwy_data_field_area_copy(df, dfield, fabs(2*xborder), 0, xres + 2*xborder, yres + 2*yborder, 0, 0); else { if (yborder <= 0) gwy_data_field_area_copy(df, dfield, 0, fabs(2*yborder), xres + 2*xborder, yres + 2*yborder, 0, 0); else gwy_data_field_area_copy(df, dfield, 0, 0, xres + 2*xborder, yres + 2*yborder, 0, 0); } gwy_data_field_set_xreal(dfield, xreal*(xres + 2.0*xborder)/xres); gwy_data_field_set_yreal(dfield, yreal*(yres + 2.0*yborder)/yres); g_object_unref(df); }
static void selection_finished_cb(GwyUnitoolState *state) { GwyContainer *data; GObject *dfield; GwyDataField *mask = NULL; GwyDataViewLayer *layer; ToolControls *controls; GwySIUnit *siunit; gint isel[4]; controls = (ToolControls*)state->user_data; layer = GWY_DATA_VIEW_LAYER(state->layer); data = gwy_data_view_get_data(GWY_DATA_VIEW(layer->parent)); dfield = gwy_container_get_object_by_name(data, "/0/data"); gwy_container_gis_object_by_name(data, "/0/mask", (GObject**)&mask); gwy_unitool_rect_info_table_fill(state, &controls->labels, NULL, isel); switch (controls->mode) { case MASK_EDIT_SET: gwy_app_undo_checkpoint(data, "/0/mask", NULL); if (!mask) { mask = GWY_DATA_FIELD(gwy_serializable_duplicate(dfield)); siunit = GWY_SI_UNIT(gwy_si_unit_new("")); gwy_data_field_set_si_unit_z(mask, siunit); g_object_unref(siunit); gwy_container_set_object_by_name(data, "/0/mask", (GObject*)mask); g_object_unref(mask); } gwy_data_field_fill(mask, 0.0); gwy_data_field_area_fill(mask, isel[0], isel[1], isel[2], isel[3], 1.0); break; case MASK_EDIT_ADD: gwy_app_undo_checkpoint(data, "/0/mask", NULL); if (!mask) { mask = GWY_DATA_FIELD(gwy_serializable_duplicate(dfield)); siunit = GWY_SI_UNIT(gwy_si_unit_new("")); gwy_data_field_set_si_unit_z(mask, siunit); g_object_unref(siunit); gwy_container_set_object_by_name(data, "/0/mask", (GObject*)mask); g_object_unref(mask); gwy_data_field_fill(mask, 0.0); } gwy_data_field_area_fill(mask, isel[0], isel[1], isel[2], isel[3], 1.0); break; case MASK_EDIT_REMOVE: if (mask) { gwy_app_undo_checkpoint(data, "/0/mask", NULL); gwy_data_field_area_fill(mask, isel[0], isel[1], isel[2], isel[3], 0.0); } break; case MASK_EDIT_INTERSECT: if (mask) { gwy_app_undo_checkpoint(data, "/0/mask", NULL); gwy_data_field_clamp(mask, 0.0, 1.0); gwy_data_field_area_add(mask, isel[0], isel[1], isel[2], isel[3], 1.0); gwy_data_field_add(mask, -1.0); gwy_data_field_clamp(mask, 0.0, 1.0); } break; default: break; } gwy_vector_layer_unselect(GWY_VECTOR_LAYER(layer)); gwy_app_data_view_update(layer->parent); }
static gint fill_data_fields(MProFile *mprofile, const guchar *buffer) { GwyDataField *dfield, *vpmask; gdouble *data, *mask; gdouble xreal, yreal, q; const guchar *p; guint n, id, i, j, ndata; ndata = 0; mprofile->intensity_data = NULL; mprofile->intensity_mask = NULL; mprofile->phase_data = NULL; mprofile->phase_mask = NULL; p = buffer + mprofile->header_size; /* Intensity data */ n = mprofile->intens_xres * mprofile->intens_yres; /* Enorce consistency */ if (!n && mprofile->nbuckets) { g_warning("nbuckets > 0, but intensity data have zero dimension"); mprofile->nbuckets = 0; } if (mprofile->nbuckets) { const guint16 *d16; mprofile->intensity_data = g_new(GwyDataField*, mprofile->nbuckets); mprofile->intensity_mask = g_new(GwyDataField*, mprofile->nbuckets); q = mprofile->data_inverted ? -1.0 : 1.0; if (mprofile->camera_res) { xreal = mprofile->intens_xres * mprofile->camera_res; yreal = mprofile->intens_yres * mprofile->camera_res; } else { /* whatever */ xreal = mprofile->intens_xres; yreal = mprofile->intens_yres; } for (id = 0; id < mprofile->nbuckets; id++) { ndata++; dfield = gwy_data_field_new(mprofile->intens_xres, mprofile->intens_yres, xreal, yreal, FALSE); vpmask = gwy_data_field_new_alike(dfield, FALSE); gwy_data_field_fill(vpmask, 1.0); data = gwy_data_field_get_data(dfield); mask = gwy_data_field_get_data(vpmask); d16 = (const guint16*)p; for (i = 0; i < mprofile->intens_yres; i++) { for (j = 0; j < mprofile->intens_xres; j++) { guint v16 = GUINT16_FROM_BE(*d16); if (v16 >= 65412) { mask[i*mprofile->intens_xres + j] = 0.0; } else *data = q*v16; d16++; data++; } } set_units(dfield, mprofile, ""); if (!gwy_app_channel_remove_bad_data(dfield, vpmask)) gwy_object_unref(vpmask); mprofile->intensity_data[id] = dfield; mprofile->intensity_mask[id] = vpmask; p += sizeof(guint16)*n; } } /* Phase data */ n = mprofile->phase_xres * mprofile->phase_yres; if (n) { const gint32 *d32; gint32 d; ndata++; i = 4096; if (mprofile->phase_res == 1) i = 32768; q = mprofile->scale_factor * mprofile->obliquity_factor * mprofile->wavelength_in/i; if (mprofile->data_inverted) q = -q; gwy_debug("q: %g", q); if (mprofile->camera_res) { xreal = mprofile->phase_xres * mprofile->camera_res; yreal = mprofile->phase_yres * mprofile->camera_res; } else { /* whatever */ xreal = mprofile->phase_xres; yreal = mprofile->phase_yres; } dfield = gwy_data_field_new(mprofile->phase_xres, mprofile->phase_yres, xreal, yreal, FALSE); vpmask = gwy_data_field_new_alike(dfield, FALSE); gwy_data_field_fill(vpmask, 1.0); data = gwy_data_field_get_data(dfield); mask = gwy_data_field_get_data(vpmask); d32 = (const gint32*)p; for (i = 0; i < mprofile->phase_yres; i++) { for (j = 0; j < mprofile->phase_xres; j++) { d = GINT32_FROM_BE(*d32); if (d >= 2147483640) { mask[i*mprofile->phase_xres + j] = 0.0; } else *data = q*d; d32++; data++; } } set_units(dfield, mprofile, "m"); if (!gwy_app_channel_remove_bad_data(dfield, vpmask)) gwy_object_unref(vpmask); mprofile->phase_data = dfield; mprofile->phase_mask = vpmask; p += sizeof(gint32)*n; } return ndata; }
static void put_fields(GwyDataField *dfield1, GwyDataField *dfield2, GwyDataField *result, GwyDataField *outsidemask, GwyMergeBoundaryType boundary, gint px1, gint py1, gint px2, gint py2) { GwyRectangle res_rect; GwyCoord f1_pos; GwyCoord f2_pos; gint w1, w2, h1, h2; gdouble xreal, yreal; gwy_debug("field1 %dx%d", dfield1->xres, dfield1->yres); gwy_debug("field2 %dx%d", dfield2->xres, dfield2->yres); gwy_debug("result %dx%d", result->xres, result->yres); gwy_debug("px1: %d, py1: %d, px2: %d, py2: %d", px1, py1, px2, py2); gwy_data_field_fill(result, MIN(gwy_data_field_get_min(dfield1), gwy_data_field_get_min(dfield2))); w1 = gwy_data_field_get_xres(dfield1); h1 = gwy_data_field_get_yres(dfield1); w2 = gwy_data_field_get_xres(dfield2); h2 = gwy_data_field_get_yres(dfield2); if (boundary == GWY_MERGE_BOUNDARY_SECOND) { gwy_data_field_area_copy(dfield1, result, 0, 0, w1, h1, px1, py1); gwy_data_field_area_copy(dfield2, result, 0, 0, w2, h2, px2, py2); } else { gwy_data_field_area_copy(dfield2, result, 0, 0, w2, h2, px2, py2); gwy_data_field_area_copy(dfield1, result, 0, 0, w1, h1, px1, py1); } if (outsidemask) { gwy_data_field_fill(outsidemask, 1.0); gwy_data_field_area_clear(outsidemask, px1, py1, w1, h1); gwy_data_field_area_clear(outsidemask, px2, py2, w2, h2); } /* adjust boundary to be as smooth as possible */ if (boundary == GWY_MERGE_BOUNDARY_AVERAGE || boundary == GWY_MERGE_BOUNDARY_INTERPOLATE) { if (px1 < px2) { res_rect.x = px2; res_rect.width = px1 + w1 - px2; } else { res_rect.x = px1; res_rect.width = px2 + w2 - px1; } if (py1 < py2) { res_rect.y = py2; res_rect.height = py1 + h1 - py2; } else { res_rect.y = py1; res_rect.height = py2 + h2 - py1; } res_rect.height = MIN(res_rect.height, MIN(h1, h2)); res_rect.width = MIN(res_rect.width, MIN(w1, w2)); /* This is where the result rectangle is positioned in the fields, * not where the fields themselves are placed! */ f1_pos.x = res_rect.x - px1; f1_pos.y = res_rect.y - py1; f2_pos.x = res_rect.x - px2; f2_pos.y = res_rect.y - py2; merge_boundary(dfield1, dfield2, result, res_rect, f1_pos, f2_pos, boundary); } /* Use the pixels sizes of field 1 -- they must be identical. */ xreal = result->xres * gwy_data_field_get_xmeasure(dfield1); yreal = result->yres * gwy_data_field_get_ymeasure(dfield1); gwy_data_field_set_xreal(result, xreal); gwy_data_field_set_yreal(result, yreal); if (outsidemask) { gwy_data_field_set_xreal(outsidemask, xreal); gwy_data_field_set_yreal(outsidemask, yreal); } }
static GwyDataField* sensofar_read_data_field(SensofarDataDesc *data_desc, GwyDataField **maskfield, const guchar **p, gsize size, GError **error) { GwyDataField *dfield, *mfield; guint xres, yres, i, j, mcount; GwySIUnit *units = NULL; gdouble *data, *mdata; if (maskfield) *maskfield = NULL; yres = gwy_get_guint32_le(p); xres = gwy_get_guint32_le(p); gwy_debug("Data size: %dx%d", xres, yres); if (err_SIZE_MISMATCH(error, xres*yres*sizeof(gfloat), size - 2*sizeof(guint32), FALSE)) return NULL; if (err_DIMENSION(error, xres) || err_DIMENSION(error, yres)) return NULL; if (!((data_desc->axes_config.mppx = fabs(data_desc->axes_config.mppx)) > 0)) { g_warning("Real x size is 0.0, fixing to 1.0"); data_desc->axes_config.mppx = 1.0; } if (!((data_desc->axes_config.mppy = fabs(data_desc->axes_config.mppy)) > 0)) { g_warning("Real y size is 0.0, fixing to 1.0"); data_desc->axes_config.mppy = 1.0; } dfield = gwy_data_field_new(xres, yres, data_desc->axes_config.mppx * xres * Micrometer, data_desc->axes_config.mppy * yres * Micrometer, FALSE); units = gwy_si_unit_new("m"); // values are in um only gwy_data_field_set_si_unit_xy(dfield, units); g_object_unref(units); units = gwy_si_unit_new("m"); gwy_data_field_set_si_unit_z(dfield, units); g_object_unref(units); mfield = gwy_data_field_new_alike(dfield, FALSE); gwy_data_field_fill(mfield, 1.0); data = gwy_data_field_get_data(dfield); mdata = gwy_data_field_get_data(mfield); for (i = 0; i < yres; i++) { for (j = 0; j < xres; j++) { gdouble v = gwy_get_gfloat_le(p); if (v == 1000001.0) mdata[i*xres + j] = 0.0; else data[i*xres + j] = v*Micrometer; } } gwy_debug("Offset: %g %g", data_desc->axes_config.x_0, data_desc->axes_config.y_0); //FIXME: offset later, support of offset determined by version? //gwy_data_field_set_xoffset(d, pow10(power10)*data_desc.axes_config.x_0); //gwy_data_field_set_yoffset(d, pow10(power10)*data_desc.axes_config.y_0); mcount = gwy_app_channel_remove_bad_data(dfield, mfield); if (maskfield && mcount) *maskfield = mfield; else g_object_unref(mfield); return dfield; }
/** * 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); }