Пример #1
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);
		}
	}
Пример #2
0
static void paint_2d_lift_soften(ImBuf *ibuf, ImBuf *ibufb, int *pos, const bool is_torus)
{
    int x, y, count, xi, yi, xo, yo;
    int out_off[2], in_off[2], dim[2];
    float outrgb[4];

    dim[0] = ibufb->x;
    dim[1] = ibufb->y;
    in_off[0] = pos[0];
    in_off[1] = pos[1];
    out_off[0] = out_off[1] = 0;

    if (!is_torus) {
        IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
                     &out_off[1], &dim[0], &dim[1]);

        if ((dim[0] == 0) || (dim[1] == 0))
            return;
    }

    for (y = 0; y < dim[1]; y++) {
        for (x = 0; x < dim[0]; x++) {
            /* get input pixel */
            xi = in_off[0] + x;
            yi = in_off[1] + y;

            count = 1;
            paint_2d_ibuf_rgb_get(ibuf, xi, yi, is_torus, outrgb);

            count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi - 1, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi - 1, yi + 1, outrgb, is_torus);

            count += paint_2d_ibuf_add_if(ibuf, xi, yi - 1, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi, yi + 1, outrgb, is_torus);

            count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi - 1, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi, outrgb, is_torus);
            count += paint_2d_ibuf_add_if(ibuf, xi + 1, yi + 1, outrgb, is_torus);

            mul_v4_fl(outrgb, 1.0f / (float)count);

            /* write into brush buffer */
            xo = out_off[0] + x;
            yo = out_off[1] + y;
            paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
        }
    }
}
Пример #3
0
static float paint_2d_ibuf_add_if(ImBuf *ibuf, int x, int y, float *outrgb, short tile, float w)
{
	float inrgb[4];

	if (tile) paint_2d_ibuf_tile_convert(ibuf, &x, &y, tile);
	/* need to also do clipping here always since tiled coordinates
	 * are not always within bounds */
	if (x < ibuf->x && x >= 0 && y < ibuf->y && y >= 0) {
		paint_2d_ibuf_rgb_get(ibuf, x, y, inrgb);
	}
	else return 0;

	mul_v4_fl(inrgb, w);
	add_v4_v4(outrgb, inrgb);

	return w;
}
Пример #4
0
static float paint_2d_ibuf_add_if(ImBuf *ibuf, unsigned int x, unsigned int y, float *outrgb, short torus, float w)
{
	float inrgb[4];

	// XXX: signed unsigned mismatch
	if ((x >= (unsigned int)(ibuf->x)) || (y >= (unsigned int)(ibuf->y))) {
		if (torus) paint_2d_ibuf_rgb_get(ibuf, x, y, 1, inrgb);
		else return 0;
	}
	else {
		paint_2d_ibuf_rgb_get(ibuf, x, y, 0, inrgb);
	}

	mul_v4_fl(inrgb, w);
	add_v4_v4(outrgb, inrgb);

	return w;
}
void PlaneDistortWarpImageOperation::executePixelSampled(float output[4],
                                                         float x,
                                                         float y,
                                                         PixelSampler /*sampler*/)
{
  float uv[2];
  float deriv[2][2];
  if (this->m_motion_blur_samples == 1) {
    warpCoord(x, y, this->m_samples[0].perspectiveMatrix, uv, deriv);
    m_pixelReader->readFiltered(output, uv[0], uv[1], deriv[0], deriv[1]);
  }
  else {
    zero_v4(output);
    for (int sample = 0; sample < this->m_motion_blur_samples; ++sample) {
      float color[4];
      warpCoord(x, y, this->m_samples[sample].perspectiveMatrix, uv, deriv);
      m_pixelReader->readFiltered(color, uv[0], uv[1], deriv[0], deriv[1]);
      add_v4_v4(output, color);
    }
    mul_v4_fl(output, 1.0f / (float)this->m_motion_blur_samples);
  }
}
Пример #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 paint_2d_lift_soften(ImagePaintState *s, ImBuf *ibuf, ImBuf *ibufb, int *pos, const short tile)
{
	bool sharpen = (s->painter->cache.invert ^ ((s->brush->flag & BRUSH_DIR_IN) != 0));
	float threshold = s->brush->sharp_threshold;
	int x, y, xi, yi, xo, yo, xk, yk;
	float count;
	int out_off[2], in_off[2], dim[2];
	int diff_pos[2];
	float outrgb[4];
	float rgba[4];
	BlurKernel *kernel = s->blurkernel;

	dim[0] = ibufb->x;
	dim[1] = ibufb->y;
	in_off[0] = pos[0];
	in_off[1] = pos[1];
	out_off[0] = out_off[1] = 0;

	if (!tile) {
		IMB_rectclip(ibuf, ibufb, &in_off[0], &in_off[1], &out_off[0],
		             &out_off[1], &dim[0], &dim[1]);

		if ((dim[0] == 0) || (dim[1] == 0))
			return;
	}

	/* find offset inside mask buffers to sample them */
	sub_v2_v2v2_int(diff_pos, out_off, in_off);

	for (y = 0; y < dim[1]; y++) {
		for (x = 0; x < dim[0]; x++) {
			/* get input pixel */
			xi = in_off[0] + x;
			yi = in_off[1] + y;

			count = 0.0;
			if (tile) {
				paint_2d_ibuf_tile_convert(ibuf, &xi, &yi, tile);
				if (xi < ibuf->x && xi >= 0 && yi < ibuf->y && yi >= 0)
					paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
				else
					zero_v4(rgba);
			}
			else {
				/* coordinates have been clipped properly here, it should be safe to do this */
				paint_2d_ibuf_rgb_get(ibuf, xi, yi, rgba);
			}
			zero_v4(outrgb);

			for (yk = 0; yk < kernel->side; yk++) {
				for (xk = 0; xk < kernel->side; xk++) {
					count += paint_2d_ibuf_add_if(ibuf, xi + xk - kernel->pixel_len,
					                               yi + yk - kernel->pixel_len, outrgb, tile,
					                               kernel->wdata[xk + yk * kernel->side]);
				}
			}

			if (count > 0.0f) {
				mul_v4_fl(outrgb, 1.0f / (float)count);

				if (sharpen) {
					/* subtract blurred image from normal image gives high pass filter */
					sub_v3_v3v3(outrgb, rgba, outrgb);

					/* now rgba_ub contains the edge result, but this should be converted to luminance to avoid
					 * colored speckles appearing in final image, and also to check for threshold */
					outrgb[0] = outrgb[1] = outrgb[2] = IMB_colormanagement_get_luminance(outrgb);
					if (fabsf(outrgb[0]) > threshold) {
						float mask = BKE_brush_alpha_get(s->scene, s->brush);
						float alpha = rgba[3];
						rgba[3] = outrgb[3] = mask;

						/* add to enhance edges */
						blend_color_add_float(outrgb, rgba, outrgb);
						outrgb[3] = alpha;
					}
					else
						copy_v4_v4(outrgb, rgba);
				}
			}
			else
				copy_v4_v4(outrgb, rgba);
			/* write into brush buffer */
			xo = out_off[0] + x;
			yo = out_off[1] + y;
			paint_2d_ibuf_rgb_set(ibufb, xo, yo, 0, outrgb);
		}
	}
}
Пример #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);
  }
}