GPU端到端目标检测YOLOV3全过程(中)

GPU端到端目标检测YOLOV3全过程(中)
 
计算机视觉初级部分知识体系
 
 
 
 
 
 
 
 
 
 
 

总结了一下自己在计算机视觉初级部分的知识框架,整理如下。 
个人所学并不全面(比如图像频域方面了解就比较少),仅做参考。

图像点(pixel值)运算

1. 直方图;
2. 线性/非线性变换;
3. 灰度均衡化/规定化;
4. H-S直方图

图像几何变换

1. 平移、旋转、镜像、缩放(图像金字塔,图像多尺度表达的一种方法,高斯金字塔、拉普拉斯金字塔);
2. 仿射变换

空间域滤波

1. 线性滤波
2. 均值滤波、高斯滤波
3. 非线性滤波
4.  中值滤波、双边滤波   

频域图像处理

傅里叶变换

形态学处理

腐蚀、膨胀、开运算、闭运算
   

边缘检测

Canny
;
sobel
算子(求梯度)、
和
DoG
(
DoG
是
的一种简化算法)

hough变换

适用于直线、圆等其他具有解析式的简单形状

阈值

1. 自适应阈值;
2. 双阈值(Canny中有使用);
3. 非极大值抑制(应用广泛,如目标检测)

轮廓

寻找轮廓、存储轮廓、多边形包围、轮廓的矩

局部特征

1. 特征检测
2.     blob detection
3.         SIFT(尺度不变性、旋转不变性)、SURF(可用于不同帧间的匹配)
4.     corner detection
5.         Harris(单帧图像中)、Shi-Tomasi、亚像素级
6. 特征描述
7.     梯度统计直方图
8.         SIFT、SURF、HOG、KAZE
9.     二进制字符串特征描述子(使用汉明距离匹配)
10.                   ORB、LBP、BRIEF、BRISK、FREAK
11.           应用
12.               寻找已知物体(匹配,模板匹配)、透视变换    

相机几何模型与相机标定

2D-to-3D reconstruction

1. single image
2. 2-image
3. 3-image
4. N-image
5. bundle adjustment approach
6. Kalman Filter

Novel sensors

1. Structured light(Kinect)
2. Time of flight laser

 

视频采集的基本流程

 

2、 打开视频设备

在V4L2中,视频设备被看做一个文件。使用open函数打开这个设备:

// 用非阻塞模式打开摄像头设备
int cameraFd;
cameraFd = open("/dev/video0", O_RDWR | O_NONBLOCK, 0);
// 如果用阻塞模式打开摄像头设备,上述代码变为:
//cameraFd = open("/dev/video0", O_RDWR, 0);

关于阻塞模式和非阻塞模式:应用程序能够使用阻塞模式或非阻塞模式打开视频设备,如果使用非阻塞模式调用视频设备,即使尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序。

3、 设定属性及采集方式

打开视频设备后,可以设置该视频设备的属性,例如裁剪、缩放等。这一步是可选的。在Linux编程中,一般使用ioctl函数来对设备的I/O通道进行管理:

extern int ioctl (int __fd, unsigned long int __request, ...) __THROW;

__fd:设备的ID,例如刚才用open函数打开视频通道后返回的cameraFd;

__request:具体的命令标志符。

在进行V4L2开发中,一般会用到以下的命令标志符:

VIDIOC_REQBUFS:分配内存 

VIDIOC_QUERYBUF:把VIDIOC_REQBUFS中分配的数据缓存转换成物理地址 

VIDIOC_QUERYCAP:查询驱动功能 

VIDIOC_ENUM_FMT:获取当前驱动支持的视频格式 

VIDIOC_S_FMT:设置当前驱动的频捕获格式 

VIDIOC_G_FMT:读取当前驱动的频捕获格式 

VIDIOC_TRY_FMT:验证当前驱动的显示格式 

VIDIOC_CROPCAP:查询驱动的修剪能力 

VIDIOC_S_CROP:设置视频信号的边框 

VIDIOC_G_CROP:读取视频信号的边框 

VIDIOC_QBUF:把数据从缓存中读取出来 

VIDIOC_DQBUF:把数据放回缓存队列 

VIDIOC_STREAMON:开始视频显示函数 

VIDIOC_STREAMOFF:结束视频显示函数 

VIDIOC_QUERYSTD:检查当前视频设备支持的标准,例如PAL或NTSC。 

这些IO调用,有些是必须的,有些是可选择的。

4、 检查当前视频设备支持的标准

在亚洲,一般使用PAL(720X576)制式的摄像头,而欧洲一般使用NTSC(720X480),使用VIDIOC_QUERYSTD来检测:

v4l2_std_id std;
do {
  ret = ioctl(fd, VIDIOC_QUERYSTD, &std);
} while (ret == -1 && errno == EAGAIN);
switch (std) {
    case V4L2_STD_NTSC:
        //……
    case V4L2_STD_PAL:
        //……
}

5、 设置视频捕获格式

当检测完视频设备支持的标准后,还需要设定视频捕获格式:

struct v4l2_format    fmt;
memset ( &fmt, 0, sizeof(fmt) );
fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width       = 720;
fmt.fmt.pix.height      = 576;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) {
  return -1;
}

v4l2_format结构体定义如下:

struct v4l2_format
{
    enum v4l2_buf_type type;    // 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE 
    union
    {
        struct v4l2_pix_format    pix;  
        struct v4l2_window        win;  
        struct v4l2_vbi_format    vbi;  
        __u8    raw_data[200];          
    } fmt;
};
struct v4l2_pix_format
{
    __u32                   width;         // 宽,必须是16的倍数
    __u32                   height;        // 高,必须是16的倍数
    __u32                   pixelformat;   // 视频数据存储类型,例如是YUV4:2:2还是RGB
    enum v4l2_field         field;
    __u32                   bytesperline;    
    __u32                   sizeimage;
    enum v4l2_colorspace    colorspace;
    __u32                   priv;       
};

6、 分配内存

接下来可以为视频捕获分配内存:

struct v4l2_requestbuffers  req;
if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) {
  return -1;
}

v4l2_requestbuffers定义如下:

struct v4l2_requestbuffers
{
    __u32               count;  // 缓存数量,也就是说在缓存队列里保持多少张照片
    enum v4l2_buf_type  type;   // 数据流类型,必须永远是V4L2_BUF_TYPE_VIDEO_CAPTURE 
    enum v4l2_memory    memory; // V4L2_MEMORY_MMAP 或 V4L2_MEMORY_USERPTR
    __u32               reserved[2];
};

7、 获取并记录缓存的物理空间

 

使用VIDIOC_REQBUFS,获取了req.count个缓存,下一步通过调用VIDIOC_QUERYBUF命令来获取这些缓存的地址,然后使用mmap函数转换成应用程序中的绝对地址,最后把这段缓存放入缓存队列:

typedef struct VideoBuffer {
    void   *start;
    size_t  length;
} VideoBuffer;

VideoBuffer*          buffers = calloc( req.count, sizeof(*buffers) );
struct v4l2_buffer    buf;

for (numBufs = 0; numBufs < req.count; numBufs++) {
    memset( &buf, 0, sizeof(buf) );
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = numBufs;
    // 读取缓存
    if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) {
        return -1;
    }

    buffers[numBufs].length = buf.length;
    // 转换成相对地址
    buffers[numBufs].start = mmap(NULL, buf.length,
        PROT_READ | PROT_WRITE,
        MAP_SHARED,
        fd, buf.m.offset);

    if (buffers[numBufs].start == MAP_FAILED) {
        return -1;
    }

    // 放入缓存队列
    if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) {
        return -1;
    }
}

8、 关于视频采集方式

操作系统一般把系统使用的内存划分成用户空间和内核空间,分别由应用程序管理和操作系统管理。应用程序可以直接访问内存的地址,而内核空间存放的是 供内核访问的代码和数据,用户不能直接访问。v4l2捕获的数据,最初是存放在内核空间的,这意味着用户不能直接访问该段内存,必须通过某些手段来转换地址。

一共有三种视频采集方式:

1)使用read、write方式:直接使用 read 和 write 函数进行读写。这种方式最简单,但是这种方式会在 用户空间和内核空间不断拷贝数据 ,同时在用户空间和内核空间占用 了 大量内存,效率不高。

2)内存映射方式(mmap):把设备里的内存映射到应用程序中的内存控件,直接处理设备内存,这是一种有效的方式。上面的mmap函数就是使用这种方式。

3)用户指针模式:内存由用户空间的应用程序分配,并把地址传递到内核中的驱动程序,然后由 v4l2 驱动程序直接将数据填充到用户空间的内存中。这点需要在v4l2_requestbuffers里将memory字段设置成V4L2_MEMORY_USERPTR。

第一种方式效率是最低的,后面两种方法都能提高执行的效率,但是对于mmap 方式,文档中有这样一句描述 --Remember the buffers are allocated in physical memory, as opposed to virtual memory which can be swapped out to disk. Applications should free the buffers as soon as possible with the munmap () function .(使用mmap方法的时候,buffers相当于是在内核空间中分配的,这种情况下,这些buffer是不能被交换到虚拟内存中,虽然这种方法不怎么影响读写效率,但是它一直占用着内核空间中的内存,当系统的内存有限的时候,如果同时运行有大量的进程,则对系统的整体性能会有一定的影响。) 

  所以,对于三种视频采集方式的选择,推荐的顺序是 userptr 、 mmap 、 read-write 。当使用 mmap 或 userptr 方式的时候,有一个环形缓冲队列的概念,这个队列中,有 n 个 buffer ,驱动程序采集到的视频帧数据,就是存储在每个 buffer 中。在每次用 VIDIOC_DQBUF 取出一个 buffer ,并且处理完数据后,一定要用 VIDIOC_QBUF 将这个 buffer 再次放回到环形缓冲队列中。环形缓冲队列,也使得这两种视频采集方式的效率高于直接 read/write 。

9、 处理采集数据

V4L2有一个数据缓存,存放req.count数量的缓存数据。数据缓存采用FIFO的方式,当应用程序调用缓存数据时,缓存队列将最先采集到的 视频数据缓存送出,并重新采集一张视频数据。这个过程需要用到两个ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF:

struct v4l2_buffer buf;
memset(&buf,0,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=0;

//读取缓存
if (ioctl(cameraFd, VIDIOC_DQBUF, &buf) == -1)
{
    return -1;
}
//…………视频处理算法
//重新放入缓存队列
if (ioctl(cameraFd, VIDIOC_QBUF, &buf) == -1) {

    return -1;
}

10、 关闭视频设备

使用close函数关闭一个视频设备

close(cameraFd)

linux FFMPEG 摄像头采集数据推流

环境vmware14    Ubuntu14

1)   搭建推流服务器Nginx-rtmp

下载源码

1.    
2.   mkdir /home/ffmpeg
3.   cd /home/ffmpeg
4.   wget http://nginx.org/download/nginx-1.7.5.tar.gz
5.   wget https://github.com/arut/nginx-rtmp-module/archive/master.zip
6.    

解压两个源码包

cd nginx-1.7.5
./configure --with-http_ssl_module --add-module=../nginx-rtmp-module-master
1.   make
2.   make install
1.   wget https://raw.github.com/JasonGiedymin/nginx-init-ubuntu/master/nginx -O /etc/init.d/nginx
2.   chmod +x /etc/init.d/nginx
3.   update-rc.d nginx defaults

推流:ffmpeg -re -i /home/ffmpeg

配置 nginx-rtmp 服务器

打开 /usr/local/nginx/conf/nginx.conf

1.   rtmp {
2.       server {
3.               listen 1935;
4.               chunk_size 4096;
5.    
6.               application live {
7.                       live on;
8.                       record off;
9.                       exec ffmpeg -i rtmp://localhost/live/$name -threads 1 -c:v libx264 -profile:v baseline -b:v 350K -s 640x360 -f flv -c:a aac -ac 1 -strict -2 -b:a 56k rtmp://localhost/live360p/$name;
10.             }
11.             application live360p {
12.                     live on;
13.                     record off;
14.         }
15.     }
16. }

到这里服务器安装成功


2)安装ffmpeg

下载源码

wget http://ffmpeg.org/releases/ffmpeg-3.4.4.tar.bz2

关于这个的安装教程很多暂且略过


 安装VLC media player


 在虚拟机准备一个MP4文件然后进行推流

推流命令:ffmpeg -re -i /home/ffmpeg/test1.mp4  -vcodec copy -acodec copy -f flv "rtmp://127.0.0.1:1935/live/test1"


后面尝试外接摄像头进行推流,发现ffmpeg一些功能还未编译进去,在虚拟机启用v4l2的时候报错误

重新配置编译

./configure --prefix=/usr/
/ffmpeg --
-gpl --
-shared --
-nonfree  --
-libx264   --
-libxcb --
-libv4l2

使能libx264 libv4l2等功能,

在执行上面这个配置命令可能会报not found x264 v4l2等错误

(具体可参考https://blog.csdn.net/fgf00/article/details/78203399?locationNum=5&fps=1

apt-get install libx264-dev  

apt-get install libv4l-dev

即可解决

make

make install

到安装目录下执行推流命令

./ffmpeg -f video4linux2 -s  640x480 -i /dev/video0  -f flv rtmp://127.0.0.1:1935/live/live

附上常用命令

ffmpeg常用命令
-f 强迫采用格式fmt
-i filename 输入文件
-s size 设置帧大小 默认是160x128
-r 设置帧频,默认25  (待验证,确认非标准桢率会导致音画不同步,所以只能设定为15或者29.97)
-qscale:v n(q:v n) n表示视频质量级别1-31(待验证值越小,质量越好)
-ab bitrate设置音频码率
-ar freq 设置音频采样率
-ac channels设置通道,默认为1
-vd device 设置视频捕获设备 eg:/dev/video0
-av device 设置音频设备 eg:/dev/dsp
-vcodec

opencv—视频和图片的相互转换

视频分解成图片

**

"""
视频分解成图片
1.load读取视频
2.读取视频的info信息
3.parse解码,拿到单针视频
4.展示imshow 保存imwrite
"""
 
import cv2
cap
cv2
VideoCapture
 

isOpen 
 cap
isOpened 

isOpen

 
fps 
cap
get
cv2
CAP_PROP_FPS
 

width 
 
cap
get
cv2
CAP_PROP_FRAME_WIDTH
 

height 
 
cap
get
cv2
CAP_PROP_FRAME_HEIGHT
 

 
fps
width
height

# 15.0  272  480
 
i

isOpen

    
 i

        

    

        i
i

    
flag
frame
cap
read
 

    fileName 
 
 
i
 
 

    
 flag 

        cv2
imwrite
fileName
frame
cv2
IMWRITE_JPEG_QUALITY
 

 
print("end")

图片合成视频

import cv2

img=cv2.imread("image1.jpg")

imgInfo=img.shape

size = (imgInfo[1],imgInfo[0])

 

#文件名称 可以使用的编码器  选择帧率5帧,size视频的大小

videoWrite = cv2.VideoWriter("2.mp4",-1,5,size) # 创建一个对象

 

for i in range(1,10):

    fileName = "image" + str(i) + ".jpg"

    img = cv2.imread(fileName)

    videoWrite.write(img) # 写入

   

print("end")

opencv-python将视频转为图片,将图片转为视频

视频转为图片

import cv2
import os
 
 
videoPath
 imgPath

    
 
 os
path
exists
imgPath

        os
makedirs
imgPath
             

    cap 
 cv2
VideoCapture
videoPath
    

    judge 
 cap
isOpened
                 

    
judge

    fps 
 cap
get
cv2
CAP_PROP_FPS
      

    
fps

 
    frames 
 
                           

    count 
 
                            

 
    
judge

        flag
 frame 
 cap
read
         

        
 
 flag

            
flag

            

            

        

            
 frames 
 
 
 
         

                imgname 
 
 
 
count
rjust
 
 

                newPath 
 imgPath 
 imgname
                
imgname

                cv2
imwrite
newPath
 frame
 
cv2
IMWRITE_JPEG_QUALITY
 

                

                count 
 

        frames 
 

    cap
release

    
count

video2imgs('/home/jim/Documents/document_fly/10_9/111.webm','./jpgs/')
 
posted @   吴建明wujianming  阅读(464)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示