void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *data) { float color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float multiplier_accum = 0.0f; MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); int bufferwidth = inputBuffer->getWidth(); int bufferstartx = inputBuffer->getRect()->xmin; int bufferstarty = inputBuffer->getRect()->ymin; int miny = y; int minx = x - this->m_rad; int maxx = x + this->m_rad; miny = max(miny, inputBuffer->getRect()->ymin); minx = max(minx, inputBuffer->getRect()->xmin); maxx = min(maxx, inputBuffer->getRect()->xmax - 1); int step = getStep(); int offsetadd = getOffsetAdd(); int bufferindex = ((minx - bufferstartx) * 4) + ((miny - bufferstarty) * 4 * bufferwidth); for (int nx = minx, index = (minx - x) + this->m_rad; nx <= maxx; nx += step, index += step) { const float multiplier = this->m_gausstab[index]; madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier); multiplier_accum += multiplier; bufferindex += offsetadd; } mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum); }
void GaussianYBlurOperation::executePixel(float output[4], int x, int y, void *data) { float color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float multiplier_accum = 0.0f; MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); int bufferwidth = inputBuffer->getWidth(); int bufferstartx = inputBuffer->getRect()->xmin; int bufferstarty = inputBuffer->getRect()->ymin; rcti &rect = *inputBuffer->getRect(); int xmin = max_ii(x, rect.xmin); int ymin = max_ii(y - m_filtersize, rect.ymin); int ymax = min_ii(y + m_filtersize + 1, rect.ymax); int index; int step = getStep(); const int bufferIndexx = ((xmin - bufferstartx) * 4); for (int ny = ymin; ny < ymax; ny += step) { index = (ny - y) + this->m_filtersize; int bufferindex = bufferIndexx + ((ny - bufferstarty) * 4 * bufferwidth); const float multiplier = this->m_gausstab[index]; madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier); multiplier_accum += multiplier; } mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum); }
void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, void * /*data*/) { float in1[4]; float in2[4]; int x1 = x - 1; int x2 = x; int x3 = x + 1; int y1 = y - 1; int y2 = y; int y3 = y + 1; CLAMP(x1, 0, getWidth() - 1); CLAMP(x2, 0, getWidth() - 1); CLAMP(x3, 0, getWidth() - 1); CLAMP(y1, 0, getHeight() - 1); CLAMP(y2, 0, getHeight() - 1); CLAMP(y3, 0, getHeight() - 1); float value[4]; this->m_inputValueOperation->read(value, x2, y2, NULL); const float mval = 1.0f - value[0]; zero_v4(output); this->m_inputOperation->read(in1, x1, y1, NULL); madd_v4_v4fl(output, in1, this->m_filter[0]); this->m_inputOperation->read(in1, x2, y1, NULL); madd_v4_v4fl(output, in1, this->m_filter[1]); this->m_inputOperation->read(in1, x3, y1, NULL); madd_v4_v4fl(output, in1, this->m_filter[2]); this->m_inputOperation->read(in1, x1, y2, NULL); madd_v4_v4fl(output, in1, this->m_filter[3]); this->m_inputOperation->read(in2, x2, y2, NULL); madd_v4_v4fl(output, in2, this->m_filter[4]); this->m_inputOperation->read(in1, x3, y2, NULL); madd_v4_v4fl(output, in1, this->m_filter[5]); this->m_inputOperation->read(in1, x1, y3, NULL); madd_v4_v4fl(output, in1, this->m_filter[6]); this->m_inputOperation->read(in1, x2, y3, NULL); madd_v4_v4fl(output, in1, this->m_filter[7]); this->m_inputOperation->read(in1, x3, y3, NULL); madd_v4_v4fl(output, in1, this->m_filter[8]); output[0] = output[0] * value[0] + in2[0] * mval; output[1] = output[1] * value[0] + in2[1] * mval; output[2] = output[2] * value[0] + in2[2] * mval; output[3] = output[3] * value[0] + in2[3] * mval; /* Make sure we don't return negative color. */ output[0] = max(output[0], 0.0f); output[1] = max(output[1], 0.0f); output[2] = max(output[2], 0.0f); output[3] = max(output[3], 0.0f); }
/** * Perform the actual accumulation along a ray segment from source to pt. * Only pixels withing dist_min..dist_max contribute. * * The loop runs backwards(!) over the primary sector space axis u, i.e. increasing distance to pt. * After each step it decrements v by dv < 1, adding a buffer shift when necessary. */ static void eval(MemoryBuffer *input, float output[4], const float pt_ofs[2], const float source[2], float dist_min, float dist_max) { rcti rect = *input->getRect(); int buffer_width = input->getWidth(); int x, y, num; float v, dv; float falloff_factor; /* initialise the iteration variables */ float *buffer = init_buffer_iterator(input, source, pt_ofs, dist_min, dist_max, x, y, num, v, dv, falloff_factor); int tot = 0; /* v_local keeps track of when to decrement v (see below) */ float v_local = v - floorf(v); for (int i = 0; i < num; i++) { /* range check, abort when running beyond the image border */ if (x < rect.xmin || x >= rect.xmax || y < rect.ymin || y >= rect.ymax) break; float f = 1.0f - (float)i * falloff_factor; madd_v4_v4fl(output, buffer, buffer[3] * f * f); /* TODO implement proper filtering here, see * http://en.wikipedia.org/wiki/Lanczos_resampling * http://en.wikipedia.org/wiki/Sinc_function * * using lanczos with x = distance from the line segment, * normalized to a == 0.5f, could give a good result * * for now just count samples and divide equally at the end ... */ tot++; /* decrement u */ x -= fxx; y -= fyx; buffer -= (fxx + fyx * buffer_width) * COM_NUMBER_OF_CHANNELS; /* decrement v (in steps of dv < 1) */ v_local -= dv; if (v_local < 0.0f) { v_local += 1.0f; x -= fxy; y -= fyy; buffer -= (fxy + fyy * buffer_width) * COM_NUMBER_OF_CHANNELS; } } /* normalize */ if (num > 0) { mul_v4_fl(output, 1.0f / (float)num); } }
void GaussianXBlurOperation::executePixel(float output[4], int x, int y, void *data) { float color_accum[4] = {0.0f, 0.0f, 0.0f, 0.0f}; float multiplier_accum = 0.0f; MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); int bufferwidth = inputBuffer->getWidth(); int bufferstartx = inputBuffer->getRect()->xmin; int bufferstarty = inputBuffer->getRect()->ymin; rcti &rect = *inputBuffer->getRect(); int xmin = max_ii(x - m_filtersize, rect.xmin); int xmax = min_ii(x + m_filtersize + 1, rect.xmax); int ymin = max_ii(y, rect.ymin); int step = getStep(); int offsetadd = getOffsetAdd(); int bufferindex = ((xmin - bufferstartx) * 4) + ((ymin - bufferstarty) * 4 * bufferwidth); #ifdef __SSE2__ __m128 accum_r = _mm_load_ps(color_accum); for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax; nx += step, index += step) { __m128 reg_a = _mm_load_ps(&buffer[bufferindex]); reg_a = _mm_mul_ps(reg_a, this->m_gausstab_sse[index]); accum_r = _mm_add_ps(accum_r, reg_a); multiplier_accum += this->m_gausstab[index]; bufferindex += offsetadd; } _mm_store_ps(color_accum, accum_r); #else for (int nx = xmin, index = (xmin - x) + this->m_filtersize; nx < xmax; nx += step, index += step) { const float multiplier = this->m_gausstab[index]; madd_v4_v4fl(color_accum, &buffer[bufferindex], multiplier); multiplier_accum += multiplier; bufferindex += offsetadd; } #endif mul_v4_v4fl(output, color_accum, 1.0f / multiplier_accum); }
/** * Filtering method based on * "Creating raster omnimax images from multiple perspective views using the elliptical weighted average filter" * by Ned Greene and Paul S. Heckbert (1986) */ void MemoryBuffer::readEWA(float result[4], const float uv[2], const float derivatives[2][2], PixelSampler sampler) { zero_v4(result); int width = this->getWidth(), height = this->getHeight(); if (width == 0 || height == 0) return; float u = uv[0], v = uv[1]; float Ux = derivatives[0][0], Vx = derivatives[1][0], Uy = derivatives[0][1], Vy = derivatives[1][1]; float A, B, C, F, ue, ve; ellipse_params(Ux, Uy, Vx, Vy, A, B, C, F, ue, ve); /* Note: highly eccentric ellipses can lead to large texture space areas to filter! * This is limited somewhat by the EWA_WTS size in the loop, but a nicer approach * could be the one found in * "High Quality Elliptical Texture Filtering on GPU" * by Pavlos Mavridis and Georgios Papaioannou * in which the eccentricity of the ellipse is clamped. */ int U0 = (int)u; int V0 = (int)v; /* pixel offset for interpolation */ float ufac = u - floorf(u), vfac = v - floorf(v); /* filter size */ int u1 = (int)(u - ue); int u2 = (int)(u + ue); int v1 = (int)(v - ve); int v2 = (int)(v + ve); /* sane clamping to avoid unnecessarily huge loops */ /* note: if eccentricity gets clamped (see above), * the ue/ve limits can also be lowered accordingly */ if (U0 - u1 > EWA_MAXIDX) u1 = U0 - EWA_MAXIDX; if (u2 - U0 > EWA_MAXIDX) u2 = U0 + EWA_MAXIDX; if (V0 - v1 > EWA_MAXIDX) v1 = V0 - EWA_MAXIDX; if (v2 - V0 > EWA_MAXIDX) v2 = V0 + EWA_MAXIDX; float DDQ = 2.0f * A; float U = u1 - U0; float ac1 = A * (2.0f * U + 1.0f); float ac2 = A * U * U; float BU = B * U; float sum = 0.0f; for (int v = v1; v <= v2; ++v) { float V = v - V0; float DQ = ac1 + B * V; float Q = (C * V + BU) * V + ac2; for (int u = u1; u <= u2; ++u) { if (Q < F) { float tc[4]; const float wt = EWA_WTS[CLAMPIS((int)Q, 0, EWA_MAXIDX)]; switch (sampler) { case COM_PS_NEAREST: read(tc, u, v); break; case COM_PS_BILINEAR: readBilinear(tc, (float)u + ufac, (float)v + vfac); break; case COM_PS_BICUBIC: readBilinear(tc, (float)u + ufac, (float)v + vfac); break; /* XXX no readBicubic method yet */ default: zero_v4(tc); break; } madd_v4_v4fl(result, tc, wt); sum += wt; } Q += DQ; DQ += DDQ; } } mul_v4_fl(result, (sum != 0.0f ? 1.0f / sum : 0.0f)); }
static void colorband_init_from_table_rgba_resample( ColorBand *coba, const float (*array)[4], const int array_len, bool filter_samples) { BLI_assert(array_len >= 2); const float eps_2x = ((1.0f / 255.0f) + 1e-6f); struct ColorResampleElem *c, *carr = MEM_mallocN(sizeof(*carr) * array_len, __func__); int carr_len = array_len; c = carr; { const float step_size = 1.0f / (float)(array_len - 1); for (int i = 0; i < array_len; i++, c++) { copy_v4_v4(carr[i].rgba, array[i]); c->next = c + 1; c->prev = c - 1; c->pos = i * step_size; } } carr[0].prev = NULL; carr[array_len - 1].next = NULL; /* -2 to remove endpoints. */ Heap *heap = BLI_heap_new_ex(array_len - 2); c = carr; for (int i = 0; i < array_len; i++, c++) { float cost = color_sample_remove_cost(c); if (cost != -1.0f) { c->node = BLI_heap_insert(heap, cost, c); } else { c->node = NULL; } } while ((carr_len > 1 && !BLI_heap_is_empty(heap)) && ((carr_len >= MAXCOLORBAND) || (BLI_heap_node_value(BLI_heap_top(heap)) <= eps_2x))) { c = BLI_heap_pop_min(heap); struct ColorResampleElem *c_next = c->next, *c_prev = c->prev; c_prev->next = c_next; c_next->prev = c_prev; /* Clear data (not essential, avoid confusion). */ c->prev = c->next = NULL; c->node = NULL; /* Update adjacent */ for (int i = 0; i < 2; i++) { struct ColorResampleElem *c_other = i ? c_next : c_prev; if (c_other->node != NULL) { const float cost = color_sample_remove_cost(c_other); if (cost != -1.0) { BLI_heap_node_value_update(heap, c_other->node, cost); } else { BLI_heap_remove(heap, c_other->node); c_other->node = NULL; } } } carr_len -= 1; } BLI_heap_free(heap, NULL); /* First member is never removed. */ int i = 0; BLI_assert(carr_len < MAXCOLORBAND); if (filter_samples == false) { for (c = carr; c != NULL; c = c->next, i++) { copy_v4_v4(&coba->data[i].r, c->rgba); coba->data[i].pos = c->pos; coba->data[i].cur = i; } } else { for (c = carr; c != NULL; c = c->next, i++) { const int steps_prev = c->prev ? (c - c->prev) - 1 : 0; const int steps_next = c->next ? (c->next - c) - 1 : 0; if (steps_prev == 0 && steps_next == 0) { copy_v4_v4(&coba->data[i].r, c->rgba); } else { float rgba[4]; float rgba_accum = 1; copy_v4_v4(rgba, c->rgba); if (steps_prev) { const float step_size = 1.0 / (float)(steps_prev + 1); int j = steps_prev; for (struct ColorResampleElem *c_other = c - 1; c_other != c->prev; c_other--, j--) { const float step_pos = (float)j * step_size; BLI_assert(step_pos > 0.0f && step_pos < 1.0f); const float f = filter_gauss(step_pos); madd_v4_v4fl(rgba, c_other->rgba, f); rgba_accum += f; } } if (steps_next) { const float step_size = 1.0 / (float)(steps_next + 1); int j = steps_next; for (struct ColorResampleElem *c_other = c + 1; c_other != c->next; c_other++, j--) { const float step_pos = (float)j * step_size; BLI_assert(step_pos > 0.0f && step_pos < 1.0f); const float f = filter_gauss(step_pos); madd_v4_v4fl(rgba, c_other->rgba, f); rgba_accum += f; } } mul_v4_v4fl(&coba->data[i].r, rgba, 1.0f / rgba_accum); } coba->data[i].pos = c->pos; coba->data[i].cur = i; } } BLI_assert(i == carr_len); coba->tot = i; coba->cur = 0; MEM_freeN(carr); }
void DespeckleOperation::executePixel(float output[4], int x, int y, void * /*data*/) { float w = 0.0f; float color_org[4]; float color_mid[4]; float color_mid_ok[4]; float in1[4]; int x1 = x - 1; int x2 = x; int x3 = x + 1; int y1 = y - 1; int y2 = y; int y3 = y + 1; CLAMP(x1, 0, getWidth() - 1); CLAMP(x2, 0, getWidth() - 1); CLAMP(x3, 0, getWidth() - 1); CLAMP(y1, 0, getHeight() - 1); CLAMP(y2, 0, getHeight() - 1); CLAMP(y3, 0, getHeight() - 1); float value[4]; this->m_inputValueOperation->read(value, x2, y2, NULL); // const float mval = 1.0f - value[0]; this->m_inputOperation->read(color_org, x2, y2, NULL); #define TOT_DIV_ONE 1.0f #define TOT_DIV_CNR (float)M_SQRT1_2 #define WTOT (TOT_DIV_ONE * 4 + TOT_DIV_CNR * 4) #define COLOR_ADD(fac) \ { \ madd_v4_v4fl(color_mid, in1, fac); \ if (color_diff(in1, color_org, this->m_threshold)) { \ w += fac; \ madd_v4_v4fl(color_mid_ok, in1, fac); \ } \ } zero_v4(color_mid); zero_v4(color_mid_ok); this->m_inputOperation->read(in1, x1, y1, NULL); COLOR_ADD(TOT_DIV_CNR) this->m_inputOperation->read(in1, x2, y1, NULL); COLOR_ADD(TOT_DIV_ONE) this->m_inputOperation->read(in1, x3, y1, NULL); COLOR_ADD(TOT_DIV_CNR) this->m_inputOperation->read(in1, x1, y2, NULL); COLOR_ADD(TOT_DIV_ONE) #if 0 this->m_inputOperation->read(in2, x2, y2, NULL); madd_v4_v4fl(color_mid, in2, this->m_filter[4]); #endif this->m_inputOperation->read(in1, x3, y2, NULL); COLOR_ADD(TOT_DIV_ONE) this->m_inputOperation->read(in1, x1, y3, NULL); COLOR_ADD(TOT_DIV_CNR) this->m_inputOperation->read(in1, x2, y3, NULL); COLOR_ADD(TOT_DIV_ONE) this->m_inputOperation->read(in1, x3, y3, NULL); COLOR_ADD(TOT_DIV_CNR) mul_v4_fl(color_mid, 1.0f / (4.0f + (4.0f * (float)M_SQRT1_2))); // mul_v4_fl(color_mid, 1.0f / w); if ((w != 0.0f) && ((w / WTOT) > (this->m_threshold_neighbor)) && color_diff(color_mid, color_org, this->m_threshold)) { mul_v4_fl(color_mid_ok, 1.0f / w); interp_v4_v4v4(output, color_org, color_mid_ok, value[0]); } else { copy_v4_v4(output, color_org); } }