使用OpenTK展示3D点云图像(C#)

news2024/12/12 13:26:10

最近在研究3D显示,找到一款在winform上展示3D点云的控件,并且实现了点线面的展示,及光照渲染纹理贴图等功能,如下面几张图所展示。

一些基础知识可以在LearnOpenTK - OpenTK 这个网站上学习到。

我这边使用的是openTK3.3.3版本,展示点云很好实现,把读到的点云数据放进去即可展示。如下图展示点云。

我们需要把点连成面,有很多算法可以实现,但我拿到的图为一张tif格式16位的深度图,如下图

快速获取此图的深度信息

IntPtr pointer = model.ImgDepth.GetImagePointer1(out string type, out width, out height);
length = width * height;
short[] pointZCloud = new short[length];
Marshal.Copy(pointer, pointZCloud, 0, length);
point3Ds = new Vector3[length];
normals = new Vector3[length];
zGoodList = new List<float>();
for (int i = 0; i < length; i++)
{
    int row = i / width;
    int col = i % width;
    byte[] bytes = BitConverter.GetBytes(pointZCloud[i]);
    ushort z = BitConverter.ToUInt16(bytes, 0);
    float tempZ = z * model.ScaleZ +model.OffsetZ;
    point3Ds[i] = new Vector3(row * model.ScaleY, col * model.ScaleX, tempZ);
    if (z > 0)
    {
        zGoodList.Add(tempZ);
    }
}

我们很容易知道哪三个点可以连成一个面,如某个点为(row,col),和它组成三角形的另外两个点为(row+1,col),(row,col+1),如下图组成一个个三角形,即可形成面

图中存在一个空的点,可通过阈值分割过滤掉,然后如何保证某个点必然存在后面两个和它构成三角形的点,用一个2x2的结构元腐蚀阈值分割出的区域,得到剩下所有的点必然每个点可以构成三角形,这种得到三角形的算法效率会非常高。

model.ImgDepth.Threshold((double)1, 65535).ErosionRectangle1(2, 2).GetRegionPoints(out HTuple rows1, out HTuple columns1);

long[] rows1Int = rows1.LArr;
long[] columns1Int = columns1.LArr;
int triLength = rows1Int.Length;

indices_Triangle = new uint[triLength * 6];
for (int i = 0; i < triLength; i++)
{
    uint a1 = (uint)(rows1Int[i] * width + columns1Int[i]);
    uint a2 = a1 + 1;
    uint a3 = a1 + (uint)width;
    uint a4 = a3 + 1;
    indices_Triangle[i * 6] = a1;
    indices_Triangle[i * 6 + 1] = a2;
    indices_Triangle[i * 6 + 2] = a3;
    indices_Triangle[i * 6 + 3] = a2;
    indices_Triangle[i * 6 + 4] = a3;
    indices_Triangle[i * 6 + 5] = a4;
}

不同高度渲染颜色从红色到蓝色

 objColors = new float[length * 3];
 for (int i = 0; i < length; i++)
 {
     if (point3Ds[i].Z > zMid)
     {
         objColors[i * 3] = (point3Ds[i].Z - zMid) / zHalfHigh;
         objColors[i * 3 + 1] = 1.0f - objColors[i * 3];
         objColors[i * 3 + 2] = 0;
     }
     else
     {
         objColors[i * 3] = 0;
         objColors[i * 3 + 1] = 1.0f - (zMid - point3Ds[i].Z) / zHalfHigh;
         objColors[i * 3 + 2] = (zMid - point3Ds[i].Z) / zHalfHigh;
     }
 }

然后还有光照,无光照和有光照效果差异很大,处理光照核心在于得到每个点的法向量,用上面的三角形的两条边构成的向量叉乘,及得到这个点的法向量,输入给着色器处理得到光照的渲染效果,如下面两张图对比

叉乘如下代码

Vector3 a1 = new Vector3(point3Ds[i].X, point3Ds[i].Y, point3Ds[i].Z);
Vector3 a2 = new Vector3(point3Ds[i + 1].X, point3Ds[i + 1].Y, point3Ds[i + 1].Z);
Vector3 a3 = new Vector3(point3Ds[i + width].X, point3Ds[i + width].Y, point3Ds[i + width].Z);
Vector3 b1 = a3 - a1;
Vector3 b2 = a2 - a1;
normals[i] = new Vector3(b1.Y * b2.Z - b2.Y * b1.Z, b1.Z * b2.X - b1.X * b2.Z, b1.X * b2.Y - b1.Y * b2.X);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2258257.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

李宏毅机器学习-批次 (batch)和动量(momentum)

一.batch&#xff08;批次&#xff09; 在计算微分时&#xff0c;不是对所有的数据算出来的Loss值做微分&#xff0c;而是将所有的数据分成一个一个的batch。一个batch是一个B&#xff0c;在更新参数时&#xff0c;拿B的资料计算Loss&#xff0c;计算gradient&#xff0c;再更新…

洗鞋小程序(源码+文档+部署+讲解)

本文将深入解析“洗鞋小程序”的项目&#xff0c;探究其架构、功能以及技术栈&#xff0c;并分享获取完整源码的途径。 系统概述 为洗鞋提供服务&#xff0c;包含小程序和管理端。 本项目名称为洗鞋小程序&#xff0c;是一个基于小程序的在线洗鞋平台。该系统提供下单、订单管…

【数据结构】二叉树的性质和存储结构

性质 在二叉树的第i层上至多有2^{i-1}个结点,至少有1个结点 深度为k的二叉树至多有2^{k-1}个结点&#xff08;k≥1&#xff09;&#xff0c;至少有k个结点 对任何一棵二叉树T&#xff0c;如果其叶子数为n0&#xff0c;度为2的结点数为n2&#xff0c;则n0n21 具有n个结点的完…

交换排序(Swap Sort)详解

交换排序Swap Sort详解 冒泡排序冒泡算法代码实现冒泡分析 快速排序快排算法代码实现快排分析 交换类排序主要是通过两两比较待排元素的关键字&#xff0c;若发现与排序要求相逆&#xff0c;则交换之。在这类排序方法中最常见的是起泡排序&#xff08;冒泡排序&#xff09;和快…

MySQL追梦旅途之性能优化

1、索引优化 索引可以显著加速查询操作&#xff0c;但过多或不适当的索引也会带来负面影响&#xff08;如增加写入开销&#xff09;。因此&#xff0c;选择合适的索引至关重要。 创建索引&#xff1a; 为经常用于WHERE子句、JOIN条件和ORDER BY排序的列创建索引。 CREATE I…

小程序IOS安全区域优化:safe-area-inset-bottom

ios下边有一个小黑线&#xff0c;位于底部的元素会被黑线阻挡 safe-area-inset-bottom 一 用法及作用&#xff1a; IOS全面屏底部有小黑线&#xff0c;位于底部的元素会被黑线阻挡&#xff0c;可以使用以下样式&#xff1a; .model{padding-bottom: constant(safe-area-ins…

矩阵的乘(包括乘方)和除

矩阵的乘分为两种&#xff1a; 一种是高等代数中对矩阵的乘的定义&#xff1a;可以去这里看看包含矩阵的乘。总的来说&#xff0c;若矩阵 A s ∗ n A_{s*n} As∗n​列数和矩阵 B n ∗ t B_{n*t} Bn∗t​的行数相等&#xff0c;则 A A A和 B B B可相乘&#xff0c;得到一个矩阵 …

解决阿里云轻量级服务器 Ubuntu 24.04.1 LTS 没网也 ping 不通 8.8.8.8 以及 route -n 没有输出任何转发信息

事情发生在两天前&#xff0c;位于公网的阿里云轻量级服务器&#xff08;Ubuntu 24.04.1 LTS&#xff09;忽然没网。主要是上次上服务器进行配置已经是一个多月前&#xff0c;最近也没有做什么事情&#xff0c;就忽然没网了&#xff0c;让人纳闷。更主要的是&#xff0c;上次备…

Cesium中实现仿ArcGIS三维的动态图层加载方式

Cesium 加载 ArcGIS 动态图层的方式 如果你在 Cesium 中加载过 ArcGIS 的动态图层&#xff0c;你会发现&#xff0c;Cesium 对于动态图层仍然采用类似切片图层的逻辑进行加载。也就是每个固定的瓦片 export 一张图片。 这样会造成一些问题&#xff1a; 请求量大&#xff0c;…

Tablesaw封装Plot.ly实现数据可视化

上文介绍tablesaw的数据处理功能&#xff0c;本文向你展示其数据可视化功能&#xff0c;并通过几个常用图表示例进行说明。 Plot.ly包装 可视化是数据分析的重要组成部分&#xff0c;无论你只是“查看”新数据集还是验证机器学习算法的结果。Tablesaw是一个开源、高性能的Java…

智慧商城项目2(vue核心技术与实战)

页面访问拦截了解 router/index.js import Vue from vue import VueRouter from vue-router import Login from /views/login import Layout from /views/layout import Search from /views/search import SearchList from /views/search/list import Prodetail from /views/…

第一个C++程序--(蓝桥杯备考版)

第一个C程序 基础程序 #include <iostream>//头⽂件 using namespace std;//使⽤std的名字空间 int main()//main函数 {cout << "hello world!" << endl; //输出&#xff1a;在屏幕打印"hello world!" return 0;}main函数 main 函数是…

华为云域名网站,域名切换到Cloudflare CDN出现访问报错:DNS 重定向次过多

网站域名切换到Cloudflare出现访问报错&#xff1a;重定向次过多&#xff0c;应该如何处理&#xff1f; 最近我自己已经遇到很多次这个情况了&#xff0c;将网站域名DNS切换到Cloudflare之后&#xff0c;网站会打不开&#xff0c;出现重定向次数过多报错。 网站域名切换到Clo…

颜色的基本处理

数码相机能够获取彩色图像&#xff0c;但相机的色彩处理是一个非常复杂的过程&#xff0c;是非常重要的。 此过程生产制造商在细节方面都是不公布的&#xff0c;但是基本的概念是相同的。当相机捕捉一个真实场景时&#xff0c;是怎么还原成人眼所看到的图像呢&#xff1f; 1.R…

与 Cursor AI 对话编程:2小时开发报修维修微信小程序

本文记录了如何通过与 Cursor AI 对话&#xff0c;全程不写一行代码的情况下&#xff0c;完成一个完整的报修小程序。整个过程展示了 AI 如何帮助我们&#xff1a; 生成代码 、解决问题、优化实现、完善细节。 先看一下效果图&#xff1a; 一、项目配置 首先我是这样和 AI 对…

System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本

问题1&#xff1a;“/”应用程序中的服务器错误。 System.Data.OracleClient 需要 Oracle 客户端软件 version 8.1.7 或更高版本。 说明: 执行当前 Web 请求期间&#xff0c;出现未经处理的异常。请检查堆栈跟踪信息&#xff0c;以了解有关该错误以及代码中导致错误的出处的详细…

leetcode909:蛇梯棋

给你一个大小为 n x n 的整数矩阵 board &#xff0c;方格按从 1 到 n2 编号&#xff0c;编号遵循 转行交替方式 &#xff0c;从左下角开始 &#xff08;即&#xff0c;从 board[n - 1][0] 开始&#xff09;的每一行改变方向。 你一开始位于棋盘上的方格 1。每一回合&#xf…

【特殊子序列 DP】力扣552. 学生出勤记录 II

可以用字符串表示一个学生的出勤记录&#xff0c;其中的每个字符用来标记当天的出勤情况&#xff08;缺勤、迟到、到场&#xff09;。记录中只含下面三种字符&#xff1a; ‘A’&#xff1a;Absent&#xff0c;缺勤 ‘L’&#xff1a;Late&#xff0c;迟到 ‘P’&#xff1a;Pr…

Datawhale AI 冬令营(第一期)定制你的第一个专属模型-学习笔记

最近我报名参加了Datawhale组织的主题为“动手学系列&#xff0c;人人都能应用的AI”的Datawhale AI冬令营&#xff08;第一期&#xff09;。 本次学习一共12天&#xff0c;从12月10日-12月21日&#xff0c;学习会包含【跑通速通手册】&#xff0c;【学习大模型微调&数据集…

【GL009】C/C++总结(一)

自查目录 1. typedef 和 #define 的区别 2. const 、volatile 和 static 的区别 3. const修饰指针 4. 数组指针和指针数组 5. 函数指针和指针函数 6. C/C内存管理 6.1 内存分布图解 6.2 C语言中的内存分配方式 6.3 堆&#xff08;Heap&#xff09;和栈&#xff08;Sta…