void rgbTween (float r1, float g1, float b1, float r2, float g2, float b2, float tween, int direction, float &outr, float &outg, float &outb) { float h1, s1, l1, h2, s2, l2, outh, outs, outl; rgb2hsl (r1, g1, b1, h1, s1, l1); rgb2hsl (r2, g2, b2, h2, s2, l2); hslTween (h1, s1, l1, h2, s2, l2, tween, direction, outh, outs, outl); hsl2rgb (outh, outs, outl, outr, outg, outb); }
void rgbTween(double r1, double g1, double b1, double r2, double g2, double b2, double tween, int direction, double &outr, double &outg, double &outb){ double h1, s1, l1, h2, s2, l2, outh, outs, outl; rgb2hsl(r1, g1, b1, h1, s1, l1); rgb2hsl(r2, g2, b2, h2, s2, l2); hslTween(h1, s1, l1, h2, s2, l2, tween, direction, outh, outs, outl); hsl2rgb(outh, outs, outl, outr, outg, outb); }
mat3f dcolor(const vec3f &rgb, const vec3f &) { vec3f hsl = rgb2hsl(rgb); vec3f RGB; mat3f m; RGB = hsl2rgb(hsl + vec3f(0.01f, 0, 0)); m.setColumn(0, (RGB - rgb) / 0.01f * amp.x); RGB = hsl2rgb(hsl + vec3f(0, 0.01f, 0)); m.setColumn(1, (RGB - rgb) / 0.01f * amp.y); RGB = hsl2rgb(hsl + vec3f(0, 0, 0.01f)); m.setColumn(2, (RGB - rgb) / 0.01f * amp.z); return m; }
static void colorpick_callback (GtkDarktableButton *button, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_splittoning_gui_data_t *g = (dt_iop_splittoning_gui_data_t *)self->gui_data; if(self->dt->gui->reset) return; dt_iop_splittoning_params_t *p = (dt_iop_splittoning_params_t *)self->params; GtkColorSelectionDialog *csd = GTK_COLOR_SELECTION_DIALOG(gtk_color_selection_dialog_new(_("select tone color"))); gtk_window_set_transient_for(GTK_WINDOW(csd), GTK_WINDOW(dt_ui_main_window(darktable.gui->ui))); GtkWidget *okButton, *cancelButton = 0; g_object_get(G_OBJECT(csd), "ok-button", &okButton, NULL); g_object_get(G_OBJECT(csd), "cancel-button", &cancelButton, NULL); g_signal_connect (G_OBJECT (okButton), "clicked", G_CALLBACK (colorpick_button_callback), csd); g_signal_connect (G_OBJECT (cancelButton), "clicked", G_CALLBACK (colorpick_button_callback), csd); GtkColorSelection *cs = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(csd)); GdkColor c; float color[3],h,s,l; h=(button==g->colorpick1)?p->shadow_hue:p->highlight_hue; s=(button==g->colorpick1)?p->shadow_saturation:p->highlight_saturation; l=0.5; hsl2rgb(color,h,s,l); c.red= 65535 * color[0]; c.green= 65535 * color[1]; c.blue= 65535 * color[2]; gtk_color_selection_set_current_color(cs,&c); if(gtk_dialog_run(GTK_DIALOG(csd))==GTK_RESPONSE_ACCEPT) { gtk_color_selection_get_current_color(cs,&c); color[0]=c.red/65535.0; color[1]=c.green/65535.0; color[2]=c.blue/65535.0; rgb2hsl(color,&h,&s,&l); l=0.5; hsl2rgb(color,h,s,l); dt_bauhaus_slider_set( (button==g->colorpick1)? g->gslider1: g->gslider3 ,h ); dt_bauhaus_slider_set( (button==g->colorpick1)? g->gslider2: g->gslider4 ,s ); } gtk_widget_destroy(GTK_WIDGET(csd)); dt_dev_add_history_item(darktable.develop, self, TRUE); }
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { dt_iop_splittoning_data_t *data = (dt_iop_splittoning_data_t *)piece->data; float *in; float *out; const int ch = piece->colors; const float compress = (data->compress / 110.0) / 2.0; // Dont allow 100% compression.. #ifdef _OPENMP #pragma omp parallel for default(none) shared(ivoid, ovoid, roi_out, data) private(in, out) schedule(static) #endif for(int k = 0; k < roi_out->height; k++) { in = ((float *)ivoid) + (size_t)ch * k * roi_out->width; out = ((float *)ovoid) + (size_t)ch * k * roi_out->width; for(int j = 0; j < roi_out->width; j++, in += ch, out += ch) { double ra, la; float mixrgb[3]; float h, s, l; rgb2hsl(in, &h, &s, &l); if(l < data->balance - compress || l > data->balance + compress) { h = l < data->balance ? data->shadow_hue : data->highlight_hue; s = l < data->balance ? data->shadow_saturation : data->highlight_saturation; ra = l < data->balance ? CLIP((fabs(-data->balance + compress + l) * 2.0)) : CLIP((fabs(-data->balance - compress + l) * 2.0)); la = (1.0 - ra); hsl2rgb(mixrgb, h, s, l); out[0] = CLIP(in[0] * la + mixrgb[0] * ra); out[1] = CLIP(in[1] * la + mixrgb[1] * ra); out[2] = CLIP(in[2] * la + mixrgb[2] * ra); } else { out[0] = in[0]; out[1] = in[1]; out[2] = in[2]; } out[3] = in[3]; } } }
static void colorpick_callback (GtkDarktableButton *button, gpointer user_data) { dt_iop_module_t *self = (dt_iop_module_t *)user_data; dt_iop_colorize_gui_data_t *g = (dt_iop_colorize_gui_data_t *)self->gui_data; if(self->dt->gui->reset) return; dt_iop_colorize_params_t *p = (dt_iop_colorize_params_t *)self->params; GtkColorSelectionDialog *csd = GTK_COLOR_SELECTION_DIALOG(gtk_color_selection_dialog_new(_("select tone color"))); g_signal_connect (G_OBJECT (csd->ok_button), "clicked", G_CALLBACK (colorpick_button_callback), csd); g_signal_connect (G_OBJECT (csd->cancel_button), "clicked", G_CALLBACK (colorpick_button_callback), csd); GtkColorSelection *cs = GTK_COLOR_SELECTION(gtk_color_selection_dialog_get_color_selection(csd)); GdkColor c; float color[3],h,s,l; h = p->hue; s = p->saturation; l=0.5; hsl2rgb(color,h,s,l); c.red= 65535 * color[0]; c.green= 65535 * color[1]; c.blue= 65535 * color[2]; gtk_color_selection_set_current_color(cs,&c); if(gtk_dialog_run(GTK_DIALOG(csd))==GTK_RESPONSE_ACCEPT) { gtk_color_selection_get_current_color(cs,&c); color[0]=c.red/65535.0; color[1]=c.green/65535.0; color[2]=c.blue/65535.0; rgb2hsl(color,&h,&s,&l); l=0.5; hsl2rgb(color,h,s,l); dtgtk_gradient_slider_set_value(g->gslider1, h); dtgtk_gradient_slider_set_value(g->gslider2, s); } gtk_widget_destroy(GTK_WIDGET(csd)); dt_dev_add_history_item(darktable.develop, self, TRUE); }
static void colorpick_callback(GtkColorButton *widget, dt_iop_module_t *self) { if(self->dt->gui->reset) return; dt_iop_splittoning_gui_data_t *g = (dt_iop_splittoning_gui_data_t *)self->gui_data; float color[3], h, s, l; GdkRGBA c; gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(widget), &c); color[0] = c.red; color[1] = c.green; color[2] = c.blue; rgb2hsl(color, &h, &s, &l); dt_bauhaus_slider_set((GTK_WIDGET(widget) == g->colorpick1) ? g->gslider1 : g->gslider3, h); dt_bauhaus_slider_set((GTK_WIDGET(widget) == g->colorpick1) ? g->gslider2 : g->gslider4, s); dt_dev_add_history_item(darktable.develop, self, TRUE); }
// BANG - calculate and output void cs_bang(t_cs *x) { if(x->attr_mode == ps_rgb2hsl) rgb2hsl(x, x->val1, x->val2, x->val3); // first for speed else if(x->attr_mode == ps_hsl2rgb) hsl2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_no_transform) no_transform(x); else if(x->attr_mode == ps_rgb2cmy) rgb2cmy(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_cmy2rgb) cmy2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2hsv) rgb2hsv(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_hsv2rgb) hsv2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2xyz) rgb2xyz(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_xyz2rgb) xyz2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2uvw) rgb2uvw(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_uvw2rgb) uvw2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2retinalcone) rgb2cone(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_retinalcone2rgb) cone2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2lab) rgb2lab(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_lab2rgb) lab2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2yiq) rgb2yiq(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_yiq2rgb) yiq2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2hls) rgb2hls(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_hls2rgb) hls2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2rgbcie) rgb2rgbcie(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgbcie2rgb) rgbcie2rgb(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgb2rgbsmpte) rgb2rgbsmpte(x, x->val1, x->val2, x->val3); else if(x->attr_mode == ps_rgbsmpte2rgb) rgbsmpte2rgb(x, x->val1, x->val2, x->val3); if(x->attr_outputtype == ps_packed){ Atom temp_list[3]; atom_setlong(temp_list+0, x->calc1); atom_setlong(temp_list+1, x->calc2); atom_setlong(temp_list+2, x->calc3); outlet_list(x->out1, 0L, 3, temp_list); // output the result } else{ outlet_int(x->out3, x->calc3); // output the result outlet_int(x->out2, x->calc2); // output the result outlet_int(x->out1, x->calc1); // output the result } }
int main(int argc, char** argv) { int i, j, count; //char** filenames; char id[50] = {0}; char filename[50]; //char seg_file_name[50] = {'s', 'e', 'g', '/', 's', 'e', 'g', '\0'}; //char suffix[5] = {'.', 't', 'x', 't', '\0'}; //FILE* fpout; if (argc != 2) { printf("Please input the path to the pictures.\n");// & the output file name!\n"); exit(1); } // define those features fbrightness brightness; fsaturation saturation; float colorfulness; float naturalness; float contrast; float sharpness; fgray_simplicity gray_simplicity; frgb_simplicity rgb_simplicity; fhsv_simplicity hsv_simplicity; fhue_hist hue_hist; fcolor_harmony color_harmony; fcolor_coherence color_coherence; fsegment_lightness segment_lightness; fSegment_size segment_size; fSegment_hues segment_hues; fcolor_harmony segment_color_harmony; fsaliency_map saliency_map; int n_sift; int n_faces; // point to images IplImage* opencv_img; image_rgb* rgb; image_hsl* hsl; image_hsv* hsv; image_gray* gray; //filenames = get_files_list(argv[1], &count); //fpout = fopen(argv[2], "w"); CvHaarClassifierCascade* classifier = (CvHaarClassifierCascade*)cvLoad("haarcascade_frontalface_alt_tree.xml", 0, 0, 0); strcpy(filename, argv[1]); opencv_img = cvLoadImage(/*filenames[i]*/filename, 1); rgb = load_cv_image(opencv_img); hsl = rgb2hsl(rgb); hsv = rgb2hsv(rgb); gray = rgb2gray(rgb); // tune the filename int loc_beg = -1, loc_end = 0; for (i = 0; i < strlen(filename); ++i) { if (filename[i] == '/') loc_beg = i; if (filename[i] == '.') loc_end = i; } strncpy(id, filename+loc_beg+1, loc_end-loc_beg-1); id[loc_end-loc_beg] = '\0'; /* strncpy(seg_file_name+7, id, strlen(id)); strcpy(seg_file_name+7+strlen(id), suffix); //printf("%s\n", seg_file_name); */ // compute those features brightness = get_brightness_feature(hsl); saturation = get_saturation_feature(hsl); colorfulness = get_colorfulness_feature(rgb); naturalness = get_naturalness_feature(hsl); contrast = get_contrast_feature(hsl); sharpness = get_sharpness_feature(hsl); gray_simplicity = get_grayscale_simplicity_feature(gray); rgb_simplicity = get_rgb_simplicity_feature(rgb); hsv_simplicity = get_hsv_simplicity_feature(hsv); hue_hist = get_hue_histogram_feature(hsv); color_harmony = get_color_harmony_feature(hsl); color_coherence = get_color_coherence_feature(hsv); // KGL //ncut_seg seg_arg = ncut_main_seg_from_file(seg_file_name, rgb->height, rgb->width); int height = rgb->height, width = rgb->width; double double_gray[height * width]; for (i = 0; i < height; ++i) { for (j = 0; j < width; ++j) { // 矩阵存储是按列存储的 double_gray[j*height+i] = 0.299*rgb->r[i*width+j] + 0.587*rgb->g[i*width+j] + 0.114*rgb->b[i*width+j]; } } Map<MatrixXd> imageX(double_gray, height, width); SparseMatrix<double> W = ICgraph(imageX); int* asgn = ncutW(W, 5); int seglable[height * width]; for (j = 0; j < width; ++j) { for (i = 0; i < height; ++i) { seglable[i*width+j] = asgn[j*height+i]; } } free(asgn); ncut_seg seg_arg = ncut_main_seg_from_memory(seglable, height, width); segment_size = get_segsize_feature(seg_arg.seglable, seg_arg.nr, seg_arg.nc, seg_arg.lablenum); segment_hues = get_seghues_feature(seg_arg.seglable, hsv, seg_arg.nr, seg_arg.nc, seg_arg.lablenum); segment_color_harmony = get_segcolor_harmony_feature(hsl, seg_arg.seglable, seg_arg.lablenum); segment_lightness = get_seglightness_feature(hsl, seg_arg.seglable, seg_arg.lablenum); //free(seg_arg.seglable); // - KGL float* saliency = get_saliency_map(rgb); saliency_map = get_saliency_map_feature(saliency, rgb->width, rgb->height); n_sift = get_sift_number(opencv_img); n_faces = get_face_feature(opencv_img, classifier, cvSize(10, 20)); // free those space cvReleaseImage(&opencv_img); image_rgb_delete(rgb); image_hsl_delete(hsl); image_hsv_delete(hsv); image_gray_delete(gray); free(saliency); // output printf("%s,", id); // the filename of the image without suffix printf("%f,%f,%f,%f,", brightness.mean, brightness.stdev, brightness.max, brightness.min); // brightness printf("%f,%f,%f,%f,", saturation.mean, saturation.stdev, saturation.max, saturation.min); // saturation printf("%f,%f,%f,%f,", colorfulness, naturalness, contrast, sharpness); printf("%d,%d,%f,", gray_simplicity.contrast, gray_simplicity.sig_pixels_num, gray_simplicity.stdev); // gray simplicity printf("%d,%f,", rgb_simplicity.sig_pixels_num, rgb_simplicity.ratio); // RGB simplicity printf("%d,%f,", hsv_simplicity.sig_pixels_num, hsv_simplicity.ratio); // HSV simplicity printf("%d,%f,%f,", hue_hist.sig_pixels_num, hue_hist.contrast, hue_hist.stdev); // Hue histogram printf("%f,%f,%f,", color_harmony.bestfit, color_harmony.first_two_dev, color_harmony.avg_dev); // color harmony printf("%d,%f,%f,%d,%d,", color_coherence.n_ccc, color_coherence.r_lc, color_coherence.r_slc, color_coherence.rank, color_coherence.s_rank); // color coherence // KGL printf("%f,%f,", segment_size.rmaxsize, segment_size.rcontrast); // Segment size printf("%d,%d,%d,%d,%f,%f,", segment_hues.fhues1, segment_hues.fhues2, segment_hues.fhues3, segment_hues.fhues4, segment_hues.fhues5, segment_hues.fhues6); // Segment hues printf("%f,%f,%f,", segment_color_harmony.bestfit, segment_color_harmony.first_two_dev, segment_color_harmony.avg_dev); // Segment color harmony printf("%f,%f,%f,", segment_lightness.mseg_ave, segment_lightness.seg_ave_std, segment_lightness.seg_ave_contrast); // Segment lightness // - KGL printf("%f,%d,%f,%f,%d,%f,%f,%f,%f,", saliency_map.r_bg, saliency_map.n_cc, saliency_map.r_lc, saliency_map.asv_lc, saliency_map.n_cc_bg, saliency_map.r_lc_bg, saliency_map.d_cc, saliency_map.d_rtp, saliency_map.d_ci); printf("%d,", n_sift); printf("%d", n_faces); //fclose(fpout); cvReleaseHaarClassifierCascade( &classifier ); //free(filenames); //printf(" - progress: 100.00%%\n"); return (EXIT_SUCCESS); }
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) { dt_iop_rlce_data_t *data = (dt_iop_rlce_data_t *)piece->data; const int ch = piece->colors; // PASS1: Get a luminance map of image... float *luminance = (float *)malloc(((size_t)roi_out->width * roi_out->height) * sizeof(float)); // double lsmax=0.0,lsmin=1.0; #ifdef _OPENMP #pragma omp parallel for default(none) schedule(static) shared(luminance) #endif for(int j = 0; j < roi_out->height; j++) { float *in = (float *)ivoid + (size_t)j * roi_out->width * ch; float *lm = luminance + (size_t)j * roi_out->width; for(int i = 0; i < roi_out->width; i++) { double pmax = CLIP(fmax(in[0], fmax(in[1], in[2]))); // Max value in RGB set double pmin = CLIP(fmin(in[0], fmin(in[1], in[2]))); // Min value in RGB set *lm = (pmax + pmin) / 2.0; // Pixel luminocity in += ch; lm++; } } // Params const int rad = data->radius * roi_in->scale / piece->iscale; const int bins = 256; const float slope = data->slope; // CLAHE #ifdef _OPENMP #pragma omp parallel for default(none) schedule(static) shared(luminance) #endif for(int j = 0; j < roi_out->height; j++) { int yMin = fmax(0, j - rad); int yMax = fmin(roi_in->height, j + rad + 1); int h = yMax - yMin; int xMin0 = fmax(0, 0 - rad); int xMax0 = fmin(roi_in->width - 1, rad); int hist[bins + 1]; int clippedhist[bins + 1]; float dest[roi_out->width]; /* initially fill histogram */ memset(hist, 0, (bins + 1) * sizeof(int)); for(int yi = yMin; yi < yMax; ++yi) for(int xi = xMin0; xi < xMax0; ++xi) ++hist[ROUND_POSISTIVE(luminance[(size_t)yi * roi_in->width + xi] * (float)bins)]; // Destination row memset(dest, 0, roi_out->width * sizeof(float)); float *ld = dest; for(int i = 0; i < roi_out->width; i++) { int v = ROUND_POSISTIVE(luminance[(size_t)j * roi_in->width + i] * (float)bins); int xMin = fmax(0, i - rad); int xMax = i + rad + 1; int w = fmin(roi_in->width, xMax) - xMin; int n = h * w; int limit = (int)(slope * n / bins + 0.5f); /* remove left behind values from histogram */ if(xMin > 0) { int xMin1 = xMin - 1; for(int yi = yMin; yi < yMax; ++yi) --hist[ROUND_POSISTIVE(luminance[(size_t)yi * roi_in->width + xMin1] * (float)bins)]; } /* add newly included values to histogram */ if(xMax <= roi_in->width) { int xMax1 = xMax - 1; for(int yi = yMin; yi < yMax; ++yi) ++hist[ROUND_POSISTIVE(luminance[(size_t)yi * roi_in->width + xMax1] * (float)bins)]; } /* clip histogram and redistribute clipped entries */ memcpy(clippedhist, hist, (bins + 1) * sizeof(int)); int ce = 0, ceb = 0; do { ceb = ce; ce = 0; for(int b = 0; b <= bins; b++) { int d = clippedhist[b] - limit; if(d > 0) { ce += d; clippedhist[b] = limit; } } int d = (ce / (float)(bins + 1)); int m = ce % (bins + 1); for(int h = 0; h <= bins; h++) clippedhist[h] += d; if(m != 0) { int s = bins / (float)m; for(int h = 0; h <= bins; h += s) ++clippedhist[h]; } } while(ce != ceb); /* build cdf of clipped histogram */ int hMin = bins; for(int h = 0; h < hMin; h++) if(clippedhist[h] != 0) hMin = h; int cdf = 0; for(int h = hMin; h <= v; h++) cdf += clippedhist[h]; int cdfMax = cdf; for(int h = v + 1; h <= bins; h++) cdfMax += clippedhist[h]; int cdfMin = clippedhist[hMin]; *ld = (cdf - cdfMin) / (float)(cdfMax - cdfMin); ld++; } // Apply row float *in = ((float *)ivoid) + (size_t)j * roi_out->width * ch; float *out = ((float *)ovoid) + (size_t)j * roi_out->width * ch; for(int r = 0; r < roi_out->width; r++) { float H, S, L; rgb2hsl(in, &H, &S, &L); // hsl2rgb(out,H,S,( L / dest[r] ) * (L-lsmin) + lsmin ); hsl2rgb(out, H, S, dest[r]); out += ch; in += ch; ld++; } } // Cleanup free(luminance); }
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { dt_iop_soften_data_t *data = (dt_iop_soften_data_t *)piece->data; float *in = (float *)ivoid; float *out = (float *)ovoid; const int ch = piece->colors; const float brightness = 1.0 / exp2f ( -data->brightness ); const float saturation = data->saturation/100.0; /* create overexpose image and then blur */ #ifdef _OPENMP #pragma omp parallel for default(none) shared(in,out,roi_out) schedule(static) #endif for(int k=0; k<roi_out->width*roi_out->height; k++) { int index = ch*k; float h,s,l; rgb2hsl(&in[index],&h,&s,&l); s*=saturation; l*=brightness; hsl2rgb(&out[index],h,CLIP(s),CLIP(l)); } const float w = piece->iwidth*piece->iscale; const float h = piece->iheight*piece->iscale; int mrad = sqrt( w*w + h*h) * 0.01; int rad = mrad*(fmin(100.0,data->size+1)/100.0); const int radius = MIN(mrad, ceilf(rad * roi_in->scale / piece->iscale)); /* horizontal blur out into out */ const int range = 2*radius+1; const int hr = range/2; const int size = roi_out->width > roi_out->height ? roi_out->width : roi_out->height; float *scanline[3]= {0}; scanline[0] = malloc((size*sizeof(float))*ch); scanline[1] = malloc((size*sizeof(float))*ch); scanline[2] = malloc((size*sizeof(float))*ch); for(int iteration=0; iteration<BOX_ITERATIONS; iteration++) { int index=0; for(int y=0; y<roi_out->height; y++) { for(int k=0; k<3; k++) { float L=0; int hits = 0; for(int x=-hr; x<roi_out->width; x++) { int op = x - hr-1; int np = x+hr; if(op>=0) { L-=out[(index+op)*ch+k]; hits--; } if(np < roi_out->width) { L+=out[(index+np)*ch+k]; hits++; } if(x>=0) scanline[k][x] = L/hits; } } for (int k=0; k<3; k++) for (int x=0; x<roi_out->width; x++) out[(index+x)*ch+k] = scanline[k][x]; index+=roi_out->width; } /* vertical pass on blurlightness */ const int opoffs = -(hr+1)*roi_out->width; const int npoffs = (hr)*roi_out->width; for(int x=0; x < roi_out->width; x++) { for(int k=0; k<3; k++) { float L=0; int hits=0; int index = -hr*roi_out->width+x; for(int y=-hr; y<roi_out->height; y++) { int op=y-hr-1; int np= y + hr; if(op>=0) { L-=out[(index+opoffs)*ch+k]; hits--; } if(np < roi_out->height) { L+=out[(index+npoffs)*ch+k]; hits++; } if(y>=0) scanline[k][y] = L/hits; index += roi_out->width; } } for(int k=0; k<3; k++) for (int y=0; y<roi_out->height; y++) out[(y*roi_out->width+x)*ch+k] = scanline[k][y]; } } const float amount = data->amount/100.0; #ifdef _OPENMP #pragma omp parallel for default(none) shared(roi_out, in, out, data) schedule(static) #endif for(int k=0; k<roi_out->width*roi_out->height; k++) { int index = ch*k; out[index+0] = in[index+0]*(1-amount) + CLIP(out[index+0])*amount; out[index+1] = in[index+1]*(1-amount) + CLIP(out[index+1])*amount; out[index+2] = in[index+2]*(1-amount) + CLIP(out[index+2])*amount; out[index+3] = in[index+3]; } for(int i=0; i<3; ++i) if(scanline[i]) free(scanline[i]); }
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { const dt_iop_channelmixer_data_t *data = (dt_iop_channelmixer_data_t *)piece->data; const gboolean gray_mix_mode = ( data->red[CHANNEL_GRAY] !=0.0 || data->green[CHANNEL_GRAY] !=0.0 || data->blue[CHANNEL_GRAY] !=0.0)?TRUE:FALSE; const int ch = piece->colors; #ifdef _OPENMP #pragma omp parallel for default(none) shared(ivoid, ovoid, roi_in, roi_out, data) schedule(static) #endif for(int j=0; j<roi_out->height; j++) { const float *in = ((float *)ivoid) + (size_t)ch*j*roi_out->width; float *out = ((float *)ovoid) + (size_t)ch*j*roi_out->width; for(int i=0; i<roi_out->width; i++) { float h,s,l, hmix,smix,lmix,rmix,gmix,bmix,graymix; // Calculate the HSL mix hmix = CLIP( in[0] * data->red[CHANNEL_HUE] )+( in[1] * data->green[CHANNEL_HUE])+( in[2] * data->blue[CHANNEL_HUE] ); smix = CLIP( in[0] * data->red[CHANNEL_SATURATION] )+( in[1] * data->green[CHANNEL_SATURATION])+( in[2] * data->blue[CHANNEL_SATURATION] ); lmix = CLIP( in[0] * data->red[CHANNEL_LIGHTNESS] )+( in[1] * data->green[CHANNEL_LIGHTNESS])+( in[2] * data->blue[CHANNEL_LIGHTNESS] ); // If HSL mix is used apply to out[] if( hmix != 0.0 || smix != 0.0 || lmix != 0.0 ) { // mix into HSL output channels rgb2hsl(in,&h,&s,&l); h = (hmix != 0.0 ) ? hmix : h; s = (smix != 0.0 ) ? smix : s; l = (lmix != 0.0 ) ? lmix : l; hsl2rgb(out,h,s,l); } else // no HSL copt in[] to out[] for(int i=0; i<3; i++) out[i]=in[i]; // Calculate graymix and RGB mix graymix = CLIP(( out[0] * data->red[CHANNEL_GRAY] )+( out[1] * data->green[CHANNEL_GRAY])+( out[2] * data->blue[CHANNEL_GRAY] )); rmix = CLIP(( out[0] * data->red[CHANNEL_RED] )+( out[1] * data->green[CHANNEL_RED])+( out[2] * data->blue[CHANNEL_RED] )); gmix = CLIP(( out[0] * data->red[CHANNEL_GREEN] )+( out[1] * data->green[CHANNEL_GREEN])+( out[2] * data->blue[CHANNEL_GREEN] )); bmix = CLIP(( out[0] * data->red[CHANNEL_BLUE] )+( out[1] * data->green[CHANNEL_BLUE])+( out[2] * data->blue[CHANNEL_BLUE] )); if (gray_mix_mode) // Graymix is used... out[0] = out[1] = out[2] = graymix; else // RGB mix is used... { out[0] = rmix; out[1] = gmix; out[2] = bmix; } /*mix = CLIP( in[0] * data->red)+( in[1] * data->green)+( in[2] * data->blue ); if( data->output_channel <= CHANNEL_LIGHTNESS ) { // mix into HSL output channels rgb2hsl(in,&h,&s,&l); h = ( data->output_channel == CHANNEL_HUE ) ? mix : h; s = ( data->output_channel == CHANNEL_SATURATION ) ? mix : s; l = ( data->output_channel == CHANNEL_LIGHTNESS ) ? mix : l; hsl2rgb(out,h,s,l); } else if( data->output_channel > CHANNEL_LIGHTNESS && data->output_channel < CHANNEL_GRAY) { // mix into rgb output channels out[0] = ( data->output_channel == CHANNEL_RED ) ? mix : in[0]; out[1] = ( data->output_channel == CHANNEL_GREEN ) ? mix : in[1]; out[2] = ( data->output_channel == CHANNEL_BLUE ) ? mix : in[2]; } else if( data->output_channel <= CHANNEL_GRAY ) { out[0]=out[1]=out[2] = mix; } */ out += ch; in += ch; } } if(piece->pipe->mask_display) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height); }
void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { dt_iop_soften_data_t *data = (dt_iop_soften_data_t *)piece->data; float *in = (float *)ivoid; float *out = (float *)ovoid; const int ch = piece->colors; const float brightness = 1.0 / exp2f ( -data->brightness ); const float saturation = data->saturation/100.0; /* create overexpose image and then blur */ #ifdef _OPENMP #pragma omp parallel for default(none) shared(in,out,roi_out) schedule(static) #endif for(size_t k=0; k<(size_t)roi_out->width*roi_out->height; k++) { size_t index = ch*k; float h,s,l; rgb2hsl(&in[index],&h,&s,&l); s*=saturation; l*=brightness; hsl2rgb(&out[index],h,CLIP(s),CLIP(l)); } const float w = piece->iwidth*piece->iscale; const float h = piece->iheight*piece->iscale; int mrad = sqrt( w*w + h*h) * 0.01; int rad = mrad*(fmin(100.0,data->size+1)/100.0); const int radius = MIN(mrad, ceilf(rad * roi_in->scale / piece->iscale)); const int size = roi_out->width > roi_out->height ? roi_out->width : roi_out->height; for(int iteration=0; iteration<BOX_ITERATIONS; iteration++) { #ifdef _OPENMP #pragma omp parallel for default(none) shared(out,roi_out) schedule(static) #endif /* horizontal blur out into out */ for(int y=0; y<roi_out->height; y++) { __m128 scanline[size]; size_t index = (size_t)y * roi_out->width; __m128 L = _mm_setzero_ps(); int hits = 0; for(int x=-radius; x<roi_out->width; x++) { int op = x - radius-1; int np = x+radius; if(op>=0) { L = _mm_sub_ps(L, _mm_load_ps(&out[(index+op)*ch])); hits--; } if(np < roi_out->width) { L = _mm_add_ps(L, _mm_load_ps(&out[(index+np)*ch])); hits++; } if(x>=0) scanline[x] = _mm_div_ps(L, _mm_set_ps1(hits)); } for (int x=0; x<roi_out->width; x++) _mm_store_ps(&out[(index+x)*ch], scanline[x]); } /* vertical pass on blurlightness */ const int opoffs = -(radius+1)*roi_out->width; const int npoffs = (radius)*roi_out->width; #ifdef _OPENMP #pragma omp parallel for default(none) shared(out,roi_out) schedule(static) #endif for(int x=0; x < roi_out->width; x++) { __m128 scanline[size]; __m128 L = _mm_setzero_ps(); int hits=0; size_t index = (size_t)x - radius*roi_out->width; for(int y=-radius; y<roi_out->height; y++) { int op=y-radius-1; int np= y + radius; if(op>=0) { L = _mm_sub_ps(L, _mm_load_ps(&out[(index+opoffs)*ch])); hits--; } if(np < roi_out->height) { L = _mm_add_ps(L, _mm_load_ps(&out[(index+npoffs)*ch])); hits++; } if(y>=0) scanline[y] = _mm_div_ps(L, _mm_set_ps1(hits)); index += roi_out->width; } for (int y=0; y<roi_out->height; y++) _mm_store_ps(&out[((size_t)y*roi_out->width+x)*ch], scanline[y]); } } const __m128 amount = _mm_set1_ps(data->amount/100.0); const __m128 amount_1 = _mm_set1_ps(1-(data->amount)/100.0); #ifdef _OPENMP #pragma omp parallel for default(none) shared(roi_out, in, out, data) schedule(static) #endif for(size_t k=0; k<(size_t)roi_out->width*roi_out->height; k++) { int index = ch*k; _mm_store_ps(&out[index], _mm_add_ps(_mm_mul_ps(_mm_load_ps(&in[index]), amount_1), _mm_mul_ps(MM_CLIP_PS(_mm_load_ps(&out[index])), amount))); } }
//recursive function to handle higher dimension matrices, by processing 2D sections at a time void jit_colortrack_calculate_ndim(t_max_jit_colortrack *x, long dimcount, long *dim, t_jit_matrix_info *in_minfo, char *bip) { t_atom my_val[6]; // for output float normalized_bounds[4]; long i, j, n; long min_x[4], min_y[4], max_x[4], max_y[4]; char inrange_flag_x[4], inrange_flag_y[4]; int tracker; uchar *ip; char red, green, blue; short hue, saturation, lightness; bool no_match; n = dim[0]; min_x[TRACKER_1] = min_x[TRACKER_2] = min_x[TRACKER_3] = min_x[TRACKER_4] = min_y[TRACKER_1] = min_y[TRACKER_2] = min_y[TRACKER_3] = min_y[TRACKER_4] = 0x7FFFFFFF; // a really high number, because we're looking to see if a pixel is less than the one stored max_x[TRACKER_1] = max_x[TRACKER_2] = max_x[TRACKER_3] = max_x[TRACKER_4] = max_y[TRACKER_1] = max_y[TRACKER_2] = max_y[TRACKER_3] = max_y[TRACKER_4] = -1; //object_post((t_object *)x, "1 is looking for this: %i %i - %i %i - %i %i", x->min[TRACKER_1][HUE], x->max[TRACKER_1][HUE], x->min[TRACKER_1][SATURATION], x->max[TRACKER_1][SATURATION], x->min[TRACKER_1][BRIGHTNESS], x->max[TRACKER_1][BRIGHTNESS]); //object_post((t_object *)x, "2 is looking for this: %i %i - %i %i - %i %i", x->min[TRACKER_2][HUE], x->max[TRACKER_2][HUE], x->min[TRACKER_2][SATURATION], x->max[TRACKER_2][SATURATION], x->min[TRACKER_2][BRIGHTNESS], x->max[TRACKER_2][BRIGHTNESS]); for(i=0; i<dim[1]; i++) { // ITERATE THROUGH THE Y-AXIS ip = (uchar *)(bip + i * in_minfo->dimstride[1]); // ip = bip + i * in_minfo->dimstride[1]; inrange_flag_y[TRACKER_1] = inrange_flag_y[TRACKER_2] = inrange_flag_y[TRACKER_3] = inrange_flag_y[TRACKER_4] = FALSE; for(j=0; j<n; j++) { // ITERATE THROUGH THE X-AXIS ip++; // skip the alpha channel red = *ip++; green = *ip++; blue = *ip++; rgb2hsl(red, green, blue, &hue, &saturation, &lightness); //object_post((t_object *)x, "The incoming HSL is: %i %i %i", hue, saturation, lightness); // ********* UNROLLING THIS FOR-LOOP FOR SPEED ******************** // for(tracker = TRACKER_1; tracker < NUM_TRACKERS; tracker++){ // if(x->use[tracker]){ // ** NOTE: MAY WANT TO REPLACE SOME BRANCHING WITH FUNCTION POINTERS if(x->use[TRACKER_1]) { tracker = TRACKER_1; inrange_flag_x[tracker] = TRUE; if(x->hue_check[tracker]) { if(hue > x->min[tracker][HUE]) // HUE - range to match crosses 0 on the color wheel inrange_flag_x[tracker] = FALSE; else if(hue < x->max[tracker][HUE]) inrange_flag_x[tracker] = FALSE; } else { if(hue < x->min[tracker][HUE]) // HUE - normal inrange_flag_x[tracker] = FALSE; else if(hue > x->max[tracker][HUE]) inrange_flag_x[tracker] = FALSE; } if(saturation < x->min[tracker][SATURATION]) // SATURATION inrange_flag_x[tracker] = FALSE; else if(saturation > x->max[tracker][SATURATION]) inrange_flag_x[tracker] = FALSE; if(lightness < x->min[tracker][LIGHTNESS]) // LIGHTNESS inrange_flag_x[tracker] = FALSE; else if(lightness > x->max[tracker][LIGHTNESS]) inrange_flag_x[tracker] = FALSE; if(inrange_flag_x[tracker]) { // ANY TIME A PIXEL IS TRUE inrange_flag_y[tracker] = TRUE; // set the Y-axis flag to true if(j < min_x[tracker]) // min_x or max_x = is updated with the X-axis pixel location min_x[tracker] = j; else if(j > max_x[tracker]) max_x[tracker] = j; } } if(x->use[TRACKER_2]) { tracker = TRACKER_2; inrange_flag_x[tracker] = TRUE; if(x->hue_check[tracker]) { if(hue > x->min[tracker][HUE]) // HUE - range to match crosses 0 on the color wheel inrange_flag_x[tracker] = FALSE; else if(hue < x->max[tracker][HUE]) inrange_flag_x[tracker] = FALSE; } else { if(hue < x->min[tracker][HUE]) // HUE - normal inrange_flag_x[tracker] = FALSE; else if(hue > x->max[tracker][HUE]) inrange_flag_x[tracker] = FALSE; } if(saturation < x->min[tracker][SATURATION]) // SATURATION inrange_flag_x[tracker] = FALSE; else if(saturation > x->max[tracker][SATURATION]) inrange_flag_x[tracker] = FALSE; if(lightness < x->min[tracker][LIGHTNESS]) // LIGHTNESS inrange_flag_x[tracker] = FALSE; else if(lightness > x->max[tracker][LIGHTNESS]) inrange_flag_x[tracker] = FALSE; if(inrange_flag_x[tracker]) { // ANY TIME A PIXEL IS TRUE inrange_flag_y[tracker] = TRUE; // set the Y-axis flag to true if(j < min_x[tracker]) // min_x or max_x = is updated with the X-axis pixel location min_x[tracker] = j; else if(j > max_x[tracker]) max_x[tracker] = j; } } if(x->use[TRACKER_3]) { tracker = TRACKER_3; inrange_flag_x[tracker] = TRUE; if(x->hue_check[tracker]) { if(hue > x->min[tracker][HUE]) // HUE - range to match crosses 0 on the color wheel inrange_flag_x[tracker] = FALSE; else if(hue < x->max[tracker][HUE]) inrange_flag_x[tracker] = FALSE; } else { if(hue < x->min[tracker][HUE]) // HUE - normal inrange_flag_x[tracker] = FALSE; else if(hue > x->max[tracker][HUE]) inrange_flag_x[tracker] = FALSE; } if(saturation < x->min[tracker][SATURATION]) // SATURATION inrange_flag_x[tracker] = FALSE; else if(saturation > x->max[tracker][SATURATION]) inrange_flag_x[tracker] = FALSE; if(lightness < x->min[tracker][LIGHTNESS]) // LIGHTNESS inrange_flag_x[tracker] = FALSE; else if(lightness > x->max[tracker][LIGHTNESS]) inrange_flag_x[tracker] = FALSE; if(inrange_flag_x[tracker]) { // ANY TIME A PIXEL IS TRUE inrange_flag_y[tracker] = TRUE; // set the Y-axis flag to true if(j < min_x[tracker]) // min_x or max_x = is updated with the X-axis pixel location min_x[tracker] = j; else if(j > max_x[tracker]) max_x[tracker] = j; } } if(x->use[TRACKER_4]) { tracker = TRACKER_4; inrange_flag_x[tracker] = TRUE; if(x->hue_check[tracker]) { if(hue > x->min[tracker][HUE]) // HUE - range to match crosses 0 on the color wheel inrange_flag_x[tracker] = FALSE; else if(hue < x->max[tracker][HUE]) inrange_flag_x[tracker] = FALSE; } else { if(hue < x->min[tracker][HUE]) // HUE - normal inrange_flag_x[tracker] = FALSE; else if(hue > x->max[tracker][HUE]) inrange_flag_x[tracker] = FALSE; } if(saturation < x->min[tracker][SATURATION]) // SATURATION inrange_flag_x[tracker] = FALSE; else if(saturation > x->max[tracker][SATURATION]) inrange_flag_x[tracker] = FALSE; if(lightness < x->min[tracker][LIGHTNESS]) // LIGHTNESS inrange_flag_x[tracker] = FALSE; else if(lightness > x->max[tracker][LIGHTNESS]) inrange_flag_x[tracker] = FALSE; if(inrange_flag_x[tracker]) { // ANY TIME A PIXEL IS TRUE inrange_flag_y[tracker] = TRUE; // set the Y-axis flag to true if(j < min_x[tracker]) // min_x or max_x = is updated with the X-axis pixel location min_x[tracker] = j; else if(j > max_x[tracker]) max_x[tracker] = j; } } // } } /* for(tracker = TRACKER_1; tracker < NUM_TRACKERS; tracker++){ if(x->use[tracker] && inrange_flag_y[tracker]){ // ANY TIME A PIXEL IS TRUE (the y-axis flag was set in the x-axis loop) if(i < min_y[tracker]) // min_y or max_y = is updated with the Y-axis pixel location min_y[tracker] = i; else if(i > max_y[tracker]) max_y[tracker] = i; } } */ // *********** UNROLLED VERSION OF THE ABOVE FOR-LOOP FOR SPEED ************ if(x->use[TRACKER_1] && inrange_flag_y[TRACKER_1]) { // ANY TIME A PIXEL IS TRUE (the y-axis flag was set in the x-axis loop) if(i < min_y[TRACKER_1]) // min_y or max_y = is updated with the Y-axis pixel location min_y[TRACKER_1] = i; else if(i > max_y[TRACKER_1]) max_y[TRACKER_1] = i; } if(x->use[TRACKER_2] && inrange_flag_y[TRACKER_2]) { // ANY TIME A PIXEL IS TRUE (the y-axis flag was set in the x-axis loop) if(i < min_y[TRACKER_2]) // min_y or max_y = is updated with the Y-axis pixel location min_y[TRACKER_2] = i; else if(i > max_y[TRACKER_2]) max_y[TRACKER_2] = i; } if(x->use[TRACKER_3] && inrange_flag_y[TRACKER_3]) { // ANY TIME A PIXEL IS TRUE (the y-axis flag was set in the x-axis loop) if(i < min_y[TRACKER_3]) // min_y or max_y = is updated with the Y-axis pixel location min_y[TRACKER_3] = i; else if(i > max_y[TRACKER_3]) max_y[TRACKER_3] = i; } if(x->use[TRACKER_4] && inrange_flag_y[TRACKER_4]) { // ANY TIME A PIXEL IS TRUE (the y-axis flag was set in the x-axis loop) if(i < min_y[TRACKER_4]) // min_y or max_y = is updated with the Y-axis pixel location min_y[TRACKER_4] = i; else if(i > max_y[TRACKER_4]) max_y[TRACKER_4] = i; } } // *************** // POST PROCESSING for(tracker = TRACKER_1; tracker < NUM_TRACKERS; tracker++) { if(x->use[tracker]) { no_match = true; if(min_x[tracker] == 0x7FFFFFFF) { min_x[tracker] = -1; // goto nomatch; // This is bad because if tracker1 doesn't match, but tracker 2 does it still skips tracker2! } else no_match = false; if(min_y[tracker] == 0x7FFFFFFF) { min_y[tracker] = -1; // goto nomatch; } else no_match = false; if(max_x[tracker] == -1) { max_x[tracker] = min_x[tracker]; // goto nomatch; } else no_match = false; if(max_y[tracker] == -1) { max_y[tracker] = min_y[tracker]; // goto nomatch; } else no_match = false; if(no_match) goto nomatch; // Normalize normalized_bounds[0] = (float)min_x[tracker] / dim[0]; normalized_bounds[1] = (float)min_y[tracker] / dim[1]; normalized_bounds[2] = (float)max_x[tracker] / dim[0]; normalized_bounds[3] = (float)max_y[tracker] / dim[1]; if(x->output_bounds[tracker]) { atom_setlong(&(my_val[0]), tracker+1); atom_setsym(&(my_val[1]), gensym("bounds")); atom_setfloat(&(my_val[2]), normalized_bounds[0]); atom_setfloat(&(my_val[3]), normalized_bounds[1]); atom_setfloat(&(my_val[4]), normalized_bounds[2]); atom_setfloat(&(my_val[5]), normalized_bounds[3]); // outlet_list(x->valout, 0L, 6, &my_val); outlet_list(x->valout, 0L, 6, &my_val[0]); } if(x->output_center[tracker]) { atom_setlong(&(my_val[0]), tracker+1); atom_setsym(&(my_val[1]),gensym("center")); atom_setfloat(&(my_val[2]), (normalized_bounds[2] + normalized_bounds[0]) * 0.5); atom_setfloat(&(my_val[3]), (normalized_bounds[3] + normalized_bounds[1]) * 0.5); // outlet_list(x->valout, 0L, 4, &my_val); outlet_list(x->valout, 0L, 4, &my_val[0]); } if(x->output_size[tracker]) { atom_setlong(&(my_val[0]), tracker+1); atom_setsym(&(my_val[1]),gensym("size")); atom_setfloat(&(my_val[2]), (normalized_bounds[2] - normalized_bounds[0]) * (normalized_bounds[3] - normalized_bounds[1])); // outlet_list(x->valout, 0L, 3, &my_val); outlet_list(x->valout, 0L, 3, &my_val[0]); } nomatch: ; } } return; }
void testRgb2hsl() { image_rgb* rgb = load_image("tests/test.jpg", 1); image_hsl* hsl = rgb2hsl(rgb); image_rgb* rgb2 = image_rgb_new(2, 2); image_rgb* rgb3 = load_image("tests/test.bmp", 1); int i, j; for (i = 0; i < 3; ++i) { for (j = 0; j < 3; ++j) { CU_ASSERT_EQUAL(rgb->r[i*3+j], rgb3->r[i*3+j]); CU_ASSERT_EQUAL(rgb->g[i*3+j], rgb3->g[i*3+j]); CU_ASSERT_EQUAL(rgb->b[i*3+j], rgb3->b[i*3+j]); } } rgb2->r[0] = 255; rgb2->r[1] = 220; rgb2->r[2] = 100; rgb2->r[3] = 3; rgb2->g[0] = 245; rgb2->g[1] = 200; rgb2->g[2] = 155; rgb2->g[3] = 3; rgb2->b[0] = 2; rgb2->b[1] = 200; rgb2->b[2] = 100; rgb2->b[3] = 3; image_hsl* hsl2 = rgb2hsl(rgb2); CU_ASSERT_DOUBLE_EQUAL(hsl->h[0], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->h[1], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->h[2], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->h[3], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->h[4], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->h[5], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->h[6], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->h[7], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->h[8], 0.1111, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->l[4], 0.01765, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->l[5], 0.02549, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->s[6], 0.60000, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl->s[7], 0.33333, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->h[0], 0.16008, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->h[1], 0.00000, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->h[2], 0.33333, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->h[3], 0.00000, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->s[0], 1.00000, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->s[1], 0.22222, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->s[2], 0.21569, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->s[3], 0.00000, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->l[0], 0.50392, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->l[1], 0.82353, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->l[2], 0.50000, 0.0001); CU_ASSERT_DOUBLE_EQUAL(hsl2->l[3], 0.01176, 0.0001); image_rgb_delete(rgb); image_rgb_delete(rgb2); image_rgb_delete(rgb3); image_hsl_delete(hsl); image_hsl_delete(hsl2); }