opengles在车载360环视avm系统中的应用简介

        360环视是辅助驾驶系统的一个技术点,通过鱼眼相机模型标定,图像拼接,鸟瞰图生成,3d渲染等手段把车体周围图像经过3D渲染后,生成2D鸟瞰图和3D环视图,在中控屏幕上显示,用于辅助倒车等。其具体的技术实现手段如下:

        1 场景布置,包括在车体周围放置标定布,棋盘格标定布或圆点标定布。

        2 四路鱼眼相机的标定,包括内参标定和鱼眼相机的外参标定,标定每个鱼眼相机之间的相对位姿关系包括两两相机之间的平移与旋转矩阵,具体标定可以通过opencv实现,并配合自动选点算法或手动选点算法。以便于接下来进行全景图像的拼接和融合。

        3 每路鱼眼相机的图像透视变换,将标定后的鱼眼相机根据标定参数和场景布置点位,将鱼眼相机原始图像透视变换后投影到车体的正前方,后方,和两侧方。

        4 全景图像拼接生成鸟瞰图,经透视变换投影后的图,可以通过融合算法进行拼接,对于四个角的重合区域可以通过权重参数和其他融合算法进行融合拼接得到四路相机图像拼接后的2D鸟瞰图。

        5 360环视图的拼接融合,四路鱼眼相机可以通过两两图像间的特征匹配点进行两两融合或者通过相机外参经过旋转变化和平移变换后拼接融合,融合处要处理颜色变化,四路图拼接后得到360环视图,即车体周围整个区域的场景环视图。

        6 模型准备,包括车体模型,碗状模型,和道路模型与停车位模型,以及地面模型。其中车体模型可以由建模软件生成,包括对应的纹理图。碗状模型是把车体周围空间模拟成碗的周围,车体置身于碗底中间位置。

        7 调用opengles进行模型渲染,加载车体模型和碗状模型,加载车体模型纹理文件,进行三角面片的纹理贴图操作对车体进行渲染,利用之前制作的360环视拼接图对碗状模型进行纹理映射,主要是把环视图映射到碗状三角面片顶点,并利用顶点着色器和片段着色器进行模型渲染。同时可以选择不同的视角进行观察。

        8 车体行进路线渲染,根据底板发送的传感器数据,包括转向等参数,利用贝塞尔曲线绘制车道线。

        9 透明底盘,利用opengles的功能函数,可以调整整个车体的透明度,实现透明地盘效果,同时将前视摄像头的图像,透视投影变换后投影到地面上并保存一系列帧,根据车体的行进时间计算并选择历史帧,融合到碗状模型地面上,得到车体透明与行进的效果。同时根据车体轮式里程计的计算结果,可以进行位姿的预测,将当前位姿与历史帧对应起来,后续根据更新的里程计位姿增量选择对应的历史帧,可以改进透明底盘的效果。

        10 仿真平台软件,其实现原理是利用数据回灌,将采集的数据集保存日志,并将其他的传感器信息和任务信息同时保存,包括轮式里程计信息保存。上位机运行opengl,并渲染车体模型,和地面模型后,根据日志回放的数据,对车体和行进路线与相机内容进行渲染计算显示,并动态显示周围停车位检测结果与2D鸟瞰图,3D环视图。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 Android 操作系统,可以使用 OpenGL ES 来创建一个窗口并显示 RGB 图片到屏幕上。下面是一些基本步骤: 1. 创建一个 EGL 上下文和一个窗口表面。 2. 初始化 OpenGL ES 环境和着色器程序。 3. 创建一个纹理对象并将 RGB 图片数据加载到该纹理对象。 4. 将纹理绑定到纹理单元并激活纹理单元。 5. 将纹理坐标和顶点坐标传递到着色器程序。 6. 最后,使用 glDrawArrays() 函数绘制图像。 下面是一些示例代码: ```java public class OpenGLRenderer implements GLSurfaceView.Renderer { private int textureId; @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { // 初始化 OpenGL 环境和着色器程序 GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f); String vertexShaderCode = "attribute vec4 aPosition;" + "attribute vec2 aTextureCoord;" + "varying vec2 vTextureCoord;" + "void main() {" + " gl_Position = aPosition;" + " vTextureCoord = aTextureCoord;" + "}"; String fragmentShaderCode = "precision mediump float;" + "uniform sampler2D uTextureSampler;" + "varying vec2 vTextureCoord;" + "void main() {" + " gl_FragColor = texture2D(uTextureSampler, vTextureCoord);" + "}"; int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); int program = GLES20.glCreateProgram(); GLES20.glAttachShader(program, vertexShader); GLES20.glAttachShader(program, fragmentShader); GLES20.glLinkProgram(program); GLES20.glUseProgram(program); // 创建纹理对象并将 RGB 图片数据加载到该纹理对象 Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.rgb_image); int[] texture = new int[1]; GLES20.glGenTextures(1, texture, 0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, texture[0]); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0); textureId = texture[0]; } @Override public void onSurfaceChanged(GL10 gl, int width, int height) { // 创建 EGL 上下文和一个窗口表面 GLES20.glViewport(0, 0, width, height); EGLDisplay eglDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); int[] version = new int[2]; EGL14.eglInitialize(eglDisplay, version, 0, version, 1); int[] configAttribs = { EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, EGL14.EGL_RED_SIZE, 8, EGL14.EGL_GREEN_SIZE, 8, EGL14.EGL_BLUE_SIZE, 8, EGL14.EGL_ALPHA_SIZE, 8, EGL14.EGL_DEPTH_SIZE, 0, EGL14.EGL_STENCIL_SIZE, 0, EGL14.EGL_NONE }; EGLConfig[] configs = new EGLConfig[1]; int[] numConfigs = new int[1]; EGL14.eglChooseConfig(eglDisplay, configAttribs, 0, configs, 0, configs.length, numConfigs, 0); EGLConfig config = configs[0]; int[] surfaceAttribs = { EGL14.EGL_NONE }; EGLSurface surface = EGL14.eglCreateWindowSurface(eglDisplay, config, getWindow().getDecorView(), surfaceAttribs, 0); int[] contextAttribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE }; EGLContext context = EGL14.eglCreateContext(eglDisplay, config, EGL14.EGL_NO_CONTEXT, contextAttribs, 0); EGL14.eglMakeCurrent(eglDisplay, surface, surface, context); } @Override public void onDrawFrame(GL10 gl) { // 将纹理绑定到纹理单元并激活纹理单元 GLES20.glActiveTexture(GLES20.GL_TEXTURE0); GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId); int uTextureSamplerHandle = GLES20.glGetUniformLocation(program, "uTextureSampler"); GLES20.glUniform1i(uTextureSamplerHandle, 0); // 将纹理坐标和顶点坐标传递到着色器程序 float[] textureCoords = { 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }; int aTextureCoordHandle = GLES20.glGetAttribLocation(program, "aTextureCoord"); GLES20.glEnableVertexAttribArray(aTextureCoordHandle); GLES20.glVertexAttribPointer(aTextureCoordHandle, 2, GLES20.GL_FLOAT, false, 0, ByteBuffer.allocateDirect(textureCoords.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(textureCoords).position(0)); float[] vertices = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; int aPositionHandle = GLES20.glGetAttribLocation(program, "aPosition"); GLES20.glEnableVertexAttribArray(aPositionHandle); GLES20.glVertexAttribPointer(aPositionHandle, 2, GLES20.GL_FLOAT, false, 0, ByteBuffer.allocateDirect(vertices.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(vertices).position(0)); // 使用 glDrawArrays() 函数绘制图像 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4); } private int loadShader(int type, String shaderCode) { int shader = GLES20.glCreateShader(type); GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); return shader; } } ``` 上述代码,`onSurfaceCreated()` 方法初始化 OpenGL 环境和着色器程序,并将 RGB 图片数据加载到纹理对象。`onSurfaceChanged()` 方法创建 EGL 上下文和一个窗口表面。`onDrawFrame()` 方法将纹理绑定到纹理单元并激活纹理单元,将纹理坐标和顶点坐标传递到着色器程序,并使用 glDrawArrays() 函数绘制图像。 请注意,这只是一个基本的示例,实际使用可能需要进行更多的优化和调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江山如画,佳人北望

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值