opengl 在显示的图像视频上画框

论坛 期权论坛 脚本     
匿名网站用户   2020-12-21 09:09   48   0

在前面的博客中opengl 显示BMP图像,总结了如何使用opengl显示BMP图像,如何显示BMP图像序列。

在做Object detection的一些工作中,经常会将检测到object用一个框标记出来,这次探索一下如何实现这个功能。

这要使用Opengl的blend功能。

void glBlendFunc(GLenum sfactor,GLenum dfactor);

sfactor

指定如何计算红色,绿色,蓝色和alpha源混合因子。下列符号常量被接受:GL_ZERO,GL_ONE,GL_SRC_COLOR,GL_ONE_MINUS_SRC_COLOR,GL_DST_COLOR,GL_ONE_MINUS_DST_COLOR,GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_DST_ALPHA,GL_ONE_MINUS_DST_ALPHA,GL_CONSTANT_COLOR,GL_ONE_MINUS_CONSTANT_COLOR,GL_CONSTANT_ALPHA,GL_ONE_MINUS_CONSTANT_ALPHA和GL_SRC_ALPHA_SATURATE。初始值为GL_ONE

dfactor

指定如何计算红色,绿色,蓝色和alpha目标混合因子。接受以下符号常量:GL_ZERO,GL_ONE,GL_SRC_COLOR,GL_ONE_MINUS_SRC_COLOR,GL_DST_COLOR,GL_ONE_MINUS_DST_COLOR,GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA,GL_DST_ALPHA,GL_ONE_MINUS_DST_ALPHA。 GL_CONSTANT_COLOR,GL_ONE_MINUS_CONSTANT_COLOR,GL_CONSTANT_ALPHA和GL_ONE_MINUS_CONSTANT_ALPHA。初始值为GL_ZERO

其实原理还时很简单的,图片是一个图层,将框画到另外一个图层上面,将这两个图层进行alpha blending即可。

能用代码说明的问题,尽量上代码:

// show_yuv422p.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <GLTools.h> // OpenGL toolkit
#include <GLShaderManager.h>

#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>


#include <Windows.h>

#include <iostream>
using namespace std;


// settings
const int SCR_WIDTH = 640, SCR_HEIGHT = 480;
GLuint base_prog;
GLuint quad_vbo;
GLuint tex;
unsigned char* image;


GLShaderManager shaderManager;
GLBatch squareBatch;
GLfloat blockSize = 0.2f;
GLfloat vVerts[] = { -blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize, blockSize, 0.0f,
-blockSize, blockSize, 0.0f };


//----------------------------------------------------------------------------
void glAttachShaderSource(GLuint prog, GLenum type, const char * source)
{
 GLuint sh;

 sh = glCreateShader(type);
 glShaderSource(sh, 1, &source, NULL);
 glCompileShader(sh);
 char buffer[4096];
 glGetShaderInfoLog(sh, sizeof(buffer), NULL, buffer);
 glAttachShader(prog, sh);
 glDeleteShader(sh);
}

//----------------------------------------------------------------------------
void Init()
{
 glClearColor(0.0, 0.0, 0.0, 0.0);
 glEnable(GL_DEBUG_OUTPUT);
 //(1) 编写Vertex shader和 Fragment Shader
 static const char quad_shader_vs[] =
  "#version 330 core\n"
  "\n"
  "layout (location = 0) in vec2 in_position;\n"
  "layout (location = 1) in vec2 in_tex_coord;\n"
  "\n"
  "out vec2 tex_coord;\n"
  "\n"
  "void main(void)\n"
  "{\n"
  "    gl_Position = vec4(in_position, 0.0, 1.0);\n"
  "    tex_coord = in_tex_coord;\n"
  "}\n"
  ;

 static const char quad_shader_fs[] =
  "#version 330 core\n"
  "\n"
  "in vec2 tex_coord;\n"
  "\n"
  "layout (location = 0) out vec4 color;\n"
  "\n"
  "uniform sampler2D tex;\n"
  "\n"
  "void main(void)\n"
  "{\n"
  "    color = texture(tex,tex_coord);\n"
  "}\n"
  ;

 //(2) 创建两个Shader实例

 //创建Program对象
 base_prog = glCreateProgram();
 //绑定shader到program对象
 glAttachShaderSource(base_prog, GL_VERTEX_SHADER, quad_shader_vs);
 glAttachShaderSource(base_prog, GL_FRAGMENT_SHADER, quad_shader_fs);
 //链接program
 glLinkProgram(base_prog);


 //初始化Texture
 //定义定点数组
 static const GLfloat quad_data[] =
 {
  -1.0f, -1.0f,
  1.0f, -1.0f,
  -1.0f, 1.0f,
  1.0f, 1.0f,
  /*
  
  0.0f, 1.0f,
  1.0f, 1.0f,
  0.0f, 0.0f,
  1.0f, 0.0f,
  */

  0.0f, 0.0f,
  1.0f, 0.0f,
  0.0f, 1.0f,
  1.0f, 1.0f,
 };


 glGenBuffers(1, &quad_vbo);
 glBindBuffer(GL_ARRAY_BUFFER, quad_vbo);
 glBufferData(GL_ARRAY_BUFFER, sizeof(quad_data), quad_data, GL_STATIC_DRAW);

 glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
 /*
 glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *ptr);
 函数的意义是为 Atrtribute 变量制定VBO中的数据。
  参数:
  1): index  , Attribute的索引
  2): size, Attribute 变量数据是由几个元素组成的, x, y, z, w; 最多四个。
  3): normalized, 是否归一化, 编程1.0以内的数,这样做的目的是减少向gpu传递数据的带宽。
  4): stride, 元素间隔, , 通常是0
  */
 glEnableVertexAttribArray(0);
 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)(8 * sizeof(float)));
 glEnableVertexAttribArray(1);


 char buf[1024];
 glGetProgramInfoLog(base_prog, 1024, NULL, buf);
 printf("Program Info Log = %s\n", buf);

 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
 /*
 void glPixelStorei(GLenum pname,GLint param);
 它含有两个参数:
  pname:指定所要被设置参数的符号名。这里,参数的符号名有两种
    一种是GL_PACK_ALIGNMENT,它影响将像素数据写回到主存的打包形式,对glReadPixels的调用产生影响;
    还有一种是GL_UNPACK_ALIGNMENT,它影响从主存读到的像素数据的解包形式,对glTexImage2D以及glTexSubImage2D产生影响。

  param:指定相应的pname设置为什么值。这个数值一般是1、2、4或8,用于指定存储器中每个像素行有多少个字节对齐。对齐的字节数越高,系统就越能优化。
  在实际代码中,我们看到的是glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  实际上,我们可以这里可以用4(默认值)。因为checkImage能够保证是4字节对齐的。当然,我们可以通过对checkImage的修改使其保证是8字节对齐:
 */

 // texture
 glGenTextures(1, &tex);
 glBindTexture(GL_TEXTURE_2D, tex);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 //如果你想加载视频帧,或图片序列,你需要将以下的glTexImage2D()代码放到display()函数中,并且加上计时函数以便更新画面,如果从摄像机读的帧数据直接贴也是可以的
 int width, height;
 FILE *fp = fopen("D:\\vmshare\\show_yuv422p\\show_yuv422p_on_screen_00000001.bmp", "rb");
 if (!fp) {
  printf("read file error\n");
  return;
 }

 unsigned char buff[4] = { 0 };
 fseek(fp, 18, SEEK_SET);
 fread(buff, 1, 4, fp);
 width = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];
 memset(buff, 0, sizeof(buff));
 fread(buff, 1, 4, fp);
 height = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];

 int line_stride = (width * 3 + 3) / 4 * 4;

 image = (unsigned char *)calloc(1, height * line_stride);
 fseek(fp, 54, SEEK_SET);
 fread(image, 1, height * line_stride, fp);
 fclose(fp);

 
 
 
 if (image)
 {
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, image);
 }
 else
 {
  printf("Failed to load texture");
 }


 glBindTexture(GL_TEXTURE_2D, 0);



 

 shaderManager.InitializeStockShaders();

 //GLint line_width = 0;
 //glGetIntegerv(GL_ALIASED_LINE_WIDTH_RANGE, &line_width);
 //printf("max line width is = %d\n", line_width);
 // Load up a triangle fan
 //squareBatch.Begin(GL_TRIANGLE_FAN, 4);
 //squareBatch.Begin(GL_LINE_STRIP, 4);
 squareBatch.Begin(GL_LINE_LOOP, 4);
 glLineWidth(2.0f);
 squareBatch.CopyVertexData3f(vVerts);
 squareBatch.End();

 
 
}

void load_frame(unsigned char *frame_rgb_buf, int *w, int *h)
{
 char tmp_buf[1024] = { 0 };
 static int index = 1;
 sprintf(tmp_buf, "D:\\vmshare\\show_yuv422p\\show_yuv422p_on_screen_%08d.bmp", index++);
 int width, height;
 FILE *fp = fopen(tmp_buf, "rb");
 if (!fp) {
  printf("read file error\n");
  return;
 }

 printf("read file %s\n", tmp_buf);
 unsigned char buff[4] = { 0 };
 fseek(fp, 18, SEEK_SET);
 fread(buff, 1, 4, fp);
 width = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];
 memset(buff, 0, sizeof(buff));
 fread(buff, 1, 4, fp);
 height = (buff[3] << 24) + (buff[2] << 16) + (buff[1] << 8) + buff[0];

 int line_stride = (width * 3 + 3) / 4 * 4;

 fseek(fp, 54, SEEK_SET);
 fread(frame_rgb_buf, 1, height * line_stride, fp);
 fclose(fp);

 *w = width;
 *h = height;
}
//----------------------------------------------------------------------------
void add_rect_roi()
{
 //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

 GLfloat vRed[] = { 1.0f, 0.0f, 0.9f, 0.5f };

 glEnable(GL_BLEND);
 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
 shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
 squareBatch.Draw();
 glDisable(GL_BLEND);
}

void display(void)
{

 int width = 0;
 int height = 0;
 load_frame(image, &width, &height);
 
 
 if (image)
 {
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, image);
 }
 else
 {
  printf("Failed to load texture");
 }
 
 //glBindTexture(GL_TEXTURE_2D, 0);
 
 glClearColor(0.0, 255, 0.0, 0.0);
 glClear(GL_COLOR_BUFFER_BIT);

 glUseProgram(base_prog);
 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, tex);
 glUniform1i(glGetUniformLocation(base_prog, "tex"), 0);

 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
 add_rect_roi();

 glutSwapBuffers();
}

//----------------------------------------------------------------------------
void OnShutdown()
{
 glUseProgram(0);
 glDeleteProgram(base_prog);
 glDeleteTextures(1, &tex);
 glDeleteVertexArrays(1, &tex);
 //销毁vbo
 glDeleteBuffers(1, &quad_vbo);
 printf("Shutdown successfull");

 if (image) {
  free(image);
  image = NULL;
 }
}


void timeFunc(int value){
 display();
 // Present frame every 40 ms
 glutTimerFunc(40, timeFunc, 0);
}

int main(int argc, char **argv)
{
 glutInit(&argc, argv);

 glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
 glutInitWindowPosition(100, 100);
 glutInitWindowSize(SCR_WIDTH, SCR_HEIGHT);
 glutCreateWindow("GL_MultiThread_Video");
 printf("Version: %s\n", glGetString(GL_VERSION));

 if (glewInit() != GLEW_OK)
 {
  printf("Failed to initialize GLEW ... exiting");
  exit(EXIT_FAILURE);
 }

 Init();

 glutDisplayFunc(display);
 glutTimerFunc(40, timeFunc, 0);
 glutCloseFunc(OnShutdown);

 glutMainLoop();

 return 0;
}

可以通过glLineWidth修改线宽。

如果将这个项目持续下去,下次可以弄一段YUV序列来播放一下。

如果在框上再画一些东西,该如何做呢?多层融合该如何实现呢?稍后分解

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1136255
帖子:227251
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP