The method Frame::pointCloud() does not perform any copying from GPU memory.
备注
Camera::capture2D3D() and Camera::capture3D() methods return at some moment in time after the camera completes capturing raw images.
The handle from Frame::pointCloud() is available instantly.
However, the actual point cloud data becomes available only after the processing on the GPU is finished.
Any calls to data-copy functions (section below) will block and wait for processing to finish before proceeding with the requested copy operation.
Getting the property Frame.PointCloud does not perform any copying from GPU memory.
备注
Camera.Capture2D3D() and Camera.Capture3D() methods return at some moment in time after the camera completes capturing raw images.
The handle from Frame.PointCloud is available instantly.
However, the actual point cloud data becomes available only after the processing on the GPU is finished.
Any calls to data-copy methods (section below) will block and wait for processing to finish before proceeding with the requested copy operation.
std::cout<<"Capturing frame"<<std::endl;frame=camera.capture2D3D(settings);constautoframe2D=frame.frame2D();if(!frame2D.has_value()){throwstd::runtime_error("Captured frame does not contain a 2D image.");}std::cout<<"Copying colors with Zivid API from GPU to CPU"<<std::endl;autocolors=frame2D->imageBGRA_SRGB();std::cout<<"Casting the data pointer as a void*, since this is what the OpenCV matrix constructor requires."<<std::endl;auto*dataPtrZividAllocated=const_cast<void*>(static_cast<constvoid*>(colors.data()));std::cout<<"Wrapping this block of data in an OpenCV matrix. This is possible since the layout of \n"<<"Zivid::ColorBGRA_SRGB exactly matches the layout of CV_8UC4. No copying occurs in this step."<<std::endl;constcv::MatbgraZividAllocated(colors.height(),colors.width(),CV_8UC4,dataPtrZividAllocated);std::cout<<"Displaying image"<<std::endl;cv::imshow("BGRA image Zivid Allocated",bgraZividAllocated);cv::waitKey(CI_WAITKEY_TIMEOUT_IN_MS);
将选定数据从GPU复制到CPU内存(用户分配)
In the above example, ownership of the data was held by the returned Zivid::Array2D<> objects.
Alternatively, you may provide a pre-allocated memory buffer to Zivid::PointCloud::copyData(dataPtr).
The type of dataPtr defines what shall be copied (PointXYZ, ColorRGBA, etc.).
std::cout<<"Allocating the necessary storage with OpenCV API based on resolution info before any capturing"<<std::endl;autobgraUserAllocated=cv::Mat(resolution.height(),resolution.width(),CV_8UC4);std::cout<<"Capturing frame"<<std::endl;autoframe=camera.capture2D3D(settings);autopointCloud=frame.pointCloud();std::cout<<"Copying data with Zivid API from the GPU into the memory location allocated by OpenCV"<<std::endl;pointCloud.copyData(&(*bgraUserAllocated.begin<Zivid::ColorBGRA_SRGB>()));std::cout<<"Displaying image"<<std::endl;cv::imshow("BGRA image User Allocated",bgraUserAllocated);cv::waitKey(CI_WAITKEY_TIMEOUT_IN_MS);
参见
Copy Speed benchmarks for the time it takes to copy each data type from GPU to system memory.
The following example shows how create a new instance of UnorganizedPointCloud with a transformation applied to it.
Note that in this sample is is not necessary to create a new instance, as the untransformed point cloud is not used after the transformation.
If the object of interest is a subset of the ROI-cropped point cloud, you can further refine it by applying a binary mask.
A typical workflow is to capture a 2D image, run a segmentation algorithm to identify the object, and apply the resulting mask to the 3D point cloud.
This invalidates all points outside the segmented region.
You can mask the point cloud to keep only a specific region of interest.
A typical use case is to capture a 2D image, run it through a segmentation algorithm to produce a binary mask, and apply it to the 3D point cloud.
Non-zero values in the mask invalidate the corresponding points (set to NaN), while zero values preserve them.
The mask can be applied using mask() (in-place) or masked() (returns a new copy), on both PointCloud and Frame.
// Create a ones-filled maskZivid::Maskmask(resolution);// Calculate rectangle boundsconstintheight=static_cast<int>(resolution.height());constintwidth=static_cast<int>(resolution.width());constintheightMin=(height-pixelsToDisplay)/2;constintheightMax=(height+pixelsToDisplay)/2;constintwidthMin=(width-pixelsToDisplay)/2;constintwidthMax=(width+pixelsToDisplay)/2;// Create OpenCV Mat wrapper for the mask datacv::MatmaskMat(height,width,CV_8UC1,mask.data());// Draw filled rectangle on the mask to unmask the central regioncv::rectangle(maskMat,cv::Point(widthMin,heightMin),cv::Point(widthMax,heightMax),cv::Scalar(0),cv::FILLED);returnmask;automaskedPointCloud=pointCloud.masked(mask);
// Create a ones-filled maskvarmask=newZivid.NET.Mask(resolution);// Calculate rectangle boundsintheight=(int)resolution.Height;intwidth=(int)resolution.Width;intheightMin=(height-pixelsToDisplay)/2;intheightMax=(height+pixelsToDisplay)/2;intwidthMin=(width-pixelsToDisplay)/2;intwidthMax=(width+pixelsToDisplay)/2;// Set pixels inside the rectangle to zerofor(inty=heightMin;y<heightMax;++y){for(intx=widthMin;x<widthMax;++x){mask[x,y]=0;}}returnmask;varmaskedPointCloud=pointCloud.Masked(mask);
pixels_to_display=300print(f"Generating binary mask of central {pixels_to_display} x {pixels_to_display} pixels")height=frame.point_cloud().heightwidth=frame.point_cloud().widthmask=np.ones((height,width),bool)h_min=(height-pixels_to_display)//2h_max=(height+pixels_to_display)//2w_min=(width-pixels_to_display)//2w_max=(width+pixels_to_display)//2mask[h_min:h_max,w_min:w_max]=0print("Masking point cloud")point_cloud.mask(mask)
A mask can also be constructed from third-party data, such as an OpenCV image.
// Create a circular mask in OpenCVconstintcenterX=static_cast<int>(resolution.width())/2;constintcenterY=static_cast<int>(resolution.height())/2;constintradius=pixelsToDisplay;cv::circle(opencvMask,cv::Point(centerX,centerY),radius,cv::Scalar(0),cv::FILLED);// Convert OpenCV mask to Zivid::MaskconstZivid::MaskcircularMask(resolution,opencvMask.datastart,opencvMask.dataend);
The mask supports implicit resampling: if the mask resolution differs from the point cloud resolution by an integer factor (2, 3, or 4), it is automatically resampled.
This is useful when creating a mask from a 2D capture with a different resolution than the 3D capture.
std::cout<<"Setting up visualization"<<std::endl;Zivid::Visualization::Visualizervisualizer;std::cout<<"Visualizing point cloud"<<std::endl;visualizer.showMaximized();visualizer.show(frame);visualizer.resetToFit();std::cout<<"Running visualizer. Blocking until window closes."<<std::endl;visualizer.run();
Console.WriteLine("Setting up visualization");using(varvisualizer=newZivid.NET.Visualization.Visualizer()){Console.WriteLine("Visualizing point cloud");visualizer.Show(frame);visualizer.ShowMaximized();visualizer.ResetToFit();Console.WriteLine("Running visualizer. Blocking until window closes.");visualizer.Run();}
std::cout<<"Getting point cloud from frame"<<std::endl;autopointCloud=frame.pointCloud();std::cout<<"Setting up visualization"<<std::endl;Zivid::Visualization::Visualizervisualizer;std::cout<<"Visualizing point cloud"<<std::endl;visualizer.showMaximized();visualizer.show(pointCloud);visualizer.resetToFit();std::cout<<"Running visualizer. Blocking until window closes."<<std::endl;visualizer.run();
Console.WriteLine("Getting point cloud from frame");varpointCloud=frame.PointCloud;Console.WriteLine("Setting up visualization");varvisualizer=newZivid.NET.Visualization.Visualizer();Console.WriteLine("Visualizing point cloud");visualizer.Show(pointCloud);visualizer.ShowMaximized();visualizer.ResetToFit();Console.WriteLine("Running visualizer. Blocking until window closes.");visualizer.Run();