发布版本:1.0
日期:2020.09
前言
概述
本文档简单介绍了点云PLC库以及PC和Android端实时预览点云
修订记录
日期 | 版本 | 作者 | |
---|---|---|---|
2020-09-15 | V1.0 | wingceltis-c/[email protected] |
扫描资料以点的形式记录,每一个点包含有三维坐标,有些可能含有颜色信息(RGB)或反射强度信息(Intensity)。
点云与三维图像的关系:三维图像是一种特殊的信息表达形式,其特征是表达的空间中三个维度的数据,表现形式包括:深度图(以灰度表达物体与相机的距离),几何模型(由CAD软件建立),点云模型(所有逆向工程设备都将物体采样成点云)。和二维图像相比,三维图像借助第三个维度的信息,可以实现天然的物体——背景解耦。点云数据是最为常见也是最基础的三维模型。点云模型往往由测量直接得到,每个点对应一个测量点,未经过其他处理手段,故包含了最大的信息量。这些信息隐藏在点云中需要以其他提取手段将其萃取出来,提取点云中信息的过程则为三维图像处理。
点云的概念:点云是在同一空间参考系下表达目标空间分布和目标表面特性的海量点集合,在获取物体表面每个采样点的空间坐标后,得到的是点的集合,称之为“点云”(Point Cloud)。
点云的获取设备:RGBD设备是获取点云的设备,比如PrimeSense公司的PrimeSensor、微软的Kinect、华硕的XTionPRO。
点云的内容:根据激光测量原理得到的点云,包括三维坐标(XYZ)和激光反射强度(Intensity),强度信息与目标的表面材质、粗糙度、入射角方向,以及仪器的发射能量,激光波长有关。
根据摄影测量原理得到的点云,包括三维坐标(XYZ)和颜色信息(RGB)。
结合激光测量和摄影测量原理得到点云,包括三维坐标(XYZ)、激光反射强度(Intensity)和颜色信息(RGB)。
点云的属性:空间分辨率、点位精度、表面法向量等。
点云存储格式:*.pts; *.asc ; *.dat; .stl ; [1] *.imw;*.xyz;.las。LAS格式文件已成为LiDAR数据的工业标准格式,LAS文件按每条扫描线排列方式存放数据,包括激光点的三维坐标、多次回波信息、强度信息、扫描角度、分类信息、飞行航带信息、飞行姿态信息、项目信息、GPS信息、数据点颜色信息等。
点云处理的三个层次:Marr将图像处理分为三个层次,低层次包括图像强化,滤波,关键点/边缘检测等基本操作。中层次包括连通域标记(label),图像分割等操作。高层次包括物体识别,场景分析等操作。工程中的任务往往需要用到多个层次的图像处理手段。
点云库Point Cloud Library (or PCL) 是一个大型的用于处理2D/3D图像和点云的开源项目。它实现了立体视觉领域众多的前沿算法,包括滤波,特征提取,表面重建,相机标定,模型拟合,分割,可视化等许多功能,
源码:https://github.com/PointCloudLibrary/pcl/releases
安装参考链接:https://blog.csdn.net/sangnanpo/article/details/100562305
Q:提示xxx.dll找不到
A: 需要在工程中添加dll路径,或者把dll复制到工程中。
右键工程属性->调试->环境->PATH=%PATH% 可以在这里添加绝对路径,可以把对应路径放到系统环境变量中,直接按照我这里写的就行。注意这里路径不能有空格,系统环境可以有。
#include
#include
#include
#include
#include
#include
#include
#include
#include "UVCCamera.h"
#include
typedef struct {
float x;
float y;
union
{
float depth;
float z;
};
}CloudPoint , *CloudPoint_t;
#define DEPTH_FRAME_WIDTH 640
#define DEPTH_FRAME_HEIGHT 480
using namespace std;
#if 1 //Camera数据实时预览
int main(int argc, char** argv) {
pcl::PointCloud::Ptr pcloud1(new pcl::PointCloud);
pcl::visualization::CloudViewer viewer("3D Viewer");
CloudPoint_t point = new CloudPoint[DEPTH_FRAME_WIDTH*DEPTH_FRAME_HEIGHT];
BYTE dat_consequent_mode[4] = { 0xEF,0xFF,0xFF,0xFF };
unsigned char *frameData = nullptr;
UVCCamera cam("UVC DEPTH", UVCCamera::YUY2);
cam.open(DEPTH_FRAME_WIDTH, DEPTH_FRAME_HEIGHT);
Sleep(2000); // 等待相机初始化完成
cam.send_UVC_Ext_Command(dat_consequent_mode, 4);
while (true)
{
frameData = cam.getPixels();
if (frameData != nullptr) {
clock_t start_time, end_time;
start_time = clock(); //获取开始执行时间
int count = getPointCloudDepth((unsigned short *)frameData, nullptr, point, DEPTH_FRAME_WIDTH, DEPTH_FRAME_HEIGHT);
pcloud1->points.resize(count);
for (int i = 0; i < count; i++)
{
pcloud1->points[i].x = point[i].x;
pcloud1->points[i].y = point[i].y;
pcloud1->points[i].z = point[i].z;
}
pcloud1->width = pcloud1->size();
pcloud1->height = 1;
pcloud1->is_dense = true;
end_time = clock(); //获取结束时间
double Times = (double)(end_time - start_time) / CLOCKS_PER_SEC;
printf("%f seconds count = %d\n", Times, count);
viewer.showCloud(pcloud1);
}
}
cam.close();
delete[] point;
return 0;
}
#endif
#if 0 //文件预览
typedef std::vector StringList;
StringList splitstr(const std::string& str, char tag)
{
StringList li;
std::string subStr;
//遍历字符串,同时将i位置的字符放入到子串中,当遇到tag(需要切割的字符时)完成一次切割
//遍历结束之后即可得到切割后的字符串数组
for (size_t i = 0; i < str.length(); i++)
{
if (tag == str[i]) //完成一次切割
{
if (!subStr.empty())
{
li.push_back(subStr);
subStr.clear();
}
}
else //将i位置的字符放入子串
{
subStr.push_back(str[i]);
}
}
if (!subStr.empty()) //剩余的子串作为最后的子字符串
{
li.push_back(subStr);
}
return li;
}
int main(int argc, char** argv) {
pcl::PointCloud::Ptr cloud(new pcl::PointCloud);
//Fill in the cloud data
cloud->width = 848;
cloud->height = 480;
cloud->points.resize(cloud->width*cloud->height);
string path = "000001.txt";
// 2 创建流对象
ifstream ifs;
// 3 打开文件 判断是否打开成功
ifs.open(path, ios::in);
if (!ifs.is_open()) {
cout << "文件打开失败!" << endl;
system("pause");
return -1;
}
string buf;
int i = 0;
while (true) {
//cout << buf << " ----------"<points[i].x = atof(list[0].c_str());
cloud->points[i].y = atof(list[1].c_str());
cloud->points[i].z = atof(list[2].c_str());
i++;
}
pcl::visualization::CloudViewer viewer("test");
viewer.showCloud(cloud);
while (!viewer.wasStopped()) {};
return 0;
}
VTK API
VTK,全称是Visualization Toolkit,即可视化工具包。是一个开源、跨平台、可自由获取、支持并行处理的图形应用函数库。
ubuntu 18.04
下载ndk
wget https://dl.google.com/android/repository/android-ndk-r16b-linux-x86_64.zip
unzip android-ndk-r16b-linux-x86_64.zip
下载VTK源码
wget https://www.vtk.org/files/release/8.2/VTK-8.2.0.tar.gz
tar zxvf VTK-8.2.0.tar.gz
运行编译脚本
cd VTK-8.2.0
mkdir build
cd build
./auto_build_android.sh
_编译脚本 auto_buildandroid.sh 内容
#!/bin/bash
export NDK_ROOT=/home/VTK/android-ndk-r16b
export ANDROID_NDK=/home/VTK/android-ndk-r16b
export PATH PATH=$PATH:$NDK_ROOT:$GOROOT/bin:$GOPAHT/bin
cmake -DCMAKE_TOOLCHAIN_FILE=$NDK_ROOT/build/cmake/android.toolchain.cmake \
-DCMAKE_ANDROID_NDK=$NDK_ROOT \
-DCMAKE_VERBOSE_MAKE=ON \
-DCMAKE_SYSTEM_NAME=Android \
-DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS='-std=c++11 -fpic -fexceptions -frtti' \
-DCMAKE_C_FLAGS='-fpic' \
-DCMAKE_ANDROID_STL_TYPE='c++_static' \
-DCMAKE_SYSTEM_VERSION=24 \
-DVTK_ANDROID_BUILD=ON \
-DANDROID_NATIVE_API_LEVEL=24 \
-DOPENGL_ES_VERSION=3.0 ..
cmake --build .
注意:遇到 vtk error: ‘round’ is not a member of ‘std’ ,则将 “std::round” 直接修改为 “round” 即可继续编译
编译好的库目录在: ls CMakeExternals/Install/vtk-android 包括 include lib share等3个目录,分别存放头文件 库文件
源码见: https://github.com/panyingyun/vtkandroiddemo/tree/master/JavaVTK2
编译 libJavaVTK.so
cmake .
cmake --build . --config Release
详细CMakeLists.txt
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SYSTEM_NAME Android)
set(CMAKE_SYSTEM_VERSION "24")
set(CMAKE_ANDROID_ARCH_ABI "armeabi-v7a")
set(CMAKE_ANDROID_NDK "/home/VTK/android-ndk-r16b")
set(VTK_DIR "/home/VTK/vtk-android/lib/cmake/vtk-8.2")
project(JavaVTK)
find_package(VTK REQUIRED)
include(${VTK_USE_FILE})
set(sources main.cxx)
add_library(JavaVTK SHARED ${sources})
target_link_libraries(JavaVTK android log EGL GLESv3 stdc++ ${VTK_LIBRARIES})
参考链接:https://www.michaelapp.com/posts/2019/VTK-Android%E7%A7%BB%E6%A4%8D%E5%92%8C%E7%A4%BA%E4%BE%8B/
new vtkRenderWindow()
vtkRenderWindow()->AddRenderer(vtkRenderer())
vtkAndroidRenderWindowInteractor->SetRenderWindow(vtkRenderWindow())
vtkPolyData->SetPoints(Point)
vtkPolyDataMapper->SetInputData(vtkPolyData())
vtkActor->SetMapper(vtkPolyDataMapper);
vtkRenderer->AddActor(vtkActor)
刷新点云数据:
直接操作前面初始化配置的 vtkPoints points ; vtkCellArray cells;
points->Initialize(); //清空数据以及内存
cells->Initialize();
for (int i = 0; i < len/3; i++) //添加点云信息
{
fx = pIn[i*3 + 0];
fy = pIn[i*3 + 1];
fz = pIn[i*3 + 2];
idtype = points->InsertNextPoint(fx,fy,fz);
cells->InsertNextCell(1, &idtype);
}
//刷新点云
vtkRenderWindow->SwapBuffersOff(); // android does it
vtkRenderWindow->Render(); //这个方法在Android 上耗时200多ms,应该是哪里配置问题需要优化。
vtkRenderWindow->SwapBuffersOn(); // reset
资源释放
if(foo != NULL) {
points->Initialize();
cells->Initialize();
foo->Renderer->Delete();
//foo->RenderWindow->Delete(); //系统jni拥有window,所以不用我们去释放
foo->Interactor->Delete();
free(foo);
foo = NULL;
}
资源地址:
预览工程:https://download.csdn.net/download/wingceltis/12890417