- 转载请注明作者和出处:http://blog.csdn.net/u011475210
- 嵌入式平台:NVIDIA Jetson TX1
- 嵌入式系统:Ubuntu16.04
- 虚拟机系统:Ubuntu14.04
- 编者: WordZzzz
写在前面:
本篇博文主要用来讲解上篇博文中关于V4L2框架的程序部分,并在其基础上实现预览和拍照功能的实现.其中,预览分辨率640480,用键盘检测来改变标志位,当标志位改变时进行拍照,拍照分辨率19201080,随后自动切换回预览模式,肉眼基本看不出切换卡顿。
一、V4L2框架:
V4L2程序是基于标准的V4L2框架来写的,大部分程序注释都已给出,如果还有什么不清楚的地方,可以评论、私信或自行查阅V4L2开发手册。
下图是标准V4L2程序流程图。
博客中的程序,在标准V4L2程序的基础上进一步进行了封装,主要是为了实现拍照与预览模式的切换。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55/*
* v4l2cap.h
*
* Created on: Jul 26, 2017
* Author: wordzzzz
*/
#ifndef V4L2CAP_H_
#define V4L2CAP_H_
#include "include.h"
#define CLEAR(x) memset(&(x), 0, sizeof(x))
#define TRUE 1
#define FALSE 0
class V4L2Capture {
public:
V4L2Capture(char *devName, int width, int height, int width_cap, int height_cap);
virtual ~V4L2Capture();
int openDevice();
int closeDevice();
int initDevice();
int initDeviceCap();
int startCapture();
int stopCapture();
int freeBuffers();
int getFrame(void **,size_t *);
int backFrame();
int pre2cap();
int cap2pre();
int preBegin();
int preEnd();
int initBuffers();
struct cam_buffer
{
void* start;
unsigned int length;
};
char *devName;
int widthCap;
int heightCap;
int width;
int height;
int fd_cam;
cam_buffer *buffers;
unsigned int n_buffers;
int frameIndex;
};
#endif /* V4L2CAP_H_ */
1 | /* |
二、键盘检测:
主要实现的功能是通过模拟kbhit功能,实现在线程中完成对键盘的检测功能(检测到‘c’时标志位置1)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28/*
* pthread.h
*
* Created on: Jul 27, 2017
* Author: wordzzzz
*/
#ifndef PTHREAD_H_
#define PTHREAD_H_
#include "include.h"
static __inline
int tty_reset(void);
static __inline
int tty_set(void);
static __inline
int kbhit(void);
void *thread(void *arg);
static struct termios ori_attr, cur_attr;
extern uchar flag;
#endif /* PTHREAD_H_ */
1 | /* |
三、主函数:
include.h里面包含我们所有用到的头文件。
1 | /* |
主函数主要实现预览模式的开启、键盘检测线程开启,预览和拍照模式的切换等功能,总体程序比较简单。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88/*
* main.cpp
*
* Created on: Jul 26, 2017
* Author: wordzzzz
*/
#include "include.h"
#include "v4l2cap.h"
#include "thread.h"
#define IMAGEWIDTH_CAP 1920 //拍照分辨率
#define IMAGEHEIGHT_CAP 1080//拍照分辨率
#define IMAGEWIDTH 640 //预览分辨率
#define IMAGEHEIGHT 480 //预览分辨率
#define TRUE 1
#define FALSE 0
uchar flag;
int main()
{
IplImage* img,* img_cap;
CvMat cvmat,cvmat_cap;
double t;
flag=0;
unsigned char *frame = NULL;
unsigned long frameSize = 0;
string videoDev="/dev/video1";//制定设备号
V4L2Capture *vcap = new V4L2Capture(const_cast<char*>(videoDev.c_str()),
IMAGEWIDTH, IMAGEHEIGHT, IMAGEWIDTH_CAP, IMAGEHEIGHT_CAP);
vcap->preBegin();//预览模式开启
cvNamedWindow("one",CV_WINDOW_AUTOSIZE);//创建显示窗口
pthread_t id;
printf("Main thread id is %d \n",pthread_self());
if(!pthread_create(&id,NULL,thread,NULL))
{
printf("succeed!\n");
}
else
{printf("Fail to Create Thread");
return -1;
}
while(1){
//如果flag为1,则抓取一张照片
if(flag == 1){
vcap->pre2cap(); //预览模式切换至拍照模式
//这里多获取几次图像队列,以便得到更高的图像质量(刚打开设备时图像模糊)
vcap->getFrame((void **) &frame, &frameSize);vcap->backFrame();
vcap->getFrame((void **) &frame, &frameSize);vcap->backFrame();
vcap->getFrame((void **) &frame, &frameSize);
cvmat_cap = cvMat(IMAGEHEIGHT_CAP,IMAGEWIDTH_CAP,CV_8UC3,frame);//CV_8UC3
img_cap = cvDecodeImage(&cvmat_cap,1);//OpenCV图像解码
if(!img_cap) printf("No img_cap\n");
cvSaveImage("cap.jpg",img_cap); //保存图片
cvReleaseImage(&img_cap); //释放img_cap
vcap->backFrame(); //返回队列
vcap->cap2pre(); //拍照模式切换至预览模式
flag = 0;
}
t = (double)cvGetTickCount();
vcap->getFrame((void **) &frame, &frameSize);
cvmat = cvMat(IMAGEHEIGHT,IMAGEWIDTH,CV_8UC3,frame);//CV_8UC3
img = cvDecodeImage(&cvmat,1); //OpenCV图像解码
if(!img) printf("No img\n");
cvShowImage("one",img); //显示图片
cvReleaseImage(&img); //释放img
vcap->backFrame(); //返回队列
cvWaitKey(1); //没有这句话图像无法显示
t=(double)cvGetTickCount()-t;
printf("used time is %gms\n",(t/(cvGetTickFrequency()*1000)));
}
pthread_exit(0); //退出键盘检测线程
vcap->preEnd(); //预览模式结束
return 0;
}
系列教程持续发布中,欢迎订阅、关注、收藏、评论、点赞哦~~( ̄▽ ̄~)~
完的汪(∪。∪)。。。zzz