static int filter_get_image( mlt_frame frame, uint8_t **image, mlt_image_format *format, int *width, int *height, int writable ) { mlt_filter filter = (mlt_filter) mlt_frame_pop_service( frame ); int error = 0; // Regenerate the LUT if necessary mlt_service_lock( MLT_FILTER_SERVICE( filter ) ); refresh_lut( filter, frame ); mlt_service_unlock( MLT_FILTER_SERVICE( filter ) ); // Make sure the format is acceptable if( *format != mlt_image_rgb24 && *format != mlt_image_rgb24a ) { *format = mlt_image_rgb24; } // Get the image writable = 1; error = mlt_frame_get_image( frame, image, format, width, height, writable ); // Apply the LUT if( !error ) { apply_lut( filter, *image, *format, *width, *height ); } return error; }
void histo_l_algo(const TRasterImageP &image, int reference) { int lx, ly, wrap; int x, y, grey, ref_grey, m, d, dd; UCHAR *buffer, *pix, *north, *south; int g_histo[256]; int d_histo[256][256]; int cum[256]; long n; BIG s; float mean_d[256]; int max_d_grey; float max_d; int conf; int edgelen; float fac; UCHAR lut[256]; if (!Edge_init_done) edge_init(); get_virtual_buffer(image, &lx, &ly, &wrap, &buffer); for (grey = 0; grey < 256; grey++) { g_histo[grey] = 0; for (d = 0; d < 256; d++) d_histo[grey][d] = 0; } /* istogramma dei grigi e istogramma delle derivate */ for (y = 1; y < ly - 1; y++) { pix = buffer + y * wrap + 1; north = pix + wrap; south = pix - wrap; for (x = 1; x < lx - 1; x++, pix++, north++, south++) { m = 2 * ((int)north[0] + (int)pix[-1] + 2 * (int)pix[0] + (int)pix[1] + (int)south[0]) + (int)north[-1] + (int)north[1] + (int)south[-1] + (int)south[1]; m = (m + 8) >> 4; d = (int)north[-1] + (int)north[0] * 2 + (int)north[1] - (int)south[-1] - (int)south[0] * 2 - (int)south[1]; TO_ABS(d) dd = (int)north[-1] + (int)pix[-1] * 2 + (int)south[-1] - (int)north[1] - (int)pix[1] * 2 - (int)south[1]; TO_ABS(dd) if (dd > d) d = dd; dd = (int)pix[-1] + (int)north[-1] * 2 + (int)north[0] - (int)pix[1] - (int)south[1] * 2 - (int)south[0]; TO_ABS(dd) if (dd > d) d = dd; dd = (int)pix[1] + (int)north[1] * 2 + (int)north[0] - (int)pix[-1] - (int)south[-1] * 2 - (int)south[0]; TO_ABS(dd) if (dd > d) d = dd; d = (d + 2) >> 2; d_histo[m][d]++; g_histo[*pix]++; } } build_cum(g_histo, cum); /* costruzione pendenze medie */ for (grey = 0; grey < 256; grey++) { n = 0; CLEAR_BIG(s); for (d = 0; d < 256; d++) { ADD_BIG(s, d_histo[grey][d] * d); n += d_histo[grey][d]; } if (n) mean_d[grey] = (float)(BIG_TO_DOUBLE(s) / n); else mean_d[grey] = 0.0; } smooth_func256(mean_d, 5); /* determinazione grigio di massima pendenza */ max_d_grey = 0; max_d = 0.0; for (grey = 0; grey < 256; grey++) { if (max_d < mean_d[grey]) { max_d = mean_d[grey]; max_d_grey = grey; } } /* stima della lunghezza dei bordi */ edgelen = 0; for (y = 1; y < ly - 1; y++) { pix = buffer + y * wrap + 1; north = pix + wrap; south = pix - wrap; conf = -1; for (x = 1; x < lx - 1; x++, pix++, north++, south++) { if (pix[0] <= max_d_grey) { if (conf >= 0) { conf = ((conf << 1) & ((1 << 7) | (1 << 6) | (1 << 2) | (1 << 1))) | ((north[1] <= max_d_grey) << 5) | ((1) << 4) | ((pix[1] <= max_d_grey) << 3) | ((south[1] <= max_d_grey)); } else { conf = ((north[-1] <= max_d_grey) << 7) | ((north[0] <= max_d_grey) << 6) | ((north[1] <= max_d_grey) << 5) | ((pix[-1] <= max_d_grey) << 4) | ((pix[1] <= max_d_grey) << 3) | ((south[-1] <= max_d_grey) << 2) | ((south[0] <= max_d_grey) << 1) | ((south[1] <= max_d_grey)); } edgelen += Edge_value[conf]; } else conf = -1; } } if (reference) { for (grey = 0; grey < 256; grey++) Ref_cum[grey] = cum[grey]; Ref_edgelen = edgelen; return; } /* normalizza la cumulativa per il numero di linee */ fac = (float)Ref_edgelen / edgelen; /*** printf ("fac: %f\n", fac); printf ("cum prima:\n"); for (grey = 0; grey < 256; grey++) printf ("%9d\n", cum[grey]); ***/ for (grey = 0; grey < 255; grey++) { cum[grey] = (int)(cum[grey] * fac); notMoreThan(cum[255], cum[grey]); } /*** printf ("cum dopo:\n"); for (grey = 0; grey < 256; grey++) printf ("%9d\n", cum[grey]); printf ("Ref_cum:\n"); for (grey = 0; grey < 256; grey++) printf ("%9d\n", Ref_cum[grey]); ***/ /* equalizza l'istogramma */ ref_grey = 0; for (grey = 0; grey < 255; grey++) { while (Ref_cum[ref_grey] < cum[grey]) ref_grey++; lut[grey] = ref_grey; } lut[255] = 255; /* DAFARE if (Wl_flag) write_lut_image (lut); */ apply_lut(image, lut); }
void black_eq_algo(const TRasterImageP &image) { int lx, ly, wrap; int x, y, grey /*, width*/; int d_histo[256][256]; int d, dd, m; UCHAR *buffer, *pix, *north, *south; UCHAR prev, darkest; long n; float mean_d[256]; BIG s; int max_d_grey; float max_d; float fac; int val; UCHAR lut[256]; image->getRaster()->lock(); get_virtual_buffer(image, &lx, &ly, &wrap, &buffer); for (grey = 0; grey < 256; grey++) { for (d = 0; d < 256; d++) d_histo[grey][d] = 0; } for (y = 1; y < ly - 1; y++) { pix = buffer + y * wrap + 1; north = pix + wrap; south = pix - wrap; for (x = 1; x < lx - 1; x++, pix++, north++, south++) { m = 2 * ((int)north[0] + (int)pix[-1] + 2 * (int)pix[0] + (int)pix[1] + (int)south[0]) + (int)north[-1] + (int)north[1] + (int)south[-1] + (int)south[1]; m = (m + 8) >> 4; d = (int)north[-1] + (int)north[0] * 2 + (int)north[1] - (int)south[-1] - (int)south[0] * 2 - (int)south[1]; TO_ABS(d) dd = (int)north[-1] + (int)pix[-1] * 2 + (int)south[-1] - (int)north[1] - (int)pix[1] * 2 - (int)south[1]; TO_ABS(dd) if (dd > d) d = dd; dd = (int)pix[-1] + (int)north[-1] * 2 + (int)north[0] - (int)pix[1] - (int)south[1] * 2 - (int)south[0]; TO_ABS(dd) if (dd > d) d = dd; dd = (int)pix[1] + (int)north[1] * 2 + (int)north[0] - (int)pix[-1] - (int)south[-1] * 2 - (int)south[0]; TO_ABS(dd) if (dd > d) d = dd; d = (d + 2) >> 2; d_histo[m][d]++; } } for (grey = 0; grey < 256; grey++) { n = 0; CLEAR_BIG(s); for (d = 0; d < 256; d++) { ADD_BIG(s, d_histo[grey][d] * d); n += d_histo[grey][d]; } if (n) mean_d[grey] = (float)(BIG_TO_DOUBLE(s) / n); else mean_d[grey] = 0; } smooth_func256(mean_d, 5); max_d_grey = 0; max_d = 0.0; for (grey = 0; grey < 256; grey++) { if (max_d < mean_d[grey]) { max_d = mean_d[grey]; max_d_grey = grey; } } n = 0; CLEAR_BIG(s); for (y = 0; y < ly; y++) { pix = buffer + y * wrap; prev = 255; darkest = 255; for (x = 0; x < lx; x++, pix++) { if (*pix < max_d_grey) { if (prev < max_d_grey) notMoreThan(*pix, darkest); else darkest = *pix; } else { if (prev < max_d_grey) { ADD_BIG(s, darkest); n++; } } prev = *pix; } } darkest = troundp(BIG_TO_DOUBLE(s) / n); /* for (grey = 0; grey < darkest; grey++) lut[grey] = 0; fac = (float)255 / (float)(255 - darkest); for (grey = darkest; grey < 256; grey++) lut[grey] = 255 - troundp ((255 - grey) * fac); */ notLessThan(0, Black); ; notMoreThan(255, Black); fac = (float)(255 - Black) / (float)(255 - darkest); for (grey = 0; grey < 256; grey++) { val = 255 - troundp((255 - grey) * fac); notLessThan(0, val); notMoreThan(255, val); lut[grey] = val; } apply_lut(image, lut); image->getRaster()->unlock(); }
// Now the thumbnail generation is combined with the stats calculations, // to speed things up a little. Both require a pass through the entire // image, so it seems natural, and the stats calculation doesn't add much // overhead. (The user is waiting while the thumbnail is being generated, // so we do want this to be as quick as possible.) unsigned char *generate_thumbnail_data(ImageInfo *ii, int tsx, int tsy) { int i,j; unsigned char *bdata = MALLOC(sizeof(unsigned char)*tsx*tsy*3); ImageStats *stats = &(ii->stats); // we will estimate the stats from the thumbnail data clear_stats(ii); // Here we do the rather ugly thing of making the thumbnail // loading code specific to each supported data type. This is // because we've combined the stats calculation into this... if (ii->data_ci->data_type == GREYSCALE_FLOAT) { // store data used to build the small image pixmap // we will calculate the stats on this subset float *fdata = CALLOC(sizeof(float), tsx*tsy); load_thumbnail_data(ii->data_ci, tsx, tsy, fdata); set_ignores(ii, !g_startup); // split out the case where we have no ignore value -- // should be quite a bit faster... if (have_ignore(stats)) { // Compute stats -- ignore "no data" value int n=0; for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { float v = fdata[j+i*tsx]; if (!is_ignored(stats, v) && fabs(v)<999999999) { stats->avg += v; // first valid pixel --> initialize max/min // subsequent pixels --> update max/min if needed if (n==0) { stats->act_max = stats->act_min = v; } else { if (v > stats->act_max) stats->act_max = v; if (v < stats->act_min) stats->act_min = v; } ++n; } } } stats->avg /= (double)n; for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { float v = fdata[j+i*tsx]; if (!is_ignored(stats, v) && fabs(v)<999999999) { stats->stddev += (v - stats->avg)*(v - stats->avg); } } } stats->stddev = sqrt(stats->stddev / (double)n); } else { // Compute stats, no ignore (actually, do ignore data that is NaN) stats->act_max = stats->act_min = fdata[0]; for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { float v = fdata[j+i*tsx]; // added in the fabs<999... thing... sometimes values // are just ridiculous and we must ignore them if (meta_is_valid_double(v) && fabs(v)<999999999) { stats->avg += v; if (v > stats->act_max) stats->act_max = v; if (v < stats->act_min) stats->act_min = v; } } } stats->avg /= (double)(tsx*tsy); for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { float v = fdata[j+i*tsx]; if (meta_is_valid_double(v) && fabs(v)<999999999) stats->stddev += (v - stats->avg) * (v - stats->avg); } } stats->stddev = sqrt(stats->stddev / (double)(tsx*tsy)); } //printf("Avg, StdDev: %f, %f\n", stats->avg, stats->stddev); set_mapping(ii, !g_startup); // Now actually scale the data, and convert to bytes. // Note that we need 3 values, one for each of the RGB channels. if (have_lut()) { // look up table case -- no scaling, just use the lut // to convert from float to rgb byte for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int index = j+i*tsx; int n = 3*index; float val = fdata[index]; int ival; if (is_ignored(stats, val) || val<0) ival = ignore_grey_value; else ival = (int)val; apply_lut(ival, &bdata[n], &bdata[n+1], &bdata[n+2]); // histogram will appear as if we were scaling // to greyscale byte unsigned char uval = (unsigned char) calc_scaled_pixel_value(stats, val); stats->hist[uval] += 1; } } } else { // normal case -- no lut, apply selected scaling to convert from // floating point to byte for display for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int index = j+i*tsx; float val = fdata[index]; int n = 3*index; unsigned char uval = (unsigned char) calc_scaled_pixel_value(stats, val); if (is_ignored(stats, val)) { bdata[n] = bdata[n+1] = bdata[n+2] = ignore_grey_value; } else { bdata[n] = uval; bdata[n+1] = uval; bdata[n+2] = uval; stats->hist[uval] += 1; } } } } // done with our subset free(fdata); } else if (ii->data_ci->data_type == RGB_BYTE) { // store data used to build the small image pixmap // we will calculate the stats on this subset unsigned char *rgbdata = CALLOC(sizeof(unsigned char), tsx*tsy*3); load_thumbnail_data(ii->data_ci, tsx, tsy, (void*)rgbdata); set_ignores(ii, !g_startup); ImageStatsRGB *stats_r = &ii->stats_r; ImageStatsRGB *stats_g = &ii->stats_g; ImageStatsRGB *stats_b = &ii->stats_b; stats_r->act_min = rgbdata[0]; stats_r->act_max = rgbdata[0]; stats_g->act_min = rgbdata[1]; stats_g->act_max = rgbdata[1]; stats_b->act_min = rgbdata[2]; stats_b->act_max = rgbdata[2]; int nr=0, ng=0, nb=0; for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int kk = 3*(j+i*tsx); if (!is_ignored_rgb(stats_r, rgbdata[kk])) { stats_r->avg += rgbdata[kk]; ++nr; if (rgbdata[kk] < stats_r->act_min) stats_r->act_min = rgbdata[kk]; if (rgbdata[kk] > stats_r->act_max) stats_r->act_max = rgbdata[kk]; } if (!is_ignored_rgb(stats_g, rgbdata[kk+1])) { stats_g->avg += rgbdata[kk+1]; ++ng; if (rgbdata[kk+1] < stats_g->act_min) stats_g->act_min = rgbdata[kk+1]; if (rgbdata[kk+1] > stats_g->act_max) stats_g->act_max = rgbdata[kk+1]; } if (!is_ignored_rgb(stats_b, rgbdata[kk+2])) { stats_b->avg += rgbdata[kk+2]; ++nb; if (rgbdata[kk+2] < stats_b->act_min) stats_b->act_min = rgbdata[kk+2]; if (rgbdata[kk+2] > stats_b->act_max) stats_b->act_max = rgbdata[kk+2]; } } } if (nr>1) stats_r->avg /= (double)nr; if (ng>1) stats_g->avg /= (double)ng; if (nb>1) stats_b->avg /= (double)nb; for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int kk = 3*(j+i*tsx); if (!is_ignored_rgb(stats_r, rgbdata[kk])) { float d = rgbdata[kk] - stats_r->avg; stats_r->stddev += d*d; } if (!is_ignored_rgb(stats_g, rgbdata[kk+1])) { float d = rgbdata[kk+1] - stats_g->avg; stats_g->stddev += d*d; } if (!is_ignored_rgb(stats_b, rgbdata[kk+2])) { float d = rgbdata[kk+2] - stats_b->avg; stats_b->stddev += d*d; } } } stats_r->stddev = sqrt(stats_r->stddev / (double)nr); stats_g->stddev = sqrt(stats_g->stddev / (double)ng); stats_b->stddev = sqrt(stats_b->stddev / (double)nb); set_mapping(ii, !g_startup); // clear out the stats for the greyscale image - we'll just use // the histogram stats->avg = 0; stats->stddev = 0; // these are used for the axis labels on the histogram, so we put // in the averages of the mins... these are sort of bogus anyway, we // really should have 3 histograms stats->map_min = calc_fake_min(ii); stats->map_max = calc_fake_max(ii); for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int kk = 3*(j+i*tsx); if (!is_ignored_rgb(stats_r, rgbdata[kk]) && !is_ignored_rgb(stats_g, rgbdata[kk+1]) && !is_ignored_rgb(stats_b, rgbdata[kk+2])) { bdata[kk] = (unsigned char)calc_rgb_scaled_pixel_value( stats_r, rgbdata[kk]); bdata[kk+1] = (unsigned char)calc_rgb_scaled_pixel_value( stats_g, rgbdata[kk+1]); bdata[kk+2] = (unsigned char)calc_rgb_scaled_pixel_value( stats_b, rgbdata[kk+2]); } else { bdata[kk] = ignore_red_value; bdata[kk+1] = ignore_green_value; bdata[kk+2] = ignore_blue_value; } } } // Update the histogram -- use greyscale average for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int kk = 3*(j+i*tsx); if (!is_ignored_rgb(stats_r, rgbdata[kk]) && !is_ignored_rgb(stats_g, rgbdata[kk+1]) && !is_ignored_rgb(stats_b, rgbdata[kk+2])) { unsigned char uval = (bdata[kk]+bdata[kk+1]+bdata[kk+2])/3; stats->hist[uval] += 1; } } } free(rgbdata); } else if (ii->data_ci->data_type == GREYSCALE_BYTE) { // this case is very similar to the RGB case, above, except we // have to first grab the data into a greyscale buffer, and // then copy it over to the 3-band buffer we're supposed to return unsigned char *gsdata = MALLOC(sizeof(unsigned char)*tsx*tsy); load_thumbnail_data(ii->data_ci, tsx, tsy, (void*)gsdata); set_ignores(ii, !g_startup); stats->act_max = 0; stats->act_min = 255; stats->map_min = 0; stats->map_max = 255; for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { unsigned char uval = gsdata[j+i*tsx]; stats->avg += uval; if (uval > stats->act_max) stats->act_max = uval; if (uval < stats->act_min) stats->act_min = uval; } } stats->avg /= (double)(tsx*tsy); for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { unsigned char uval = gsdata[j+i*tsx]; stats->stddev += (uval - stats->avg) * (uval - stats->avg); } } stats->stddev = sqrt(stats->stddev / (double)(tsx*tsy)); set_mapping(ii, !g_startup); for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { unsigned char uval = gsdata[j+i*tsx]; int kk = 3*(j+i*tsx); if (have_lut()) { apply_lut(uval, &bdata[kk], &bdata[kk+1], &bdata[kk+2]); stats->hist[uval] += 1; } else if (!is_ignored(stats, uval)) { // apply selected scaling to display values unsigned char display_value = (unsigned char) calc_scaled_pixel_value(stats, uval); bdata[kk] = bdata[kk+1] = bdata[kk+2] = display_value; stats->hist[display_value] += 1; } else { bdata[kk] = bdata[kk+1] = bdata[kk+2] = ignore_grey_value; } } } free(gsdata); } else if (ii->data_ci->data_type == RGB_FLOAT) { // store data used to build the small image pixmap // we will calculate the stats on this subset float *fdata = MALLOC(sizeof(float)*tsx*tsy*3); load_thumbnail_data(ii->data_ci, tsx, tsy, fdata); set_ignores(ii, !g_startup); ImageStatsRGB *stats_r = &ii->stats_r; ImageStatsRGB *stats_g = &ii->stats_g; ImageStatsRGB *stats_b = &ii->stats_b; stats_r->act_min = fdata[0]; stats_r->act_max = fdata[0]; stats_g->act_min = fdata[1]; stats_g->act_max = fdata[1]; stats_b->act_min = fdata[2]; stats_b->act_max = fdata[2]; int nr=0, ng=0, nb=0; for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int kk = 3*(j+i*tsx); if (!is_ignored_rgb(stats_r, fdata[kk])) { stats_r->avg += fdata[kk]; ++nr; if (fdata[kk] < stats_r->act_min) stats_r->act_min = fdata[kk]; if (fdata[kk] > stats_r->act_max) stats_r->act_max = fdata[kk]; } if (!is_ignored_rgb(stats_g, fdata[kk+1])) { stats_g->avg += fdata[kk+1]; ++ng; if (fdata[kk+1] < stats_g->act_min) stats_g->act_min = fdata[kk+1]; if (fdata[kk+1] > stats_g->act_max) stats_g->act_max = fdata[kk+1]; } if (!is_ignored_rgb(stats_b, fdata[kk+2])) { stats_b->avg += fdata[kk+2]; ++nb; if (fdata[kk+2] < stats_b->act_min) stats_b->act_min = fdata[kk+2]; if (fdata[kk+2] > stats_b->act_max) stats_b->act_max = fdata[kk+2]; } } } if (nr>1) stats_r->avg /= (double)nr; if (ng>1) stats_g->avg /= (double)ng; if (nb>1) stats_b->avg /= (double)nb; for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int kk = 3*(j+i*tsx); if (!is_ignored_rgb(stats_r, fdata[kk])) { float d = fdata[kk] - stats_r->avg; stats_r->stddev += d*d; } if (!is_ignored_rgb(stats_g, fdata[kk+1])) { float d = fdata[kk+1] - stats_g->avg; stats_g->stddev += d*d; } if (!is_ignored_rgb(stats_b, fdata[kk+2])) { float d = fdata[kk+2] - stats_b->avg; stats_b->stddev += d*d; } } } stats_r->stddev = sqrt(stats_r->stddev / (double)nr); stats_g->stddev = sqrt(stats_g->stddev / (double)ng); stats_b->stddev = sqrt(stats_b->stddev / (double)nb); set_mapping(ii, !g_startup); // clear out the stats for the greyscale image - we'll just use // the histogram stats->avg = 0; stats->stddev = 0; // these are used for the axis labels on the histogram, so we put // in the averages of the mins... these are sort of bogus anyway, we // really should have 3 histograms stats->map_min = calc_fake_min(ii); stats->map_max = calc_fake_max(ii); for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int kk = 3*(j+i*tsx); if (!is_ignored_rgb(stats_r, fdata[kk]) && !is_ignored_rgb(stats_g, fdata[kk+1]) && !is_ignored_rgb(stats_b, fdata[kk+2])) { bdata[kk] = (unsigned char)calc_rgb_scaled_pixel_value( stats_r, fdata[kk]); bdata[kk+1] = (unsigned char)calc_rgb_scaled_pixel_value( stats_g, fdata[kk+1]); bdata[kk+2] = (unsigned char)calc_rgb_scaled_pixel_value( stats_b, fdata[kk+2]); } else { bdata[kk] = ignore_red_value; bdata[kk+1] = ignore_green_value; bdata[kk+2] = ignore_blue_value; } } } // Update the histogram -- use greyscale average for (i=0; i<tsy; ++i) { for (j=0; j<tsx; ++j) { int kk = 3*(j+i*tsx); if (!is_ignored_rgb(stats_r, fdata[kk]) && !is_ignored_rgb(stats_g, fdata[kk+1]) && !is_ignored_rgb(stats_b, fdata[kk+2])) { unsigned char uval = (bdata[kk]+bdata[kk+1]+bdata[kk+2])/3; stats->hist[uval] += 1; } } } // done with our subset free(fdata); } else { asfPrintError("Unexpected data type: %d!\n", ii->data_ci->data_type); } return bdata; }