10#ifndef MVE_IMAGE_TOOLS_HEADER
11#define MVE_IMAGE_TOOLS_HEADER
50 float vmin = 0.0f,
float vmax = 1.0f);
58 double vmin = 0.0,
double vmax = 1.0);
73 uint16_t vmin = 0, uint16_t vmax = 65535);
86template <
typename SRC,
typename DST>
87typename Image<DST>::Ptr
116typename Image<T>::Ptr
127typename Image<T>::Ptr
129 double focal_length,
double k2,
double k4);
138typename Image<T>::Ptr
140 double focal_length,
double k1);
152typename Image<T>::Ptr
153crop (
typename Image<T>::ConstPtr image, int64_t width, int64_t height,
154 int64_t left, int64_t top, T
const* fill_color);
174 int64_t width, int64_t height);
194 float sigma = 0.866025403784439f);
451template <
typename T_IN,
typename T_OUT>
464 int64_t x1, int64_t y1, int64_t x2, int64_t y2, int64_t cc = 0);
473 int64_t thumb_width, int64_t thumb_height);
486template <
typename SRC,
typename DST>
495 std::copy_n(src_buf, size, dst_buf);
505 *vmin = std::numeric_limits<T>::max();
506 *vmax = std::numeric_limits<T>::is_signed
507 ? -std::numeric_limits<T>::max()
508 : std::numeric_limits<T>::min();
510 for (T
const* ptr = image->
begin(); ptr != image->
end(); ++ptr)
524 int64_t width, int64_t height)
526 if (width == 0 && height == 0)
527 throw std::invalid_argument(
"Invalid size request");
530 if (width == img->
width() && height == img->
height())
536 else if (height == 0)
542 while (2 * width <= img->width() && 2 * height <= img->height())
543 img = rescale_half_size<T>(img);
552 rescale_nearest<T>(img, out);
555 rescale_linear<T>(img, out);
559 rescale_cubic(img, out);
563 rescale_gaussian<T>(img, out);
567 throw std::invalid_argument(
"Invalid interpolation type");
579 int64_t
const iw = img->
width();
580 int64_t
const ih = img->
height();
582 int64_t
const ow = (iw + 1) >> 1;
583 int64_t
const oh = (ih + 1) >> 1;
585 if (iw < 2 || ih < 2)
586 throw std::invalid_argument(
"Input image too small for half-sizing");
592 int64_t rowstride = iw * ic;
593 for (int64_t y = 0; y < oh; ++y)
595 int64_t irow1 = y * 2 * rowstride;
596 int64_t irow2 = irow1 + rowstride * (y * 2 + 1 < ih);
598 for (int64_t x = 0; x < ow; ++x)
600 int64_t ipix1 = irow1 + x * 2 * ic;
601 int64_t ipix2 = irow2 + x * 2 * ic;
602 int64_t hasnext = (x * 2 + 1 < iw);
604 for (int64_t c = 0; c < ic; ++c)
605 out->
at(outpos++) = math::interpolate<T>(
606 img->
at(ipix1 + c), img->
at(ipix1 + ic * hasnext + c),
607 img->
at(ipix2 + c), img->
at(ipix2 + ic * hasnext + c),
608 0.25f, 0.25f, 0.25f, 0.25f);
621 int64_t
const iw = img->
width();
622 int64_t
const ih = img->
height();
624 int64_t
const ow = (iw + 1) >> 1;
625 int64_t
const oh = (ih + 1) >> 1;
627 if (iw < 2 || ih < 2)
628 throw std::invalid_argument(
"Invalid input image");
638 float const w1 = std::exp(-0.5f / (2.0f *
MATH_POW2(sigma)));
639 float const w2 = std::exp(-2.5f / (2.0f *
MATH_POW2(sigma)));
640 float const w3 = std::exp(-4.5f / (2.0f *
MATH_POW2(sigma)));
643 int64_t
const rowstride = iw * ic;
644 for (int64_t y = 0; y < oh; ++y)
647 int64_t
const y2 = y * 2;
649 row[0] = &img->
at(std::max<int64_t>(0, y2 - 1) * rowstride);
650 row[1] = &img->
at(y2 * rowstride);
651 row[2] = &img->
at(std::min(ih - 1, y2 + 1) * rowstride);
652 row[3] = &img->
at(std::min(ih - 1, y2 + 2) * rowstride);
654 for (int64_t x = 0; x < ow; ++x)
659 xi[0] = std::max<int64_t>(0, x2 - 1) * ic;
661 xi[2] = std::min(iw - 1, x2 + 1) * ic;
662 xi[3] = std::min(iw - 1, x2 + 2) * ic;
665 for (int64_t c = 0; c < ic; ++c)
668 accum.
add(row[0][xi[0] + c], w3);
669 accum.
add(row[0][xi[1] + c], w2);
670 accum.
add(row[0][xi[2] + c], w2);
671 accum.
add(row[0][xi[3] + c], w3);
673 accum.
add(row[1][xi[0] + c], w2);
674 accum.
add(row[1][xi[1] + c], w1);
675 accum.
add(row[1][xi[2] + c], w1);
676 accum.
add(row[1][xi[3] + c], w2);
678 accum.
add(row[2][xi[0] + c], w2);
679 accum.
add(row[2][xi[1] + c], w1);
680 accum.
add(row[2][xi[2] + c], w1);
681 accum.
add(row[2][xi[3] + c], w2);
683 accum.
add(row[3][xi[0] + c], w3);
684 accum.
add(row[3][xi[1] + c], w2);
685 accum.
add(row[3][xi[2] + c], w2);
686 accum.
add(row[3][xi[3] + c], w3);
702 int64_t
const iw = img->
width();
703 int64_t
const ih = img->
height();
705 int64_t
const ow = (iw + 1) >> 1;
706 int64_t
const oh = (ih + 1) >> 1;
707 int64_t
const irs = iw * ic;
713 for (int64_t iy = 0; iy < ih; iy += 2)
715 int64_t rowoff = iy * irs;
716 int64_t pixoff = rowoff;
717 for (int64_t ix = 0; ix < iw; ix += 2)
719 T
const* iptr = &img->
at(pixoff);
720 T* optr = &out->
at(iter);
721 std::copy(iptr, iptr + ic, optr);
736 int64_t
const iw = img->
width();
737 int64_t
const ih = img->
height();
739 int64_t
const ow = iw << 1;
740 int64_t
const oh = ih << 1;
741 int64_t
const irs = iw * ic;
746 float w[4] = { 0.75f*0.75f, 0.25f*0.75f, 0.75f*0.25f, 0.25f*0.25f };
748 T
const* row1 = img->
begin();
749 T
const* row2 = img->
begin();
752 for (int64_t y = 0; y < oh; ++y)
756 row2 = row1 + (y < oh - 1 ? irs : 0);
760 T
const* px[4] = { row1, row1, row2, row2 };
761 for (int64_t x = 0; x < ow; ++x)
766 int64_t off = (x < ow - 1 ? ic : 0);
776 for (int64_t c = 0; c < ic; ++c, ++i)
778 (px[0][c], px[1][c], px[2][c], px[3][c],
779 w[0], w[1], w[2], w[3]);
792 int64_t
const iw = img->
width();
793 int64_t
const ih = img->
height();
795 int64_t
const ow = iw << 1;
796 int64_t
const oh = ih << 1;
802 for (int64_t y = 0; y < oh; ++y)
804 bool nexty = (y + 1 < oh);
805 int64_t yoff[2] = { iw * (y >> 1), iw * ((y + nexty) >> 1) };
806 for (int64_t x = 0; x < ow; ++x)
808 bool nextx = (x + 1 < ow);
809 int64_t xoff[2] = { x >> 1, (x + nextx) >> 1 };
812 &img->
at(yoff[0] + xoff[0], 0),
813 &img->
at(yoff[0] + xoff[1], 0),
814 &img->
at(yoff[1] + xoff[0], 0),
815 &img->
at(yoff[1] + xoff[1], 0)
818 for (int64_t c = 0; c < ic; ++c, ++witer)
820 (val[0][c], val[1][c], val[2][c], val[3][c],
821 0.25f, 0.25f, 0.25f, 0.25f);
835 throw std::invalid_argument(
"Image channel mismatch");
837 int64_t
const iw = img->
width();
838 int64_t
const ih = img->
height();
840 int64_t
const ow = out->
width();
841 int64_t
const oh = out->
height();
844 for (int64_t y = 0; y < oh; ++y)
846 float ly = ((float)y + 0.5f) * (float)ih / (
float)oh;
847 int64_t iy =
static_cast<int64_t
>(ly);
848 for (int64_t x = 0; x < ow; ++x)
850 float lx = ((float)x + 0.5f) * (float)iw / (
float)ow;
851 int64_t ix =
static_cast<int64_t
>(lx);
852 for (int64_t c = 0; c < ic; ++c)
853 out->
at(outpos++) = img->
at(ix,iy,c);
865 throw std::invalid_argument(
"Image channel mismatch");
867 int64_t
const iw = img->
width();
868 int64_t
const ih = img->
height();
870 int64_t
const ow = out->
width();
871 int64_t
const oh = out->
height();
875 for (int64_t y = 0; y < oh; ++y)
877 float fy = ((float)y + 0.5f) * (float)ih / (
float)oh;
878 for (int64_t x = 0; x < ow; ++x, outpos += ic)
880 float fx = ((float)x + 0.5f) * (float)iw / (
float)ow;
881 img->
linear_at(fx - 0.5f, fy - 0.5f, out_ptr + outpos);
891 float x,
float y, int64_t c,
float sigma)
893 int64_t
const width = img->
width();
894 int64_t
const height = img->
height();
908 float ks = sigma * 2.884f;
911 float kx_min = std::floor(x - ks);
912 float kx_max = std::ceil(x + ks - 1.0f);
913 float ky_min = std::floor(y - ks);
914 float ky_max = std::ceil(y + ks - 1.0f);
916 int64_t kxi_min =
static_cast<int64_t
>(std::max(0.0f, kx_min));
918 static_cast<int64_t
>(std::min((
float)width - 1.0f, kx_max));
919 int64_t kyi_min =
static_cast<int64_t
>(std::max(0.0f, ky_min));
921 static_cast<int64_t
>(std::min((
float)height - 1.0f, ky_max));
924 float wx_start = kx_min > 0.0f ? kx_min + 1.0f + ks - x : 1.0f;
925 float wx_end = kx_max < (float)width - 1.0f ? ks + x - kx_max : 1.0f;
926 float wy_start = ky_min > 0.0f ? ky_min + 1.0f + ks - y : 1.0f;
927 float wy_end = ky_max < (float)height - 1.0f ? ks + y - ky_max : 1.0f;
931 for (int64_t yi = kyi_min; yi <= kyi_max; ++yi)
932 for (int64_t xi = kxi_min; xi <= kxi_max; ++xi)
935 weight *= (xi == kxi_min ? wx_start : 1.0f);
936 weight *= (xi == kxi_max ? wx_end : 1.0f);
937 weight *= (yi == kyi_min ? wy_start : 1.0f);
938 weight *= (yi == kyi_max ? wy_end : 1.0f);
939 float dx =
static_cast<float>(xi) + 0.5f - x;
940 float dy =
static_cast<float>(yi) + 0.5f - y;
943 accum.
add(img->
at(xi, yi, c), weight);
957 throw std::invalid_argument(
"Image channels mismatch");
959 int64_t
const ow = out->
width();
960 int64_t
const oh = out->
height();
964 float const scale_x = (float)img->
width() / (float)ow;
965 float const scale_y = (float)img->
height() / (float)oh;
966 float const sigma = sigma_factor * std::max(scale_x, scale_y) / 2.0f;
970 for (int64_t y = 0; y < oh; ++y)
971 for (int64_t x = 0; x < ow; ++x, ++i)
973 float xf = ((float)x + 0.5f) * scale_x;
974 float yf = ((float)y + 0.5f) * scale_y;
975 for (int64_t c = 0; c < oc; ++c)
976 out->
at(i, c) = gaussian_kernel<T>(img, xf, yf, c, sigma);
985 int64_t left, int64_t top, T
const* fill_color)
987 if (width < 0 || height < 0 || !image.get())
988 throw std::invalid_argument(
"Invalid width/height or null image given");
993 int64_t
const iw = image->
width();
994 int64_t
const ih = image->
height();
995 int64_t
const ic = image->
channels();
998 if (left < 0 || top < 0 || left + width > iw || top + height > ih)
1002 if (left >= iw || left <= -width || top >= ih || top <= -height)
1006 int64_t
const overlap =
1007 ic * (std::min(iw, left + width) - std::max<int64_t>(0, left));
1008 for (int64_t y = std::max<int64_t>(0, -top);
1009 y < std::min(height, ih - top); ++y)
1011 int64_t lookup_y = top + y;
1014 T* out_ptr = &out->
at(left < 0 ? -left : 0, y, 0);
1015 T
const* in_ptr = &image->
at(left > 0 ? left : 0, lookup_y, 0);
1016 std::copy(in_ptr, in_ptr + overlap, out_ptr);
1024template <
typename T>
1029 throw std::invalid_argument(
"Null image given");
1035 int64_t
const w = in->
width();
1036 int64_t
const h = in->
height();
1038 int64_t
const ks = std::ceil(sigma * 2.884f);
1039 std::vector<float> kernel(ks + 1);
1042 for (int64_t i = 0; i < ks + 1; ++i)
1050 for (int64_t y = 0; y < h; ++y)
1051 for (int64_t x = 0; x < w; ++x, ++px)
1052 for (int64_t cc = 0; cc < c; ++cc)
1055 for (int64_t i = -ks; i <= ks; ++i)
1057 int64_t idx = math::clamp<int64_t>(x + i, 0, w - 1);
1058 accum.
add(in->
at(y * w + idx, cc), kernel[std::abs(i)]);
1066 for (int64_t y = 0; y < h; ++y)
1067 for (int64_t x = 0; x < w; ++x, ++px)
1068 for (int64_t cc = 0; cc < c; ++cc)
1071 for (int64_t i = -ks; i <= ks; ++i)
1073 int64_t idx = math::clamp<int64_t>(y + i, 0, h - 1);
1074 accum.
add(sep->
at(idx * w + x, cc), kernel[std::abs(i)]);
1083 for (int64_t y = 0; y < h; ++y)
1084 for (int64_t x = 0; x < w; ++x, ++px)
1085 for (int64_t cc = 0; cc < c; ++cc)
1089 for (int64_t ky = -ks; ky <= ks; ++ky)
1090 for (int64_t kx = -ks; kx <= ks; ++kx)
1094 accum.
add(in->
at(idx_y * w + idx_x, cc),
1095 kernel[std::abs(kx)] * kernel[std::abs(ky)]);
1108template <
typename T>
1113 throw std::invalid_argument(
"Null image given");
1115 int64_t w(in->
width());
1124 T
const* row = &in->
at(0);
1125 T* outrow = &sep->
at(0);
1126 for (int64_t y = 0; y < h; ++y, row += w * c, outrow += w * c)
1128 for (int64_t cc = 0; cc < c; ++cc)
1131 for (
int i = 0; i < ks; ++i)
1132 for (int64_t cc = 0; cc < c; ++cc)
1133 accums[cc].add(row[i * c + cc], 1.0f);
1135 for (int64_t x = 0; x < w; ++x)
1138 for (int64_t cc = 0; cc < c; ++cc)
1139 accums[cc].add(row[(x + ks) * c + cc], 1.0f);
1141 for (int64_t cc = 0; cc < c; ++cc)
1142 accums[cc].sub(row[(x - ks - 1) * c + cc], 1.0f);
1143 for (int64_t cc = 0; cc < c; ++cc)
1144 outrow[x * c + cc] = accums[cc].normalized();
1150 T
const* col = &sep->
at(0);
1151 T* outcol = &out->
at(0);
1152 for (int64_t x = 0; x < w; ++x, col += c, outcol += c)
1154 for (int64_t cc = 0; cc < c; ++cc)
1157 for (
int i = 0; i < ks; ++i)
1158 for (int64_t cc = 0; cc < c; ++cc)
1159 accums[cc].add(col[i * wc + cc], 1.0f);
1161 for (int64_t y = 0; y < h; ++y)
1164 for (int64_t cc = 0; cc < c; ++cc)
1165 accums[cc].add(col[(y + ks) * wc + cc], 1.0f);
1167 for (int64_t cc = 0; cc < c; ++cc)
1168 accums[cc].sub(col[(y - ks - 1) * wc + cc], 1.0f);
1169 for (int64_t cc = 0; cc < c; ++cc)
1170 outcol[y * wc + cc] = accums[cc].normalized();
1180 for (int64_t y = 0; y < h; ++y)
1181 for (int64_t x = 0; x < w; ++x)
1182 for (int64_t cc = 0; cc < c; ++cc)
1185 for (
int ky = -ks; ky <= ks; ++ky)
1186 for (
int kx = -ks; kx <= ks; ++kx)
1190 accum.
add(in->
at(idx_x, idx_y, cc), 1.0f);
1201template <
typename T>
1205 if (image ==
nullptr)
1206 throw std::invalid_argument(
"Null image given");
1208 int64_t
const iw = image->
width();
1209 int64_t
const ih = image->
height();
1210 int64_t
const ic = image->
channels();
1211 int64_t
const ow = type ==
ROTATE_180 ? iw : ih;
1212 int64_t
const oh = type ==
ROTATE_180 ? ih : iw;
1218 for (int64_t y = 0; y < ih; ++y)
1219 for (int64_t x = 0; x < iw; ++x, idx += ic)
1225 case ROTATE_180: dx = iw - x - 1; dy = ih - y - 1;
break;
1226 case ROTATE_CW: dx = ih - y - 1; dy = x;
break;
1227 case ROTATE_CCW: dx = y; dy = iw - x - 1;
break;
1232 T
const* in_pixel = &image->
at(idx);
1233 T* out_pixel = &ret->
at(dx, dy, 0);
1234 std::copy(in_pixel, in_pixel + ic, out_pixel);
1242template <
typename T>
1246 if (image ==
nullptr)
1247 throw std::invalid_argument(
"Null image given");
1249 int64_t
const w = image->
width();
1250 int64_t
const h = image->
height();
1251 int64_t
const c = image->
channels();
1252 float const w2 =
static_cast<float>(w - 1) / 2.0f;
1253 float const h2 =
static_cast<float>(h - 1) / 2.0f;
1256 float const sin_angle = std::sin(-angle);
1257 float const cos_angle = std::cos(-angle);
1258 T* ret_ptr = ret->
begin();
1259 for (int64_t y = 0; y < h; ++y)
1260 for (int64_t x = 0; x < w; ++x, ret_ptr += c)
1262 float const sample_x =
1263 cos_angle * (x - w2) - sin_angle * (y - h2) + w2;
1264 float const sample_y =
1265 sin_angle * (x - w2) + cos_angle * (y - h2) + h2;
1266 if (sample_x < -0.5f || sample_x > w - 0.5f
1267 || sample_y < -0.5f || sample_y > h - 0.5f)
1268 std::copy(fill_color, fill_color + c, ret_ptr);
1270 image->
linear_at(sample_x, sample_y, ret_ptr);
1277template <
typename T>
1283 if (image ==
nullptr)
1284 throw std::invalid_argument(
"Null image given");
1288 int64_t
const iw = image->
width();
1289 int64_t
const ih = image->
height();
1290 int64_t
const ic = image->
channels();
1291 int64_t
const max_x = fh ? iw / 2 : iw;
1292 int64_t
const max_y = fv && !fh ? ih / 2 : ih;
1294 for (int64_t y = 0; y < max_y; ++y)
1295 for (int64_t x = 0; x < max_x; ++x)
1299 T* src = &image->
at(x, y, 0);
1300 T* dst = &image->
at(dx, dy, 0);
1301 std::swap_ranges(src, src + ic, dst);
1307template <
typename T>
1311 return *std::max_element(v, v + 3);
1314template <
typename T>
1318 T
const* max = std::max_element(v, v + 3);
1319 T
const* min = std::min_element(v, v + 3);
1323template <
typename T>
1330template <
typename T>
1337template <
typename T>
1341 float third(1.0f / 3.0f);
1347template <
typename T>
1352 throw std::invalid_argument(
"Null image given");
1355 if (ic != 3 && ic != 4)
1356 throw std::invalid_argument(
"Image must be RGB or RGBA");
1358 bool has_alpha = (ic == 4);
1363 typedef T(*DesaturateFunc)(T
const*);
1364 DesaturateFunc func;
1372 default:
throw std::invalid_argument(
"Invalid desaturate type");
1378 for (int64_t i = 0; i < pixels; ++i)
1380 T
const* v = &img->
at(inpos);
1381 out->
at(outpos) = func(v);
1384 out->
at(outpos + 1) = img->
at(inpos + 3);
1386 outpos += 1 + has_alpha;
1387 inpos += 3 + has_alpha;
1395template <
typename T>
1399 if (image ==
nullptr)
1400 throw std::invalid_argument(
"Null image given");
1402 int64_t
const ic = image->
channels();
1403 if (ic != 1 && ic != 2)
1404 throw std::invalid_argument(
"Image must be in G or GA");
1406 bool const has_alpha = (ic == 2);
1412 for (int64_t i = 0; i < pixels; ++i)
1414 out->
at(i, 0) = image->
at(i, 0);
1415 out->
at(i, 1) = image->
at(i, 0);
1416 out->
at(i, 2) = image->
at(i, 0);
1418 out->
at(i, 3) = image->
at(i, 1);
1426template <
typename T>
1430 int64_t
const channels = img->
channels();
1431 if (channels != 2 && channels != 4)
1432 throw std::invalid_argument(
"Image must be in GA or RGBA");
1438template <
typename T>
1442 int64_t
const width = img->
width();
1443 int64_t
const height = img->
height();
1444 int64_t
const chans = img->
channels();
1445 int64_t
const row_stride = width * chans;
1447 double const max_value =
static_cast<double>(std::numeric_limits<T>::max());
1449 (width, height, chans);
1453 for (int64_t y = 0; y < height; ++y)
1454 for (int64_t x = 0; x < width; ++x, pos += chans)
1456 if (y == 0 || y == height - 1 || x == 0 || x == width - 1)
1458 std::fill(out_ptr + pos, out_ptr + pos + chans, T(0));
1462 for (int64_t cc = 0; cc < chans; ++cc)
1464 int64_t
const i = pos + cc;
1465 double gx = 1.0 * (double)img->
at(i + chans - row_stride)
1466 - 1.0 * (double)img->
at(i - chans - row_stride)
1467 + 2.0 * (double)img->
at(i + chans)
1468 - 2.0 * (double)img->
at(i - chans)
1469 + 1.0 * (double)img->
at(i + chans + row_stride)
1470 - 1.0 * (double)img->
at(i - chans + row_stride);
1471 double gy = 1.0 * (double)img->
at(i + row_stride - chans)
1472 - 1.0 * (double)img->
at(i - row_stride - chans)
1473 + 2.0 * (double)img->
at(i + row_stride)
1474 - 2.0 * (double)img->
at(i - row_stride)
1475 + 1.0 * (double)img->
at(i + row_stride + chans)
1476 - 1.0 * (double)img->
at(i - row_stride + chans);
1477 double g = std::sqrt(gx * gx + gy * gy);
1478 out_ptr[i] =
static_cast<T
>(std::min(max_value, g));
1487template <
typename T>
1491 int64_t
const iw = i1->
width();
1492 int64_t
const ih = i1->
height();
1495 if (i1 ==
nullptr || i2 ==
nullptr)
1496 throw std::invalid_argument(
"Null image given");
1499 throw std::invalid_argument(
"Image dimensions do not match");
1506 out->
at(i) = i1->
at(i) - i2->
at(i);
1513template <
typename T>
1517 int64_t
const iw = i1->
width();
1518 int64_t
const ih = i1->
height();
1521 if (i1 ==
nullptr || i2 ==
nullptr)
1522 throw std::invalid_argument(
"Null image given");
1525 throw std::invalid_argument(
"Image dimensions do not match");
1532 if (i1->
at(i) < i2->
at(i))
1533 out->
at(i) = i2->
at(i) - i1->
at(i);
1535 out->
at(i) = i1->
at(i) - i2->
at(i);
1543template <
typename T>
1548 std::for_each(image->
begin(), image->
end(), f);
1553template <
typename T>
1557 static_assert(std::is_floating_point<T>::value,
1558 "Only implemented for floating point images");
1560 for (int64_t i = 0; i < num_values; i++)
1562 if (image->
at(i) <= T(0.0031308))
1563 image->
at(i) *= T(12.92);
1566 T corrected = std::pow(image->
at(i), T(1.0)/T(2.4));
1567 image->
at(i) = T(1.055) * corrected - T(0.055);
1574template <
typename T>
1578 static_assert(std::is_floating_point<T>::value,
1579 "Only implemented for floating point images");
1581 for (int64_t i = 0; i < num_values; i++)
1583 if (image->
at(i) <= T(0.04045))
1584 image->
at(i) /= T(12.92);
1587 T base = (image->
at(i) + T(0.055)) / T(1.055);
1588 image->
at(i) = std::pow(base, T(2.4));
1595template <
typename T_IN,
typename T_OUT>
1599 if (image ==
nullptr)
1600 throw std::invalid_argument(
"Null image given");
1602 int64_t
const width = image->
width();
1603 int64_t
const height = image->
height();
1604 int64_t
const chans = image->
channels();
1605 int64_t
const row_stride = width * chans;
1608 ret->
allocate(width, height, chans);
1611 std::vector<T_OUT> zeros(row_stride, T_OUT(0));
1614 T_OUT* prev = &zeros[0];
1619 for (int64_t y = 0; y < height; ++y)
1622 for (int64_t cc = 0; cc < chans; ++cc)
1623 dest[cc] =
static_cast<T_OUT
>(inrow[cc]) + prev[cc];
1625 for (int64_t i = chans; i < row_stride; ++i)
1626 dest[i] = inrow[i] + prev[i] + dest[i - chans] - prev[i - chans];
1630 inrow += row_stride;
1638template <
typename T>
1641 int64_t x1, int64_t y1, int64_t x2, int64_t y2, int64_t cc)
1644 int64_t
const channels = sat->
channels();
1645 T ret = sat->
at(y2 * row_stride + x2 * channels + cc);
1647 ret -= sat->
at(y2 * row_stride + (x1-1) * channels + cc);
1649 ret -= sat->
at((y1-1) * row_stride + x2 * channels + cc);
1650 if (x1 > 0 && y1 > 0)
1651 ret += sat->
at((y1-1) * row_stride + (x1-1) * channels + cc);
1657template <
typename T>
1660 int64_t thumb_width, int64_t thumb_height)
1662 int64_t
const width = image->
width();
1663 int64_t
const height = image->
height();
1664 float const image_aspect =
static_cast<float>(width) / height;
1665 float const thumb_aspect =
static_cast<float>(thumb_width) / thumb_height;
1667 int64_t rescale_width, rescale_height;
1668 int64_t crop_left, crop_top;
1669 if (image_aspect > thumb_aspect)
1671 rescale_width = std::ceil(thumb_height * image_aspect);
1672 rescale_height = thumb_height;
1673 crop_left = (rescale_width - thumb_width) / 2;
1678 rescale_width = thumb_width;
1679 rescale_height = std::ceil(thumb_width / image_aspect);
1681 crop_top = (rescale_height - thumb_height) / 2;
1686 thumb = mve::image::crop<T>(thumb, thumb_width, thumb_height,
1687 crop_left, crop_top,
nullptr);
1694template <
typename T>
1698 int64_t
const width = img->
width();
1699 int64_t
const height = img->
height();
1700 int64_t
const chans = img->
channels();
1701 int64_t
const D = std::max(width, height);
1703 double const width_half =
static_cast<double>(width) / 2.0;
1704 double const height_half =
static_cast<double>(height) / 2.0;
1710 for (int64_t y = 0; y < height; y++)
1711 for (int64_t x = 0; x < width; x++, out_ptr += chans)
1713 double fx =
static_cast<double>(x) - width_half;
1714 double fy =
static_cast<double>(y) - height_half;
1715 double const s1 = D * D + k1 * (fx * fx + fy * fy);
1716 double const s2 = D * D + k0 * (fx * fx + fy * fy);
1717 double const factor = s1 / s2;
1718 fx = fx * factor + width_half;
1719 fy = fy * factor + height_half;
1721 if (fx < -0.5 || fx > width - 0.5 || fy < -0.5 || fy > height - 0.5)
1731template <
typename T>
1734 double focal_length,
double k2,
double k4)
1737 throw std::invalid_argument(
"Null image given");
1739 if (k2 == 0.0 && k4 == 0.0)
1742 int64_t
const width = img->
width();
1743 int64_t
const height = img->
height();
1744 int64_t
const chans = img->
channels();
1749 double const fwidth2 =
static_cast<double>(width) / 2.0;
1750 double const fheight2 =
static_cast<double>(height) / 2.0;
1751 double const fnorm =
static_cast<double>(std::max(width, height));
1752 for (int64_t y = 0; y < height; ++y)
1753 for (int64_t x = 0; x < width; ++x, out_ptr += chans)
1755 double const fx = (
static_cast<double>(x) + 0.5 - fwidth2) / fnorm;
1756 double const fy = (
static_cast<double>(y) + 0.5 - fheight2) / fnorm;
1757 double const rd = (fx * fx + fy * fy) /
MATH_POW2(focal_length);
1758 double const rd_factor = 1.0 + k2 * rd + k4 * rd * rd;
1759 double const dist_x = fx * rd_factor;
1760 double const dist_y = fy * rd_factor;
1761 float const ix = dist_x * fnorm + fwidth2 - 0.5;
1762 float const iy = dist_y * fnorm + fheight2 - 0.5;
1763 if (ix < -0.5 || ix > width - 0.5 || iy < -0.5 || iy > height - 0.5)
1773template <
typename T>
1776 double focal_length,
double k1)
1779 throw std::invalid_argument(
"Null image given");
1784 int64_t
const width = img->
width();
1785 int64_t
const height = img->
height();
1786 int64_t
const chans = img->
channels();
1793 double const norm = focal_length * std::max(width, height);
1794 double const width_half =
static_cast<double>(width) / 2.0;
1795 double const height_half =
static_cast<double>(height) / 2.0;
1799 T* out_ptr = out->
begin();
1801 for (int64_t y = 0; y < height; ++y)
1803 for (int64_t x = 0; x < width; ++x, out_ptr += chans)
1805 double fx = (
static_cast<double>(x) - width_half) / norm;
1806 double fy = (
static_cast<double>(y) - height_half) / norm;
1810 double const t2 = fy * fy;
1811 double const t3 = t2 * t2 * t2;
1812 double const t4 = fx * fx;
1813 double const t7 = k1 * (t2 + t4);
1817 double const t8 = 1.0 / t7;
1818 double const t10 = t3 / (t7 * t7);
1819 double const t14 = std::sqrt(t10 * (0.25 + t8 / 27.0));
1820 double const t15 = t2 * t8 * fy * 0.5;
1821 double const t17 = std::pow(t14 + t15, 1.0/3.0);
1822 double const t18 = t17 - t2 * t8 / (t17 * 3.0);
1828 double const t9 = t3 / (t7 * t7 * 4.0);
1829 double const t11 = t3 / (t7 * t7 * t7 * 27.0);
1830 std::complex<double>
const t12 = t9 + t11;
1831 std::complex<double>
const t13 = std::sqrt(t12);
1832 double const t14 = t2 / t7;
1833 double const t15 = t14 * fy * 0.5;
1834 std::complex<double>
const t16 = t13 + t15;
1835 std::complex<double>
const t17 = std::pow(t16, 1.0/3.0);
1836 std::complex<double>
const t18 = (t17 + t14 / (t17 * 3.0))
1837 * std::complex<double>(0.0, std::sqrt(3.0));
1838 std::complex<double>
const t19 = -0.5 * (t17 + t18)
1839 + t14 / (t17 * 6.0);
1840 fx = t19.real() * fx / fy;
1844 fx = fx * norm + width_half;
1845 fy = fy * norm + height_half;
1847 if (fx < -0.5 || fx > width - 0.5 || fy < -0.5 || fy > height - 0.5)
Accumulator class that operates on arbitrary types.
void add(T const &value, float weight)
Adds the weighted given value to the internal value.
T normalized(float weight) const
Returns a normalized version of the internal value, i.e.
int64_t height(void) const
Returns the height of the image.
int64_t channels(void) const
Returns the amount of channels in the image.
int64_t width(void) const
Returns the width of the image.
Multi-channel image class of arbitrary but homogenous data type.
std::shared_ptr< Image< T > > Ptr
std::shared_ptr< Image< T > const > ConstPtr
T const & at(int64_t index) const
Linear indexing of image data.
T linear_at(float x, float y, int64_t channel) const
Linear interpolation (more expensive) for a single color channel.
Ptr duplicate(void) const
Duplicates the image.
static Ptr create(void)
Smart pointer image constructor.
void fill_color(T const *color)
Fills every pixel of the image with the given color.
void delete_channel(int64_t channel)
Deletes a channel from the image.
int64_t get_pixel_amount(void) const
Returns the amount of pixels in the image (w * h).
int64_t get_value_amount(void) const
Returns the amount of values in the image (w * h * c).
void fill(T const &value)
Fills the data with a constant value.
T * begin(void)
Returns data pointer to beginning.
T * end(void)
Returns data pointer to end.
T const * get_data_pointer(void) const
Returns the data pointer.
void allocate(int64_t width, int64_t height, int64_t chans)
Allocates new image space, clearing previous content.
#define MATH_EPSILON_EQ(x, v, eps)
#define MVE_IMAGE_NAMESPACE_END
#define MVE_NAMESPACE_BEGIN
#define MVE_IMAGE_NAMESPACE_BEGIN
#define MVE_NAMESPACE_END
T const & clamp(T const &v, T const &min=T(0), T const &max=T(1))
Returns value 'v' clamped to the interval specified by 'min' and 'max'.
T gaussian(T const &x, T const &sigma)
Gaussian function g(x) = exp( -1/2 * (x/sigma)^2 ).
T interpolate(T const &v1, float w1)
Generic interpolation (weighting) of a single value.
T gaussian_xx(T const &xx, T const &sigma)
Gaussian function that expects x to be squared.
Image< T >::Ptr rescale(typename Image< T >::ConstPtr image, RescaleInterpolation interp, int64_t width, int64_t height)
Returns a rescaled version of 'image' with dimensions 'width' times 'height' using 'interp' for value...
RotateType
Image rotation type.
@ ROTATE_SWAP
Exchanges x- and y-axis.
@ ROTATE_CW
Clock wise rotation.
@ ROTATE_180
180 degree rotation
@ ROTATE_CCW
Counter-clock wise rotation.
T desaturate_luminance(T const *v)
T desaturate_lightness(T const *v)
Image< T >::Ptr rescale_half_size(typename Image< T >::ConstPtr image)
Returns a rescaled version of image, scaled by factor 1/2, by grouping blocks of 2x2 pixel into one p...
FloatImage::Ptr byte_to_float_image(ByteImage::ConstPtr image)
Converts a given byte image to a float image.
void gamma_correct_inv_srgb(typename Image< T >::Ptr image)
Applies inverse gamma correction to float/double (in-place) images with nonlinear R'G'B' values in th...
ByteImage::Ptr int_to_byte_image(IntImage::ConstPtr image)
Convertes a given int image to a byte image.
Image< T >::Ptr difference(typename Image< T >::ConstPtr i1, typename Image< T >::ConstPtr i2)
Creates a difference image by computing the absolute difference per value.
void rescale_nearest(typename Image< T >::ConstPtr in, typename Image< T >::Ptr out)
Rescales image 'in' using nearest neighbor.
Image< T >::Ptr rescale_double_size(typename Image< T >::ConstPtr img)
Returns a rescaled version of the image, upscaled with linear interpolation by factor 2.
Image< T >::Ptr subtract(typename Image< T >::ConstPtr i1, typename Image< T >::ConstPtr i2)
Subtracts two images to create the signed difference between the values.
T desaturate_maximum(T const *v)
Image< T >::Ptr rescale_half_size_gaussian(typename Image< T >::ConstPtr image, float sigma=0.866025403784439f)
Returns a rescaled version of the image, scaled with a gaussian approximation by factor 1/2.
DoubleImage::Ptr byte_to_double_image(ByteImage::ConstPtr image)
Converts a given byte image to a double image.
ByteImage::Ptr float_to_byte_image(FloatImage::ConstPtr image, float vmin, float vmax)
Converts a given float image to a byte image.
Image< T >::Ptr blur_boxfilter(typename Image< T >::ConstPtr in, int ks)
Blurs the image using a box filter of integer size 'ks'.
Image< T >::Ptr desaturate(typename Image< T >::ConstPtr image, DesaturateType type)
Desaturates an RGB or RGBA image to G or GA respectively.
T desaturate_average(T const *v)
Image< T >::Ptr blur_gaussian(typename Image< T >::ConstPtr in, float sigma)
Blurs the image using a gaussian convolution kernel.
Image< DST >::Ptr type_to_type_image(typename Image< SRC >::ConstPtr image)
Generic conversion between image types without scaling or clamping.
void rescale_gaussian(typename Image< T >::ConstPtr in, typename Image< T >::Ptr out, float sigma_factor=1.0f)
Rescales image 'in' using a gaussian kernel mask.
Image< T >::Ptr image_undistort_k2k4(typename Image< T >::ConstPtr img, double focal_length, double k2, double k4)
Undistorts the input image given the focal length of the image and two undistortion parameters.
void rescale_linear(typename Image< T >::ConstPtr in, typename Image< T >::Ptr out)
Rescales image 'in' using linear interpolation.
mve::Image< T >::Ptr sobel_edge(typename mve::Image< T >::ConstPtr img)
Implementation of the Sobel operator.
RescaleInterpolation
Rescale interpolation type.
@ RESCALE_GAUSSIAN
Not suited for byte images.
FlipType
Image flipping type.
void float_image_normalize(FloatImage::Ptr image)
Normalizes a float image IN-PLACE such that all values are [0, 1].
Image< T >::Ptr image_undistort_msps(typename Image< T >::ConstPtr img, double k0, double k1)
Undistorts the input image given the two undistortion parameters.
ByteImage::Ptr double_to_byte_image(DoubleImage::ConstPtr image, double vmin, double vmax)
Converts a given double image to a byte image.
Image< T >::Ptr rescale_half_size_subsample(typename Image< T >::ConstPtr image)
Returns a rescaled version of the image by subsampling every second column and row.
void find_min_max_value(typename mve::Image< T >::ConstPtr image, T *vmin, T *vmax)
Finds the smallest and largest value in the given image.
void gamma_correct(ByteImage::Ptr image, float power)
Applies fast gamma correction to byte image using a lookup table.
DesaturateType
Desaturaturation type.
@ DESATURATE_LIGHTNESS
(max(R,G,B) + min(R,G,B)) * 1/2
@ DESATURATE_AVERAGE
(R + G + B) * 1/3
@ DESATURATE_LUMINANCE
0.30 * R + 0.59 * G + 0.11 * B
@ DESATURATE_LUMINOSITY
0.21 * R + 0.72 * G + 0.07 * B
@ DESATURATE_MAXIMUM
max(R,G,B)
Image< T >::Ptr crop(typename Image< T >::ConstPtr image, int64_t width, int64_t height, int64_t left, int64_t top, T const *fill_color)
Returns a sub-image by cropping against a rectangular region.
Image< T >::Ptr rescale_double_size_supersample(typename Image< T >::ConstPtr img)
Returns a rescaled version of the image, upscaled with linear interpolation.
Image< T >::Ptr create_thumbnail(typename Image< T >::ConstPtr image, int64_t thumb_width, int64_t thumb_height)
Creates a thumbnail of the given size by first rescaling the image and then cropping to fill the thum...
Image< T >::Ptr rotate(typename Image< T >::ConstPtr image, RotateType type)
Returns a rotated copy of the given image either rotated clock wise, counter-clock wise,...
void reduce_alpha(typename mve::Image< T >::Ptr img)
Reduce alpha: Reduces RGBA or GA images to RGB or G images.
void gamma_correct_srgb(typename Image< T >::Ptr image)
Applies gamma correction to float/double images (in-place) with linear RGB values in range [0,...
T desaturate_luminosity(T const *v)
void flip(typename Image< T >::Ptr image, FlipType type)
Flips the given image either horizontally, vertically or both IN-PLACE.
ByteImage::Ptr raw_to_byte_image(RawImage::ConstPtr image, uint16_t vmin, uint16_t vmax)
Converts a given raw image to a byte image.
Image< T_OUT >::Ptr integral_image(typename Image< T_IN >::ConstPtr image)
Calculates the integral image (or summed area table) for the input image.
Image< T >::Ptr expand_grayscale(typename Image< T >::ConstPtr image)
Expands a gray image (one or two channels) to an RGB or RGBA image.
FloatImage::Ptr raw_to_float_image(RawImage::ConstPtr image)
Converts a given raw image to a float image.
Image< T >::Ptr image_undistort_vsfm(typename Image< T >::ConstPtr img, double focal_length, double k1)
Undistorts the input image given the focal length of the image and a single distortion parameter.
T integral_image_area(typename Image< T >::ConstPtr sat, int64_t x1, int64_t y1, int64_t x2, int64_t y2, int64_t cc=0)
Sums over the rectangle defined by A=(x1,y1) and B=(x2,y2) on the given SAT for channel cc.
T gaussian_kernel(typename Image< T >::ConstPtr img, float x, float y, int64_t c, float sigma)
void swap(mve::Image< T > &a, mve::Image< T > &b)
Specialization of std::swap for efficient image swapping.
for-each functor: raises each operand to the power of constant value.