35 #include <visp3/core/vpCPUFeatures.h>
36 #include <visp3/core/vpImageConvert.h>
37 #include <visp3/core/vpImageTools.h>
38 #include <visp3/core/vpImageException.h>
40 #if defined(VISP_HAVE_SIMDLIB)
41 #include <Simd/SimdLib.hpp>
105 unsigned char B_star)
113 double factor =
static_cast<double>((B_star - A_star) /
static_cast<double>((B - A)));
116 unsigned int i_width = I.
getWidth();
117 for (
unsigned int i = 0; i < i_height; ++i) {
118 for (
unsigned int j = 0; j < i_width; ++j) {
128 I[i][j] =
static_cast<unsigned char>(A_star + (factor * (v - A)));
157 #if defined(VISP_HAVE_SIMDLIB)
160 for (
unsigned int i = 0; i < I1.
getSize(); ++i) {
162 Idiff.
bitmap[i] =
static_cast<unsigned char>(std::max<unsigned char>(std::min<unsigned char>(diff, 255), 0));
184 "Cannot compute image difference. The two images "
185 "(%ux%u) and (%ux%u) have not the same size",
193 #if defined(VISP_HAVE_SIMDLIB)
194 SimdImageDifference(
reinterpret_cast<unsigned char *
>(I1.
bitmap),
reinterpret_cast<unsigned char *
>(I2.
bitmap),
195 I1.
getSize() * 4,
reinterpret_cast<unsigned char *
>(Idiff.
bitmap));
197 unsigned int i1_size = I1.
getSize();
198 for (
unsigned int i = 0; i < (i1_size * 4); ++i) {
233 for (
unsigned int b = 0; b < n; ++b) {
257 for (
unsigned int b = 0; b < n; ++b) {
286 for (
unsigned int b = 0; b < n; ++b) {
323 #if defined(VISP_HAVE_SIMDLIB)
324 typedef Simd::View<Simd::Allocator> View;
329 Simd::OperationBinary8u(img1, img2, imgAdd,
330 saturate ? SimdOperationBinary8uSaturatedAddition : SimdOperationBinary8uAddition);
332 unsigned char *ptr_I1 = I1.
bitmap;
333 unsigned char *ptr_I2 = I2.
bitmap;
334 unsigned char *ptr_Ires = Ires.
bitmap;
335 unsigned int ires_size = Ires.
getSize();
336 for (
unsigned int cpt = 0; cpt < ires_size; ++cpt, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
337 *ptr_Ires = saturate ? vpMath::saturate<unsigned char>(
static_cast<short int>(*ptr_I1) +
static_cast<short int>(*ptr_I2)) : ((*ptr_I1) + (*ptr_I2));
366 #if defined(VISP_HAVE_SIMDLIB)
367 typedef Simd::View<Simd::Allocator> View;
372 Simd::OperationBinary8u(img1, img2, imgAdd,
373 saturate ? SimdOperationBinary8uSaturatedSubtraction : SimdOperationBinary8uSubtraction);
375 unsigned char *ptr_I1 = I1.
bitmap;
376 unsigned char *ptr_I2 = I2.
bitmap;
377 unsigned char *ptr_Ires = Ires.
bitmap;
378 unsigned int ires_size = Ires.
getSize();
379 for (
unsigned int cpt = 0; cpt < ires_size; ++cpt, ++ptr_I1, ++ptr_I2, ++ptr_Ires) {
380 *ptr_Ires = saturate ?
381 vpMath::saturate<unsigned char>(
static_cast<short int>(*ptr_I1) -
static_cast<short int>(*ptr_I2)) :
382 ((*ptr_I1) - (*ptr_I2));
402 mapU.
resize(height, width,
false,
false);
403 mapV.
resize(height, width,
false,
false);
404 mapDu.
resize(height, width,
false,
false);
405 mapDv.
resize(height, width,
false,
false);
408 bool is_KannalaBrandt =
411 float u0 =
static_cast<float>(cam.
get_u0());
412 float v0 =
static_cast<float>(cam.
get_v0());
413 float px =
static_cast<float>(cam.
get_px());
414 float py =
static_cast<float>(cam.
get_py());
416 std::vector<double> dist_coefs;
418 if (!is_KannalaBrandt) {
419 kud =
static_cast<float>(cam.
get_kud());
425 if ((!is_KannalaBrandt) && (std::fabs(
static_cast<double>(kud)) <= std::numeric_limits<double>::epsilon())) {
427 for (
unsigned int i = 0; i < height; ++i) {
428 for (
unsigned int j = 0; j < width; ++j) {
429 mapU[i][j] =
static_cast<int>(j);
430 mapV[i][j] =
static_cast<int>(i);
440 float kud_px2 = 0., kud_py2 = 0., deltau_px, deltav_py = 0;
442 float deltav, deltau;
443 float u_float, v_float;
444 int u_round, v_round;
446 double theta, theta_d;
447 double theta2, theta4, theta6, theta8;
448 const unsigned int index_0 = 0;
449 const unsigned int index_1 = 1;
450 const unsigned int index_2 = 2;
451 const unsigned int index_3 = 3;
456 if (!is_KannalaBrandt) {
457 kud_px2 = kud * invpx * invpx;
458 kud_py2 = kud * invpy * invpy;
461 for (
unsigned int v = 0; v < height; ++v) {
464 if (!is_KannalaBrandt) {
465 fr1 = 1.0f + (kud_py2 * deltav * deltav);
468 deltav_py = deltav * invpy;
471 for (
unsigned int u = 0; u < width; ++u) {
474 if (!is_KannalaBrandt) {
475 fr2 = fr1 + (kud_px2 * deltau * deltau);
477 u_float = (deltau * fr2) + u0;
478 v_float = (deltav * fr2) + v0;
482 deltau_px = deltau * invpx;
488 theta6 = theta2 * theta4;
491 theta_d = theta * (1 + (dist_coefs[index_0] * theta2) + (dist_coefs[index_1] * theta4) + (dist_coefs[index_2] * theta6) +
492 (dist_coefs[index_3] * theta8));
495 scale = (std::fabs(r) < std::numeric_limits<double>::epsilon()) ? 1.0 : (theta_d / r);
496 u_float =
static_cast<float>((deltau * scale) + u0);
497 v_float =
static_cast<float>((deltav * scale) + v0);
500 u_round =
static_cast<int>(u_float);
501 v_round =
static_cast<int>(v_float);
503 mapU[v][u] = u_round;
504 mapV[v][u] = v_round;
506 mapDu[v][u] = u_float - u_round;
507 mapDv[v][u] = v_float - v_round;
526 std::cerr <<
"Error, input image is empty." << std::endl;
534 unsigned int ii_width = II.
getWidth();
535 for (
unsigned int i = 1; i < ii_height; ++i) {
536 for (
unsigned int j = 1; j < ii_width; ++j) {
537 II[i][j] = (I[i - 1][j - 1] + II[i - 1][j] + II[i][j - 1]) - II[i - 1][j - 1];
538 IIsq[i][j] = (
vpMath::sqr(I[i - 1][j - 1]) + IIsq[i - 1][j] + IIsq[i][j - 1]) - IIsq[i - 1][j - 1];
554 "Error: in vpImageTools::normalizedCorrelation(): "
555 "image dimension mismatch between I1=%ux%u and I2=%ux%u",
566 #if defined(VISP_HAVE_SIMDLIB)
567 SimdNormalizedCorrelation(I1.
bitmap, a, I2.
bitmap, b, I1.
getSize(), a2, b2, ab, useOptimized);
569 unsigned int i1_size = I1.
getSize();
570 for (
unsigned int cpt = 0; cpt < i1_size; ++cpt) {
578 return ab / sqrt(a2 * b2);
592 for (
unsigned int i = 0; i < height; ++i) {
593 for (
unsigned int j = 0; j < width; ++j) {
597 for (
unsigned int j = 0; j < width; ++j) {
610 unsigned int i_width = I.
getWidth();
611 for (
unsigned int i = 0; i < i_height; ++i) {
612 for (
unsigned int j = 0; j < i_width; ++j) {
613 I(i, j, I(i, j) / s);
627 int x1 =
static_cast<int>(floor(point.
get_i()));
628 int x2 =
static_cast<int>(ceil(point.
get_i()));
629 int y1 =
static_cast<int>(floor(point.
get_j()));
630 int y2 =
static_cast<int>(ceil(point.
get_j()));
637 v1 = ((x2 - point.
get_i()) * I(x1, y1)) + ((point.
get_i() - x1) * I(x2, y1));
638 v2 = ((x2 - point.
get_i()) * I(x1, y2)) + ((point.
get_i() - x1) * I(x2, y2));
643 return ((y2 - point.
get_j()) * v1) + ((point.
get_j() - y1) * v2);
661 return interpolationNearest(I, point);
665 "vpImageTools::interpolate(): bi-cubic interpolation is not implemented.");
686 double cos_t = cos(t);
687 double sin_t = sin(t);
689 for (
unsigned int x = 0; x < x_d; ++x) {
690 double x_cos_t = x * cos_t;
691 double x_sin_t = x * sin_t;
692 for (
unsigned int y = 0; y < y_d; ++y) {
694 static_cast<unsigned char>(
interpolate(src,
vpImagePoint(x1 + x_cos_t + (y * sin_t), (y1 - x_sin_t) + (y * cos_t)),
713 double cos_t = cos(t);
714 double sin_t = sin(t);
716 for (
unsigned int x = 0; x < x_d; ++x) {
717 double x_cos_t = x * cos_t;
718 double x_sin_t = x * sin_t;
719 for (
unsigned int y = 0; y < y_d; ++y) {
746 std::cerr <<
"Error, input image is empty." << std::endl;
751 std::cerr <<
"Error, template image is empty." << std::endl;
756 std::cerr <<
"Error, template image is bigger than input image." << std::endl;
775 const double sum2 = (((II_tpl[height_tpl][width_tpl] + II_tpl[0][0]) - II_tpl[0][width_tpl]) - II_tpl[height_tpl][0]);
776 const double mean2 = sum2 / I_tpl.
getSize();
777 unsigned int i_tpl_double_size = I_tpl_double.
getSize();
778 for (
unsigned int cpt = 0; cpt < i_tpl_double_size; ++cpt) {
779 I_tpl_double.
bitmap[cpt] -= mean2;
782 #if defined(_OPENMP) && (_OPENMP >= 200711)
783 #pragma omp parallel for schedule(dynamic)
784 for (
unsigned int i = 0; i < I.
getHeight() - height_tpl; i += step_v) {
785 for (
unsigned int j = 0; j < I.
getWidth() - width_tpl; j += step_u) {
791 int end =
static_cast<int>((I.
getHeight() - height_tpl) / step_v) + 1;
792 std::vector<unsigned int> vec_step_v(
static_cast<size_t>(end));
794 for (
unsigned int cpt = 0, idx = 0; cpt < (i_height - height_tpl); cpt += step_v, ++idx) {
795 vec_step_v[
static_cast<size_t>(idx)] = cpt;
798 #pragma omp parallel for schedule(dynamic)
800 for (
int cpt = 0; cpt < end; ++cpt) {
801 unsigned int i_width = I.
getWidth();
802 for (
unsigned int j = 0; j < (i_width - width_tpl); j += step_u) {
803 I_score[vec_step_v[cpt]][j] =
813 unsigned int i_width = I.
getWidth();
814 for (
unsigned int i = 0; i < (i_height - height_tpl); i += step_v) {
815 for (
unsigned int j = 0; j < (i_width - width_tpl); j += step_u) {
832 float vpImageTools::cubicHermite(
const float A,
const float B,
const float C,
const float D,
const float t)
834 float a = (((-A + (3.0f * B)) - (3.0f * C)) + D) / 2.0f;
835 float b = (A + (2.0f * C)) - (((5.0f * B) + D) / 2.0f);
836 float c = (-A + C) / 2.0f;
839 return (a * t * t * t) + (b * t * t) + (c * t) + d;
842 int vpImageTools::coordCast(
double x) {
return x < 0 ? -1 :
static_cast<int>(x); }
844 double vpImageTools::lerp(
double A,
double B,
double t) {
return (A * (1.0 - t)) + (B * t); }
846 float vpImageTools::lerp(
float A,
float B,
float t) {
return (A * (1.0f - t)) + (B * t); }
848 int64_t vpImageTools::lerp2(int64_t A, int64_t B, int64_t t, int64_t t_1) {
return (A * t_1) + (B * t); }
853 unsigned int i0,
unsigned int j0)
857 #if defined(VISP_HAVE_SIMDLIB)
861 unsigned int i2_width = I2.
getWidth();
862 for (
unsigned int i = 0; i < i2_height; ++i) {
863 for (
unsigned int j = 0; j < i2_width; ++j) {
864 ab += (I1[i0 + i][j0 + j]) * I2[i][j];
871 (((II[i0 + height_tpl][j0 + width_tpl] + II[i0][j0]) - II[i0][j0 + width_tpl]) - II[i0 + height_tpl][j0]);
872 const double sum2 = (((II_tpl[height_tpl][width_tpl] + II_tpl[0][0]) - II_tpl[0][width_tpl]) - II_tpl[height_tpl][0]);
881 return ab / sqrt(a2 * b2);
898 const int I_height =
static_cast<int>(I.
getHeight());
901 #pragma omp parallel for schedule(dynamic)
903 for (
int i_ = 0; i_ < I_height; ++i_) {
904 const unsigned int i =
static_cast<unsigned int>(i_);
905 unsigned int i_width = I.
getWidth();
906 for (
unsigned int j = 0; j < i_width; ++j) {
908 int u_round = mapU[i][j];
909 int v_round = mapV[i][j];
911 float du = mapDu[i][j];
912 float dv = mapDv[i][j];
914 if ((0 <= u_round) && (0 <= v_round) && (u_round < (
static_cast<int>(I.
getWidth()) - 1)) &&
915 (v_round < (I_height - 1))) {
917 float col0 = lerp(I[v_round][u_round], I[v_round][u_round + 1], du);
918 float col1 = lerp(I[v_round + 1][u_round], I[v_round + 1][u_round + 1], du);
919 float value = lerp(col0, col1, dv);
921 Iundist[i][j] =
static_cast<unsigned char>(value);
944 const int I_height =
static_cast<int>(I.
getHeight());
946 #pragma omp parallel for schedule(dynamic)
948 for (
int i = 0; i < I_height; ++i) {
949 #if defined(VISP_HAVE_SIMDLIB)
951 mapV.
data, mapDu.
data, mapDv.
data,
reinterpret_cast<unsigned char *
>(Iundist.
bitmap));
953 const unsigned int i_ =
static_cast<unsigned int>(i);
954 unsigned int i_width = I.
getWidth();
955 for (
unsigned int j = 0; j < i_width; ++j) {
957 int u_round = mapU[i_][j];
958 int v_round = mapV[i_][j];
960 float du = mapDu[i_][j];
961 float dv = mapDv[i_][j];
963 if ((0 <= u_round) && (0 <= v_round) && (u_round < (
static_cast<int>(I.
getWidth()) - 1))
964 && (v_round < (I_height - 1))) {
966 float col0 = lerp(I[v_round][u_round].R, I[v_round][u_round + 1].R, du);
967 float col1 = lerp(I[v_round + 1][u_round].R, I[v_round + 1][u_round + 1].R, du);
968 float value = lerp(col0, col1, dv);
970 Iundist[i][j].R =
static_cast<unsigned char>(value);
972 col0 = lerp(I[v_round][u_round].G, I[v_round][u_round + 1].G, du);
973 col1 = lerp(I[v_round + 1][u_round].G, I[v_round + 1][u_round + 1].G, du);
974 value = lerp(col0, col1, dv);
976 Iundist[i][j].G =
static_cast<unsigned char>(value);
978 col0 = lerp(I[v_round][u_round].B, I[v_round][u_round + 1].B, du);
979 col1 = lerp(I[v_round + 1][u_round].B, I[v_round + 1][u_round + 1].B, du);
980 value = lerp(col0, col1, dv);
982 Iundist[i][j].B =
static_cast<unsigned char>(value);
984 col0 = lerp(I[v_round][u_round].A, I[v_round][u_round + 1].A, du);
985 col1 = lerp(I[v_round + 1][u_round].A, I[v_round + 1][u_round + 1].A, du);
986 value = lerp(col0, col1, dv);
988 Iundist[i][j].A =
static_cast<unsigned char>(value);
998 #if defined(VISP_HAVE_SIMDLIB)
999 void vpImageTools::resizeSimdlib(
const vpImage<vpRGBa> &Isrc,
unsigned int resizeWidth,
unsigned int resizeHeight,
1002 Idst.
resize(resizeHeight, resizeWidth);
1004 typedef Simd::View<Simd::Allocator> View;
1008 Simd::Resize(src, dst, method ==
INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
1014 Idst.
resize(resizeHeight, resizeWidth);
1016 typedef Simd::View<Simd::Allocator> View;
1020 Simd::Resize(src, dst, method ==
INTERPOLATION_LINEAR ? SimdResizeMethodBilinear : SimdResizeMethodArea);
1024 bool vpImageTools::checkFixedPoint(
unsigned int x,
unsigned int y,
const vpMatrix &T,
bool affine)
1026 const unsigned int index_0 = 0;
1027 const unsigned int index_1 = 1;
1028 const unsigned int index_2 = 2;
1029 double a0 = T[index_0][index_0];
1030 double a1 = T[index_0][index_1];
1031 double a2 = T[index_0][index_2];
1032 double a3 = T[index_1][index_0];
1033 double a4 = T[index_1][index_1];
1034 double a5 = T[index_1][index_2];
1035 double a6 = affine ? 0.0 : T[index_2][index_0];
1036 double a7 = affine ? 0.0 : T[index_2][index_1];
1037 double a8 = affine ? 1.0 : T[index_2][index_2];
1039 double w = (a6 * x) + (a7 * y) + a8;
1040 double x2 = ((a0 * x) + (a1 * y) + a2) / w;
1041 double y2 = ((a3 * x) + (a4 * y) + a5) / w;
1043 const double limit = 1 << 15;
1058 "Error in vpImageTools::inMask(): image (%dx%d) and mask (%dx%d) size doesn't match",
1063 int cpt_in_mask = 0;
1064 int size_ =
static_cast<int>(I.
getSize());
1065 #if defined(_OPENMP)
1066 #pragma omp parallel for reduction(+:cpt_in_mask)
1068 for (
int i = 0; i < size_; ++i) {
1069 if (mask.
bitmap[i] == 0) {
1070 I_mask.
bitmap[i] = black;
1091 "Error in vpImageTools::inMask(): image (%dx%d) and mask (%dx%d) size doesn't match",
1095 int cpt_in_mask = 0;
1096 int size_ =
static_cast<int>(I.
getSize());
1097 #if defined(_OPENMP)
1098 #pragma omp parallel for reduction(+:cpt_in_mask)
1100 for (
int i = 0; i < size_; ++i) {
1101 if (mask.
bitmap[i] == 0) {
1129 const vpColVector &hsv_range,
unsigned char *mask,
unsigned int size)
1131 if ((hue ==
nullptr) || (saturation ==
nullptr) || (value ==
nullptr)) {
1133 "Error in vpImageTools::inRange(): hsv pointer are empty"));
1135 else if (hsv_range.
size() != 6) {
1137 "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.
size()));
1139 const unsigned int index_0 = 0;
1140 const unsigned int index_1 = 1;
1141 const unsigned int index_2 = 2;
1142 const unsigned int index_3 = 3;
1143 const unsigned int index_4 = 4;
1144 const unsigned int index_5 = 5;
1145 unsigned char h_low =
static_cast<unsigned char>(hsv_range[index_0]);
1146 unsigned char h_high =
static_cast<unsigned char>(hsv_range[index_1]);
1147 unsigned char s_low =
static_cast<unsigned char>(hsv_range[index_2]);
1148 unsigned char s_high =
static_cast<unsigned char>(hsv_range[index_3]);
1149 unsigned char v_low =
static_cast<unsigned char>(hsv_range[index_4]);
1150 unsigned char v_high =
static_cast<unsigned char>(hsv_range[index_5]);
1151 int size_ =
static_cast<int>(size);
1152 int cpt_in_range = 0;
1153 #if defined(_OPENMP)
1154 #pragma omp parallel for reduction(+:cpt_in_range)
1156 for (
int i = 0; i < size_; ++i) {
1157 bool check_h_low_high_hue = (h_low <= hue[i]) && (hue[i] <= h_high);
1158 bool check_s_low_high_saturation = (s_low <= saturation[i]) && (saturation[i] <= s_high);
1159 bool check_v_low_high_value = (v_low <= value[i]) && (value[i] <= v_high);
1160 if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
1168 return cpt_in_range;
1189 const std::vector<int> &hsv_range,
unsigned char *mask,
unsigned int size)
1191 if ((hue ==
nullptr) || (saturation ==
nullptr) || (value ==
nullptr)) {
1193 "Error in vpImageTools::inRange(): hsv pointer are empty"));
1195 else if (hsv_range.size() != 6) {
1197 "Error in vpImageTools::inRange(): wrong values vector size (%d)", hsv_range.size()));
1199 const unsigned int index_0 = 0;
1200 const unsigned int index_1 = 1;
1201 const unsigned int index_2 = 2;
1202 const unsigned int index_3 = 3;
1203 const unsigned int index_4 = 4;
1204 const unsigned int index_5 = 5;
1205 unsigned char h_low =
static_cast<unsigned char>(hsv_range[index_0]);
1206 unsigned char h_high =
static_cast<unsigned char>(hsv_range[index_1]);
1207 unsigned char s_low =
static_cast<unsigned char>(hsv_range[index_2]);
1208 unsigned char s_high =
static_cast<unsigned char>(hsv_range[index_3]);
1209 unsigned char v_low =
static_cast<unsigned char>(hsv_range[index_4]);
1210 unsigned char v_high =
static_cast<unsigned char>(hsv_range[index_5]);
1211 int size_ =
static_cast<int>(size);
1212 int cpt_in_range = 0;
1213 #if defined(_OPENMP)
1214 #pragma omp parallel for reduction(+:cpt_in_range)
1216 for (
int i = 0; i < size_; ++i) {
1217 bool check_h_low_high_hue = (h_low <= hue[i]) && (hue[i] <= h_high);
1218 bool check_s_low_high_saturation = (s_low <= saturation[i]) && (saturation[i] <= s_high);
1219 bool check_v_low_high_value = (v_low <= value[i]) && (value[i] <= v_high);
1220 if (check_h_low_high_hue && check_s_low_high_saturation && check_v_low_high_value) {
1228 return cpt_in_range;
Implementation of a generic 2D array used as base class for matrices and vectors.
Type * data
Address of the first element of the data array.
void resize(unsigned int nrows, unsigned int ncols, bool flagNullify=true, bool recopy_=true)
unsigned int size() const
Return the number of elements of the 2D array.
Generic class defining intrinsic camera parameters.
std::vector< double > getKannalaBrandtDistortionCoefficients() const
vpCameraParametersProjType
@ ProjWithKannalaBrandtDistortion
Projection with Kannala-Brandt distortion model.
vpCameraParametersProjType get_projModel() const
Implementation of column vector and the associated operations.
error that can be emitted by ViSP classes.
@ dimensionError
Bad dimension.
@ notImplementedError
Not implemented.
static void convert(const vpImage< unsigned char > &src, vpImage< vpRGBa > &dest)
Error that can be emitted by the vpImage class and its derivatives.
@ notInitializedError
Image not initialized.
@ incorrectInitializationError
Wrong image initialization.
Class that defines a 2D point in an image. This class is useful for image processing and stores only ...
double getSum(const vpImage< bool > *p_mask=nullptr, unsigned int *nbValidPoints=nullptr) const
Compute the sum of image intensities.
unsigned int getWidth() const
void resize(unsigned int h, unsigned int w)
resize the image : Image initialization
unsigned int getSize() const
Type * bitmap
points toward the bitmap
unsigned int getHeight() const
double getMeanValue(const vpImage< bool > *p_mask=nullptr, unsigned int *nbValidPoints=nullptr) const
Return the mean value of the bitmap.
static Type maximum(const Type &a, const Type &b)
static double sqr(double x)
static Type abs(const Type &x)
static int round(double x)
static Type minimum(const Type &a, const Type &b)
Implementation of a matrix and operations on matrices.
unsigned char B
Blue component.
unsigned char R
Red component.
unsigned char G
Green component.
unsigned char A
Additionnal component.
Defines an oriented rectangle in the plane.
double getHeight() const
Get the rectangle height.
double getOrientation() const
Get the rectangle orientation (rad).
double getWidth() const
Get the rectangle width.
vpImagePoint getTopLeft() const
Get the top-left corner.
Defines a rectangle in the plane.
Implementation of row vector and the associated operations.
void resize(unsigned int i, bool flagNullify=true)