1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 //     * Redistributions of source code must retain the above copyright
8 //       notice, this list of conditions and the following disclaimer.
9 //
10 //     * Redistributions in binary form must reproduce the above copyright
11 //       notice, this list of conditions and the following disclaimer in the
12 //       documentation and/or other materials provided with the distribution.
13 //
14 //     * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 //       its contributors may be used to endorse or promote products derived
16 //       from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #include "ui/qt_utils.h"
33 
34 #include "base/camera_models.h"
35 #include "util/misc.h"
36 
37 namespace colmap {
38 
QMatrixToEigen(const QMatrix4x4 & matrix)39 Eigen::Matrix4f QMatrixToEigen(const QMatrix4x4& matrix) {
40   Eigen::Matrix4f eigen;
41   for (size_t r = 0; r < 4; ++r) {
42     for (size_t c = 0; c < 4; ++c) {
43       eigen(r, c) = matrix(r, c);
44     }
45   }
46   return eigen;
47 }
48 
EigenToQMatrix(const Eigen::Matrix4f & matrix)49 QMatrix4x4 EigenToQMatrix(const Eigen::Matrix4f& matrix) {
50   QMatrix4x4 qt;
51   for (size_t r = 0; r < 4; ++r) {
52     for (size_t c = 0; c < 4; ++c) {
53       qt(r, c) = matrix(r, c);
54     }
55   }
56   return qt;
57 }
58 
BitmapToQImageRGB(const Bitmap & bitmap)59 QImage BitmapToQImageRGB(const Bitmap& bitmap) {
60   QImage image(bitmap.Width(), bitmap.Height(), QImage::Format_RGB32);
61   for (int y = 0; y < image.height(); ++y) {
62     QRgb* image_line = (QRgb*)image.scanLine(y);
63     for (int x = 0; x < image.width(); ++x) {
64       BitmapColor<uint8_t> color;
65       if (bitmap.GetPixel(x, y, &color)) {
66         image_line[x] = qRgba(color.r, color.g, color.b, 255);
67       }
68     }
69   }
70   return image;
71 }
72 
ShowImagesSideBySide(const QPixmap & image1,const QPixmap & image2)73 QPixmap ShowImagesSideBySide(const QPixmap& image1, const QPixmap& image2) {
74   QPixmap image = QPixmap(QSize(image1.width() + image2.width(),
75                                 std::max(image1.height(), image2.height())));
76 
77   image.fill(Qt::black);
78 
79   QPainter painter(&image);
80   painter.drawImage(0, 0, image1.toImage());
81   painter.drawImage(image1.width(), 0, image2.toImage());
82 
83   return image;
84 }
85 
DrawKeypoints(QPixmap * pixmap,const FeatureKeypoints & points,const QColor & color)86 void DrawKeypoints(QPixmap* pixmap, const FeatureKeypoints& points,
87                    const QColor& color) {
88   if (pixmap->isNull()) {
89     return;
90   }
91 
92   const int pen_width = std::max(pixmap->width(), pixmap->height()) / 2048 + 1;
93   const int radius = 3 * pen_width + (3 * pen_width) % 2;
94   const float radius2 = radius / 2.0f;
95 
96   QPainter painter(pixmap);
97   painter.setRenderHint(QPainter::Antialiasing);
98 
99   QPen pen;
100   pen.setWidth(pen_width);
101   pen.setColor(color);
102   painter.setPen(pen);
103 
104   for (const auto& point : points) {
105     painter.drawEllipse(point.x - radius2, point.y - radius2, radius, radius);
106   }
107 }
108 
DrawMatches(const QPixmap & image1,const QPixmap & image2,const FeatureKeypoints & points1,const FeatureKeypoints & points2,const FeatureMatches & matches,const QColor & keypoints_color)109 QPixmap DrawMatches(const QPixmap& image1, const QPixmap& image2,
110                     const FeatureKeypoints& points1,
111                     const FeatureKeypoints& points2,
112                     const FeatureMatches& matches,
113                     const QColor& keypoints_color) {
114   QPixmap image = ShowImagesSideBySide(image1, image2);
115 
116   QPainter painter(&image);
117   painter.setRenderHint(QPainter::Antialiasing);
118 
119   // Draw keypoints
120 
121   const int pen_width = std::max(image.width(), image.height()) / 2048 + 1;
122   const int radius = 3 * pen_width + (3 * pen_width) % 2;
123   const float radius2 = radius / 2.0f;
124 
125   QPen pen;
126   pen.setWidth(pen_width);
127   pen.setColor(keypoints_color);
128   painter.setPen(pen);
129 
130   for (const auto& point : points1) {
131     painter.drawEllipse(point.x - radius2, point.y - radius2, radius, radius);
132   }
133   for (const auto& point : points2) {
134     painter.drawEllipse(image1.width() + point.x - radius2, point.y - radius2,
135                         radius, radius);
136   }
137 
138   // Draw matches
139 
140   pen.setWidth(std::max(pen_width / 2, 1));
141 
142   for (const auto& match : matches) {
143     const point2D_t idx1 = match.point2D_idx1;
144     const point2D_t idx2 = match.point2D_idx2;
145     pen.setColor(QColor(0, 255, 0));
146     painter.setPen(pen);
147     painter.drawLine(QPoint(points1[idx1].x, points1[idx1].y),
148                      QPoint(image1.width() + points2[idx2].x, points2[idx2].y));
149   }
150 
151   return image;
152 }
153 
154 }  // namespace colmap
155