2019-10-19 19:59:39 unchainedmelody 阅读数 11

1、从视频中截取图片并打标签

import os
import numpy as np
import cv2


def mkdir(path):
    # 去除首位空格
    path = path.strip()
    # 去除尾部 \ 符号
    # path = path.rstrip("\\")
    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    is_exists = os.path.exists(path)
    # 判断结果
    if not is_exists:
        # 如果不存在则创建目录
        # 创建目录操作函数
        os.makedirs(path)
        print(path + ' 创建成功')
        return True
    else:
        # 如果目录存在则不创建,并提示目录已存在
        print(path + ' 目录已存在')
        return False


def get_all_video_file_name(file_path: str):
    """
    :parameter:
        file_path: 视频文件路径
    :return:
        video_files:返回所有视频文件名
    """
    video_files_path = []
    all_files = []
    iter_files(file_path, all_files)
    for f in all_files:
        if is_video_file(f):
            video_files_path.append(f)
    return video_files_path


def iter_files(root_dir, all_files=[]):
    for root, dirs, files in os.walk(root_dir):
        for file in files:
            file_name = os.path.join(root, file)
            all_files.append(file_name)


def is_video_file(file):
    suffix = os.path.splitext(file)[1]
    if suffix == '.mp4' or suffix == '.mkv' or suffix == '.wmv' \
            or suffix == '.avi' or suffix == '.mpg':
        return True
    return False


def rotate_bound(image, angle):
    # grab the dimensions of the image and then determine the
    # center
    (h, w) = image.shape[:2]
    (cX, cY) = (w // 2, h // 2)
    # grab the rotation matrix (applying the negative of the
    # angle to rotate clockwise), then grab the sine and cosine
    # (i.e., the rotation components of the matrix)
    M = cv2.getRotationMatrix2D((cX, cY), -angle, 1.0)
    cos = np.abs(M[0, 0])
    sin = np.abs(M[0, 1])
    # compute the new bounding dimensions of the image
    nW = int((h * sin) + (w * cos))
    nH = int((h * cos) + (w * sin))
    # adjust the rotation matrix to take into account translation
    M[0, 2] += (nW / 2) - cX
    M[1, 2] += (nH / 2) - cY

    # perform the actual rotation and return the image
    return cv2.warpAffine(image, M, (nW, nH))


def interception_frame_by_file_name(input_video_path: str, output_img_path: str, times_frame: int, video_area=None):
    """
        视频文件以label命名
    :parameter:
        input_video_path: 要处理的视频文件路径
        output_video_path: 输出路径
        video_area:截取的区域,list类型,如 [row_start,row_end,col_start,col_end]
        timesFrame: 间隔多少帧取一帧
    :return:
    """

    if video_area is None:
        video_area = [150, 150 + 64, 300, 300 + 64]

    file_name_arr = get_all_video_file_name(input_video_path)
    cnt = 1  # 当前截取的图片个数
    # 使用opencv按一定间隔截取视频帧,并保存为图片
    for file_path in file_name_arr:
        print('正在处理' + file_path)

        # 创建相关文件夹
        folder_name = str.split(file_path, '\\')[-1][:-4]
        dif_img_path = output_img_path + '\\differenceImage\\' + folder_name
        static_img_path = output_img_path + '\\staticImage\\' + folder_name
        mkdir(dif_img_path)
        mkdir(static_img_path)

        vc = cv2.VideoCapture(file_path)  # 读取视频文件
        c = 1  # 计数器,记录当前的帧数

        if vc.isOpened():  # 判断是否正常打开
            # vc.read(),如果正确读取帧,将返回True以及图像
            rval, frame = vc.read()
        else:
            rval = False
        frame_prev = None
        while rval:  # 循环读取视频帧
            rval, frame = vc.read()
            if c % times_frame == 0:  # 每隔timeF帧进行存储操作
                frame = frame[video_area[0]:video_area[1], video_area[2]:video_area[3]]
                cv2.imwrite(static_img_path + '\\' + str(cnt) + '.jpg', frame)  # 存储静态图

                if frame_prev:
                    frame_dif = cv2.absdiff(frame_prev, frame)
                    cv2.imwrite(dif_img_path + '\\' + str(cnt) + '.jpg', frame_dif)  # 存储残差图

                frame_prev = frame
                cnt += 1

            c = c + 1
            cv2.waitKey(1)

    vc.release()


def interception_frame(input_video_path: str, output_img_path: str, label_arr: list, times_frame: int, video_area=None):
    """
    从视频指定区域截取图片
    :parameter:
        input_video_path: 要处理的视频文件路径
        output_video_path: 输出路径
        label_arr: 存放视频文件的label
        video_area:截取的区域,list类型,如 [row_start,row_end,col_start,col_end]
        timesFrame: 间隔多少帧取一帧
    :return:
    """

    if video_area is None:
        video_area = [150, 150 + 64, 300, 300 + 64]

    # 使用opencv按一定间隔截取视频帧,并保存为图片
    for j, folder_name in enumerate(label_arr):
        cnt = 1  # 当前截取的图片个数

        print('正在处理' + str(j + 1) + '.mp4')

        dif_img_path = output_img_path + '\\differenceImage\\' + str(folder_name)
        static_img_path = output_img_path + '\\staticImage\\' + str(folder_name)
        mkdir(dif_img_path)
        mkdir(static_img_path)

        vc = cv2.VideoCapture(input_video_path + '\\' + str(j + 1) + '.mp4')  # 读取视频文件
        c = 1  # 计数器,记录当前的帧数

        if vc.isOpened():  # 判断是否正常打开
            # vc.read(),如果正确读取帧,将返回True以及图像
            rval, frame = vc.read()
        else:
            rval = False
        frame_prev = np.array([])
        while rval:  # 循环读取视频帧
            rval, frame = vc.read()

            if c % times_frame == 0 and rval:  # 每隔timeF帧进行存储操作
                frame = frame[video_area[0]:video_area[1], video_area[2]:video_area[3]]
                cv2.imwrite(static_img_path + '\\' + str(cnt) + '.jpg', frame)  # 存储静态图

                if len(frame_prev) > 0:
                    frame_dif = cv2.absdiff(frame_prev, frame)
                    cv2.imwrite(dif_img_path + '\\' + str(cnt) + '.jpg', frame_dif)  # 存储残差图

                frame_prev = frame
                cnt += 1

            c = c + 1
            cv2.waitKey(1)

    vc.release()


# 处理训练集
input_video_path = r'E:\research\beihaivideo\train'
output_img_path = r'E:\research\beihaivideo\train'
label_arr = [7, 6, 6, 5, 5, 2, 2, 3, 3]
times_frame = 12
video_area = None
interception_frame(input_video_path, output_img_path, label_arr, times_frame)

# # 处理测试集
# input_video_path = r'E:\research\beihaivideo\test'
# output_img_path = r'E:\research\beihaivideo\test'
# label_arr = [6, 5, 2, 3]
# times_frame = 12
# video_area = None
# interception_frame(input_video_path,output_img_path,label_arr,times_frame)

2、从文件夹中分批读取图像,供模型使用

import tensorflow as tf
import os


def read_image(root_path: str, batch_size: int, shape: tuple, shuffle=True):
    """tensorflow 用队列读取大量图片
    将root_path下所有图片(.jpg)以batch_size分块读取;
    同一label的图片放在同一个文件夹里,文件夹以label命名
    :param root_path: 要读取的图片放在此文件夹下
    :param batch_size:
    :param shape: (height,width,channels)
    :param shuffle:
    :return:
    """
    (img_height, img_width, img_channels) = shape

    image_paths_list = []
    labels_list = []
    classes_list = sorted(os.walk(root_path).__next__()[1])
    for c in classes_list:
        c_dir = os.path.join(root_path, c)
        walk = os.walk(c_dir).__next__()[2]
        for sample in walk:
            if sample.endswith('.jpg') or sample.endswith('.jpeg'):
                image_paths_list.append(os.path.join(c_dir, sample))
                labels_list.append(int(c))

    # 将img_paths_list 和 labels_list 转换为tf可以处理的格式
    image_paths_list = tf.convert_to_tensor(image_paths_list, tf.string)
    labels_list = tf.convert_to_tensor(labels_list, tf.int32)
    # 建立 Queue, num_epochs=None,生成器可以无限次遍历tensor列表,如果设置为 num_epochs=N,生成器只遍历tensor列表N次。
    img_path, label = tf.train.slice_input_producer([image_paths_list, labels_list], shuffle=shuffle, num_epochs=1)

    # 读取图片,并进行解码,处理其他格式的图片则需要修改此处
    image = tf.read_file(img_path)
    image = tf.image.decode_jpeg(image, channels=img_channels)

    # 对图片进行裁剪和正则化(将数值[0,255]转化为[-1,1])
    image = tf.image.resize_images(image, size=[img_height, img_width])
    image = image * 1.0 / 127.5 - 1.0

    # 创建 batch
    X, Y = tf.train.batch([image, label], batch_size=batch_size, num_threads=1, capacity=batch_size * 4)
    return X, Y

2018-09-30 22:18:49 crazyeden 阅读数 394

作者Rgb

在这之前大部分物体检测算法都是基于传统的图像处理方法,这是第一篇将深度学习用到物体检测上的文章,直接影响是2012年ALEXNET在比赛中的重大成功。

简单来说,RCNN使用以下四步实现目标检测:

a. 在图像中用slective search 方法 确定约1000-2000个候选框

具体为什么使用这个方法,原文在第三页中有说While R-CNN is agnostic to the particular region proposal method, we use selective search to enable a controlled comparison with prior detection work。意思是R-CNN和区域选择方法并没有联系,对任何选择方法都是兼容的,这里选用SS目的是方便于同之前别人的工作进行对比。

b. 对于每个候选框内图像块,使用深度网络提取特征,得到一个固定长度的特征向量

We extract a 4096-dimensional feature vector from each region proposal using the Caffe implementation of the CNN described by Krizhevsky etal.这里很清楚的说了,作者就是用了AlexNet的网络结构最好提取4096维的一维向量,作为特征向量。

输入去均值化的227×227 RBG通道图片,然后经过5个卷积2个全连接。因为经过SS得到的候选框大小不一,但是CNN要求的输入必须是227×227的。这里就涉及到几种归一化方法。原论文在第11页给出了几种填充和缩放方法。这里方法的选择会影响3-5mAP。作者这里使用了在得到原始的proposal region之后,再在原始图片中选取p=16的像素作为背景扩充,即向外扩展BBX的边界,然后进行wrap到227*227。

这里设计到CNN模型的训练问题。

论文中采用的办法是直接使用alexnet之前训练好的模型参数,去掉最后一层1000个分类,换成你想要的分类数量+1,因为背景也要算是一类。这里使用了迁移学习,在alexnet的基础上进行finetune。训练数据使用的是进行wrap之后得到的proposal region,对于某个类别,认为iou大于0.5为正样本,否则为负样本,每个batch为128,32个正样本(包含20个类别),96个负样本。然后使用SGD进行训练。这样我们就完成了对CNN的调优,这样得到的CNN模型,可以用于提取特征。将提取到的特征在用于SVM训练。这里论文中提到了一句说训练SVM时,样本很大内存无法容纳,使用了一种hard negative mining method的方法,这里还没有搞清楚

c. 对候选框中提取出的特征,使用SVM二分类器判别是否属于一个特定类

这里对SVM进行训练也涉及到正负样本的问题,这里的对于负样本的判断同CNN不同,从0-0.5,间距为0.1,发现0.3的效果最好,即IOU低于0.3则为负样本。正样本的定义也不一样,当BBX把整个物体都包括进去的时候,才认为是正样本。

论文的附录B讨论了,为什么这里CNN的finetune和SVM的训练使用不同的正负样本标准?

因为作者最初训练SVM的时候,并没有使用cnn上进行 finetune之后的特征,而是直接使用ImageNet pre-trained CNN,发现论文中现在使用的SVM的训练样本标准是最优的;然后后来又考虑使用finetune之后,发现使用同样的正负样本标准,结果很差。

还讨论了最后为什么要用SVM,而不是直接使用softmax分类回归?因为这样mAP下降了。

对于每个类别的物体,将提取的特征使用SVM进行打分。对于所有打分超过阈值的区域进行极大值抑制算法再次进行筛选,排除同一个物体出现多个回归框的问题。

d. 对于属于某一特征的候选框,用回归器进一步调整其位置

给定了一个目标函数,好像用了岭回归和权值的L2范数,来确定BBX的映射结果。

遗留问题:

1 SVM具体训练实现细节

2 回归框的训练方法

原论文地址链接:https://arxiv.org/pdf/1311.2524.pdf

2018-05-20 13:16:09 hiudawn 阅读数 12299

介绍

MatConvNet是一个实现卷积神经网络(CNN)的MATLAB工具箱,用于计算机视觉应用。 用这个工具箱,能很方便地在MATLAB中用GPU来进行训练。


要求

足够新的MATLAB版本(R2015b或更高版本)和一个支持C ++ 11的编译器(Visual Studio 2015,GCC 4.8,Xcode 7.3.1或更高版本)。 对于GPU计算,至少需要CUDA 7.5以及CuDNN v4(可选)或更新版本。

本次安装在如下实验环境中通过。

环境:

MATLAB2018a
Visual Studio 2015
matconvnet-1.0-beta25


安装

1.下载工具箱

首先下载MatConvNet,并解压到你希望的文件夹,暂且称这个文件夹为<MatConvNet>

2.编译库

1)CPU版本编译

  • 打开MATLAB,在命令行输入
mex -setup 
mex -setup C++

>>> mex -setup C++
MEX 配置为使用 ‘Microsoft Visual C++ 2015’ 以进行 C++ 语言编译。
警告: MATLAB C 和 Fortran API 已更改,现可支持
包含 2^32-1 个以上元素的 MATLAB 变量。您需要
更新代码以利用新的 API。
您可以在以下网址找到更多的相关信息:
https://www.mathworks.com/help/matlab/matlab_external/upgrading-mex-files-to-use-64-bit-api.html

  • 打开MATLAB,cd到你解压的那个matconvnet目录<MatConvNet>,输入下面3行
cd F:\hiudawn\matlab\matconvnet-1.0-beta25
addpath matlab
vl_compilenn

>>> vl_compilenn
警告: CL.EXE not found in PATH. Trying to guess out of mex setup.
> In vl_compilenn>check_clpath (line 650)
In vl_compilenn (line 426)
用于 x64 的 Microsoft (R) C/C++ 优化编译器 19.00.23026 版
版权所有(C) Microsoft Corporation。保留所有权利。

用法: cl [ 选项… ] 文件名… [ /link 链接选项… ]
Location of cl.exe (C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC..\VC\bin\amd64) successfully added to your PATH.
使用 ‘Microsoft Visual C++ 2015’ 编译。
MEX 已成功完成。

若干行一样的内容

使用 ‘Microsoft Visual C++ 2015 (C)’ 编译。
MEX 已成功完成。

到此CPU版本的就已经编译完成,在MATLAB命令行输入如下命令可以测试

vl_testnn

3)GPU版本编译

  • 首先你的GPU运算能力要有2.0以上,之后CUDA版本要满足下表
MATLAB CUDA toolkit
R2017a 8.0
R2016b 7.5
R2016a 7.5
R2015b 7.0

你要是不知道该用哪个版本CUDA,输入下面命令,有人会告诉你

gpuDevice
  • 接下来,假设你只有唯一的CUDA且匹配你的MATLAB版本
    直接运行如下命令
vl_compilenn('enableGpu', true)
  • 如果你有很多CUDA,可以通过下面命令选择一个
vl_compilenn('enableGpu', true, 'cudaRoot', 'yourpath/NVIDIA/CUDA-n.0')
  • 安装完试一下
vl_testnn('gpu', true)

如果可以就成功了

3)cuDNN support

上面其实已经可以暂时使用了,这里我没GPU没法继续安装。

3.开启你的MATLAB

输入:

run <MatConvNet>/matlab/vl_setupnn

测试CPU:

vl_testnn

测试GPU:

vl_testnn('gpu', true)

总结

安装不成功请自己参考官网

更新(Ubuntu安装)

本文在Ubuntu环境下也进行了设置,并配置了GPU,用Ubuntu的话,编译器要换成:

mex -setup c
mex -setup c++

其他内容大同小异,另外我这里出了一个奇怪的错误
Error using mex

/usr/bin/ld: cannot find -ljpeg

collect2: error: ld returned 1 exit status

Error in vl_compilenn>mex_link (line 528)

mex(mopts{:}) ;

Error in vl_compilenn (line 479)

mex_link(opts, objs, mex_dir, flags.mexlink) ;

2019-01-30 22:19:24 weixin_43692212 阅读数 98

在这里插入图片描述
在这里插入图片描述
(a)中u=0.5是常用的正负样本界定值,但当u取0.5时会出现较多的误检。因为该阈值会使正负样本中有较多的背景。
(b)中用0.7的阈值会减小误检,但正样本的数量会呈指数级的减少,出现过拟合的现象。
(c)和(d)中的曲线是用来表示不听IOU阈值下的定位性能和检测性能,从C中可以看出,当检测模型采用某个阈值来界定正负样本时,当输入proposal的IOU阈值在这个值附近时,该检测模型比其他阈值训练的检测模型效果好。从D中可以看出来一味地使用较大的阈值来训练检测模型可以看出检测效果在下降,容易出现过拟合。
cascade r-cnn是由一系列的检测模型组成,每个检测模型都是根据不同的IOU阈值的正负样本训练得到,前一个检测模型的输出作为后一个检测模型的输入,因此是stage by stage的训练方式,而且越往后的检测模型的IOU阈值是不断上升的。在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2020-03-02 21:25:55 qq_36560894 阅读数 54

论文阅读方法

三遍论文法

第一遍(摘要+简介+结论)

在这里插入图片描述
通过摘要可以看出,AlexNet是源于一个基于ImagNet数据集的比赛ImageNet LSVRC-2012,它成功地将卷积神经网络应用到了图像分类任务中来,用来GPU训练,Dropout防止过拟合,吊打传统方案。原文中用了一个’record-breaking result’来形容其效果。

第二遍(分段阅读文章其他内容)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 作者采用了ReLU代替饱和非线性模块(Sigmoid),这样既加快了速度,其实也跟符合生物学原理(单边抑制、宽兴奋边界),在一定程度上缓解了梯度消失的问题;
  • GPU训练就不多说了,那个时候还没有我们现在TF、Torch这种框架,所以作者在GPU的处理上很麻烦。
  • LRN 局部相应归一化
    这个其实也是一个防止过拟合的方法,它计算i节点相邻N个位置上的特征映射,使得响应值比较大的值变得更大,抑制那些反馈少的神经元,增强了模型的泛化能力。这一块其实后期在其他网络中基本上没有被采用,然后我在复现的时候,是参考了别人的代码,有点模糊,希望大家指正。
  • 当步长等于卷积核大小m时,就是传统的局部pooling;当小于卷积核大小时,就叫做overlapping pooling,这篇论文就是overlapping pooling。
  • 模型的结构其实比较明了:五层卷积做特征提取 + 三层全连接做分类器 具体可见我表中所列举的,具体模型参数可以看我Pytorch代码实现。
    在这里插入图片描述
    在这里插入图片描述
  • 这一段主要是将如何减少过拟合的:
    ①数据增广(现在都可以通过cv2或者torch中的视觉库轻松实现)
    ②引入了‘Dropout’层:Dropout就是把隐藏层中神经元的输出设置为0,每个神经元被Dropout概率为r(这是个超参数,在这个网络中r=0.5),这些被‘dropout’掉的神经元不会参与前向计算和后向传播。每次输入一次,这个神经网络就采取的是不一样的神经结构(因为每个神经元被dropout的概率是一样的),但是这些结构都是权值共享的。这样就相当于训练了多个不同的网络模型,提高了泛化能力。
    在这里插入图片描述
  • 这一段就主要讲了训练的细节了,如何初始化参数权重,用了什么优化器,以及学习率的设置。值得提的是,初始化学习率为0.01,当验证集的error rate不在下降时,就除以10,以找到最合适的学习率。
    在这里插入图片描述
    在这里插入图片描述
  • 定性和定量地分析了模型的结果,暴打传统方法。然后需要再模型上需要可解释性,作者可视化了第一个卷积层的内核学习效果:发现网络已经学习到了频率选择、方向选择以及色彩等特征。并且GPU1上的内核学习到的特征是颜色无关的、而GPU2是颜色相关的。
  • 即使偏离中心的物体也是可以被识别的。
  • 关于欧几里得距离那一段我还是有点模糊,我的理解是:两个欧几里得距离很近的图像在网络高层通常会被认为是相似的,但是他的效率比较低,并且很多时候同一类别的物体并不是欧几里得相似的,所以才需要一个合适encoder来将向量压缩成二进制(embedding)

第三遍:

其实这篇文章读下来,大体是很清晰的,作为图像领域卷积神经网络的奠基之作,还是很有必要一读。但是神经网络模型相比于传统的视觉方法,缺乏可解释性,而且这个模型用的卷积核比较大,而且隐藏层数也比较浅,所谓前人挖坑,后人填坑,开山之作之后,视觉领域也正式迎来了深度学习的统治时代。

代码复现:

GitHub地址

欢迎大家交流指正,谢谢。

没有更多推荐了,返回首页