#include "imagecamera.h"
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <QDir>
#include <dirent.h>
#include <unistd.h>
#include <asm/types.h>
#include <math.h>
#include <malloc.h>
#include <QImage>
#include <QDebug>
#include "opencv2/imgcodecs.hpp"
#include <iostream>
std::string ImageCamera::get_device_info(const char* dev_name)
{
int fd = open(dev_name, O_RDWR);
if (fd == -1) {
perror("Failed to open device");
return std::string();
}
struct v4l2_capability cap;
if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) {
perror("VIDIOC_QUERYCAP failed");
close(fd);
return std::string();
}
std::cout << "Device: " << dev_name << "\n";
std::cout << "Driver: " << cap.driver << "\n";
std::cout << "Card: " << cap.card << "\n";
std::cout << "Bus Info: " << cap.bus_info << "\n";
std::cout << "Version: " << cap.version << "\n";
std::cout << "Capabilities: 0x" << std::hex << cap.capabilities << "\n";
close(fd);
return std::string((const char*)cap.card);
}
std::map<std::string,std::string> ImageCamera::listCameras()
{
DIR *dir;
struct dirent *ent;
std::map<std::string,std::string> l_card_device;//key:card value:device
if ((dir = opendir("/dev")))
{
while ((ent = readdir(dir)) != NULL)
{
if (strncmp(ent->d_name, "video", 5) == 0) {
std::string dev_name = "/dev/";
dev_name += ent->d_name;
auto l_card=get_device_info(dev_name.c_str());
l_card_device[l_card]=dev_name;
}
}
closedir(dir);
} else {
perror("Failed to open /dev directory");
return l_card_device;
}
return l_card_device;
}
ImageCamera::ImageCamera(QString c, QObject *parent)
:QObject(parent)
{
camera = c;
err.clear();
memset(pix_format, 0, sizeof(pix_format));
cam_fd = -1;
buffer_count = 1; //5; // count 指定根据图像占用空间大小申请的缓存区个数
video_buffer_ptr = new u8*[buffer_count];
}
ImageCamera::~ImageCamera()
{
if(video_buffer_ptr!=nullptr)
delete video_buffer_ptr;
}
bool ImageCamera::OpenCamera(const int width,const int height)
{
nWidth = width;
nHeight = height;
nSize = nWidth * nHeight * 2;
int index = 0;
int ret = 0;
if(camera.isEmpty())
{
err = QString("设备节点位置为空");
return false;
}
if(cam_fd != -1)
{
close(cam_fd);
}
// 打开相机设备节点
cam_fd = open(camera.toStdString().c_str(), O_RDWR);
if(cam_fd == -1)
{
err = QString("打开相机节点失败");
return false;
}
// 设置使用的相机通道,此处为0
if(0 != ioctl(cam_fd, VIDIOC_S_INPUT, &index))
{
err = QString("%1").arg(strerror(errno));
close(cam_fd);
cam_fd=-1;
return false;
}
// 查询相机的基本信息
struct v4l2_capability cap;
ioctl(cam_fd, VIDIOC_QUERYCAP, &cap);
qDebug("Driver Name:%s, Card Name:%s, Bus info:%s, Driver Version:%u.%u.%u",
cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0xFF, (cap.version>>8)&0xFF,cap.version&0xFF);
// 查询相机支持的采图格式
struct v4l2_fmtdesc fmtdesc;
fmtdesc.index=0;
fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
qDebug("Support format:");
do{
ret=ioctl(cam_fd, VIDIOC_ENUM_FMT, &fmtdesc);
qDebug("index %d, format %s", fmtdesc.index, fmtdesc.description);
fmtdesc.index++;
}while(0==ret);
// 查询相机支持的帧率范围
struct v4l2_streamparm stream_parm;
memset(&stream_parm, 0, sizeof(struct v4l2_streamparm));
stream_parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(cam_fd, VIDIOC_G_PARM, &stream_parm);
qDebug("FrameRate: numerator = %d, denominator = %d",
stream_parm.parm.capture.timeperframe.numerator, stream_parm.parm.capture.timeperframe.denominator);
// 设置相机的输出格式,图片大小等数据
struct v4l2_format format;
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; // 设置相机输出为JPEG(V4L2_PIX_FMT_MJPEG),也可设置为yuyv(V4L2_PIX_FMT_YUYV),
format.fmt.pix.width = nWidth; // 设置输出图片宽、高
format.fmt.pix.height = nHeight;
// 尝试相机是否支持改格式
ret = ioctl(cam_fd, VIDIOC_TRY_FMT, &format);
if (ret != 0)
{
err = QString::asprintf("ioctl(VIDIOC_TRY_FMT) failed %d(%s)", errno, strerror(errno));
qDebug(err.toLatin1().constData());
close(cam_fd);
cam_fd=-1;
return false;
}
// 真正进行设置改格式
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ret = ioctl(cam_fd, VIDIOC_S_FMT, &format);
if (ret != 0)
{
err = QString::asprintf("ioctl(VIDIOC_S_FMT) failed %d(%s)", errno, strerror(errno));
qDebug(err.toLatin1().constData());
close(cam_fd);
cam_fd=-1;
return false;
}
// 获取相机输出的图片参数
if(-1 == ioctl(cam_fd, VIDIOC_G_FMT, &format)){ // 得到图片格式
err = QString("set format failed!");
qDebug(err.toLatin1().constData());
close(cam_fd);
cam_fd=-1;
return false;
}
qDebug("fmt.type:\t\t%d",format.type);
/**************************************************************/
// 此处的图片格式,决定着采集到的图片数据要怎么解析,一般分为 MJPG 和 YUYV,上面设置的和此处获取的在某些情况下会不一致,因此需要此处决定解析格式
sprintf(pix_format, "%c%c%c%c", \
format.fmt.pix.pixelformat & 0xFF,\
(format.fmt.pix.pixelformat >> 8) & 0xFF, \
(format.fmt.pix.pixelformat >> 16) & 0xFF,\
(format.fmt.pix.pixelformat >> 24) & 0xFF);
qDebug("pix.pixelformat:\t%s", pix_format);
qDebug("pix.width:\t\t%d",format.fmt.pix.width);
qDebug("pix.height:\t\t%d",format.fmt.pix.height);
qDebug("pix.field:\t\t%d",format.fmt.pix.field);
// 查询相机需要开辟的内存信息
// 向驱动申请视频流数据的帧缓冲区
struct v4l2_requestbuffers req;
req.count = buffer_count;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ret = ioctl(cam_fd, VIDIOC_REQBUFS, &req); // 申请若干个帧缓冲区
if (ret != 0)
{
err = QString::asprintf("ioctl(VIDIOC_REQBUFS) failed %d(%s)", errno, strerror(errno));
qDebug(err.toLatin1().constData());
close(cam_fd);
cam_fd=-1;
return false;
}
qDebug("req.count: %d", req.count);
if (req.count < buffer_count)
{
err = QString::asprintf("request buffer failed");
qDebug(err.toLatin1().constData());
close(cam_fd);
cam_fd=-1;
return false;
}
// 逐一将相机开辟的内存进行内存映射
// 应用程序通过内存映射,将帧缓冲区的地址映射到用户空间
struct v4l2_buffer buffer;
memset(&buffer, 0, sizeof(buffer));
buffer.type = req.type;
buffer.memory = V4L2_MEMORY_MMAP;
for (int i=0; i<req.count; i++)
{
buffer.index = i;
ret = ioctl (cam_fd, VIDIOC_QUERYBUF, &buffer); // 查询帧缓冲区的内核空间中的长度和偏移量
if (ret != 0)
{
err = QString::asprintf("ioctl(VIDIOC_QUERYBUF) failed %d(%s)", errno, strerror(errno));
qDebug(err.toLatin1().constData());
return false;
}
qDebug("buffer.length: %d", buffer.length);
qDebug("buffer.m.offset: %d", buffer.m.offse
没有合适的资源?快使用搜索试试~ 我知道了~
温馨提示
使用Qt C++实现了Linux (麒麟)系统下USB免驱相机的控制。代码包括相机输出图像的大小设置、格式设置(MJPG YUV)。能够设置相机的曝光、白平衡、色调、增益、gamma、锐度等相机参数。读取图像数据后,根据相机的格式将其转换为opencv能够处理的Mat数据格式。整个类使用了Qt C++ 开发,开发环境麒麟操作系统
资源推荐
资源详情
资源评论
收起资源包目录
linux-相机控制-opencv.7z (2个子文件)
linux-相机控制-opencv
imagecamera.h 2KB
imagecamera.cpp 18KB
共 2 条
- 1
资源评论
shaoshuaithe
- 粉丝: 3
- 资源: 18
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功