예제 #1
0
파일: group.c 프로젝트: AdamMajer/darktable
int dt_masks_group_render(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form,
                          float **buffer, int *roi, float scale)
{
  double start2 = dt_get_wtime();

  if(!form) return 0;
  float *mask = *buffer;
  // we first reset the buffer to 0
  memset(mask, 0, roi[2] * roi[3] * sizeof(float));

  // we get the mask
  float *fm = NULL;
  int fx = roi[0], fy = roi[1], fw = roi[2], fh = roi[3];
  if(!dt_masks_get_mask(module, piece, form, &fm, &fw, &fh, &fx, &fy)) return 0;

  if(darktable.unmuted & DT_DEBUG_PERF)
    dt_print(DT_DEBUG_MASKS, "[masks] get all masks took %0.04f sec\n", dt_get_wtime() - start2);
  start2 = dt_get_wtime();

  // we don't want row which are outside the roi_out
  int fxx = fx * scale;
  int fww = fw * scale;
  int fyy = fy * scale;
  int fhh = fh * scale;
  if(fxx > roi[0] + roi[2])
  {
    free(fm);
    return 1;
  }

  if(fxx < roi[0]) fww += fxx - roi[0], fxx = roi[0];
  if(fww + fxx >= roi[0] + roi[2]) fww = roi[0] + roi[2] - fxx - 1;

  // we adjust to avoid rounding errors
  if(fyy / scale - fy < 0) fyy++, fhh--;
  if(fxx / scale - fx < 0) fxx++, fww--;
  if((fyy + fhh) / scale - fy >= fh) fhh--;
  if((fxx + fww) / scale - fx >= fw) fww--;

  // we apply the mask row by row
  for(int yy = fyy; yy < fyy + fhh; yy++)
  {
    if(yy < roi[1] || yy >= roi[1] + roi[3]) continue;
    for(int xx = fxx; xx < fxx + fww; xx++)
    {
      int a = (yy / scale - fy);
      int b = (xx / scale);
      mask[(yy - roi[1]) * roi[2] + xx - roi[0]]
          = fmaxf(mask[(yy - roi[1]) * roi[2] + xx - roi[0]], fm[a * fw + b - fx]);
    }
  }

  // we free the mask
  free(fm);

  if(darktable.unmuted & DT_DEBUG_PERF)
    dt_print(DT_DEBUG_MASKS, "[masks] scale all masks took %0.04f sec\n", dt_get_wtime() - start2);

  return 1;
}
예제 #2
0
파일: group.c 프로젝트: AdamMajer/darktable
static int dt_group_get_mask(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form,
                             float **buffer, int *width, int *height, int *posx, int *posy)
{
  double start2;
  // we allocate buffers and values
  const guint nb = g_list_length(form->points);
  if(nb == 0) return 0;
  float *bufs[nb];
  int w[nb];
  int h[nb];
  int px[nb];
  int py[nb];
  int ok[nb];
  int states[nb];
  float op[nb];

  // and we get all masks
  GList *fpts = g_list_first(form->points);
  int pos = 0;
  int nb_ok = 0;
  while(fpts)
  {
    dt_masks_point_group_t *fpt = (dt_masks_point_group_t *)fpts->data;
    dt_masks_form_t *sel = dt_masks_get_from_id(module->dev, fpt->formid);
    if(sel)
    {
      ok[pos] = dt_masks_get_mask(module, piece, sel, &bufs[pos], &w[pos], &h[pos], &px[pos], &py[pos]);
      if(fpt->state & DT_MASKS_STATE_INVERSE)
      {
        start2 = dt_get_wtime();
        _inverse_mask(module, piece, sel, &bufs[pos], &w[pos], &h[pos], &px[pos], &py[pos]);
        if(darktable.unmuted & DT_DEBUG_PERF)
          dt_print(DT_DEBUG_MASKS, "[masks %s] inverse took %0.04f sec\n", sel->name, dt_get_wtime() - start2);
//         start2 = dt_get_wtime();
      }
      op[pos] = fpt->opacity;
      states[pos] = fpt->state;
      if(ok[pos]) nb_ok++;
    }
    fpts = g_list_next(fpts);
    pos++;
  }
  if(nb_ok == 0) return 0;

  // now we get the min, max, width, height of the final mask
  int l, r, t, b;
  l = t = INT_MAX;
  r = b = INT_MIN;
  for(int i = 0; i < nb; i++)
  {
    l = MIN(l, px[i]);
    t = MIN(t, py[i]);
    r = MAX(r, px[i] + w[i]);
    b = MAX(b, py[i] + h[i]);
  }
  *posx = l;
  *posy = t;
  *width = r - l;
  *height = b - t;

  // we allocate the buffer
  *buffer = malloc(sizeof(float) * (r - l) * (b - t));

  // and we copy each buffer inside, row by row
  for(int i = 0; i < nb; i++)
  {
    start2 = dt_get_wtime();
    if(states[i] & DT_MASKS_STATE_UNION)
    {
      for(int y = 0; y < h[i]; y++)
      {
        for(int x = 0; x < w[i]; x++)
        {
          (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l]
              = fmaxf((*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l], bufs[i][y * w[i] + x] * op[i]);
        }
      }
    }
    else if(states[i] & DT_MASKS_STATE_INTERSECTION)
    {
      for(int y = 0; y < b - t; y++)
      {
        for(int x = 0; x < r - l; x++)
        {
          float b1 = (*buffer)[y * (r - l) + x];
          float b2 = 0.0f;
          if(y + t - py[i] >= 0 && y + t - py[i] < h[i] && x + l - px[i] >= 0 && x + l - px[i] < w[i])
            b2 = bufs[i][(y + t - py[i]) * w[i] + x + l - px[i]];
          if(b1 > 0.0f && b2 > 0.0f)
            (*buffer)[y * (r - l) + x] = fminf(b1, b2 * op[i]);
          else
            (*buffer)[y * (r - l) + x] = 0.0f;
        }
      }
    }
    else if(states[i] & DT_MASKS_STATE_DIFFERENCE)
    {
      for(int y = 0; y < h[i]; y++)
      {
        for(int x = 0; x < w[i]; x++)
        {
          float b1 = (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l];
          float b2 = bufs[i][y * w[i] + x] * op[i];
          if(b1 > 0.0f && b2 > 0.0f) (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l] = b1 * (1.0f - b2);
        }
      }
    }
    else if(states[i] & DT_MASKS_STATE_EXCLUSION)
    {
      for(int y = 0; y < h[i]; y++)
      {
        for(int x = 0; x < w[i]; x++)
        {
          float b1 = (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l];
          float b2 = bufs[i][y * w[i] + x] * op[i];
          if(b1 > 0.0f && b2 > 0.0f)
            (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l] = fmaxf((1.0f - b1) * b2, b1 * (1.0f - b2));
          else
            (*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l]
                = fmaxf((*buffer)[(py[i] + y - t) * (r - l) + px[i] + x - l], bufs[i][y * w[i] + x] * op[i]);
        }
      }
    }
    else // if we are here, this mean that we just have to copy the shape and null other parts
    {
      for(int y = 0; y < b - t; y++)
      {
        for(int x = 0; x < r - l; x++)
        {
          float b2 = 0.0f;
          if(y + t - py[i] >= 0 && y + t - py[i] < h[i] && x + l - px[i] >= 0 && x + l - px[i] < w[i])
            b2 = bufs[i][(y + t - py[i]) * w[i] + x + l - px[i]];
          (*buffer)[y * (r - l) + x] = b2 * op[i];
        }
      }
    }

    // and we free the buffer
    free(bufs[i]);
    if(darktable.unmuted & DT_DEBUG_PERF)
      dt_print(DT_DEBUG_MASKS, "[masks %d] combine took %0.04f sec\n", i, dt_get_wtime() - start2);
//     start2 = dt_get_wtime();
  }

  return 1;
}
예제 #3
0
파일: spots.c 프로젝트: rikles/darktable
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *i, void *o, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out)
{
    dt_iop_spots_params_t *d = (dt_iop_spots_params_t *)piece->data;
    dt_develop_blend_params_t *bp = self->blend_params;

    const int ch = piece->colors;
    const float *in = (float *)i;
    float *out = (float *)o;

    // we don't modify most of the image:
#ifdef _OPENMP
    #pragma omp parallel for schedule(static) default(none) shared(out,in,roi_in,roi_out)
#endif
    for (int k=0; k<roi_out->height; k++)
    {
        float *outb = out + ch*k*roi_out->width;
        const float *inb =  in + ch*roi_in->width*(k+roi_out->y-roi_in->y) + ch*(roi_out->x-roi_in->x);
        memcpy(outb, inb, sizeof(float)*roi_out->width*ch);
    }

    // iterate through all forms
    dt_masks_form_t *grp = dt_masks_get_from_id(self->dev,bp->mask_id);
    int pos=0;
    if (grp && (grp->type & DT_MASKS_GROUP))
    {
        GList *forms = g_list_first(grp->points);
        while(forms)
        {
            dt_masks_point_group_t *grpt = (dt_masks_point_group_t *)forms->data;
            //we get the spot
            dt_masks_form_t *form = dt_masks_get_from_id(self->dev,grpt->formid);
            if (!form)
            {
                forms = g_list_next(forms);
                pos++;
                continue;
            }
            //we get the area for the form
            int fl,ft,fw,fh;
            if (!dt_masks_get_area(self,piece,form,&fw,&fh,&fl,&ft))
            {
                forms = g_list_next(forms);
                pos++;
                continue;
            }

            //if the form is outside the roi, we just skip it
            fw *= roi_in->scale, fh *= roi_in->scale, fl *= roi_in->scale, ft *= roi_in->scale;
            if (ft>=roi_out->y+roi_out->height || ft+fh<=roi_out->y || fl>=roi_out->x+roi_out->width || fl+fw<=roi_out->x)
            {
                forms = g_list_next(forms);
                pos++;
                continue;
            }
            if (d->clone_algo[pos] == 1 && (form->type & DT_MASKS_CIRCLE))
            {
                dt_masks_point_circle_t *circle = (dt_masks_point_circle_t *)g_list_nth_data(form->points,0);
                // convert from world space:
                const int rad = circle->radius* MIN(piece->buf_in.width, piece->buf_in.height)*roi_in->scale;
                const int posx  = (circle->center[0] * piece->buf_in.width)*roi_in->scale - rad;
                const int posy  = (circle->center[1] * piece->buf_in.height)*roi_in->scale - rad;
                const int posx_source = (form->source[0]*piece->buf_in.width)*roi_in->scale - rad;
                const int posy_source = (form->source[1]*piece->buf_in.height)*roi_in->scale - rad;
                const int dx = posx-posx_source;
                const int dy = posy-posy_source;
                fw = fh = 2*rad;

                // convert from world space:
                float filter[2*rad + 1];

                if(rad > 0)
                {
                    for(int k=-rad; k<=rad; k++)
                    {
                        const float kk = 1.0f - fabsf(k/(float)rad);
                        filter[rad + k] = kk*kk*(3.0f - 2.0f*kk);
                    }
                }
                else
                {
                    filter[0] = 1.0f;
                }
                for (int yy=posy ; yy<posy+fh; yy++)
                {
                    //we test if we are inside roi_out
                    if (yy<roi_out->y || yy>=roi_out->y+roi_out->height) continue;
                    //we test if the source point is inside roi_in
                    if (yy-dy<roi_in->y || yy-dy>=roi_in->y+roi_in->height) continue;
                    for (int xx=posx ; xx<posx+fw; xx++)
                    {
                        //we test if we are inside roi_out
                        if (xx<roi_out->x || xx>=roi_out->x+roi_out->width) continue;
                        //we test if the source point is inside roi_in
                        if (xx-dx<roi_in->x || xx-dx>=roi_in->x+roi_in->width) continue;

                        const float f = filter[xx-posx+1]*filter[yy-posy+1];
                        for(int c=0; c<ch; c++)
                            out[4*(roi_out->width*(yy-roi_out->y) + xx-roi_out->x) + c] =
                                out[4*(roi_out->width*(yy-roi_out->y) + xx-roi_out->x) + c] * (1.0f-f) +
                                in[4*(roi_in->width*(yy-posy+posy_source-roi_in->y) + xx-posx+posx_source-roi_in->x) + c] * f;
                    }
                }
            }
            else
            {
                //we get the mask
                float *mask;
                int posx,posy,width,height;
                dt_masks_get_mask(self,piece,form,&mask,&width,&height,&posx,&posy);
                int fts = posy*roi_in->scale, fhs = height*roi_in->scale, fls = posx*roi_in->scale, fws = width*roi_in->scale;
                //now we search the delta with the source
                int dx,dy;
                dx=dy=0;
                if (form->type & DT_MASKS_PATH)
                {
                    dt_masks_point_path_t *pt = (dt_masks_point_path_t *)g_list_nth_data(form->points,0);
                    dx = pt->corner[0]*roi_in->scale*piece->buf_in.width - form->source[0]*roi_in->scale*piece->buf_in.width;
                    dy = pt->corner[1]*roi_in->scale*piece->buf_in.height - form->source[1]*roi_in->scale*piece->buf_in.height;
                }
                else if (form->type & DT_MASKS_CIRCLE)
                {
                    dt_masks_point_circle_t *pt = (dt_masks_point_circle_t *)g_list_nth_data(form->points,0);
                    dx = pt->center[0]*roi_in->scale*piece->buf_in.width - form->source[0]*roi_in->scale*piece->buf_in.width;
                    dy = pt->center[1]*roi_in->scale*piece->buf_in.height - form->source[1]*roi_in->scale*piece->buf_in.height;
                }
                if (dx!=0 || dy!=0)
                {
                    //now we do the pixel clone
                    for (int yy=fts+1 ; yy<fts+fhs-1; yy++)
                    {
                        //we test if we are inside roi_out
                        if (yy<roi_out->y || yy>=roi_out->y+roi_out->height) continue;
                        //we test if the source point is inside roi_in
                        if (yy-dy<roi_in->y || yy-dy>=roi_in->y+roi_in->height) continue;
                        for (int xx=fls+1 ; xx<fls+fws-1; xx++)
                        {
                            //we test if we are inside roi_out
                            if (xx<roi_out->x || xx>=roi_out->x+roi_out->width) continue;
                            //we test if the source point is inside roi_in
                            if (xx-dx<roi_in->x || xx-dx>=roi_in->x+roi_in->width) continue;

                            float f = mask[((int)((yy-fts)/roi_in->scale))*width + (int)((xx-fls)/roi_in->scale)];  //we can add the opacity here

                            for(int c=0; c<ch; c++)
                                out[4*(roi_out->width*(yy-roi_out->y) + xx-roi_out->x) + c] =
                                    out[4*(roi_out->width*(yy-roi_out->y) + xx-roi_out->x) + c] * (1.0f-f) +
                                    in[4*(roi_in->width*(yy-dy-roi_in->y) + xx-dx-roi_in->x) + c] * f;
                        }
                    }
                }
                free(mask);
            }
            pos++;
            forms = g_list_next(forms);
        }
    }
}