在前面的博客中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 Shaderstatic 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);//链接programglLinkProgram(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字节对齐:*/// textureglGenTextures(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);//销毁vboglDeleteBuffers(1, &quad_vbo);printf("Shutdown successfull");if (image) {free(image);image = NULL;}
}void timeFunc(int value){display();// Present frame every 40 msglutTimerFunc(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序列来播放一下。

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

opengl 在显示的图像视频上画框相关推荐

  1. 通过cv2读取视频,并在视频上画框

    该教程适合做个十几秒的demo,先通过opencv读取视频流并将图片每帧都保存下来,然后在图片上通过labelImg软件进行画框(打标签),并将生成的xml文件保存到同一目录下. #! encodin ...

  2. 利用鼠标在图像上画框并实时显示鼠标所点击处坐标

    我们在做小型项目的时候,有时为了实现良好的交互,或者更方便实时观察输入数据,通常需要使用到下列几项功能: 1.利用鼠标在所显示的图像/视频中选取ROI区域 2.实时显示鼠标所点击位置处的坐标信息 本文 ...

  3. 基于c++的模拟爱奇艺web视频上传

    资源下载地址:https://download.csdn.net/download/sheziqiong/85883761 资源下载地址:https://download.csdn.net/downl ...

  4. OpenCv初学者学习笔记(一):图像视频的加载与显示

    目录 一.图像视频的加载与显示 1.1创建和显示窗口 1.2加载显示图片 1.3保存图片 1.4视频采集 1.5视频录制 1.1创建和显示窗口 cv2.namedWindow() 创建命名窗口 cv2 ...

  5. QT框架下的OpenGL使用---实战篇---图像的显示

    阅读本篇文章需要提前掌握OpenGL纹理的相关知识. 做计算机视觉或者播放器等项目,通常需要将图像处理的结果显示给用户看,在Qt上可以用label控件来完成,但其效率相对较低.这里我们介绍一种用Qt自 ...

  6. OpenCV初尝试1——图像视频的加载和显示

    1. 图像视频的加载和显示 第一次的内容比较基础,因为本人也是初学OpenCV甚至Python的基础都不是怎么好(之前一直在学Java). 当然首先需要准备好OpenCV的环境,这些一般B站讲Open ...

  7. jetson nano 在opencv拉流的视频上显示中文汉字(含c++完整源码)

    目录 问题 解决方案 步骤一:生成中文图片 步骤二:中文图片蒙皮到视频帧,形成中文显示效果 问题 在jetson nano这样的嵌入式设备上,用opencv拉流,并在实时视频上面,显示汉字. 关于使用 ...

  8. opencv-python 中文显示在图像上

    opencv-python 中文显示在图像上 opencv只能在图像上输出英文字符,不支持汉字.可以和PIL一起使用实现在图像上输出中文.结合使用时注意一下几点: 1)opencv读取图像后图像颜色通 ...

  9. 使用鼠标从Matplotlib显示的图像中取点,画框

    使用鼠标从Matplotlib显示的图像中取点,画框 #定义全局变量:PT表示鼠标从plt图中取到的点;默认情况下取左上角点和右下角点 PT=[]def on_press(event):if even ...

最新文章

  1. GitHub标星近1万:只需5秒音源,这个网络就能实时“克隆”你的声音
  2. 中小型互联网企业安全建设漫谈。
  3. Linux 系统工具
  4. 计算圆形是否和正方形相交 【微软面试100题 第二十三题】
  5. 【Qt】数据库用户接口层
  6. 遥感方法研究张掖市1999-2010年土地利用变化
  7. android中拷贝assets下的资源文件到SD卡中(可以超过1M)
  8. RuntimeError: Python is not installed as a framework 错误解决方案
  9. iOS 自带地图定位失败原因 Code=0和Code=1区别
  10. Django之ModelForm使用
  11. Expression Blend实例中文教程(5) - 布局控件快速入门StackPanel,ScrollViewer和Border
  12. MATLAB下载教程
  13. Office word for Mac 如何并排查看两个文档
  14. PCI E 阻抗85/100
  15. iOS shareExtension总结分享
  16. Android系统版本在6.0+以上需要动态申请权限
  17. JavaWeb购物车项目二
  18. iframe嵌入网页的用法
  19. VisionPro(1) —— 简介
  20. 一文搞懂常用的网络概念:域名、动态IP、DNS、DDNS

热门文章

  1. android hide qq红包,伪装QQ红包绕过URL检测
  2. dnf服务器未响应怎么解决方法,dnf发生未响应的解决办法途径
  3. centos6.2最小安装下的无线路由上网设置
  4. 学习笔记(01):8小时学会HTML网页开发-了解HTML
  5. [软件更新]WordPress v2.8.1 Final
  6. 日本最大菜谱网站Cookpad微服务经验总结
  7. java毕业设计大学生第二课堂Mybatis+系统+数据库+调试部署
  8. Enter键的触发事件
  9. 判断服务器IP否被墙 是否被TCP阻断
  10. 和平精英火力团竞模式怎么玩才能获得胜利?