void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings *view_settings, const ColorManagedDisplaySettings *display_settings) { int x, y, c; unsigned int nl, na, nr, ng, nb; double divl, diva, divr, divg, divb; float *rf = NULL; unsigned char *rc = NULL; unsigned int *bin_lum, *bin_r, *bin_g, *bin_b, *bin_a; int savedlines, saveline; float rgba[4], ycc[3], luma; int ycc_mode = -1; const short is_float = (ibuf->rect_float != NULL); struct ColormanageProcessor *cm_processor = NULL; if (ibuf->rect == NULL && ibuf->rect_float == NULL) return; if (scopes->ok == 1) return; if (scopes->hist.ymax == 0.f) scopes->hist.ymax = 1.f; /* hmmmm */ if (!(ELEM(ibuf->channels, 3, 4))) return; scopes->hist.channels = 3; scopes->hist.x_resolution = 256; switch (scopes->wavefrm_mode) { case SCOPES_WAVEFRM_RGB: ycc_mode = -1; break; case SCOPES_WAVEFRM_LUMA: case SCOPES_WAVEFRM_YCC_JPEG: ycc_mode = BLI_YCC_JFIF_0_255; break; case SCOPES_WAVEFRM_YCC_601: ycc_mode = BLI_YCC_ITU_BT601; break; case SCOPES_WAVEFRM_YCC_709: ycc_mode = BLI_YCC_ITU_BT709; break; } /* temp table to count pix value for histogram */ bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_a = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); /* convert to number of lines with logarithmic scale */ scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y; if (scopes->sample_full) scopes->sample_lines = ibuf->y; /* scan the image */ savedlines = 0; for (c = 0; c < 3; c++) { scopes->minmax[c][0] = 25500.0f; scopes->minmax[c][1] = -25500.0f; } scopes->waveform_tot = ibuf->x * scopes->sample_lines; if (scopes->waveform_1) MEM_freeN(scopes->waveform_1); if (scopes->waveform_2) MEM_freeN(scopes->waveform_2); if (scopes->waveform_3) MEM_freeN(scopes->waveform_3); if (scopes->vecscope) MEM_freeN(scopes->vecscope); scopes->waveform_1 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 1"); scopes->waveform_2 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 2"); scopes->waveform_3 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3"); scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel"); if (is_float) rf = ibuf->rect_float; else rc = (unsigned char *)ibuf->rect; if (ibuf->rect_float) cm_processor = IMB_colormanagement_display_processor_new(view_settings, display_settings); for (y = 0; y < ibuf->y; y++) { if (savedlines < scopes->sample_lines && y >= ((savedlines) * ibuf->y) / (scopes->sample_lines + 1)) { saveline = 1; } else { saveline = 0; } for (x = 0; x < ibuf->x; x++) { if (is_float) { copy_v4_v4(rgba, rf); IMB_colormanagement_processor_apply_v4(cm_processor, rgba); } else { for (c = 0; c < 4; c++) rgba[c] = rc[c] * INV_255; } /* we still need luma for histogram */ luma = rgb_to_luma(rgba); /* check for min max */ if (ycc_mode == -1) { for (c = 0; c < 3; c++) { if (rgba[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgba[c]; if (rgba[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgba[c]; } } else { rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode); for (c = 0; c < 3; c++) { ycc[c] *= INV_255; if (ycc[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = ycc[c]; if (ycc[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = ycc[c]; } } /* increment count for histo*/ bin_lum[get_bin_float(luma)] += 1; bin_r[get_bin_float(rgba[0])] += 1; bin_g[get_bin_float(rgba[1])] += 1; bin_b[get_bin_float(rgba[2])] += 1; bin_a[get_bin_float(rgba[3])] += 1; /* save sample if needed */ if (saveline) { const float fx = (float)x / (float)ibuf->x; const int idx = 2 * (ibuf->x * savedlines + x); save_sample_line(scopes, idx, fx, rgba, ycc); } rf += ibuf->channels; rc += ibuf->channels; } if (saveline) savedlines += 1; } /* test for nicer distribution even - non standard, leave it out for a while */ #if 0 for (x = 0; x < 256; x++) { bin_lum[x] = sqrt (bin_lum[x]); bin_r[x] = sqrt(bin_r[x]); bin_g[x] = sqrt(bin_g[x]); bin_b[x] = sqrt(bin_b[x]); bin_a[x] = sqrt(bin_a[x]); } #endif /* convert hist data to float (proportional to max count) */ nl = na = nr = nb = ng = 0; for (x = 0; x < 256; x++) { if (bin_lum[x] > nl) nl = bin_lum[x]; if (bin_r[x] > nr) nr = bin_r[x]; if (bin_g[x] > ng) ng = bin_g[x]; if (bin_b[x] > nb) nb = bin_b[x]; if (bin_a[x] > na) na = bin_a[x]; } divl = 1.0 / (double)nl; diva = 1.0 / (double)na; divr = 1.0 / (double)nr; divg = 1.0 / (double)ng; divb = 1.0 / (double)nb; for (x = 0; x < 256; x++) { scopes->hist.data_luma[x] = bin_lum[x] * divl; scopes->hist.data_r[x] = bin_r[x] * divr; scopes->hist.data_g[x] = bin_g[x] * divg; scopes->hist.data_b[x] = bin_b[x] * divb; scopes->hist.data_a[x] = bin_a[x] * diva; } MEM_freeN(bin_lum); MEM_freeN(bin_r); MEM_freeN(bin_g); MEM_freeN(bin_b); MEM_freeN(bin_a); if (cm_processor) IMB_colormanagement_processor_free(cm_processor); scopes->ok = 1; }
void scopes_update(Scopes *scopes, ImBuf *ibuf, int use_color_management) { int x, y, c; unsigned int n, nl; double div, divl; float *rf = NULL; unsigned char *rc = NULL; unsigned int *bin_r, *bin_g, *bin_b, *bin_lum; int savedlines, saveline; float rgb[3], ycc[3], luma; int ycc_mode = -1; const short is_float = (ibuf->rect_float != NULL); if (ibuf->rect == NULL && ibuf->rect_float == NULL) return; if (scopes->ok == 1) return; if (scopes->hist.ymax == 0.f) scopes->hist.ymax = 1.f; /* hmmmm */ if (!(ELEM(ibuf->channels, 3, 4))) return; scopes->hist.channels = 3; scopes->hist.x_resolution = 256; switch (scopes->wavefrm_mode) { case SCOPES_WAVEFRM_RGB: ycc_mode = -1; break; case SCOPES_WAVEFRM_LUMA: case SCOPES_WAVEFRM_YCC_JPEG: ycc_mode = BLI_YCC_JFIF_0_255; break; case SCOPES_WAVEFRM_YCC_601: ycc_mode = BLI_YCC_ITU_BT601; break; case SCOPES_WAVEFRM_YCC_709: ycc_mode = BLI_YCC_ITU_BT709; break; } /* temp table to count pix value for histo */ bin_r = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_g = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_b = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); bin_lum = MEM_callocN(256 * sizeof(unsigned int), "temp historgram bins"); /* convert to number of lines with logarithmic scale */ scopes->sample_lines = (scopes->accuracy * 0.01f) * (scopes->accuracy * 0.01f) * ibuf->y; if (scopes->sample_full) scopes->sample_lines = ibuf->y; /* scan the image */ savedlines = 0; for (c = 0; c < 3; c++) { scopes->minmax[c][0] = 25500.0f; scopes->minmax[c][1] = -25500.0f; } scopes->waveform_tot = ibuf->x * scopes->sample_lines; if (scopes->waveform_1) MEM_freeN(scopes->waveform_1); if (scopes->waveform_2) MEM_freeN(scopes->waveform_2); if (scopes->waveform_3) MEM_freeN(scopes->waveform_3); if (scopes->vecscope) MEM_freeN(scopes->vecscope); scopes->waveform_1 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 1"); scopes->waveform_2 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 2"); scopes->waveform_3 = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "waveform point channel 3"); scopes->vecscope = MEM_callocN(scopes->waveform_tot * 2 * sizeof(float), "vectorscope point channel"); if (is_float) rf = ibuf->rect_float; else rc = (unsigned char *)ibuf->rect; for (y = 0; y < ibuf->y; y++) { if (savedlines < scopes->sample_lines && y >= ((savedlines) * ibuf->y) / (scopes->sample_lines + 1)) { saveline = 1; } else { saveline = 0; } for (x = 0; x < ibuf->x; x++) { if (is_float) { if (use_color_management) linearrgb_to_srgb_v3_v3(rgb, rf); else copy_v3_v3(rgb, rf); } else { for (c = 0; c < 3; c++) rgb[c] = rc[c] * INV_255; } /* we still need luma for histogram */ luma = rgb_to_luma(rgb); /* check for min max */ if (ycc_mode == -1) { for (c = 0; c < 3; c++) { if (rgb[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = rgb[c]; if (rgb[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = rgb[c]; } } else { rgb_to_ycc(rgb[0], rgb[1], rgb[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode); for (c = 0; c < 3; c++) { ycc[c] *= INV_255; if (ycc[c] < scopes->minmax[c][0]) scopes->minmax[c][0] = ycc[c]; if (ycc[c] > scopes->minmax[c][1]) scopes->minmax[c][1] = ycc[c]; } } /* increment count for histo*/ bin_r[get_bin_float(rgb[0])] += 1; bin_g[get_bin_float(rgb[1])] += 1; bin_b[get_bin_float(rgb[2])] += 1; bin_lum[get_bin_float(luma)] += 1; /* save sample if needed */ if (saveline) { const float fx = (float)x / (float)ibuf->x; const int idx = 2 * (ibuf->x * savedlines + x); save_sample_line(scopes, idx, fx, rgb, ycc); } rf += ibuf->channels; rc += ibuf->channels; } if (saveline) savedlines += 1; } /* convert hist data to float (proportional to max count) */ n = 0; nl = 0; for (x = 0; x < 256; x++) { if (bin_r[x] > n) n = bin_r[x]; if (bin_g[x] > n) n = bin_g[x]; if (bin_b[x] > n) n = bin_b[x]; if (bin_lum[x] > nl) nl = bin_lum[x]; } div = 1.0 / (double)n; divl = 1.0 / (double)nl; for (x = 0; x < 256; x++) { scopes->hist.data_r[x] = bin_r[x] * div; scopes->hist.data_g[x] = bin_g[x] * div; scopes->hist.data_b[x] = bin_b[x] * div; scopes->hist.data_luma[x] = bin_lum[x] * divl; } MEM_freeN(bin_r); MEM_freeN(bin_g); MEM_freeN(bin_b); MEM_freeN(bin_lum); scopes->ok = 1; }
static void scopes_update_cb(void *userdata, void *userdata_chunk, const int y, const int UNUSED(threadid)) { const ScopesUpdateData *data = userdata; Scopes *scopes = data->scopes; const ImBuf *ibuf = data->ibuf; struct ColormanageProcessor *cm_processor = data->cm_processor; const unsigned char *display_buffer = data->display_buffer; const int ycc_mode = data->ycc_mode; ScopesUpdateDataChunk *data_chunk = userdata_chunk; unsigned int *bin_lum = data_chunk->bin_lum; unsigned int *bin_r = data_chunk->bin_r; unsigned int *bin_g = data_chunk->bin_g; unsigned int *bin_b = data_chunk->bin_b; unsigned int *bin_a = data_chunk->bin_a; float *min = data_chunk->min; float *max = data_chunk->max; const float *rf = NULL; const unsigned char *rc = NULL; const int rows_per_sample_line = ibuf->y / scopes->sample_lines; const int savedlines = y / rows_per_sample_line; const bool do_sample_line = (savedlines < scopes->sample_lines) && (y % rows_per_sample_line) == 0; const bool is_float = (ibuf->rect_float != NULL); if (is_float) rf = ibuf->rect_float + ((size_t)y) * ibuf->x * ibuf->channels; else { rc = display_buffer + ((size_t)y) * ibuf->x * ibuf->channels; } for (int x = 0; x < ibuf->x; x++) { float rgba[4], ycc[3], luma; if (is_float) { switch (ibuf->channels) { case 4: copy_v4_v4(rgba, rf); IMB_colormanagement_processor_apply_v4(cm_processor, rgba); break; case 3: copy_v3_v3(rgba, rf); IMB_colormanagement_processor_apply_v3(cm_processor, rgba); rgba[3] = 1.0f; break; case 2: copy_v3_fl(rgba, rf[0]); rgba[3] = rf[1]; break; case 1: copy_v3_fl(rgba, rf[0]); rgba[3] = 1.0f; break; default: BLI_assert(0); } } else { for (int c = 4; c--;) rgba[c] = rc[c] * INV_255; } /* we still need luma for histogram */ luma = IMB_colormanagement_get_luminance(rgba); /* check for min max */ if (ycc_mode == -1) { minmax_v3v3_v3(min, max, rgba); } else { rgb_to_ycc(rgba[0], rgba[1], rgba[2], &ycc[0], &ycc[1], &ycc[2], ycc_mode); mul_v3_fl(ycc, INV_255); minmax_v3v3_v3(min, max, ycc); } /* increment count for histo*/ bin_lum[get_bin_float(luma)]++; bin_r[get_bin_float(rgba[0])]++; bin_g[get_bin_float(rgba[1])]++; bin_b[get_bin_float(rgba[2])]++; bin_a[get_bin_float(rgba[3])]++; /* save sample if needed */ if (do_sample_line) { const float fx = (float)x / (float)ibuf->x; const int idx = 2 * (ibuf->x * savedlines + x); save_sample_line(scopes, idx, fx, rgba, ycc); } rf += ibuf->channels; rc += ibuf->channels; } }