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
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)
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.
virtual bool addChild(ccHObject *child, int dependencyFlags=DP_PARENT_OF_OTHER, int insertIndex=-1)
Adds a child.
ccHObject * getParent() const
Returns parent object.
Definition: ecvHObject.h:245
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 setGlobalScale(double scale)
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 double getGlobalScale() const
Returns the scale applied to original coordinates.
virtual QWidget * getActiveWindow()=0
constexpr Rgb red(MAX, 0, 0)
PCL filter description.
Definition: BasePclModule.h:26