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瀏覽量
11280 -
攝像頭
+關注
關注
60文章
4841瀏覽量
95691
發布評論請先 登錄
相關推薦
評論