rosbag_editor.cpp
Go to the documentation of this file.
1 #include "rosbag_editor.h"
2 #include "ui_rosbag_editor.h"
3 
5 #include <tf/tfMessage.h>
6 #include <tf2_msgs/TFMessage.h>
7 
8 #include <QDir>
9 #include <QString>
10 #include <QFileDialog>
11 #include <QDateTime>
12 #include <QSettings>
13 #include <QFont>
14 #include <QDateTimeEdit>
15 #include <QMessageBox>
16 #include <QItemSelectionModel>
17 #include <QPushButton>
18 #include <QListWidget>
19 #include <QStatusBar>
20 #include <QFileInfo>
21 #include <QLineEdit>
22 #include <QCheckBox>
23 #include <QProgressDialog>
24 #include "filter_frames.h"
25 
26 RosbagEditor::RosbagEditor(QWidget *parent) :
27  QMainWindow(parent),
28  ui(new Ui::RosbagEditor)
29 {
30  QApplication::setWindowIcon(QIcon("://rosbag_editor.png"));
31  ui->setupUi(this);
32 
33  QSettings settings("DavideFaconti", "rosbag_editor");
34  _previous_load_path = settings.value("RosbagEditor/prevLoadPath", QDir::currentPath()).toString();
35  _previous_save_path = settings.value("RosbagEditor/prevSavePath", _previous_load_path).toString();
36 
37  ui->radioNoCompression->setChecked(true);
38 
39  restoreGeometry(settings.value("RosbagEditor/geometry").toByteArray());
40  restoreState(settings.value("RosbagEditor/windowState").toByteArray());
41 }
42 
43 void RosbagEditor::closeEvent(QCloseEvent *event)
44 {
45  QSettings settings("DavideFaconti", "rosbag_editor");
46  settings.setValue("RosbagEditor/geometry", saveGeometry());
47  settings.setValue("RosbagEditor/windowState", saveState());
48  QMainWindow::closeEvent(event);
49 }
50 
52 {
53  delete ui;
54 }
55 
57 {
58  QString filename = QFileDialog::getOpenFileName(this,
59  tr("Open Rosbag"), _previous_load_path, tr("Rosbag Files (*.bag)"));
60 
61  if( filename.isEmpty())
62  {
63  return;
64  }
65 
66  try{
67  ui->tableWidgetInput->setRowCount(0);
68  ui->tableWidgetOutput->setRowCount(0);
69  _bag.close();
70  _bag.open( filename.toStdString() );
71  }
72  catch( rosbag::BagException& ex)
73  {
74  QMessageBox::warning(this, "Error opening the rosbag",
75  tr("rosbag::open thrown an exception: %1\n").arg( ex.what()) );
76  return;
77  }
78 
79  QSettings settings;
80  settings.setValue("RosbagEditor/prevLoadPath", QFileInfo(filename).absolutePath() );
81 
82  ui->statusbar->showMessage( tr("File loaded: %1").arg(filename));
83 
84  _loade_filename = filename;
85 
86  rosbag::View bag_view ( _bag );
87  auto connections = bag_view.getConnections();
88 
89  QDateTime datetime_begin = QDateTime::fromMSecsSinceEpoch( bag_view.getBeginTime().toSec()*1000 );
90  ui->dateTimeInputBegin->setDateTime(datetime_begin);
91 
92  QDateTime datetime_end = QDateTime::fromMSecsSinceEpoch( bag_view.getEndTime().toSec()*1000 );
93  ui->dateTimeInputEnd->setDateTime(datetime_end);
94 
95 
96  std::map<QString,QString> connections_ordered;
97 
98  for(std::size_t i = 0; i < connections.size(); i++ )
99  {
100  const rosbag::ConnectionInfo* connection = connections[i];
101  connections_ordered.insert( std::make_pair(QString::fromStdString(connection->topic),
102  QString::fromStdString(connection->datatype) ) );
103  }
104 
105  ui->tableWidgetInput->setRowCount(connections_ordered.size());
106  ui->tableWidgetInput->setColumnCount(2);
107  ui->tableWidgetInput->setEnabled(true);
108 
109  int row = 0;
110  for(const auto conn: connections_ordered )
111  {
112  auto type_item = new QTableWidgetItem( conn.second );
113  QFont font = type_item->font();
114  font.setPointSize(8);
115  font.setItalic(true);
116  type_item->setFont(font);
117 
118  ui->tableWidgetInput->setItem(row, 0, new QTableWidgetItem( conn.first ) );
119  ui->tableWidgetInput->setItem(row, 1, type_item);
120  row++;
121  }
123 }
124 
126 {
127  ui->pushButtonMove->setEnabled( ui->tableWidgetInput->selectionModel()->selectedRows().count() > 0 );
128  bool output = (ui->tableWidgetInput->rowCount() > 0);
129  ui->tableWidgetOutput->setEnabled( output );
130  ui->dateTimeOutputBegin->setEnabled( output );
131  ui->dateTimeOutputEnd->setEnabled( output );
132  ui->pushButtonSave->setEnabled( output );
133 
134  bool contains_tf = !ui->tableWidgetInput->findItems( "/tf", Qt::MatchExactly ).empty();
135  ui->pushButtonFilterTF->setEnabled( ui->checkBoxFilterTF->isChecked() && contains_tf );
136 }
137 
139 {
140  QModelIndexList selected_input = ui->tableWidgetInput->selectionModel()->selectedRows();
141  if( selected_input.count() == 0)
142  {
143  return;
144  }
145 
146  for(int i=0; i < selected_input.count(); i++)
147  {
148  QModelIndex index = selected_input.at(i);
149  QTableWidgetItem* item = ui->tableWidgetInput->item( index.row(), 0);
150  QString topic_name = item->text();
151 
152  if( ui->tableWidgetOutput->findItems( topic_name, Qt::MatchExactly ).isEmpty() )
153  {
154  int row = ui->tableWidgetOutput->rowCount();
155  ui->tableWidgetOutput->setRowCount(row+1);
156  ui->tableWidgetOutput->setItem(row, 0, new QTableWidgetItem(topic_name) );
157  QLineEdit* topic_editor = new QLineEdit(ui->tableWidgetOutput);
158  ui->tableWidgetOutput->setCellWidget(row, 1, topic_editor);
159  }
160  }
161 
162  ui->tableWidgetInput->selectionModel()->clearSelection();
163 
164  ui->pushButtonSave->setEnabled( ui->tableWidgetOutput->rowCount() );
165 
166  ui->dateTimeOutputBegin->setDateTimeRange(ui->dateTimeInputBegin->dateTime(),
167  ui->dateTimeInputEnd->dateTime() );
168  ui->dateTimeOutputBegin->setDateTime(ui->dateTimeInputBegin->dateTime());
169 
170  ui->dateTimeOutputEnd->setDateTimeRange(ui->dateTimeInputBegin->dateTime(),
171  ui->dateTimeInputEnd->dateTime() );
172  ui->dateTimeOutputEnd->setDateTime(ui->dateTimeInputEnd->dateTime());
173 
175 }
176 
178 {
179  QItemSelectionModel *select = ui->tableWidgetInput->selectionModel();
180  ui->pushButtonMove->setEnabled( select->hasSelection() );
181 }
182 
184 {
185  QItemSelectionModel *select = ui->tableWidgetOutput->selectionModel();
186  ui->pushButtonRemove->setEnabled( select->hasSelection() );
187 }
188 
190 {
191  QModelIndexList indexes;
192  while((indexes = ui->tableWidgetOutput->selectionModel()->selectedIndexes()).size())
193  {
194  ui->tableWidgetOutput->model()->removeRow(indexes.first().row());
195  }
196 
197  ui->tableWidgetOutput->sortItems(0);
198 
200 }
201 
203 {
204  QString filename = QFileDialog::getSaveFileName(this, "Save Rosbag",
206  tr("Rosbag Files (*.bag)"));
207  if( filename.isEmpty())
208  {
209  return;
210  }
211  if (QFileInfo(filename).suffix() != "bag")
212  {
213  filename.append(".bag");
214  }
215 
216  if( filename == _loade_filename)
217  {
218  QMessageBox::warning(this, "Wrong file name",
219  "You can not overwrite the input file. Choose another name or directory.",
220  QMessageBox::Ok);
221  return;
222  }
223 
224  QSettings settings;
225  settings.setValue("RosbagEditor/prevSavePath", QFileInfo(filename).absolutePath() );
226 
227  rosbag::Bag out_bag;
228 
229  out_bag.open(filename.toStdString(), rosbag::bagmode::Write);
230 
231  if( ui->radioNoCompression->isChecked()){
232  out_bag.setCompression( rosbag::CompressionType::Uncompressed );
233  }
234  else if( ui->radioLZ4->isChecked()){
235  out_bag.setCompression( rosbag::CompressionType::LZ4 );
236  }
237  else if( ui->radioBZ2->isChecked()){
238  out_bag.setCompression( rosbag::CompressionType::BZ2 );
239  }
240 
241  std::vector<std::string> input_topics;
242  std::map<std::string,std::string> topis_renamed;
243 
244  for(int row = 0; row < ui->tableWidgetOutput->rowCount(); ++row)
245  {
246  std::string name = ui->tableWidgetOutput->item(row,0)->text().toStdString();
247  QLineEdit* line_edit = qobject_cast<QLineEdit*>(ui->tableWidgetOutput->cellWidget(row, 1));
248  std::string renamed = line_edit->text().toStdString();
249  input_topics.push_back( name );
250  if( renamed.empty())
251  {
252  topis_renamed.insert( std::make_pair(name,name));
253  }
254  else{
255  topis_renamed.insert( std::make_pair(name,renamed));
256  }
257  }
258 
259  double begin_time = std::floor(-0.001 + 0.001*static_cast<double>(ui->dateTimeOutputBegin->dateTime().toMSecsSinceEpoch()));
260  double end_time = std::ceil( 0.001 + 0.001*static_cast<double>(ui->dateTimeOutputEnd->dateTime().toMSecsSinceEpoch()));
261 
262 
263  rosbag::View bag_view( _bag, rosbag::TopicQuery(input_topics),
264  ros::Time( begin_time ), ros::Time( end_time ) );
265 
266  QProgressDialog progress_dialog;
267  progress_dialog.setLabelText("Loading... please wait");
268  progress_dialog.setWindowModality( Qt::ApplicationModal );
269  progress_dialog.show();
270 
271  int msg_count = 0;
272  progress_dialog.setRange(0, bag_view.size()-1);
273 
274  bool do_tf_filtering = _filtered_frames.size() > 0 && ui->checkBoxFilterTF->isChecked();
275 
276  for(const rosbag::MessageInstance& msg: bag_view)
277  {
278  if( msg_count++ %100 == 0)
279  {
280  progress_dialog.setValue( msg_count );
281  QApplication::processEvents();
282  }
283 
284  const auto& name = topis_renamed.find(msg.getTopic())->second;
285 
286  auto removeTransform = [&](std::vector<geometry_msgs::TransformStamped>& transforms)
287  {
288  for (int i=0; i < transforms.size(); i++)
289  {
290  auto frame = std::make_pair(transforms[i].header.frame_id,
291  transforms[i].child_frame_id);
292  if( _filtered_frames.count(frame) )
293  {
294  transforms.erase( transforms.begin() + i );
295  i--;
296  }
297  }
298  };
299 
300 
301  if( msg.getTopic() == "/tf" && do_tf_filtering )
302  {
303  tf::tfMessage::Ptr tf = msg.instantiate<tf::tfMessage>();
304  if (tf)
305  {
306  removeTransform(tf->transforms);
307  out_bag.write( name, msg.getTime(), tf, msg.getConnectionHeader());
308  }
309 
310  tf2_msgs::TFMessage::Ptr tf2 = msg.instantiate<tf2_msgs::TFMessage>();
311  if (tf2)
312  {
313  removeTransform(tf2->transforms);
314  out_bag.write( name, msg.getTime(), tf2, msg.getConnectionHeader());
315  }
316  }
317  else{
318  out_bag.write( name, msg.getTime(), msg, msg.getConnectionHeader());
319  }
320  }
321  out_bag.close();
322 
323  int ret = QMessageBox::question(this, "Done", "New robag succesfully created. Do you want to close the application?",
324  QMessageBox::Cancel | QMessageBox::Close, QMessageBox::Close );
325  if( ret == QMessageBox::Close )
326  {
327  this->close();
328  }
329 }
330 
332 {
333  if( ui->dateTimeOutputBegin->dateTime() > dateTime )
334  {
335  ui->dateTimeOutputBegin->setDateTime( dateTime );
336  }
337 }
338 
340 {
341  if( ui->dateTimeOutputEnd->dateTime() < dateTime )
342  {
343  ui->dateTimeOutputEnd->setDateTime( dateTime );
344  }
345 }
346 
348 {
349  bool contains_tf = !ui->tableWidgetInput->findItems( "/tf", Qt::MatchExactly ).empty();
350  ui->pushButtonFilterTF->setEnabled( checked && contains_tf );
351 }
352 
354 {
355  FilterFrames dialog(_bag, _filtered_frames, this);
356  dialog.exec();
357 
358 }
filename
void on_tableWidgetInput_itemSelectionChanged()
void on_tableWidgetOutput_itemSelectionChanged()
std::vector< const ConnectionInfo * > getConnections()
void open(std::string const &filename, uint32_t mode=bagmode::Read)
rosbag::Bag _bag
Definition: rosbag_editor.h:52
void on_pushButtonLoad_pressed()
QString _previous_load_path
Definition: rosbag_editor.h:50
void on_dateTimeOutputEnd_dateTimeChanged(const QDateTime &dateTime)
void on_dateTimeOutputBegin_dateTimeChanged(const QDateTime &dateTime)
void on_pushButtonMove_pressed()
QString _previous_save_path
Definition: rosbag_editor.h:51
void close()
std::set< std::pair< std::string, std::string > > _filtered_frames
Definition: rosbag_editor.h:53
uint32_t size()
void closeEvent(QCloseEvent *event)
ros::Time getBeginTime()
void setCompression(CompressionType compression)
void on_checkBoxFilterTF_toggled(bool checked)
void on_pushButtonFilterTF_pressed()
void changeEnabledWidgets()
void on_pushButtonRemove_pressed()
Ui::RosbagEditor * ui
Definition: rosbag_editor.h:48
ros::Time getEndTime()
QString _loade_filename
Definition: rosbag_editor.h:49
RosbagEditor(QWidget *parent=nullptr)
void write(std::string const &topic, ros::MessageEvent< T > const &event)
void on_pushButtonSave_pressed()


rosbag_editor
Author(s):
autogenerated on Fri Jan 22 2021 03:48:11