ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
ExtractSIFT.cpp
Go to the documentation of this file.
1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
7 
8 #include "ExtractSIFT.h"
9 
10 // LOCAL
11 #include <Utils/cc2sm.h>
12 #include <Utils/sm2cc.h>
13 
14 #include "PclUtils/PCLModules.h"
15 #include "dialogs/SIFTExtractDlg.h"
16 
17 // CV_DB_LIB
18 #include <ecvPointCloud.h>
19 
20 // ECV_PLUGINS
21 #include <ecvMainAppInterface.h>
22 
23 // QT
24 #include <QMainWindow>
25 
26 // SYSTEM
27 #include <iostream>
28 
30  : BasePclModule(
31  PclModuleDescription(tr("Extract SIFT"),
32  tr("Extract SIFT Keypoints"),
33  tr("Extract SIFT keypoints for clouds with "
34  "intensity/RGB or any scalar field"),
35  ":/toolbar/PclAlgorithms/icons/sift.png")),
36  m_dialog(nullptr),
37  m_nr_octaves(0),
38  m_min_scale(0),
39  m_nr_scales_per_octave(0),
40  m_min_contrast(0),
41  m_use_min_contrast(false),
42  m_mode(RGB) {}
43 
45  // we must delete parent-less dialogs ourselves!
46  if (m_dialog && m_dialog->parent() == nullptr) delete m_dialog;
47 }
48 
50  // do we have a selected cloud?
51  int have_cloud = isFirstSelectedCcPointCloud();
52  if (have_cloud != 1) return -11;
53 
54  // do we have at least a scalar field?
55  int have_sf = hasSelectedScalarField();
56  if (have_sf == 1) return 1;
57 
58  // also having rgb data will be enough
59  if (hasSelectedRGB() != 0) return 1;
60 
61  return -51;
62 }
63 
65  // do we have scalar fields?
66  std::vector<std::string> fields = getSelectedAvailableScalarFields();
67 
68  // do we have rgb fields?
69  if (hasSelectedRGB() == 1) {
70  // add rgb field
71  fields.push_back("rgb");
72  }
73 
74  if (fields.empty()) // fields?
75  return -51;
76 
77  // initialize the dialog object
78  if (!m_dialog)
79  m_dialog =
80  new SIFTExtractDlg(m_app ? m_app->getActiveWindow() : nullptr);
81 
82  // update the combo box
84 
85  if (!m_dialog->exec()) return 0;
86 
87  return 1;
88 }
89 
91  if (!m_dialog) return;
92 
93  // get the parameters from the dialog
94  m_nr_octaves = m_dialog->nrOctaves->value();
95  m_min_scale = static_cast<float>(m_dialog->minScale->value());
96  m_nr_scales_per_octave = m_dialog->scalesPerOctave->value();
97  m_use_min_contrast = m_dialog->useMinContrast->checkState();
100  ? static_cast<float>(m_dialog->minContrast->value())
101  : 0;
102  m_field_to_use = m_dialog->intensityCombo->currentText();
103 
104  if (m_field_to_use == "rgb") {
105  m_mode = RGB;
106  } else {
108  }
109 
110  QString fieldname(m_field_to_use);
111  fieldname.replace(' ', '_');
113  qPrintable(fieldname); // DGM: warning, toStdString doesn't
114  // preserve "local" characters
115 }
116 
118  if ((m_nr_octaves > 0) && (m_min_scale > 0) &&
119  (m_nr_scales_per_octave > 0)) {
120  if (m_use_min_contrast) {
121  if (m_min_contrast > 0) {
122  return 1;
123  } else {
124  return -52;
125  }
126  } else {
127  return 1;
128  }
129  } else {
130  return -52;
131  }
132 }
133 
136  if (!cloud) return -1;
137 
138  std::list<std::string> req_fields;
139  try {
140  req_fields.push_back("xyz"); // always needed
141  switch (m_mode) {
142  case RGB:
143  req_fields.push_back("rgb");
144  break;
145  case SCALAR_FIELD:
146  req_fields.push_back(qPrintable(
147  m_field_to_use)); // DGM: warning, toStdString doesn't
148  // preserve "local" characters
149  break;
150  default:
151  assert(false);
152  break;
153  }
154  } catch (const std::bad_alloc&) {
155  // not enough memory
156  return -1;
157  }
158 
159  PCLCloud::Ptr sm_cloud = cc2smReader(cloud).getAsSM(req_fields);
160  if (!sm_cloud) return -1;
161 
162  // Now change the name of the field to use to a standard name, only if in
163  // OTHER_FIELD mode
164  if (m_mode == SCALAR_FIELD) {
165  int field_index =
166  pcl::getFieldIndex(*sm_cloud, m_field_to_use_no_space);
167  sm_cloud->fields.at(field_index).name =
168  "intensity"; // we always use intensity as name... even if it
169  // is curvature or another field.
170  }
171 
172  // initialize all possible clouds
173  pcl::PointCloud<pcl::PointXYZ>::Ptr out_cloud(
174  new pcl::PointCloud<pcl::PointXYZ>);
175 
176  // Now do the actual computation
177  if (m_mode == SCALAR_FIELD) {
178  pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_i(
179  new pcl::PointCloud<pcl::PointXYZI>);
180  FROM_PCL_CLOUD(*sm_cloud, *cloud_i);
181  PCLModules::EstimateSIFT<pcl::PointXYZI, pcl::PointXYZ>(
182  cloud_i, out_cloud, m_nr_octaves, m_min_scale,
184  } else if (m_mode == RGB) {
185  pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_rgb(
186  new pcl::PointCloud<pcl::PointXYZRGB>);
187  FROM_PCL_CLOUD(*sm_cloud, *cloud_rgb);
188  PCLModules::EstimateSIFT<pcl::PointXYZRGB, pcl::PointXYZ>(
189  cloud_rgb, out_cloud, m_nr_octaves, m_min_scale,
191  }
192 
193  PCLCloud out_cloud_sm;
194  TO_PCL_CLOUD(*out_cloud, out_cloud_sm);
195 
196  if (out_cloud_sm.height * out_cloud_sm.width == 0) {
197  // cloud is empty
198  return -53;
199  }
200 
201  ccPointCloud* out_cloud_cc = pcl2cc::Convert(out_cloud_sm);
202  if (!out_cloud_cc) {
203  // conversion failed (not enough memory?)
204  return -1;
205  }
206 
207  QString name;
208  if (m_mode == RGB)
209  name = tr("SIFT Keypoints_%1_rgb_%2_%3_%4")
210  .arg(m_nr_octaves)
211  .arg(m_min_scale)
213  .arg(m_min_contrast);
214  else
215  name = tr("SIFT Keypoints_%1_%2_%3_%4_%5")
216  .arg(m_nr_octaves)
217  .arg(m_field_to_use_no_space.c_str())
218  .arg(m_min_scale)
220  .arg(m_min_contrast);
221 
222  out_cloud_cc->setName(name);
223  out_cloud_cc->setRGBColor(ecvColor::red);
224  out_cloud_cc->showColors(true);
225  out_cloud_cc->showSF(false);
226  out_cloud_cc->setPointSize(5);
227 
228  // copy global shift & scale
229  out_cloud_cc->setGlobalScale(cloud->getGlobalScale());
230  out_cloud_cc->setGlobalShift(cloud->getGlobalShift());
231 
232  if (cloud->getParent()) cloud->getParent()->addChild(out_cloud_cc);
233 
234  emit newEntity(out_cloud_cc);
235 
236  return 1;
237 }
238 
239 QString ExtractSIFT::getErrorMessage(int errorCode) {
240  switch (errorCode) {
241  // THESE CASES CAN BE USED TO OVERRIDE OR ADD FILTER-SPECIFIC ERRORS
242  // CODES ALSO IN DERIVED CLASSES DEFULAT MUST BE ""
243 
244  case -51:
245  return "Selected entity does not have any suitable scalar field or "
246  "RGB. Intensity scalar field or RGB are needed for "
247  "computing SIFT";
248  case -52:
249  return "Wrong Parameters. One or more parameters cannot be "
250  "accepted";
251  case -53:
252  return "SIFT keypoint extraction does not returned any point. Try "
253  "relaxing your parameters";
254  default:
255  // see below
256  break;
257  }
258 
259  return BasePclModule::getErrorMessage(errorCode);
260 }
std::vector< PCLPointField > fields
std::string name
pcl::PCLPointCloud2 PCLCloud
Definition: PCLCloud.h:34
#define TO_PCL_CLOUD
Definition: PCLConv.h:12
#define FROM_PCL_CLOUD
Definition: PCLConv.h:11
Base abstract class for each implemented PCL filter.
Definition: BasePclModule.h:53
std::vector< std::string > getSelectedAvailableScalarFields()
int hasSelectedRGB()
Returns 1 if the first selected entity has RGB info.
int isFirstSelectedCcPointCloud()
Returns 1 if the first selected object is a ccPointCloud.
void newEntity(ccHObject *)
Signal emitted when a new entity is created by the filter.
ecvMainAppInterface * m_app
Associated application interface.
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
int hasSelectedScalarField()
Returns 1 if the first selected entity has at least one scalar field.
ccPointCloud * getSelectedEntityAsCCPointCloud() const
Returns the first selected entity as a ccPointCloud.
virtual int checkSelected()
Checks if current selection is compliant with the filter.
Definition: ExtractSIFT.cpp:49
virtual int openInputDialog()
Definition: ExtractSIFT.cpp:64
float m_min_scale
Definition: ExtractSIFT.h:36
Modes m_mode
Definition: ExtractSIFT.h:44
int m_nr_scales_per_octave
Definition: ExtractSIFT.h:37
SIFTExtractDlg * m_dialog
Definition: ExtractSIFT.h:34
int m_nr_octaves
Definition: ExtractSIFT.h:35
float m_min_contrast
Definition: ExtractSIFT.h:38
virtual ~ExtractSIFT()
Definition: ExtractSIFT.cpp:44
std::string m_field_to_use_no_space
Definition: ExtractSIFT.h:41
bool m_use_min_contrast
Definition: ExtractSIFT.h:39
virtual void getParametersFromDialog()
Collects parameters from the filter dialog (if openDialog is successful)
Definition: ExtractSIFT.cpp:90
virtual int compute()
Performs the actual filter job.
virtual int checkParameters()
virtual QString getErrorMessage(int errorCode)
Returns the error message corresponding to a given error code.
QString m_field_to_use
Definition: ExtractSIFT.h:40
void updateComboBox(const std::vector< std::string > &fields)
CC to PCL cloud converter.
Definition: cc2sm.h:43
PCLCloud::Ptr getAsSM(std::list< std::string > &requested_fields) const
Definition: cc2sm.cpp:607
virtual void showColors(bool state)
Sets colors visibility.
virtual void showSF(bool state)
Sets active scalarfield visibility.
void setPointSize(unsigned size=0)
Sets point size.
ccHObject * getParent() const
Returns parent object.
Definition: ecvHObject.h:245
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
Definition: ecvHObject.cpp:534
virtual void setName(const QString &name)
Sets object name.
Definition: ecvObject.h:75
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
bool setRGBColor(ColorCompType r, ColorCompType g, ColorCompType b)
Set a unique color for the whole cloud (shortcut)
virtual void setGlobalShift(double x, double y, double z)
Sets shift applied to original coordinates (information storage only)
virtual const CCVector3d & getGlobalShift() const
Returns the shift applied to original coordinates.
virtual void setGlobalScale(double scale)
virtual double getGlobalScale() const
Returns the scale applied to original coordinates.
virtual QWidget * getActiveWindow()=0
static ccMesh * Convert(PCLTextureMesh::ConstPtr textureMesh)
Converts a PCL point cloud to a ccPointCloud.
constexpr Rgb red(MAX, 0, 0)
PCL filter description.
Definition: BasePclModule.h:26