47 #include <visp3/core/vpConfig.h>
48 #include <visp3/core/vpDebug.h>
49 #include <visp3/core/vpException.h>
50 #include <visp3/core/vpImageException.h>
51 #include <visp3/core/vpImagePoint.h>
52 #include <visp3/core/vpRGBa.h>
53 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
54 #include <visp3/core/vpThread.h>
64 #if defined(_MSC_VER) && (_MSC_VER < 1700)
65 typedef long long int64_t;
66 typedef unsigned short uint16_t;
68 # include <inttypes.h>
124 template <
class Type>
class vpImage;
136 template <
class Type>
class vpImage
148 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
152 vpImage(
unsigned int height,
unsigned int width);
155 vpImage(
unsigned int height,
unsigned int width, Type value);
157 vpImage(Type *
const array,
unsigned int height,
unsigned int width,
bool copyData =
false);
177 inline unsigned int getCols()
const {
return width; }
186 inline unsigned int getHeight()
const {
return height; }
216 inline unsigned int getRows()
const {
return height; }
225 inline unsigned int getSize()
const {
return width * height; }
228 Type
getValue(
unsigned int i,
unsigned int j)
const;
230 Type
getValue(
double i,
double j)
const;
244 inline unsigned int getWidth()
const {
return width; }
250 void init(
unsigned int height,
unsigned int width);
252 void init(
unsigned int height,
unsigned int width, Type value);
254 void init(Type *
const array,
unsigned int height,
unsigned int width,
bool copyData =
false);
262 inline Type *
operator[](
int i) {
return row[i]; }
265 inline const Type *
operator[](
unsigned int i)
const {
return row[i]; }
266 inline const Type *
operator[](
int i)
const {
return row[i]; }
274 inline Type
operator()(
unsigned int i,
unsigned int j)
const {
return bitmap[i * width + j]; }
280 inline void operator()(
unsigned int i,
unsigned int j,
const Type &v) {
bitmap[i * width + j] = v; }
294 unsigned int i = (
unsigned int)ip.
get_i();
295 unsigned int j = (
unsigned int)ip.
get_j();
297 return bitmap[i * width + j];
310 unsigned int i = (
unsigned int)ip.
get_i();
311 unsigned int j = (
unsigned int)ip.
get_j();
313 bitmap[i * width + j] = v;
324 friend std::ostream &operator<< <>(std::ostream &s,
const vpImage<Type> &I);
331 void performLut(
const Type (&lut)[256],
unsigned int nbThreads = 1);
337 void resize(
unsigned int h,
unsigned int w);
339 void resize(
unsigned int h,
unsigned int w,
const Type &val);
350 unsigned int npixels;
363 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
364 for (
unsigned int j = 0; j < I.
getWidth() - 1; j++) {
386 std::ios_base::fmtflags original_flags = s.flags();
388 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
389 for (
unsigned int j = 0; j < I.
getWidth() - 1; j++) {
390 s << std::setw(3) << static_cast<unsigned>(I[i][j]) <<
" ";
394 s << std::setw(3) << static_cast<unsigned>(I[i][I.
getWidth() - 1]);
402 s.flags(original_flags);
412 std::ios_base::fmtflags original_flags = s.flags();
414 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
415 for (
unsigned int j = 0; j < I.
getWidth() - 1; j++) {
416 s << std::setw(4) << static_cast<int>(I[i][j]) <<
" ";
420 s << std::setw(4) << static_cast<int>(I[i][I.
getWidth() - 1]);
428 s.flags(original_flags);
438 std::ios_base::fmtflags original_flags = s.flags();
441 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
442 for (
unsigned int j = 0; j < I.
getWidth() - 1; j++) {
455 s.flags(original_flags);
465 std::ios_base::fmtflags original_flags = s.flags();
468 for (
unsigned int i = 0; i < I.
getHeight(); i++) {
469 for (
unsigned int j = 0; j < I.
getWidth() - 1; j++) {
482 s.flags(original_flags);
486 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
489 struct ImageLut_Param_t {
490 unsigned int m_start_index;
491 unsigned int m_end_index;
493 unsigned char m_lut[256];
494 unsigned char *m_bitmap;
496 ImageLut_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(NULL) {}
498 ImageLut_Param_t(
unsigned int start_index,
unsigned int end_index,
unsigned char *bitmap)
499 : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
506 ImageLut_Param_t *imageLut_param = static_cast<ImageLut_Param_t *>(args);
507 unsigned int start_index = imageLut_param->m_start_index;
508 unsigned int end_index = imageLut_param->m_end_index;
510 unsigned char *bitmap = imageLut_param->m_bitmap;
512 unsigned char *ptrStart = bitmap + start_index;
513 unsigned char *ptrEnd = bitmap + end_index;
514 unsigned char *ptrCurrent = ptrStart;
521 if (end_index - start_index >= 8) {
523 for (; ptrCurrent <= ptrEnd - 8;) {
524 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
527 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
530 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
533 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
536 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
539 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
542 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
545 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
550 for (; ptrCurrent != ptrEnd; ++ptrCurrent) {
551 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent];
557 struct ImageLutRGBa_Param_t {
558 unsigned int m_start_index;
559 unsigned int m_end_index;
562 unsigned char *m_bitmap;
564 ImageLutRGBa_Param_t() : m_start_index(0), m_end_index(0), m_lut(), m_bitmap(NULL) {}
566 ImageLutRGBa_Param_t(
unsigned int start_index,
unsigned int end_index,
unsigned char *bitmap)
567 : m_start_index(start_index), m_end_index(end_index), m_lut(), m_bitmap(bitmap)
574 ImageLutRGBa_Param_t *imageLut_param = static_cast<ImageLutRGBa_Param_t *>(args);
575 unsigned int start_index = imageLut_param->m_start_index;
576 unsigned int end_index = imageLut_param->m_end_index;
578 unsigned char *bitmap = imageLut_param->m_bitmap;
580 unsigned char *ptrStart = bitmap + start_index * 4;
581 unsigned char *ptrEnd = bitmap + end_index * 4;
582 unsigned char *ptrCurrent = ptrStart;
584 if (end_index - start_index >= 4 * 2) {
586 for (; ptrCurrent <= ptrEnd - 4 * 2;) {
587 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
589 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
591 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
593 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
596 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
598 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
600 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
602 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
607 while (ptrCurrent != ptrEnd) {
608 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].R;
611 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].G;
614 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].B;
617 *ptrCurrent = imageLut_param->m_lut[*ptrCurrent].A;
645 std::fill(bitmap, bitmap + npixels, value);
667 if (h != this->height) {
675 if ((h != this->height) || (w != this->width)) {
676 if (bitmap != NULL) {
688 npixels = width * height;
690 if (bitmap == NULL) {
691 bitmap =
new Type[npixels];
695 if (bitmap == NULL) {
700 row =
new Type *[height];
705 for (
unsigned int i = 0; i < height; i++)
706 row[i] = bitmap + i * width;
722 template <
class Type>
725 if (h != this->height) {
733 if ((copyData && ((h != this->height) || (w != this->width))) || !copyData) {
734 if (bitmap != NULL) {
742 hasOwnership = copyData;
746 npixels = width * height;
750 bitmap =
new Type[npixels];
752 if (bitmap == NULL) {
757 memcpy(static_cast<void*>(bitmap), static_cast<void*>(array), (
size_t)(npixels *
sizeof(Type)));
764 row =
new Type *[height];
769 for (
unsigned int i = 0; i < height; i++) {
770 row[i] = bitmap + i * width;
792 template <
class Type>
794 : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
816 template <
class Type>
818 : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
838 template <
class Type>
840 : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
842 init(array, h, w, copyData);
855 bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
900 template <
class Type>
void vpImage<Type>::resize(
unsigned int h,
unsigned int w,
const Type &val) { init(h, w, val); }
912 if (bitmap != NULL) {
940 template <
class Type>
942 : bitmap(NULL), display(NULL), npixels(0), width(0), height(0), row(NULL), hasOwnership(true)
945 memcpy(static_cast<void*>(
bitmap), static_cast<void*>(I.
bitmap), I.npixels *
sizeof(Type));
948 #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11)
952 template <
class Type>
954 : bitmap(I.bitmap), display(I.display), npixels(I.npixels), width(I.width), height(I.height), row(I.row), hasOwnership(I.hasOwnership)
962 I.hasOwnership =
false;
976 for (
unsigned int i = 0; i < npixels; i++) {
988 if ((height == 0) || (width == 0))
991 return getSum() / (height * width);
1004 for (
unsigned int i = 0; i < npixels; i++)
1022 min = max = bitmap[0];
1023 for (
unsigned int i = 0; i < npixels; i++) {
1024 if (bitmap[i] < min)
1026 if (bitmap[i] > max)
1052 template <
class Type>
1057 "values of an empty image"));
1059 Type min = bitmap[0], max = bitmap[0];
1061 for (
unsigned int i = 0; i < height; i++) {
1062 for (
unsigned int j = 0; j < width; j++) {
1063 if (row[i][j] < min) {
1068 if (row[i][j] > max) {
1112 for (
unsigned int i = 0; i < npixels; i++)
1132 for (
unsigned int i = 0; i < npixels; i++) {
1133 if (bitmap[i] != I.
bitmap[i]) {
1148 return !(*
this == I);
1196 int itl = (int)topLeft.
get_i();
1197 int jtl = (int)topLeft.
get_j();
1199 int dest_ibegin = 0;
1200 int dest_jbegin = 0;
1203 int dest_w = (int)this->getWidth();
1204 int dest_h = (int)this->getHeight();
1205 int src_w = (int)src.getWidth();
1206 int src_h = (int)src.getHeight();
1207 int wsize = (int)src.getWidth();
1208 int hsize = (int)src.getHeight();
1210 if (itl >= dest_h || jtl >= dest_w)
1223 if (src_w - src_jbegin > dest_w - dest_jbegin)
1224 wsize = dest_w - dest_jbegin;
1226 wsize = src_w - src_jbegin;
1228 if (src_h - src_ibegin > dest_h - dest_ibegin)
1229 hsize = dest_h - dest_ibegin;
1231 hsize = src_h - src_ibegin;
1233 for (
int i = 0; i < hsize; i++) {
1234 Type *srcBitmap = src.bitmap + ((src_ibegin + i) * src_w + src_jbegin);
1235 Type *destBitmap = this->bitmap + ((dest_ibegin + i) * dest_w + dest_jbegin);
1237 memcpy(static_cast<void*>(destBitmap), static_cast<void*>(srcBitmap), (
size_t)wsize *
sizeof(Type));
1273 unsigned int h = height / 2;
1274 unsigned int w = width / 2;
1276 for (
unsigned int i = 0; i < h; i++)
1277 for (
unsigned int j = 0; j < w; j++)
1278 res[i][j] = (*
this)[i << 1][j << 1];
1298 template <
class Type>
1301 unsigned int h = height / v_scale;
1302 unsigned int w = width / h_scale;
1304 for (
unsigned int i = 0; i < h; i++)
1305 for (
unsigned int j = 0; j < w; j++)
1306 sampled[i][j] = (*
this)[i * v_scale][j * h_scale];
1333 unsigned int h = height / 4;
1334 unsigned int w = width / 4;
1336 for (
unsigned int i = 0; i < h; i++)
1337 for (
unsigned int j = 0; j < w; j++)
1338 res[i][j] = (*
this)[i << 2][j << 2];
1380 for (
int i = 0; i < h; i++)
1381 for (
int j = 0; j < w; j++)
1382 res[i][j] = (*
this)[i >> 1][j >> 1];
1393 for (
int i = 0; i < h; i += 2)
1394 for (
int j = 1; j < w - 1; j += 2)
1395 res[i][j] = (Type)(0.5 * ((*this)[i >> 1][j >> 1] + (*this)[i >> 1][(j >> 1) + 1]));
1398 for (
int i = 1; i < h - 1; i += 2)
1399 for (
int j = 0; j < w; j += 2)
1400 res[i][j] = (Type)(0.5 * ((*this)[i >> 1][j >> 1] + (*this)[(i >> 1) + 1][j >> 1]));
1403 for (
int i = 1; i < h - 1; i += 2)
1404 for (
int j = 1; j < w - 1; j += 2)
1405 res[i][j] = (Type)(0.25 * ((*this)[i >> 1][j >> 1] + (*this)[i >> 1][(j >> 1) + 1] +
1406 (*
this)[(i >> 1) + 1][j >> 1] + (*
this)[(i >> 1) + 1][(j >> 1) + 1]));
1424 if (i >= height || j >= width) {
1450 if (i < 0 || j < 0 || i+1 > height || j+1 > width) {
1453 if (height * width == 0) {
1457 unsigned int iround = static_cast<unsigned int>(floor(i));
1458 unsigned int jround = static_cast<unsigned int>(floor(j));
1460 double rratio = i - static_cast<double>(iround);
1461 double cratio = j - static_cast<double>(jround);
1463 double rfrac = 1.0 - rratio;
1464 double cfrac = 1.0 - cratio;
1466 unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1467 unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1469 double value = (static_cast<double>(row[iround][jround]) * rfrac + static_cast<double>(row[iround_1][jround]) * rratio) * cfrac +
1470 (static_cast<double>(row[iround][jround_1]) * rfrac + static_cast<double>(row[iround_1][jround_1]) * rratio) * cratio;
1493 if (i < 0 || j < 0 || i+1 > height || j+1 > width) {
1496 if (height * width == 0) {
1500 unsigned int iround = static_cast<unsigned int>(floor(i));
1501 unsigned int jround = static_cast<unsigned int>(floor(j));
1503 double rratio = i - static_cast<double>(iround);
1504 double cratio = j - static_cast<double>(jround);
1506 double rfrac = 1.0 - rratio;
1507 double cfrac = 1.0 - cratio;
1509 unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1510 unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1512 return (row[iround][jround] * rfrac + row[iround_1][jround] * rratio) * cfrac +
1513 (row[iround][jround_1] * rfrac + row[iround_1][jround_1] * rratio) * cratio;
1517 if (i < 0 || j < 0 || i+1 > height || j+1 > width) {
1520 if (height * width == 0) {
1525 const int precision = 1 << 16;
1526 int64_t y = static_cast<int64_t>(i * precision);
1527 int64_t x = static_cast<int64_t>(j * precision);
1529 int64_t iround = y & (~0xFFFF);
1530 int64_t jround = x & (~0xFFFF);
1532 int64_t rratio = y - iround;
1533 int64_t cratio = x - jround;
1535 int64_t rfrac = precision - rratio;
1536 int64_t cfrac = precision - cratio;
1538 int64_t x_ = x >> 16;
1539 int64_t y_ = y >> 16;
1541 if (y_ + 1 < height && x_ + 1 < width) {
1542 uint16_t up = *reinterpret_cast<uint16_t *>(
bitmap + y_ * width + x_);
1543 uint16_t down = *reinterpret_cast<uint16_t *>(
bitmap + (y_ + 1) * width + x_);
1545 return static_cast<unsigned char>((((up & 0x00FF) * rfrac + (down & 0x00FF) * rratio) * cfrac +
1546 ((up >> 8) * rfrac + (down >> 8) * rratio) * cratio) >> 32);
1547 }
else if (y_ + 1 < height) {
1548 return static_cast<unsigned char>(((row[y_][x_] * rfrac + row[y_ + 1][x_] * rratio)) >> 16);
1549 }
else if (x_ + 1 < width) {
1550 uint16_t up = *reinterpret_cast<uint16_t *>(
bitmap + y_ * width + x_);
1551 return static_cast<unsigned char>(((up & 0x00FF) * cfrac + (up >> 8) * cratio) >> 16);
1559 if (i < 0 || j < 0 || i+1 > height || j+1 > width) {
1562 if (height * width == 0) {
1566 unsigned int iround = static_cast<unsigned int>(floor(i));
1567 unsigned int jround = static_cast<unsigned int>(floor(j));
1569 double rratio = i - static_cast<double>(iround);
1570 double cratio = j - static_cast<double>(jround);
1572 double rfrac = 1.0 - rratio;
1573 double cfrac = 1.0 - cratio;
1575 unsigned int iround_1 = (std::min)(height - 1, iround + 1);
1576 unsigned int jround_1 = (std::min)(width - 1, jround + 1);
1578 double valueR = (static_cast<double>(row[iround][jround].R) * rfrac + static_cast<double>(row[iround_1][jround].R) * rratio) * cfrac +
1579 (static_cast<double>(row[iround][jround_1].R) * rfrac + static_cast<double>(row[iround_1][jround_1].R) * rratio) * cratio;
1580 double valueG = (static_cast<double>(row[iround][jround].G) * rfrac + static_cast<double>(row[iround_1][jround].G) * rratio) * cfrac +
1581 (static_cast<double>(row[iround][jround_1].G) * rfrac + static_cast<double>(row[iround_1][jround_1].G) * rratio) * cratio;
1582 double valueB = (static_cast<double>(row[iround][jround].B) * rfrac + static_cast<double>(row[iround_1][jround].B) * rratio) * cfrac +
1583 (static_cast<double>(row[iround][jround_1].B) * rfrac + static_cast<double>(row[iround_1][jround_1].B) * rratio) * cratio;
1631 if ((height == 0) || (width == 0))
1635 for (
unsigned int i = 0; i < height * width; ++i) {
1636 res += static_cast<double>(bitmap[i]);
1675 C.
resize(this->getHeight(), this->getWidth());
1677 std::cout << me << std::endl;
1681 if ((this->getWidth() != B.
getWidth()) || (this->getHeight() != B.
getHeight())) {
1685 for (
unsigned int i = 0; i < this->getWidth() * this->getHeight(); i++) {
1708 std::cout << me << std::endl;
1733 std::cerr <<
"Not implemented !" << std::endl;
1748 unsigned char *ptrStart = (
unsigned char *)
bitmap;
1749 unsigned char *ptrEnd = ptrStart + size;
1750 unsigned char *ptrCurrent = ptrStart;
1752 bool use_single_thread = (nbThreads == 0 || nbThreads == 1);
1753 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
1754 use_single_thread =
true;
1757 if (!use_single_thread &&
getSize() <= nbThreads) {
1758 use_single_thread =
true;
1761 if (use_single_thread) {
1764 while (ptrCurrent != ptrEnd) {
1765 *ptrCurrent = lut[*ptrCurrent];
1769 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
1772 std::vector<vpThread *> threadpool;
1773 std::vector<ImageLut_Param_t *> imageLutParams;
1775 unsigned int image_size =
getSize();
1776 unsigned int step = image_size / nbThreads;
1777 unsigned int last_step = image_size - step * (nbThreads - 1);
1779 for (
unsigned int index = 0; index < nbThreads; index++) {
1780 unsigned int start_index = index * step;
1781 unsigned int end_index = (index + 1) * step;
1783 if (index == nbThreads - 1) {
1784 end_index = start_index + last_step;
1787 ImageLut_Param_t *imageLut_param =
new ImageLut_Param_t(start_index, end_index,
bitmap);
1788 memcpy(imageLut_param->m_lut, lut, 256 *
sizeof(
unsigned char));
1790 imageLutParams.push_back(imageLut_param);
1794 threadpool.push_back(imageLut_thread);
1797 for (
size_t cpt = 0; cpt < threadpool.size(); cpt++) {
1799 threadpool[cpt]->join();
1803 for (
size_t cpt = 0; cpt < threadpool.size(); cpt++) {
1804 delete threadpool[cpt];
1807 for (
size_t cpt = 0; cpt < imageLutParams.size(); cpt++) {
1808 delete imageLutParams[cpt];
1825 unsigned char *ptrStart = (
unsigned char *)
bitmap;
1826 unsigned char *ptrEnd = ptrStart + size * 4;
1827 unsigned char *ptrCurrent = ptrStart;
1829 bool use_single_thread = (nbThreads == 0 || nbThreads == 1);
1830 #if !defined(VISP_HAVE_PTHREAD) && !defined(_WIN32)
1831 use_single_thread =
true;
1834 if (!use_single_thread &&
getSize() <= nbThreads) {
1835 use_single_thread =
true;
1838 if (use_single_thread) {
1840 while (ptrCurrent != ptrEnd) {
1841 *ptrCurrent = lut[*ptrCurrent].R;
1844 *ptrCurrent = lut[*ptrCurrent].G;
1847 *ptrCurrent = lut[*ptrCurrent].B;
1850 *ptrCurrent = lut[*ptrCurrent].A;
1854 #if defined(VISP_HAVE_PTHREAD) || (defined(_WIN32) && !defined(WINRT_8_0))
1856 std::vector<vpThread *> threadpool;
1857 std::vector<ImageLutRGBa_Param_t *> imageLutParams;
1859 unsigned int image_size =
getSize();
1860 unsigned int step = image_size / nbThreads;
1861 unsigned int last_step = image_size - step * (nbThreads - 1);
1863 for (
unsigned int index = 0; index < nbThreads; index++) {
1864 unsigned int start_index = index * step;
1865 unsigned int end_index = (index + 1) * step;
1867 if (index == nbThreads - 1) {
1868 end_index = start_index + last_step;
1871 ImageLutRGBa_Param_t *imageLut_param =
new ImageLutRGBa_Param_t(start_index, end_index, (
unsigned char *)
bitmap);
1872 memcpy(imageLut_param->m_lut, lut, 256 *
sizeof(
vpRGBa));
1874 imageLutParams.push_back(imageLut_param);
1878 threadpool.push_back(imageLut_thread);
1881 for (
size_t cpt = 0; cpt < threadpool.size(); cpt++) {
1883 threadpool[cpt]->join();
1887 for (
size_t cpt = 0; cpt < threadpool.size(); cpt++) {
1888 delete threadpool[cpt];
1891 for (
size_t cpt = 0; cpt < imageLutParams.size(); cpt++) {
1892 delete imageLutParams[cpt];
1903 swap(first.npixels, second.npixels);
1904 swap(first.width, second.width);
1905 swap(first.height, second.height);
1906 swap(first.row, second.row);