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);
}
Пример #4
0
	/**
	 * 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);
}
Пример #6
0
/**
 * 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));
}
Пример #7
0
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);
}
Пример #8
0
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);
  }
}