Article directory
1. Preface
Haha, when I came up with this small tool, on the one hand, the commonly used point cloud viewing software was not in line with my own operating habits. On the other hand, it was more convenient to do some simple point cloud processing test verification on the button. Previous blog < Point Cloud Visualization Tools > A csdner asked about the tutorial on point cloud visualization tools. Let’s find time to update it today on Sunday.=D
2. Development environment
2.1 QT + PCL
- The program interface is written using Qt, mainly some buttons and appearance adjustments
- Point cloud processing mainly relies on the PCL point cloud library
- For information about the installation and environment configuration of qt and pcl, please refer to < QT Configuration PCL1.8.1 >
- If you don’t want to recompile the pcl vtk library used by Qt, you can use the same version and already compiled library as me.
3. Procedure
3.1 New project
3.2 Modify .pro file
- The original .pro file looks like this. Add the header file directory and dependent library files below.
3.2.1 Add header file directory
INCLUDEPATH += 头文件目录路径
- You can add pcl, opencv and other libraries that will be used (replace the path with your own installation path)
INCLUDEPATH += D:\PCL\PCL1.8.1\include\pcl-1.8
INCLUDEPATH += D:\PCL\PCL1.8.1\include\pcl-1.8\pcl
INCLUDEPATH += D:\PCL\PCL1.8.1\3rdParty\Boost\include\boost-1_64
INCLUDEPATH += D:\PCL\PCL1.8.1\3rdParty\Boost\include\boost-1_64\boost
INCLUDEPATH += D:\PCL\PCL1.8.1\3rdParty\Eigen\eigen3
INCLUDEPATH += D:\PCL\PCL1.8.1\3rdParty\FLANN\include
INCLUDEPATH += D:\PCL\PCL1.8.1\3rdParty\FLANN\include\flann
INCLUDEPATH += D:\PCL\PCL1.8.1\3rdParty\OpenNI2\Include
INCLUDEPATH += D:\PCL\PCL1.8.1\3rdParty\Qhull\include
INCLUDEPATH += D:\PCL\PCL1.8.1\3rdParty\VTK1\include\vtk-8.0
INCLUDEPATH += D:\OpenCV\opencv\build\include
INCLUDEPATH += D:\pthread\Pre-built.2\include
INCLUDEPATH += D:\log4cpp\include
3.2.2 Add dependent library files
LIBS += -L lib文件目录路径
-l lib文件名
CONFIG(debug,debug|release){
LIBS += -LD:\PCL\PCL1.8.1\lib\
-lpcl_common_debug\
-lpcl_features_debug\
-lpcl_filters_debug\
-lpcl_io_debug\
-lpcl_io_ply_debug\
-lpcl_kdtree_debug\
-lpcl_keypoints_debug\
-lpcl_ml_debug\
-lpcl_octree_debug\
-lpcl_outofcore_debug\
-lpcl_people_debug\
-lpcl_recognition_debug\
-lpcl_registration_debug\
-lpcl_sample_consensus_debug\
-lpcl_search_debug\
-lpcl_segmentation_debug\
-lpcl_stereo_debug\
-lpcl_surface_debug\
-lpcl_tracking_debug\
-lpcl_visualization_debug
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\Boost\lib\
-llibboost_atomic-vc141-mt-1_64\
-llibboost_bzip2-vc141-mt-1_64\
-llibboost_chrono-vc141-mt-1_64\
-llibboost_container-vc141-mt-1_64\
-llibboost_context-vc141-mt-1_64\
-llibboost_coroutine-vc141-mt-1_64\
-llibboost_date_time-vc141-mt-1_64\
-llibboost_exception-vc141-mt-1_64\
-llibboost_fiber-vc141-mt-1_64\
-llibboost_filesystem-vc141-mt-1_64\
-llibboost_graph-vc141-mt-1_64\
-llibboost_graph_parallel-vc141-mt-1_64\
-llibboost_iostreams-vc141-mt-1_64\
-llibboost_locale-vc141-mt-1_64\
-llibboost_log-vc141-mt-1_64\
-llibboost_log_setup-vc141-mt-1_64\
-llibboost_math_c99-vc141-mt-1_64\
-llibboost_math_c99f-vc141-mt-1_64\
-llibboost_math_c99l-vc141-mt-1_64\
-llibboost_math_tr1-vc141-mt-1_64\
-llibboost_math_tr1f-vc141-mt-1_64\
-llibboost_math_tr1l-vc141-mt-1_64\
-llibboost_mpi-vc141-mt-1_64\
-llibboost_numpy-vc141-mt-1_64\
-llibboost_numpy3-vc141-mt-1_64\
-llibboost_prg_exec_monitor-vc141-mt-1_64\
-llibboost_program_options-vc141-mt-1_64\
-llibboost_python-vc141-mt-1_64\
-llibboost_python3-vc141-mt-1_64\
-llibboost_random-vc141-mt-1_64\
-llibboost_regex-vc141-mt-1_64\
-llibboost_serialization-vc141-mt-1_64\
-llibboost_signals-vc141-mt-1_64\
-llibboost_system-vc141-mt-1_64\
-llibboost_test_exec_monitor-vc141-mt-1_64\
-llibboost_thread-vc141-mt-1_64\
-llibboost_timer-vc141-mt-1_64\
-llibboost_type_erasure-vc141-mt-1_64\
-llibboost_unit_test_framework-vc141-mt-1_64\
-llibboost_wave-vc141-mt-1_64\
-llibboost_wserialization-vc141-mt-1_64\
-llibboost_zlib-vc141-mt-1_64
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\FLANN\lib\
-lflann\
-lflann_cpp\
-lflann_cpp_s\
-lflann_s
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\OpenNI2\Lib\
-lOpenNI2
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\Qhull\lib\
-lqhull_d\
-lqhullcpp_d\
-lqhullstatic_d\
-lqhullstatic_r_d\
-lqhull_p_d\
-lqhull_r_d
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\VTK1\lib\
-lvtkalglib-8.0-gd\
-lvtkChartsCore-8.0-gd\
-lvtkCommonColor-8.0-gd\
-lvtkCommonComputationalGeometry-8.0-gd\
-lvtkCommonCore-8.0-gd\
-lvtkCommonDataModel-8.0-gd\
-lvtkCommonExecutionModel-8.0-gd\
-lvtkCommonMath-8.0-gd\
-lvtkCommonMisc-8.0-gd\
-lvtkCommonSystem-8.0-gd\
-lvtkCommonTransforms-8.0-gd\
-lvtkDICOMParser-8.0-gd\
-lvtkDomainsChemistry-8.0-gd\
-lvtkexoIIc-8.0-gd\
-lvtkexpat-8.0-gd\
-lvtkFiltersAMR-8.0-gd\
-lvtkFiltersCore-8.0-gd\
-lvtkFiltersExtraction-8.0-gd\
-lvtkFiltersFlowPaths-8.0-gd\
-lvtkFiltersGeneral-8.0-gd\
-lvtkFiltersGeneric-8.0-gd\
-lvtkFiltersGeometry-8.0-gd\
-lvtkFiltersHybrid-8.0-gd\
-lvtkFiltersHyperTree-8.0-gd\
-lvtkFiltersImaging-8.0-gd\
-lvtkFiltersModeling-8.0-gd\
-lvtkFiltersParallel-8.0-gd\
-lvtkFiltersParallelImaging-8.0-gd\
-lvtkFiltersPoints-8.0-gd\
-lvtkFiltersProgrammable-8.0-gd\
-lvtkFiltersSelection-8.0-gd\
-lvtkFiltersSMP-8.0-gd\
-lvtkFiltersSources-8.0-gd\
-lvtkFiltersStatistics-8.0-gd\
-lvtkFiltersTexture-8.0-gd\
-lvtkFiltersTopology-8.0-gd\
-lvtkFiltersVerdict-8.0-gd\
-lvtkfreetype-8.0-gd\
-lvtkGeovisCore-8.0-gd\
-lvtkgl2ps-8.0-gd\
-lvtkGUISupportQt-8.0-gd\
# -lvtkGUISupportQtOpenGL-8.0-gd\
-lvtkGUISupportQtSQL-8.0-gd\
-lvtkhdf5-8.0-gd\
-lvtkhdf5_hl-8.0-gd\
-lvtkImagingColor-8.0-gd\
-lvtkImagingCore-8.0-gd\
-lvtkImagingFourier-8.0-gd\
-lvtkImagingGeneral-8.0-gd\
-lvtkImagingHybrid-8.0-gd\
-lvtkImagingMath-8.0-gd\
-lvtkImagingMorphological-8.0-gd\
-lvtkImagingSources-8.0-gd\
-lvtkImagingStatistics-8.0-gd\
-lvtkImagingStencil-8.0-gd\
-lvtkInfovisCore-8.0-gd\
-lvtkInfovisLayout-8.0-gd\
-lvtkInteractionImage-8.0-gd\
-lvtkInteractionStyle-8.0-gd\
-lvtkInteractionWidgets-8.0-gd\
-lvtkIOAMR-8.0-gd\
-lvtkIOCore-8.0-gd\
-lvtkIOEnSight-8.0-gd\
-lvtkIOExodus-8.0-gd\
-lvtkIOExport-8.0-gd\
-lvtkIOExportOpenGL-8.0-gd\
-lvtkIOGeometry-8.0-gd\
-lvtkIOImage-8.0-gd\
-lvtkIOImport-8.0-gd\
-lvtkIOInfovis-8.0-gd\
-lvtkIOLegacy-8.0-gd\
-lvtkIOLSDyna-8.0-gd\
-lvtkIOMINC-8.0-gd\
-lvtkIOMovie-8.0-gd\
-lvtkIONetCDF-8.0-gd\
-lvtkIOParallel-8.0-gd\
-lvtkIOParallelXML-8.0-gd\
-lvtkIOPLY-8.0-gd\
-lvtkIOSQL-8.0-gd\
-lvtkIOTecplotTable-8.0-gd\
-lvtkIOVideo-8.0-gd\
-lvtkIOXML-8.0-gd\
-lvtkIOXMLParser-8.0-gd\
-lvtkjpeg-8.0-gd\
-lvtkjsoncpp-8.0-gd\
-lvtklibharu-8.0-gd\
-lvtklibxml2-8.0-gd\
-lvtklz4-8.0-gd\
-lvtkmetaio-8.0-gd\
-lvtkNetCDF-8.0-gd\
-lvtknetcdf_c++-gd\
-lvtkoggtheora-8.0-gd\
-lvtkParallelCore-8.0-gd\
-lvtkpng-8.0-gd\
-lvtkproj4-8.0-gd\
-lvtkRenderingAnnotation-8.0-gd\
-lvtkRenderingContext2D-8.0-gd\
-lvtkRenderingContextOpenGL-8.0-gd\
-lvtkRenderingCore-8.0-gd\
-lvtkRenderingFreeType-8.0-gd\
-lvtkRenderingGL2PS-8.0-gd\
-lvtkRenderingImage-8.0-gd\
-lvtkRenderingLabel-8.0-gd\
-lvtkRenderingLIC-8.0-gd\
-lvtkRenderingLOD-8.0-gd\
-lvtkRenderingOpenGL-8.0-gd\
-lvtkRenderingQt-8.0-gd\
-lvtkRenderingVolume-8.0-gd\
-lvtkRenderingVolumeOpenGL-8.0-gd\
-lvtksqlite-8.0-gd\
-lvtksys-8.0-gd\
-lvtktiff-8.0-gd\
-lvtkverdict-8.0-gd\
-lvtkViewsContext2D-8.0-gd\
-lvtkViewsCore-8.0-gd\
-lvtkViewsInfovis-8.0-gd\
-lvtkViewsQt-8.0-gd\
-lvtkzlib-8.0-gd\
} else {
LIBS += -LD:\PCL\PCL1.8.1\lib\
-lpcl_common_release\
-lpcl_features_release\
-lpcl_filters_release\
-lpcl_io_ply_release\
-lpcl_io_release\
-lpcl_kdtree_release\
-lpcl_keypoints_release\
-lpcl_ml_release\
-lpcl_octree_release\
-lpcl_outofcore_release\
-lpcl_people_release\
-lpcl_recognition_release\
-lpcl_registration_release\
-lpcl_sample_consensus_release\
-lpcl_search_release\
-lpcl_segmentation_release\
-lpcl_stereo_release\
-lpcl_surface_release\
-lpcl_tracking_release\
-lpcl_visualization_release
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\Boost\lib\
-llibboost_atomic-vc141-mt-1_64\
-llibboost_bzip2-vc141-mt-1_64\
-llibboost_chrono-vc141-mt-1_64\
-llibboost_container-vc141-mt-1_64\
-llibboost_context-vc141-mt-1_64\
-llibboost_coroutine-vc141-mt-1_64\
-llibboost_date_time-vc141-mt-1_64\
-llibboost_exception-vc141-mt-1_64\
-llibboost_fiber-vc141-mt-1_64\
-llibboost_filesystem-vc141-mt-1_64\
-llibboost_graph-vc141-mt-1_64\
-llibboost_graph_parallel-vc141-mt-1_64\
-llibboost_iostreams-vc141-mt-1_64\
-llibboost_locale-vc141-mt-1_64\
-llibboost_log-vc141-mt-1_64\
-llibboost_log_setup-vc141-mt-1_64\
-llibboost_math_c99-vc141-mt-1_64\
-llibboost_math_c99f-vc141-mt-1_64\
-llibboost_math_c99l-vc141-mt-1_64\
-llibboost_math_tr1-vc141-mt-1_64\
-llibboost_math_tr1f-vc141-mt-1_64\
-llibboost_math_tr1l-vc141-mt-1_64\
-llibboost_mpi-vc141-mt-1_64\
-llibboost_numpy-vc141-mt-1_64\
-llibboost_numpy3-vc141-mt-1_64\
-llibboost_prg_exec_monitor-vc141-mt-1_64\
-llibboost_program_options-vc141-mt-1_64\
-llibboost_python-vc141-mt-1_64\
-llibboost_python3-vc141-mt-1_64\
-llibboost_random-vc141-mt-1_64\
-llibboost_regex-vc141-mt-1_64\
-llibboost_serialization-vc141-mt-1_64\
-llibboost_signals-vc141-mt-1_64\
-llibboost_system-vc141-mt-1_64\
-llibboost_test_exec_monitor-vc141-mt-1_64\
-llibboost_thread-vc141-mt-1_64\
-llibboost_timer-vc141-mt-1_64\
-llibboost_type_erasure-vc141-mt-1_64\
-llibboost_unit_test_framework-vc141-mt-1_64\
-llibboost_wave-vc141-mt-1_64\
-llibboost_wserialization-vc141-mt-1_64\
-llibboost_zlib-vc141-mt-1_64
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\FLANN\lib\
-lflann\
-lflann_cpp\
-lflann_cpp_s\
-lflann_s
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\OpenNI2\Lib\
-lOpenNI2
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\Qhull\lib\
-lqhull\
-lqhullcpp\
-lqhullstatic\
-lqhullstatic_r\
-lqhull_p\
-lqhull_r
LIBS += -LD:\PCL\PCL1.8.1\3rdParty\VTK1\lib\
-lvtkalglib-8.0\
-lvtkChartsCore-8.0\
-lvtkCommonColor-8.0\
-lvtkCommonComputationalGeometry-8.0\
-lvtkCommonCore-8.0\
-lvtkCommonDataModel-8.0\
-lvtkCommonExecutionModel-8.0\
-lvtkCommonMath-8.0\
-lvtkCommonMisc-8.0\
-lvtkCommonSystem-8.0\
-lvtkCommonTransforms-8.0\
-lvtkDICOMParser-8.0\
-lvtkDomainsChemistry-8.0\
-lvtkexoIIc-8.0\
-lvtkexpat-8.0\
-lvtkFiltersAMR-8.0\
-lvtkFiltersCore-8.0\
-lvtkFiltersExtraction-8.0\
-lvtkFiltersFlowPaths-8.0\
-lvtkFiltersGeneral-8.0\
-lvtkFiltersGeneric-8.0\
-lvtkFiltersGeometry-8.0\
-lvtkFiltersHybrid-8.0\
-lvtkFiltersHyperTree-8.0\
-lvtkFiltersImaging-8.0\
-lvtkFiltersModeling-8.0\
-lvtkFiltersParallel-8.0\
-lvtkFiltersParallelImaging-8.0\
-lvtkFiltersPoints-8.0\
-lvtkFiltersProgrammable-8.0\
-lvtkFiltersSelection-8.0\
-lvtkFiltersSMP-8.0\
-lvtkFiltersSources-8.0\
-lvtkFiltersStatistics-8.0\
-lvtkFiltersTexture-8.0\
-lvtkFiltersTopology-8.0\
-lvtkFiltersVerdict-8.0\
-lvtkfreetype-8.0\
-lvtkGeovisCore-8.0\
-lvtkgl2ps-8.0\
-lvtkGUISupportQt-8.0\
# -lvtkGUISupportQtOpenGL2-8.0\
-lvtkGUISupportQtSQL-8.0\
-lvtkhdf5-8.0\
-lvtkhdf5_hl-8.0\
-lvtkImagingColor-8.0\
-lvtkImagingCore-8.0\
-lvtkImagingFourier-8.0\
-lvtkImagingGeneral-8.0\
-lvtkImagingHybrid-8.0\
-lvtkImagingMath-8.0\
-lvtkImagingMorphological-8.0\
-lvtkImagingSources-8.0\
-lvtkImagingStatistics-8.0\
-lvtkImagingStencil-8.0\
-lvtkInfovisCore-8.0\
-lvtkInfovisLayout-8.0\
-lvtkInteractionImage-8.0\
-lvtkInteractionStyle-8.0\
-lvtkInteractionWidgets-8.0\
-lvtkIOAMR-8.0\
-lvtkIOCore-8.0\
-lvtkIOEnSight-8.0\
-lvtkIOExodus-8.0\
-lvtkIOExport-8.0\
-lvtkIOExportOpenGL-8.0\
-lvtkIOGeometry-8.0\
-lvtkIOImage-8.0\
-lvtkIOImport-8.0\
-lvtkIOInfovis-8.0\
-lvtkIOLegacy-8.0\
-lvtkIOLSDyna-8.0\
-lvtkIOMINC-8.0\
-lvtkIOMovie-8.0\
-lvtkIONetCDF-8.0\
-lvtkIOParallel-8.0\
-lvtkIOParallelXML-8.0\
-lvtkIOPLY-8.0\
-lvtkIOSQL-8.0\
-lvtkIOTecplotTable-8.0\
-lvtkIOVideo-8.0\
-lvtkIOXML-8.0\
-lvtkIOXMLParser-8.0\
-lvtkjpeg-8.0\
-lvtkjsoncpp-8.0\
-lvtklibharu-8.0\
-lvtklibxml2-8.0\
-lvtklz4-8.0\
-lvtkmetaio-8.0\
-lvtkNetCDF-8.0\
-lvtknetcdf_c++\
-lvtkoggtheora-8.0\
-lvtkParallelCore-8.0\
-lvtkpng-8.0\
-lvtkproj4-8.0\
-lvtkRenderingAnnotation-8.0\
-lvtkRenderingContext2D-8.0\
-lvtkRenderingContextOpenGL2-8.0\
-lvtkRenderingCore-8.0\
-lvtkRenderingFreeType-8.0\
-lvtkRenderingGL2PS-8.0\
-lvtkRenderingGL2PSOpenGL2-8.0\
-lvtkRenderingImage-8.0\
-lvtkRenderingLabel-8.0\
-lvtkRenderingLIC-8.0\
-lvtkRenderingLOD-8.0\
-lvtkRenderingOpenGL2-8.0\
-lvtkRenderingQt-8.0\
-lvtkRenderingVolume-8.0\
-lvtkRenderingVolumeOpenGL2-8.0\
-lvtksqlite-8.0\
-lvtksys-8.0\
-lvtktiff-8.0\
-lvtkverdict-8.0\
-lvtkViewsContext2D-8.0\
-lvtkViewsCore-8.0\
-lvtkViewsInfovis-8.0\
-lvtkViewsQt-8.0\
-lvtkzlib-8.0
LIBS += -LD:\OpenCV\opencv\build\x64\vc15\lib\
-lopencv_world455
LIBS += -LD:\pthread\Pre-built.2\lib\x64\
-lpthreadVC2
LIBS += -LD:\log4cpp\msvc10\x64\Release\
-llog4cpp
}
3.3 Software interface
3.3.1 ui statement
- Double-click the xxx.ui file
3.3.2 Button icon
3.3.3 Other interface settings
- I found that the writing was a bit tedious orz, so let’s quickly end the interface and talk about point cloud processing (but it did take some time to make the interface look better haha, such as borderless, zooming, mouse hover display prompts, etc.
O_o
)
- The following operations can be written where mainwindow is initialized.
- Information prompted when the mouse hovers next to the button
ui->pushButton_box->setToolTip(QString("<span style=\"color: #4a90e2; font-size: 12px;\">%1</span>").arg("box"));
- Set the button's background color to transparent
ui->pushButton_box->setStyleSheet("background-color:transparent");
orui->pushButton_box->setStyleSheet("background-color:rgba(0,0,0,0)");
- Set as unfocused button
ui->pushButton_box->setFocusPolicy(Qt::NoFocus);
- Set whether the button is available
ui->pushButton_previous->setEnabled(false);
- Some buttons need to wait until certain conditions are met before being clickable. This can reduce misoperations. For example, the previous and next point clouds cannot be clicked until the point cloud is opened (otherwise, a location that does not exist in the container will be accessed, causing an error).
- Set background transparency
setAttribute(Qt::WA_TranslucentBackground);
- Set borderless
setWindowFlags(Qt::Window|Qt::FramelessWindowHint |Qt::WindowSystemMenuHint|Qt::WindowMinimizeButtonHint|Qt::WindowMaximizeButtonHint);
- Set window background color and border arc
this->setStyleSheet("QWidget{background-color:black;border-radius:10px;}");
- Information prompted when the mouse hovers next to the button
- Since there are problems with window scaling and dragging after setting borderless, you can add the following code
void resizeEvent(QResizeEvent *e);
//由于去掉显示界面的菜单栏和标题栏,无法拖动窗口,重写关于窗口拖动用的几个函数
void mousePressEvent(QMouseEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mouseReleaseEvent(QMouseEvent *event);
void showEvent(QShowEvent* event);
void Widget::resizeEvent(QResizeEvent *e)
{
QWidget::resizeEvent(e);
QSize sz = e->size();
QBitmap mask(sz);
QPainter painter(&mask);
painter.setRenderHint(QPainter::Antialiasing);
painter.fillRect(0, 0, sz.width(), sz.height(), Qt::white);
painter.setBrush(QColor(0, 0, 0));
painter.drawRoundedRect(0, 0, sz.width(), sz.height(), 10, 10);
setMask(mask);
}
void Widget::mousePressEvent(QMouseEvent *event)
{
isPressedWidget = true; // 当前鼠标按下的即是QWidget而非界面上布局的其它控件
last = event->globalPos();
// this->setFocus();
// if(Qt::LeftButton == event->button() && 0 == (Qt::WindowMaximized & this->windowState()))
// {
// QPoint temp=event->globalPos();
// pLast=temp; //记录鼠标按下的位置
// event->ignore();
// }
// m_bPressed = true; //标记鼠标为按下状态
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if(this->isMaximized()) //如果当前是最大化,则不允许移动
return;
if (isPressedWidget)
{
int dx = event->globalX() - last.x();
int dy = event->globalY() - last.y();
last = event->globalPos();
move(x()+dx, y()+dy);
}
// if(this->isMaximized()) //如果当前是最大化,则不允许移动
// return;
// if((event->buttons() & Qt::LeftButton) && m_bPressed)//是否左击
// {
// QPoint ptemp=event->globalPos(); //当前鼠标全局位置
// ptemp=ptemp-pLast; //计算移动变量
// ptemp=ptemp+pos(); //窗口原始位置(pos()) + 鼠标移动变量(ptemp) = 最终窗口位置
// move(ptemp); //移动窗口到新的位置
// }
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
int dx = event->globalX() - last.x();
int dy = event->globalY() - last.y();
move(x()+dx, y()+dy);
isPressedWidget = false; // 鼠标松开时,置为false
// QApplication::restoreOverrideCursor();//恢复鼠标指针性状
// event->ignore();
// m_bPressed = false;
}
void Widget::showEvent(QShowEvent *event)
{
this->setAttribute(Qt::WA_Mapped);//解决不能及时刷新的bug
QWidget::showEvent(event);
}
- To add icons to software, you can refer to the blog < QT How to add icons to QT programs >
- Remember to add RC_FILE += logo.rc in the .pro file
3.4 Point cloud processing
3.4.1 Point cloud reading and display
- You can refer to the blog < Reading and displaying point clouds in .pcd/.ply/.txt/.bin/.stl format >
- This is how you can display point clouds in Qt
- Set the member functions of point cloud and PCLVisualizer in the class
-
pcl::PointCloudpcl::PointXYZ::Ptr cloud_;
-
boost::shared_ptrpcl::visualization::PCLVisualizer viewer_;
- Perform the following operations when initializing the window class
cloud_.reset(new pcl::PointCloud<pcl::PointXYZ>);
viewer_.reset(new pcl::visualization::PCLVisualizer("tree&cat",false));
viewer_->setBackgroundColor(0,0,0);
ui->qvtkWidget->SetRenderWindow(viewer_->getRenderWindow());
viewer_->setupInteractor(ui->qvtkWidget->GetInteractor(),ui->qvtkWidget->GetRenderWindow());
viewer_->resetCamera();
ui->qvtkWidget->update();
- Where the point cloud needs to be displayed, call showPointCloud in the blog < Read and display point cloud in .pcd/.ply/.txt/.bin/.stl format > to visualize the point cloud.
3.4.2 Display the previous/next point cloud
int serialNum = 0;
Create directory index and file name list in header fileQList<QFileInfo>* fileInfo;
- Get
getOpenFileName
the name of the opened file using /
Get path name by symbol position in string- Set a filter to filter the file names of files with the suffix point cloud
- Get the paths of all point clouds in the directory and store them in the file name list fileInfo
- and iterate through the list to find the file with the same name as the currently open file to determine the index serialNum position
cloudPath_=QFileDialog::getOpenFileName(this,"pleas chose point cloud",/*""*/lastPath,
" (*.pcd *.ply *.txt *.bin *.stl);; (*.*)"/*,&selectedFilter,options*/);
QString temp=cloudPath_;
for(int i=temp.length();i>0;i--)
{
if (temp[i - 1] == "/")
{
cloudDir=temp;
break;
}
else
{
temp.chop(1);
}
}
QStringList filter;
filter<<"*.pcd"<<"*.ply"<<"*.txt"<<"*.bin"<<"*.stl";
QDir* dir =new QDir(cloudDir);
dir->setNameFilters(filter);
fileInfo=new QList<QFileInfo>(dir->entryInfoList(filter));
for (int i = 0; i < fileInfo->count(); ++i) {
if(cloudPath_==fileInfo->at(i).filePath())
{
serialNum=i;
break;
}
}
- When the previous button is clicked, the index decrements. When the index <0 after decrement, set the index to list size()-1.
- After determining that the path is not empty based on the index acquisition path, you can call readPointCloud and showPointCloud in <Blog> to read and display the point cloud .
if(--serialNum<0)
{
serialNum=fileInfo->count()-1;
}
cloudPath_=fileInfo->at(serialNum).filePath();
if(!cloudPath_.isEmpty())
{
...
}
- When the next button is clicked, the index is incremented. When the index == 0 after the increment, the index is set to 0.
if(++serialNum==fileInfo->count())
{
serialNum=0;
}
cloudPath_=fileInfo->at(serialNum).filePath();
if(!cloudPath_.isEmpty())
{
...
}
3.4.3 Status bar displays point cloud information
- You can add a label at the top of the interface. Each time the point cloud showPointCloud is updated, the current path name of the point cloud and point cloud and other information are displayed.
- You can also use getMinMax3D to calculate the maximum and minimum points of the point cloud and then display it at the top to determine the range of the point cloud (you can also calculate the point cloud density, etc. for display)
pcl::getMinMax3D(*cloud,minPoint_,maxPoint_);
QString range=" ("+QString::number(minPoint_.x)+","+QString::number(minPoint_.y)+","+QString::number(minPoint_.z)+") ("+QString::number(maxPoint_.x)+","+QString::number(maxPoint_.y)+","+QString::number(maxPoint_.z)+")";
ui->label->setText(cloudPath_+QString::fromLocal8Bit(" size:")+QString::number(cloud->size())+range);
3.4.4 Point cloud processing operations
- Processing methods including point cloud filtering, segmentation, and bounding box drawing can also be written in the slot function of the corresponding button.
- This blog has written some related processing encapsulation functions that can be copied and called < Encapsulation of common PCL visualization/filtering/segmentation functions >
3.4.5 Thread related operations
- You can use Qt's signals and slots mechanism
- For example, create a new class
cloudSegment
that inherits QObject cloudSegment *seg;
Create a new class object pointer and QThread thread object in the window classQThread segThread_;
- During initialization, place the pointer into the thread; connect signals and slots and start the thread
- Exit the thread during destruction
- (Since the sub-thread cannot operate the UI, when you need to display the point cloud of the sub-thread, you need to use signals and slots to send the point cloud of the sub-thread to the main thread for display)
- For example, create a new class
//构造
seg=new cloudSegment(this);
seg->moveToThread(&segThread_);
connect(&segThread_,&QThread::finished, base, &QObject::deleteLater);
connect(this,&Widget::segcloud,seg,&cloudSegment::segCloud);
connect(seg,&cloudSegment::segDone,this,&Widget::showSegCloud);
segThread_.start();
//析构
segThread_.quit();
segThread_.wait();
3.4.6 Save point cloud
- You can assign the interface point cloud to the member variable cloud_ each time. When clicking the save button, confirm that cloud_ is not empty and select the folder and name to save.
if(cloud_)
{
QString filename=QFileDialog::getSaveFileName(this,tr("save point cloud"),"",tr("PointCloud (*.pcd)"));
if(!filename.isNull())
{
pcl::io::savePCDFileBinary(filename.toLocal8Bit().toStdString(),*cloud_);
}
}
3.5 Others
3.5.1 Configuration file
- You can record the last folder path opened by writing the configuration .ini file. You can open this path directly the next time you open it without having to look for it from the initial path every time.
- You can use QSettings to implement it, or you can write a class to operate the configuration file yourself.
//设置为类的成员函数
QSettings setting;
//窗口类初始化时初始化列表加上setting
setting("./Setting.ini", QSettings::IniFormat)
//为setting设置键值
setting.setValue("LastFilePath",cloudPath_);
3.5.2 Writing logs
- You can use the log4cpp log library
- < QT uses log4cpp log library >
3.5.3 Software release
- For Qt project software packaging, please refer to the blog < Qt Project Release Packaging Tutorial (win10) >
- Copy the exe file generated under release to a new folder
- Open the compiler you use in qt. For example, mine is Qt 5.14.2 (MSVC 2017 64-bit)
- cd to the new folder where you save the exe and enter windeployqt name.exe (this way qt will package the required dependencies into this folder)
- For some external dlls, you need to copy them to the folder yourself
- The software generated in this way contains software and many other files under one file.
- If you want to use only one file for others to use, you can use EnigmaVirtualBox to package it.
- You can refer to < QT uses Enigma Virtual Box to package exe >
4. Software
- What may be more practical about this update is that it adds a top status bar to display the path and number of points of the point cloud file. It is more convenient to know which point cloud is displayed and part of the point cloud information.
- It may be the saving function, because point clouds in 5 formats can be opened. In the last save, what I saved here is the processed pcd point cloud displayed on the current interface. Even without processing, it can be saved, which is equivalent to making point clouds. Type conversion, 5 types of dump pcd
- Other functions can be displayed by hovering the mouse near the button, such as box to draw a bounding box for the current interface point cloud, removeOuter to filter outliers, etc.
- However, some functions I wrote in the code in order to test some functions of the project may not be applicable, such as RgnGrow area growth, plane fitting, cluster clustering, etc.
Then save the file again: D The link is still the same link as before. cloud.exe is the previous version, and treeandcat.exe is the current version. Baidu
Netdisk extraction code: 2lm2