433 ASSERT_HOST(pix !=
nullptr && pixGetDepth(pix) == 32);
436 int width = pixGetWidth(pix);
437 int height = pixGetHeight(pix);
438 int left_pad = std::max(rect.left() - 2 * factor, 0) / factor;
439 int top_pad = (rect.top() + 2 * factor + (factor - 1)) / factor;
440 top_pad = std::min(height, top_pad);
441 int right_pad = (rect.right() + 2 * factor + (factor - 1)) / factor;
442 right_pad = std::min(width, right_pad);
443 int bottom_pad = std::max(rect.bottom() - 2 * factor, 0) / factor;
444 int width_pad = right_pad - left_pad;
445 int height_pad = top_pad - bottom_pad;
446 if (width_pad < 1 || height_pad < 1 || width_pad + height_pad < 4) {
450 Box *scaled_box = boxCreate(left_pad, height - top_pad, width_pad, height_pad);
451 Image scaled = pixClipRectangle(pix, scaled_box,
nullptr);
454 STATS red_stats(0, 256);
455 STATS green_stats(0, 256);
456 STATS blue_stats(0, 256);
457 uint32_t *data = pixGetData(scaled);
459 for (
int y = 0; y < height_pad; ++y) {
460 for (
int x = 0; x < width_pad; ++x, ++data) {
461 int r = GET_DATA_BYTE(data, COLOR_RED);
462 int g = GET_DATA_BYTE(data, COLOR_GREEN);
463 int b = GET_DATA_BYTE(data, COLOR_BLUE);
465 green_stats.add(g, 1);
466 blue_stats.add(b, 1);
473 int best_l8 =
static_cast<int>(red_stats.ile(0.125f));
474 int best_u8 =
static_cast<int>(ceil(red_stats.ile(0.875f)));
475 int best_i8r = best_u8 - best_l8;
476 int x_color = COLOR_RED;
477 int y1_color = COLOR_GREEN;
478 int y2_color = COLOR_BLUE;
479 int l8 =
static_cast<int>(green_stats.ile(0.125f));
480 int u8 =
static_cast<int>(ceil(green_stats.ile(0.875f)));
481 if (u8 - l8 > best_i8r) {
485 x_color = COLOR_GREEN;
486 y1_color = COLOR_RED;
488 l8 =
static_cast<int>(blue_stats.ile(0.125f));
489 u8 =
static_cast<int>(ceil(blue_stats.ile(0.875f)));
490 if (u8 - l8 > best_i8r) {
494 x_color = COLOR_BLUE;
495 y1_color = COLOR_GREEN;
496 y2_color = COLOR_RED;
501 uint32_t *data = pixGetData(scaled);
502 for (
int im_y = 0; im_y < height_pad; ++im_y) {
503 for (
int im_x = 0; im_x < width_pad; ++im_x, ++data) {
504 int x = GET_DATA_BYTE(data, x_color);
505 int y1 = GET_DATA_BYTE(data, y1_color);
506 int y2 = GET_DATA_BYTE(data, y2_color);
511 double m1 = line1.m();
512 double c1 = line1.c(m1);
513 double m2 = line2.m();
514 double c2 = line2.c(m2);
515 double rms = line1.rms(m1, c1) + line2.rms(m2, c2);
519 color1[y1_color] =
ClipToByte(m1 * best_l8 + c1 + 0.5);
520 color1[y2_color] =
ClipToByte(m2 * best_l8 + c2 + 0.5);
523 color2[y1_color] =
ClipToByte(m1 * best_u8 + c1 + 0.5);
524 color2[y2_color] =
ClipToByte(m2 * best_u8 + c2 + 0.5);
528 color1[COLOR_RED] =
ClipToByte(red_stats.median());
529 color1[COLOR_GREEN] =
ClipToByte(green_stats.median());
530 color1[COLOR_BLUE] =
ClipToByte(blue_stats.median());
531 color1[L_ALPHA_CHANNEL] = 0;
532 memcpy(color2, color1, 4);
534 if (color_map1 !=
nullptr) {
535 pixSetInRectArbitrary(color_map1, scaled_box,
536 ComposeRGB(color1[COLOR_RED], color1[COLOR_GREEN], color1[COLOR_BLUE]));
537 pixSetInRectArbitrary(color_map2, scaled_box,
538 ComposeRGB(color2[COLOR_RED], color2[COLOR_GREEN], color2[COLOR_BLUE]));
539 pixSetInRectArbitrary(rms_map, scaled_box, color1[L_ALPHA_CHANNEL]);
542 boxDestroy(&scaled_box);
const double kRMSFitScaling
const int kMinColorDifference
static uint32_t ComposeRGB(uint32_t r, uint32_t g, uint32_t b)
static uint8_t ClipToByte(double pixel)