0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

GTK渲染摄像头图像数据

嵌入式技术 来源:嵌入式技术 作者:嵌入式技术 2022-12-01 09:19 次阅读

1.GDK简介

绘图工具集(GDK,Graphics Drawing Kit)是在GTK+ 和特定操作系统的应用编程接口(API,Application Program Interface)之间的低级绘图制层—— Linux的API是Xlib。由于GTK和机器的API之间没有直接接口,移植GTK+就成为移植GLIB和GDK的问题。GDK提供像元的绘制能力以及低层的窗口建立和处理能力。对许多应用来说,使用构件时最方便的,但是,如果你想用GTK+编写模拟时钟的应用程序,由于它没有绘制时钟表面的能力,实现这样的任务就有困难了。使用带GDK的绘图区(drawing area)构件代替封装(canned)的构件,即可绘制出任何你需要绘制的内容。

2.绘图子程序

使用GDK子程序编写应用程序并不比直接使用Xlib好多少。幸运的是,GTK+提供一种构件,即绘图区(drawing area)构件。你可以用它来建立需要的手工绘图的应用。可以像使用其它GTK+构件一样使用绘图区构件。而且,使用该构件建立依赖图形的应用也足够灵活,这种方法的优点是可以在同一应用中使用GTK+和GDK。GTK+提供菜单、工具条和其它构件,支持在绘图区构件内进行绘图,而GDK则提供用于绘制线、框、像元、圆和其它图形的API。

每个GDK子程序至少取两个参数:可绘制区(GdkDrawable)和GDKGC。GdkDrawable表示可以在他上面进行绘图的区域,GDKGC包函数颜色和字体信息以及其它绘图信息。

3.Linux下摄像头编程

V4L2是Video for linux2的简称,为linux中关于视频设备的内核驱动。在Linux中,视频设备是设备文件,可以像访问普通文件一样对其进行读写,摄像头在/dev/video*下,如果只有一个视频设备,通常为/dev/video0。

V4L2是针对uvc免驱usb设备的编程框架 ,主要用于采集usb摄像头等。

  • 摄像头框架编程步骤

(1)打开摄像头设备(/dev/video0 、/dev/video1 )。
(2)设置图像格式:VIDIOC_S_FMT(视频捕获格式、图像颜色数据格式、图像宽和高)。
(3)申请缓冲区:VIDIOC_REQBUFS(缓冲区数量、缓冲映射方式、视频捕获格式)。
(4)将缓冲区映射到进程空间:VIDIOC_QUERYBUF(要映射的缓冲区下标、缓冲映射方式、视频捕获格式)。
(5)将缓冲区添加到队列中:VIDIOC_QBUF(映射的缓冲区下标、缓冲映射方式、视频捕获格式)。
(6)开启摄像头采集:VIDIOC_STREAMON (视频捕获格式)。
(7)从采集队列中取出图像数据VIDIOC_DQBUF,进行图像渲染。

  • 摄像头采集示例
#include 
#include  //摄像头头文件
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "camera.h"
/*摄像头初始化*/
int Camera_Init(struct _CAMERA *video_info)
{
	int i=0;
	/*1.打开摄像头设备*/
	int fd=open(VIDEO_DEV,2);
	if(fd<0)return -1;//摄像头打开失败
	/*2.设置摄像头捕获格式*/
	struct v4l2_format v4l2fmt;
	memset(&v4l2fmt,0,sizeof(v4l2fmt));//初始化结构体
	v4l2fmt.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
	v4l2fmt.fmt.pix.width=640;//图像宽度
	v4l2fmt.fmt.pix.height=480;//图像高度
	v4l2fmt.fmt.pix.pixelformat=V4L2_PIX_FMT_YUYV;//YUYV颜色编码格式
	if(ioctl(fd,VIDIOC_S_FMT,&v4l2fmt))return -2;//设置格式失败
	printf("采集图像大小:%d*%dn",v4l2fmt.fmt.pix.width,v4l2fmt.fmt.pix.height);
	video_info->image_w=v4l2fmt.fmt.pix.width;
	video_info->image_h=v4l2fmt.fmt.pix.height;
	/*3.申请缓冲区*/
	struct v4l2_requestbuffers v4l2reqbuf;
    memset(&v4l2reqbuf,0,sizeof(v4l2reqbuf));//初始化结构体
	v4l2reqbuf.count=4;//申请的缓冲区个数
	v4l2reqbuf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
	v4l2reqbuf.memory=V4L2_MEMORY_MMAP;//内存映射
	if(ioctl(fd,VIDIOC_REQBUFS,&v4l2reqbuf))return -3;//申请缓冲区失败
	printf("申请的缓冲区个数:%dn",v4l2reqbuf.count);
	/*4.将缓冲区映射到进程空间*/
	struct v4l2_buffer v4l2buf;
	memset(&v4l2buf,0,sizeof(v4l2buf));//初始化结构体
	v4l2buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
	v4l2buf.memory=V4L2_MEMORY_MMAP;//内存映射
	for(i=0;ivideo_buff[i]=mmap(NULL,v4l2buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,v4l2buf.m.offset);
		printf("video_buff[%d]=%pn",i,video_info->video_buff[i]);
	}
	video_info->video_len=v4l2buf.length;//yuv图像数据字节数
	printf("yuv_size=%dn",video_info->video_len);
	/*5.将映射的空间添加到采集队列*/
	memset(&v4l2buf,0,sizeof(v4l2buf));//初始化结构体
	v4l2buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
	v4l2buf.memory=V4L2_MEMORY_MMAP;//内存映射
	for(i=0;ivideo_fd=fd;//摄像头描述符
	return 0;//初始化成功返回0
}
;i++)>;i++)>

4.GDK渲染

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include "camera.h"
struct _CAMERA video_info;/*设备结构体信息*/
int width,height;//图像宽高
guchar *rgbbuf=NULL;//保存rgb颜色数据
GtkWidget *drawarea;

int on_delete_event(GtkWidget *widget,GdkEvent *event,gpointer data)
{  
	/*释放资源*/
	g_print("释放资源n");
	for(int i=0;i<4;i++)
	{
		munmap(video_info.video_buff[i],video_info.video_len);
	}
	free(rgbbuf);
	close(video_info.video_fd); 
	gtk_main_quit();
	return FALSE;
}


int draw_image(GtkWidget *widget,GdkEvent *event,gpointer data)
{ 
 	gdk_draw_rgb_image(widget->window,widget->style->fg_gc[GTK_STATE_NORMAL],0,0,width,height,GDK_RGB_DITHER_NONE,rgbbuf,width*3);
	return FALSE;
}
/*YUYV转RGB888*/
void yuv_to_rgb(unsigned char *yuv_buffer,unsigned char *rgb_buffer,int iWidth,int iHeight)
{
	int x;
	int z=0;
	unsigned char *ptr = rgb_buffer;
	unsigned char *yuyv= yuv_buffer;
	for (x = 0; x < iWidth*iHeight; x++)
	{
		int r, g, b;
		int y, u, v;
		if (!z)
		y = yuyv[0] << 8;
		else
		y = yuyv[2] << 8;
		u = yuyv[1] - 128;
		v = yuyv[3] - 128;
		b = (y + (359 * v)) >> 8;
		g = (y - (88 * u) - (183 * v)) >> 8;
		r = (y + (454 * u)) >> 8;
		*(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);
		*(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
		*(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
		if(z++)
		{
			z = 0;
			yuyv += 4;
		}
	}
}


int read_data(GtkWidget * widget,GdkEvent * event,gpointer data)
{    
	/*读取摄像头图像数据*/
	struct v4l2_buffer v4l2buf;
	memset(&v4l2buf,0,sizeof(v4l2buf));
	//初始化结构体
	v4l2buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
	v4l2buf.memory=V4L2_MEMORY_MMAP;//内存映射
	if(ioctl(video_info.video_fd,VIDIOC_DQBUF,&v4l2buf)==-1)
	{
		printf("Dqbuf failedn");
		return FALSE;
	}
	//将yuyv转换为rgb24
	yuv_to_rgb(video_info.video_buff[v4l2buf.index],rgbbuf,width,height);
	/*保证线程安全,上锁*/
	gdk_threads_enter();
	gdk_draw_rgb_image(drawarea->window,drawarea->style->fg_gc[GTK_STATE_NORMAL],0,0,width,height,GDK_RGB_DITHER_NONE,rgbbuf,width*3);
	/*保证线程安全,释放*/
	gdk_threads_leave();
	ioctl(video_info.video_fd,VIDIOC_QBUF,&v4l2buf);//将缓冲区添加回采集队列
	return TRUE;
}


int main (int argc,char *argv[])
{
	/*摄像头初始化*/
	int ret=Camera_Init(&video_info);
	if(ret)
	{
		printf("摄像头打开失败ret=%dn",ret);
		return 0;
	}
	/*图像宽高*/
	width=video_info.image_w;
	height=video_info.image_h;
	rgbbuf=malloc(width*height*3);
	/* init Gtk */
	GtkWidget *window;
	/*gtk初始化*/
	gtk_init(&argc,&argv);
	/*创建窗口*/
	window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(window),"摄像头采集");
	/*固定窗口大小*/
	gtk_window_set_resizable (GTK_WINDOW(window),FALSE);
	
	/*连接信号*/
	g_signal_connect(G_OBJECT(window),"destroy",G_CALLBACK(on_delete_event),NULL);

	/*初始化gdk的rgb*/
	gdk_rgb_init();
	gtk_widget_push_visual(gdk_rgb_get_visual());
	gtk_widget_push_colormap(gdk_rgb_get_cmap());
	/*创建绘图区域*/
	drawarea=gtk_drawing_area_new();
	gtk_widget_pop_visual();
	gtk_widget_pop_colormap();
	
	gtk_container_add(GTK_CONTAINER(window),drawarea);
	g_signal_connect(G_OBJECT(drawarea),"expose_event",G_CALLBACK(draw_image),NULL);
	guint id=gtk_idle_add((GtkFunction)read_data,NULL);
	/*设置窗口大小*/
	gtk_widget_set_size_request(GTK_WIDGET(drawarea),width,height);
	gtk_widget_show_all(window);
	gtk_main();
	gdk_threads_leave();
	return 0;
}

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 图像数据
    +关注

    关注

    0

    文章

    52

    浏览量

    11271
  • 摄像头
    +关注

    关注

    59

    文章

    4810

    浏览量

    95442
收藏 人收藏

    评论

    相关推荐

    USB摄像头图像采集

    一个比较简单的编程,实现简单的USB摄像头图像显示
    发表于 11-12 15:48

    USB摄像头图像拍摄

      请问labview如何能实现使用USB摄像头进行时间间隔拍摄图像,并保存到数据库。请高手指点一二,谢谢
    发表于 11-26 11:12

    关于摄像头图像采集问题

    `我用labview实现电脑摄像头图像采集,运行过程中出现问题了,截图如下,还请高手指教!谢谢啦`
    发表于 05-25 16:59

    u***摄像头的使用

    u***摄像头想要采集图像信息,通过单片机驱动之后无线传输给pc终端。第一步是不是要做好u***摄像头和单片机之间的驱动啊 没做过摄像头这方面 应该从哪些地方学起啊u***和单片机之间
    发表于 02-06 11:59

    摄像头采集图像处理

    就可以做到实际中图像处理并且做到无线传输。这样的图像采集处理功能在监控系统和在线检测都有很大的前景。 本作品是基于安芯一号SLH89F5162单片机,驱动并控制带FIFO的OV7670CMOS摄像头
    发表于 11-05 22:35

    【转载分享】USB摄像头采集图像

    `如果你有USB摄像头,就是随便的那种。平时QQ视频的就可以了(笔记本上自带的摄像头,也可以),那你就可以用LabVIEW进行图像采集了。注意:由于LabVIEW8.6是个神奇的版本,有些函数改版了
    发表于 03-02 11:36

    USB摄像头怎么调图像效果?

    有没有做USB摄像头的,会调图像效果的?
    发表于 11-14 16:38

    labview图像采集怎么无法连接USB摄像头

    在labview中图像采集无法连接USB摄像头,只能连接电脑自带摄像头是怎么回事,求指教
    发表于 05-08 17:55

    【案例分享】机器视觉应用的摄像头设计

    接收器等终端数据采集系统。帧接收器在存储器中存储数据,随后可由主机应用软件对数据进行存取以处理和控制。摄像头连接到主机的电气接口包括:1 火线 IEEE 1394 接口 2 USB 接
    发表于 07-19 04:30

    回收手机摄像头,收购摄像头芯片

    芯片,国外的有索尼,OV,镁光,联咏,安霸,国内的有比亚迪微,格科微,锐芯微,思比科,中星微等等,这些品牌的图像传感器我们都高价回收。全新的感光芯片,摄像头模组,拆机的CCD板,拆机的摄像头,我们统统
    发表于 07-14 17:53

    【FPGA DEMO】Lab 4:摄像头HDMI显示(高速--HDMI&摄像头)

    `项目名称:摄像头HDMI显示。具体要求:摄像头采集的视频图像数据通过HDMI实时显示。 系统设计:Perf-V开发板可以连接高速口——HDMI&
    发表于 07-30 15:21

    如何读取摄像头图像数据

    如何读取摄像头图像数据
    发表于 11-08 07:49

    OV7725摄像头图像处理设计实现

    这次更新图像处理部分,主要是为了提取出=信标灯,并求出信标灯在图像中的坐标。程序代码可完善的地方还有很多,主要还是提供一种当时我们参赛的解决思路,抛砖引玉。摄像头采用中断的方式来采集图像
    发表于 01-11 08:03

    用QT5的qml和gstreamer来渲染摄像头图像,qml在显示相机的时候经常会报错的原因?

    你好我是用QT5的qml和gstreamer来渲染摄像头图像,但是我的CPU和内存占用率很高,但是当我用gst-launch-1.0显示摄像头实时
    发表于 04-06 06:57

    华为Mate30Pro最新渲染图曝光,与之前摄像头采用“十”字排列不同

    8月28日消息 近日,9TechEleven曝光了华为Mate 30 Pro最新渲染图,和之前摄像头采用“十”字排列不同,这次的渲染摄像头组合为正方形排列。
    的头像 发表于 08-28 08:58 3502次阅读