static int set_grad_from_points(struct dt_iop_module_t *self, float xa, float ya, float xb, float yb, float *rotation, float *offset) { // we want absolute positions float pts[4] = { xa * self->dev->preview_pipe->backbuf_width, ya * self->dev->preview_pipe->backbuf_height, xb * self->dev->preview_pipe->backbuf_width, yb * self->dev->preview_pipe->backbuf_height }; dt_dev_distort_backtransform_plus(self->dev, self->dev->preview_pipe, self->priority + 1, 9999999, pts, 2); dt_dev_pixelpipe_iop_t *piece = dt_dev_distort_get_iop_pipe(self->dev, self->dev->preview_pipe, self); pts[0] /= (float)piece->buf_out.width; pts[2] /= (float)piece->buf_out.width; pts[1] /= (float)piece->buf_out.height; pts[3] /= (float)piece->buf_out.height; // we first need to find the rotation angle // weird dichotomic solution : we may use something more cool ... float v1 = -M_PI; float v2 = M_PI; float sinv, cosv, r1, r2, v, r; sinv = sinf(v1), cosv = cosf(v1); r1 = pts[1] * cosv - pts[0] * sinv + pts[2] * sinv - pts[3] * cosv; // we search v2 so r2 as not the same sign as r1 float pas = M_PI / 16.0; do { v2 += pas; sinv = sinf(v2), cosv = cosf(v2); r2 = pts[1] * cosv - pts[0] * sinv + pts[2] * sinv - pts[3] * cosv; if(r1 * r2 < 0) break; } while(v2 <= M_PI); if(v2 == M_PI) return 9; int iter = 0; do { v = (v1 + v2) / 2.0; sinv = sinf(v), cosv = cosf(v); r = pts[1] * cosv - pts[0] * sinv + pts[2] * sinv - pts[3] * cosv; if(r < 0.01 && r > -0.01) break; if(r * r2 < 0) v1 = v; else { r2 = r; v2 = v; } } while(iter++ < 1000); if(iter >= 1000) return 8; // be careful to the gnd direction if(pts[2] - pts[0] > 0 && v > M_PI * 0.5) v = v - M_PI; if(pts[2] - pts[0] > 0 && v < -M_PI * 0.5) v = M_PI + v; if(pts[2] - pts[0] < 0 && v < M_PI * 0.5 && v >= 0) v = v - M_PI; if(pts[2] - pts[0] < 0 && v > -M_PI * 0.5 && v < 0) v = v + M_PI; *rotation = -v * 180.0 / M_PI; // and now we go for the offset (more easy) sinv = sinf(v); cosv = cosf(v); float ofs = -2.0 * sinv * pts[0] + sinv - cosv + 1.0 + 2.0 * cosv * pts[1]; *offset = ofs * 50.0; return 1; }
int dt_dev_distort_backtransform(dt_develop_t *dev, float *points, int points_count) { return dt_dev_distort_backtransform_plus(dev,dev->preview_pipe,0,99999,points,points_count); }
static int dt_circle_get_mask_roi(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, const dt_iop_roi_t *roi, float **buffer) { double start2 = dt_get_wtime(); //we get the circle values dt_masks_point_circle_t *circle = (dt_masks_point_circle_t *) (g_list_first(form->points)->data); //we create a buffer of mesh points for later interpolation. mainly in order to reduce memory footprint const int w = roi->width; const int h = roi->height; const int px = roi->x; const int py = roi->y; const float iscale = 1.0f/roi->scale; const int mesh = 4; const int mw = (w + mesh - 1) / mesh + 1; const int mh = (h + mesh - 1) / mesh + 1; float *points = malloc(mw*mh*2*sizeof(float)); if(points == NULL) return 0; #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points) #else #pragma omp parallel for shared(points) #endif #endif for (int j=0; j<mh; j++) for (int i=0; i<mw; i++) { points[(j*mw+i)*2] = (mesh*i+px)*iscale; points[(j*mw+i)*2+1] = (mesh*j+py)*iscale; } if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] circle draw took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); //we back transform all these points if (!dt_dev_distort_backtransform_plus(module->dev,piece->pipe,0,module->priority,points,mw*mh)) { free(points); return 0; } if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] circle transform took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); //we populate the buffer const int wi = piece->pipe->iwidth, hi=piece->pipe->iheight; const float center[2] = {circle->center[0]*wi, circle->center[1]*hi}; const float radius2 = circle->radius*MIN(wi,hi)*circle->radius*MIN(wi,hi); const float total2 = (circle->radius+circle->border)*MIN(wi,hi)*(circle->radius+circle->border)*MIN(wi,hi); #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points) #else #pragma omp parallel for shared(points) #endif #endif for (int i=0; i<mh; i++) for (int j=0; j<mw; j++) { float x = points[(i*mw+j)*2]; float y = points[(i*mw+j)*2+1]; float l2 = (x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1]); if (l2<radius2) points[(i*mw+j)*2] = 1.0f; else if (l2 < total2) { float f = (total2-l2)/(total2-radius2); points[(i*mw+j)*2] = f*f; } else points[(i*mw+j)*2] = 0.0f; } //we allocate the buffer *buffer = malloc(w*h*sizeof(float)); if(*buffer == NULL) { free(points); return 0; } memset(*buffer,0,w*h*sizeof(float)); //we fill the mask buffer by interpolation #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points,buffer) #else #pragma omp parallel for shared(points,buffer) #endif #endif for (int j=0; j<h; j++) { int jj = j % mesh; int mj = j / mesh; for (int i=0; i<w; i++) { int ii = i % mesh; int mi = i / mesh; (*buffer)[j*w+i] = ( points[(mj*mw+mi)*2] * (mesh-ii)*(mesh-jj) + points[(mj*mw+mi+1)*2] * ii*(mesh-jj) + points[((mj+1)*mw+mi)*2] * (mesh-ii)*jj + points[((mj+1)*mw+mi+1)*2] * ii*jj ) / (mesh*mesh); } } free(points); if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] circle fill took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); return 1; }
static int dt_circle_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 = dt_get_wtime(); //we get the area if (!dt_circle_get_area(module,piece,form,width,height,posx,posy)) return 0; if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] circle area took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); //we get the circle values dt_masks_point_circle_t *circle = (dt_masks_point_circle_t *) (g_list_first(form->points)->data); //we create a buffer of points with all points in the area int w = *width, h = *height; float *points = malloc(w*h*2*sizeof(float)); for (int i=0; i<h; i++) for (int j=0; j<w; j++) { points[(i*w+j)*2] = (j+(*posx)); points[(i*w+j)*2+1] = (i+(*posy)); } if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] circle draw took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); //we back transform all this points if (!dt_dev_distort_backtransform_plus(module->dev,piece->pipe,0,module->priority,points,w*h)) { free(points); return 0; } if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] circle transform took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); //we allocate the buffer *buffer = malloc(w*h*sizeof(float)); memset(*buffer,0,w*h*sizeof(float)); //we populate the buffer int wi = piece->pipe->iwidth, hi=piece->pipe->iheight; float center[2] = {circle->center[0]*wi, circle->center[1]*hi}; float radius2 = circle->radius*MIN(wi,hi)*circle->radius*MIN(wi,hi); float total2 = (circle->radius+circle->border)*MIN(wi,hi)*(circle->radius+circle->border)*MIN(wi,hi); for (int i=0; i<h; i++) for (int j=0; j<w; j++) { float x = points[(i*w+j)*2]; float y = points[(i*w+j)*2+1]; float l2 = (x-center[0])*(x-center[0]) + (y-center[1])*(y-center[1]); if (l2<radius2) (*buffer)[i*w+j] = 1.0f; else if (l2 < total2) { float f = (total2-l2)/(total2-radius2); (*buffer)[i*w+j] = f*f; } else (*buffer)[i*w+j] = 0.0f; } free(points); if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] circle fill took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); return 1; }
static int dt_ellipse_get_mask_roi(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, const dt_iop_roi_t *roi, float *buffer) { double start2 = dt_get_wtime(); // we get the ellipse values dt_masks_point_ellipse_t *ellipse = (dt_masks_point_ellipse_t *)(g_list_first(form->points)->data); // we create a buffer of mesh points for later interpolation. mainly in order to reduce memory footprint const int w = roi->width; const int h = roi->height; const int px = roi->x; const int py = roi->y; const float iscale = 1.0f / roi->scale; const int mesh = 4; const int mw = (w + mesh - 1) / mesh + 1; const int mh = (h + mesh - 1) / mesh + 1; float *points = malloc((size_t)mw * mh * 2 * sizeof(float)); if(points == NULL) return 0; #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points) #else #pragma omp parallel for shared(points) #endif #endif for(int j = 0; j < mh; j++) for(int i = 0; i < mw; i++) { size_t index = (size_t)j * mw + i; points[index * 2] = (mesh * i + px) * iscale; points[index * 2 + 1] = (mesh * j + py) * iscale; } if(darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] ellipse draw took %0.04f sec\n", form->name, dt_get_wtime() - start2); start2 = dt_get_wtime(); // we back transform all these points if(!dt_dev_distort_backtransform_plus(module->dev, piece->pipe, 0, module->priority, points, (size_t)mw * mh)) { free(points); return 0; } if(darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] ellipse transform took %0.04f sec\n", form->name, dt_get_wtime() - start2); start2 = dt_get_wtime(); // we populate the buffer const int wi = piece->pipe->iwidth, hi = piece->pipe->iheight; const float center[2] = { ellipse->center[0] * wi, ellipse->center[1] * hi }; const float radius[2] = { ellipse->radius[0] * MIN(wi, hi), ellipse->radius[1] * MIN(wi, hi) }; const float total[2] = { (ellipse->flags & DT_MASKS_ELLIPSE_PROPORTIONAL ? ellipse->radius[0] * (1.0f + ellipse->border) : ellipse->radius[0] + ellipse->border) * MIN(wi, hi), (ellipse->flags & DT_MASKS_ELLIPSE_PROPORTIONAL ? ellipse->radius[1] * (1.0f + ellipse->border) : ellipse->radius[1] + ellipse->border) * MIN(wi, hi) }; float a, b, ta, tb, alpha; if(radius[0] >= radius[1]) { a = radius[0]; b = radius[1]; ta = total[0]; tb = total[1]; alpha = (ellipse->rotation / 180.0f) * M_PI; } else { a = radius[1]; b = radius[0]; ta = total[1]; tb = total[0]; alpha = ((ellipse->rotation - 90.0f) / 180.0f) * M_PI; } #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points, a, b, ta, tb, alpha) #else #pragma omp parallel for shared(points, a, b, ta, tb, alpha) #endif #endif for(int i = 0; i < mh; i++) for(int j = 0; j < mw; j++) { size_t index = (size_t)i * mw + j; float x = points[index * 2] - center[0]; float y = points[index * 2 + 1] - center[1]; float v = atan2(y, x) - alpha; float cosv = cos(v); float sinv = sin(v); float radius2 = a * a * b * b / (a * a * sinv * sinv + b * b * cosv * cosv); float total2 = ta * ta * tb * tb / (ta * ta * sinv * sinv + tb * tb * cosv * cosv); float l2 = x * x + y * y; if(l2 < radius2) points[index * 2] = 1.0f; else if(l2 < total2) { float f = (total2 - l2) / (total2 - radius2); points[index * 2] = f * f; } else points[index * 2] = 0.0f; } // we fill the output buffer by interpolation #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points, buffer) #else #pragma omp parallel for shared(points, buffer) #endif #endif for(int j = 0; j < h; j++) { int jj = j % mesh; int mj = j / mesh; for(int i = 0; i < w; i++) { int ii = i % mesh; int mi = i / mesh; size_t mindex = (size_t)mj * mw + mi; buffer[(size_t)j * w + i] = (points[mindex * 2] * (mesh - ii) * (mesh - jj) + points[(mindex + 1) * 2] * ii * (mesh - jj) + points[(mindex + mw) * 2] * (mesh - ii) * jj + points[(mindex + mw + 1) * 2] * ii * jj) / (mesh * mesh); } } free(points); if(darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] ellipse fill took %0.04f sec\n", form->name, dt_get_wtime() - start2); // start2 = dt_get_wtime(); return 1; }
static int dt_ellipse_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 = dt_get_wtime(); // we get the area if(!dt_ellipse_get_area(module, piece, form, width, height, posx, posy)) return 0; if(darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] ellipse area took %0.04f sec\n", form->name, dt_get_wtime() - start2); start2 = dt_get_wtime(); // we get the ellipse values dt_masks_point_ellipse_t *ellipse = (dt_masks_point_ellipse_t *)(g_list_first(form->points)->data); // we create a buffer of points with all points in the area int w = *width, h = *height; float *points = malloc(w * h * 2 * sizeof(float)); for(int i = 0; i < h; i++) for(int j = 0; j < w; j++) { points[(i * w + j) * 2] = (j + (*posx)); points[(i * w + j) * 2 + 1] = (i + (*posy)); } if(darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] ellipse draw took %0.04f sec\n", form->name, dt_get_wtime() - start2); start2 = dt_get_wtime(); // we back transform all this points if(!dt_dev_distort_backtransform_plus(module->dev, piece->pipe, 0, module->priority, points, w * h)) { free(points); return 0; } if(darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] ellipse transform took %0.04f sec\n", form->name, dt_get_wtime() - start2); start2 = dt_get_wtime(); // we allocate the buffer *buffer = calloc(w * h, sizeof(float)); // we populate the buffer const int wi = piece->pipe->iwidth, hi = piece->pipe->iheight; const float center[2] = { ellipse->center[0] * wi, ellipse->center[1] * hi }; const float radius[2] = { ellipse->radius[0] * MIN(wi, hi), ellipse->radius[1] * MIN(wi, hi) }; const float total[2] = { (ellipse->flags & DT_MASKS_ELLIPSE_PROPORTIONAL ? ellipse->radius[0] * (1.0f + ellipse->border) : ellipse->radius[0] + ellipse->border) * MIN(wi, hi), (ellipse->flags & DT_MASKS_ELLIPSE_PROPORTIONAL ? ellipse->radius[1] * (1.0f + ellipse->border) : ellipse->radius[1] + ellipse->border) * MIN(wi, hi) }; float a, b, ta, tb, alpha; if(radius[0] >= radius[1]) { a = radius[0]; b = radius[1]; ta = total[0]; tb = total[1]; alpha = (ellipse->rotation / 180.0f) * M_PI; } else { a = radius[1]; b = radius[0]; ta = total[1]; tb = total[0]; alpha = ((ellipse->rotation - 90.0f) / 180.0f) * M_PI; } for(int i = 0; i < h; i++) for(int j = 0; j < w; j++) { float x = points[(i * w + j) * 2] - center[0]; float y = points[(i * w + j) * 2 + 1] - center[1]; float v = atan2(y, x) - alpha; float cosv = cos(v); float sinv = sin(v); float radius2 = a * a * b * b / (a * a * sinv * sinv + b * b * cosv * cosv); float total2 = ta * ta * tb * tb / (ta * ta * sinv * sinv + tb * tb * cosv * cosv); float l2 = x * x + y * y; if(l2 < radius2) (*buffer)[i * w + j] = 1.0f; else if(l2 < total2) { float f = (total2 - l2) / (total2 - radius2); (*buffer)[i * w + j] = f * f; } else (*buffer)[i * w + j] = 0.0f; } free(points); if(darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] ellipse fill took %0.04f sec\n", form->name, dt_get_wtime() - start2); // start2 = dt_get_wtime(); return 1; }
static int dt_gradient_get_mask_roi(dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, const dt_iop_roi_t *roi, float **buffer) { double start2 = dt_get_wtime(); //we get the gradient values dt_masks_point_gradient_t *gradient = (dt_masks_point_gradient_t *) (g_list_first(form->points)->data); //we create a buffer of mesh points for later interpolation. mainly in order to reduce memory footprint const int w = roi->width; const int h = roi->height; const int px = roi->x; const int py = roi->y; const float iscale = 1.0f/roi->scale; const int mesh = 4; const int mw = (w + mesh - 1) / mesh + 1; const int mh = (h + mesh - 1) / mesh + 1; float *points = malloc(mw*mh*2*sizeof(float)); if(points == NULL) return 0; #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points) #else #pragma omp parallel for shared(points) #endif #endif for (int j=0; j<mh; j++) for (int i=0; i<mw; i++) { points[(j*mw+i)*2] = (mesh*i+px)*iscale; points[(j*mw+i)*2+1] = (mesh*j+py)*iscale; } if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] gradient draw took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); //we backtransform all these points if (!dt_dev_distort_backtransform_plus(module->dev, piece->pipe, 0, module->priority, points, mw*mh)) { free(points); return 0; } if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] gradient transform took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); //we calculate the mask at mesh points and recycle point buffer to store results const float wd = piece->pipe->iwidth; const float ht = piece->pipe->iheight; const float hwscale = 1.0f/sqrtf(wd*wd+ht*ht); const float v = (-gradient->rotation/180.0f)*M_PI; const float sinv = sin(v); const float cosv = cos(v); const float offset = sinv * gradient->anchor[0]*wd - cosv * gradient->anchor[1]*ht; const float compression = fmaxf(gradient->compression, 0.001f); const float cs = powf(10.0f, gradient->steepness); const float steepness = cs*cs - 1.0f; const float normf = 0.5f * cs / compression; #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points) #else #pragma omp parallel for shared(points) #endif #endif for (int j=0; j<mh; j++) { for (int i=0; i<mw; i++) { float x = points[(j*mw+i)*2]; float y = points[(j*mw+i)*2+1]; float distance = (sinv * x - cosv * y - offset) * hwscale; float value = normf * distance / sqrtf(1.0f + steepness*distance*distance) + 0.5f; points[(j*mw+i)*2] = (value < 0.0f) ? 0.0f : ((value > 1.0f) ? 1.0f : value); } } //we allocate the buffer *buffer = malloc(w*h*sizeof(float)); if(*buffer == NULL) { free(points); return 0; } memset(*buffer,0,w*h*sizeof(float)); //we fill the mask buffer by interpolation #ifdef _OPENMP #if !defined(__SUNOS__) && !defined(__NetBSD__) #pragma omp parallel for default(none) shared(points,buffer) #else #pragma omp parallel for shared(points,buffer) #endif #endif for (int j=0; j<h; j++) { int jj = j % mesh; int mj = j / mesh; for (int i=0; i<w; i++) { int ii = i % mesh; int mi = i / mesh; (*buffer)[j*w+i] = ( points[(mj*mw+mi)*2] * (mesh-ii)*(mesh-jj) + points[(mj*mw+mi+1)*2] * ii*(mesh-jj) + points[((mj+1)*mw+mi)*2] * (mesh-ii)*jj + points[((mj+1)*mw+mi+1)*2] * ii*jj ) / (mesh*mesh); } } free(points); if (darktable.unmuted & DT_DEBUG_PERF) dt_print(DT_DEBUG_MASKS, "[masks %s] gradient fill took %0.04f sec\n", form->name, dt_get_wtime()-start2); start2 = dt_get_wtime(); return 1; }