文章目录
- 1. 序
- 2. 开发环境
- 2.1 QT + PCL
- 3. 程序
- 3.1 新建项目
- 3.2 修改.pro文件
- 3.2.1 添加头文件目录
- 3.2.2 添加依赖的库文件
- 3.3 软件界面
- 3.3.1 ui文件
- 3.3.2 按钮图标
- 3.3.3 其他界面设置
- 3.4 点云处理
- 3.4.1 点云读取显示
- 3.4.2 上/下一张显示点云
- 3.4.3 状态栏显示点云信息
- 3.4.5 线程相关操作
- 3.4.6 保存点云
- 3.5 其他
- 3.5.1 配置文件
- 3.5.2 写日志
- 3.5.3 软件发布
- 4. 软件
1. 序
哈哈当时弄这个小工具,一方面是常用的点云查看软件不太符合自己的操作习惯,另一方面是可以在按钮上做一些简单点云处理的测试验证比较方便
遥想起一年前开始写博客的初衷,源自一个朋友的一句话“记录技术成长,也方便回顾”,记录也算是一种抗衡遗忘的方式吧,有的时候遇到需要用的的一些方法也会回来翻翻自己的博客(就当作笔记本吧哈哈)
今年心态状态一直都不算好,很是惭愧博客也没怎么更新了。很多时候已经知道需要做什么,但还是止不住的去百度。
那种曾经有过的短暂内心平静如今也难以触及,关于自我、社会、科技、未来,有许多无意义的空想,有时感觉代码可以改变世界(虽然以我的能力不太可能哈哈orz
)
希望可以做到守护我所珍视的,坚持我所热爱的吧。有时感觉写下情绪表达会令自己有些尴尬所以尽量不表达,但这次随便吧大不了下次编辑删掉:D
回归正题上一篇博客<点云可视化工具>有csdner问到关于点云可视化工具的教程,趁今天星期天找时间更新一下吧=D
2. 开发环境
2.1 QT + PCL
- 程序界面是使用qt编写的,主要是一些按钮以及外观上的调整
- 点云的处理主要是借助PCL点云库
- 关于qt以及pcl的安装以及环境配置可以参考<QT 配置PCL1.8.1>
- 如果不想自己根据重新编译qt使用的pcl vtk库的话,可以使用和我一样的版本和已经编译好了的库
3. 程序
3.1 新建项目
3.2 修改.pro文件
- 原本的.pro文件长这样,在下方添加头文件目录与依赖的库文件
3.2.1 添加头文件目录
INCLUDEPATH += 头文件目录路径
- 可以把pcl、opencv等一些会用到的库加上(路径换成自己的安装路径)
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 添加依赖的库文件
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 软件界面
3.3.1 ui文件
- 双击xxx.ui文件
3.3.2 按钮图标
3.3.3 其他界面设置
- 发现写得有些繁琐了orz,还是快速结束界面相关讲点云的处理吧(但界面为了好看些也确实花了些时间哈哈
O_o
,比如说无边框、缩放、鼠标悬停显示提示等)
- 以下这些操作可以写在mainwindow初始化的地方
- 鼠标悬停在按钮旁边时提示的信息
ui->pushButton_box->setToolTip(QString("<span style=\"color: #4a90e2; font-size: 12px;\">%1</span>").arg("box"));
- 设置按钮的背景颜色为透明
ui->pushButton_box->setStyleSheet("background-color:transparent");
或者ui->pushButton_box->setStyleSheet("background-color:rgba(0,0,0,0)");
- 设置为非焦点按钮
ui->pushButton_box->setFocusPolicy(Qt::NoFocus);
- 设置按钮是否可用
ui->pushButton_previous->setEnabled(false);
- 有些按钮需等到一定条件后再设置为可点击,这样可以降低误操作,譬如上下一张点云需等打开点云后才能点击(不然将会访问容器中不存在的位置导致错误)
- 设置背景透明
setAttribute(Qt::WA_TranslucentBackground);
- 设置无边框
setWindowFlags(Qt::Window|Qt::FramelessWindowHint |Qt::WindowSystemMenuHint|Qt::WindowMinimizeButtonHint|Qt::WindowMaximizeButtonHint);
- 设置窗口背景颜色和边界弧度
this->setStyleSheet("QWidget{background-color:black;border-radius:10px;}");
- 鼠标悬停在按钮旁边时提示的信息
- 由于设置无边框后窗口缩放和拖动存在问题,可添加以下代码
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);
}
- 给软件添加图标可以参考博客<QT 如何给QT程序添加图标>
- 记得在.pro文件添加RC_FILE += logo.rc
3.4 点云处理
3.4.1 点云读取显示
- 可以参考博客<读取并显示.pcd/.ply/.txt/.bin/.stl格式的点云>
- 对于在qt中显示点云可以这样操作
- 在类中设置点云和PCLVisualizer的成员函数
-
pcl::PointCloudpcl::PointXYZ::Ptr cloud_;
-
boost::shared_ptrpcl::visualization::PCLVisualizer viewer_;
- 在窗口类进行初始化时进行以下操作
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();
- 在需要显示点云的地方调用博客<读取并显示.pcd/.ply/.txt/.bin/.stl格式的点云>中的showPointCloud即可进行点云的可视化
3.4.2 上/下一张显示点云
- 在头文件中创建目录索引
int serialNum = 0;
以及文件名列表QList<QFileInfo>* fileInfo;
- 利用
getOpenFileName
获取打开的文件名称 - 通过字符串中的
/
符号位置获取路径名称 - 设置过滤器筛选后缀为点云的文件的文件名
- 获取目录下所有点云的路径存入到文件名列表fileInfo中
- 并遍历列表找到与当前打开的文件名相同的文件以确定索引serialNum位置
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;
}
}
- 当点击上一张按钮时索引自减、当自减后索引<0时,将索引设置为列表size()-1
- 根据索引获取路径判断路径不为空后,可以调用<博客>中的readPointCloud和showPointCloud进行点云的读取和显示
if(--serialNum<0)
{
serialNum=fileInfo->count()-1;
}
cloudPath_=fileInfo->at(serialNum).filePath();
if(!cloudPath_.isEmpty())
{
...
}
- 当点击下一张按钮索引自增、当自增后索引==0时,将索引设置为0
if(++serialNum==fileInfo->count())
{
serialNum=0;
}
cloudPath_=fileInfo->at(serialNum).filePath();
if(!cloudPath_.isEmpty())
{
...
}
3.4.3 状态栏显示点云信息
- 可以在界面顶部增加一个label,每次更新显示点云showPointCloud时,显示点云的当前路径名和点云等信息
- 也可以利用getMinMax3D计算点云的最大最小点再顶部显示以确定点云的范围(还可以计算点云密度等进行显示)
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);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-96rp8RM7-1690707772337)(19.png#pic_center)]### 3.4.4 点云处理操作
- 包括点云的滤波、分割、画包围盒等处理方法也都可以写在对应按钮的槽函数中
- 这个博客里有写过一些相关处理的封装函数可以复制调用<PCL常用可视化/滤波/分割等函数的封装>
3.4.5 线程相关操作
- 可以利用qt的信号和槽机制
- 如创建一个新类
cloudSegment
继承QObject - 在窗口类中创建新类对象指针
cloudSegment *seg;
与QThread线程对象QThread segThread_;
- 初始化的时候将指针放到线程中;连接信号和槽并开启线程
- 析构的时候退出线程
- (由于子线程不能操作ui,所以需要显示子线程的点云时,需利用信号和槽将子线程的点云发送到主线程进行显示)
- 如创建一个新类
//构造
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 保存点云
- 可以每次将界面点云赋值给成员变量cloud_,点保存按钮时确认cloud_不为空则选择文件夹及名称进行保存
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 其他
3.5.1 配置文件
- 可以通过写配置.ini文件记录最后一次打开的文件夹路径,下次打开时直接打开这个路径不必每次都要从初始路径去找
- 可以利用QSettings实现,也可以自己写一个操作配置文件的类
//设置为类的成员函数
QSettings setting;
//窗口类初始化时初始化列表加上setting
setting("./Setting.ini", QSettings::IniFormat)
//为setting设置键值
setting.setValue("LastFilePath",cloudPath_);
3.5.2 写日志
- 可以借助log4cpp日志库
- <QT使用log4cpp日志库>
3.5.3 软件发布
- qt的项目软件打包可以参考博客<Qt项目发布打包教程(win10)>
- 将release下生成的exe文件复制到一个新的文件夹
- 打开你在qt中所使用的编译器如我的就是Qt 5.14.2(MSVC 2017 64-bit)
- cd到你存exe的新文件夹输入windeployqt name.exe(这样qt就会将需要的依赖打包到这个文件夹里)
- 对于一些外部的dll需要自己复制到文件夹下
- 这样生成的软件是一个文件下有软件还有很多别的文件
- 如果想给别人使用时只用一个文件可以使用EnigmaVirtualBox进行封包
- 可以参考<QT使用Enigma Virtual Box打包exe>
4. 软件
- 这次更新可能比较实用的地方是增加了顶部状态栏显示点云文件的路径和点数等比较方便知道显示的是哪个点云以及部分点云信息
- 其可能是保存功能吧,因为5种格式的点云都可以打开,最后保存这里我保存的是当前界面显示的处理后的pcd点云,即使不做处理也可以保存相当于可以做点云的类型转换吧,5种转存pcd
- 其他的功能将鼠标悬停在按钮附近便可以显示,例如box是给当前界面点云画包围盒、removeOuter是滤除离群点等
- 但是某些功能我当时是为了测试项目中部分功能,在代码里写的固定参数,可能会出现不适用情况,例如RgnGrow区域生长、plane平面拟合、cluster聚类等
那就再次存个档吧:D 链接还是之前那个链接 cloud.exe是之前的版本,treeandcat.exe是现在的版本
百度网盘 提取码:2lm2