我们就一起来实现 Android 端的 rtmp 推流,想要实现 Android 端推流必须要经过如下几个阶段.

推流监控
软编码
硬编码
音频采集

文件:url80.ctfile.com/f/25127180-739355701-3d1c1b?p=551685 (访问密码: 551685)

Android SDK 提供了两套音频采集的 API ,分别是 MediaRecorder 、AudioRecord 。前者是一个上层 API ,它可以直接对手机麦克风录入的音频数据进行编码压缩(如 AMR/MP3) 等,并存储为文件;后者则更接近底层,能够更加自由灵活地控制,其可以让开发者得到内存中的 PCM 原始音频数据流。如果想做一个简单的录音机,输出音频文件则推荐使用 MediaRecorder ; 如果需要对音频做进一步的算法处理,或者需要采用第三方的编码库进行编码,又或者需要用到网络传输等场景中,那么只能使用 AudioRecord 或者 OpenSL ES ,其实 MediaRecorder 底层也是调用了 AudioRecord 与 Android Framework 层的 AudioFlinger 进行交互的。而我们该篇的场景更倾向于第二种实现方式,即使用 AudioRecord 来采集音频。


为了了解模型的泛化能力,即判断模型的好坏,我们需要用某个指标来衡量,有了评价指标,就可以对比不同模型的优劣,并通过这个指标来进一步调参优化模型。对于分类和回归两类监督模型,分别有各自的评判标准。

不同的问题和不同的数据集都会有不同的模型评价指标,比如分类问题,数据集类别平衡的情况下可以使用准确率作为评价指标,但是现实中的数据集几乎都是类别不平衡的,所以一般都是采用 AP 作为分类的评价指标,分别计算每个类别的 AP,再计算mAP。

一,精确率、召回率与F1
1.1,准确率
准确率(精度) – Accuracy,预测正确的结果占总样本的百分比,定义如下:

准确率
错误率和精度虽然常用,但是并不能满足所有任务需求。以西瓜问题为例,假设瓜农拉来一车西瓜,我们用训练好的模型对西瓜进行判别,现如精度只能衡量有多少比例的西瓜被我们判断类别正确(两类:好瓜、坏瓜)。但是若我们更加关心的是“挑出的西瓜中有多少比例是好瓜”,或者”所有好瓜中有多少比例被挑出来“,那么精度和错误率这个指标显然是不够用的。

虽然准确率可以判断总的正确率,但是在样本不平衡的情况下,并不能作为很好的指标来衡量结果。举个简单的例子,比如在一个总样本中,正样本占 90%,负样本占 10%,样本是严重不平衡的。对于这种情况,我们只需要将全部样本预测为正样本即可得到 90% 的高准确率,但实际上我们并没有很用心的分类,只是随便无脑一分而已。这就说明了:由于样本不平衡的问题,导致了得到的高准确率结果含有很大的水分。即如果样本不平衡,准确率就会失效。

1.2,精确率、召回率
精确率(查准率)P、召回率(查全率)R 的计算涉及到混淆矩阵的定义,混淆矩阵表格如下:

名称 定义
True Positive(真正例, TP) 将正类预测为正类数
True Negative(真负例, TN) 将负类预测为负类数
False Positive(假正例, FP) 将负类预测为正类数 → 误报 (Type I error)
False Negative(假负例子, FN) 将正类预测为负类数 → 漏报 (Type II error)
查准率与查全率计算公式:

查准率(精确率)
查全率(召回率)
精准率和准确率看上去有些类似,但是完全不同的两个概念。精准率代表对正样本结果中的预测准确程度,而准确率则代表整体的预测准确程度,既包括正样本,也包括负样本。

精确率描述了模型有多准,即在预测为正例的结果中,有多少是真正例;召回率则描述了模型有多全,即在为真的样本中,有多少被我们的模型预测为正例。精确率和召回率的区别在于分母不同,一个分母是预测为正的样本数,另一个是原来样本中所有的正样本数。

1.3,F1 分数
如果想要找到 和 二者之间的一个平衡点,我们就需要一个新的指标: 分数。 分数同时考虑了查准率和查全率,让二者同时达到最高,取一个平衡。 计算公式如下:

这里的 计算是针对二分类模型,多分类任务的 的计算请看下面。

样例总数

度量的一般形式:,能让我们表达出对查准率/查全率的偏见, 计算公式如下:

其中 对查全率有更大影响, 对查准率有更大影响。

不同的计算机视觉问题,对两类错误有不同的偏好,常常在某一类错误不多于一定阈值的情况下,努力减少另一类错误。在目标检测中,mAP(mean Average Precision)作为一个统一的指标将这两种错误兼顾考虑。

很多时候我们会有多个混淆矩阵,例如进行多次训练/测试,每次都能得到一个混淆矩阵;或者是在多个数据集上进行训练/测试,希望估计算法的”全局“性能;又或者是执行多分类任务,每两两类别的组合都对应一个混淆矩阵;…总而来说,我们希望能在 个二分类混淆矩阵上综合考虑查准率和查全率。

一种直接的做法是先在各混淆矩阵上分别计算出查准率和查全率,记为 然后取平均,这样得到的是”宏查准率(Macro-P)“、”宏查准率(Macro-R)“及对应的”宏 (Macro-F1)“:

另一种做法是将各混淆矩阵对应元素进行平均,得到 、、、 的平均值,再基于这些平均值计算出”微查准率“(Micro-P)、”微查全率“(Micro-R)和”微 “(Mairo-F1)

1.4,PR 曲线
精准率和召回率的关系可以用一个 P-R 图来展示,以查准率 P 为纵轴、查全率 R 为横轴作图,就得到了查准率-查全率曲线,简称 P-R 曲线,PR 曲线下的面积定义为 AP:

PR曲线图

1.4.1,如何理解 P-R 曲线
可以从排序型模型或者分类模型理解。以逻辑回归举例,逻辑回归的输出是一个 0 到 1 之间的概率数字,因此,如果我们想要根据这个概率判断用户好坏的话,我们就必须定义一个阈值 。通常来讲,逻辑回归的概率越大说明越接近 1,也就可以说他是坏用户的可能性更大。比如,我们定义了阈值为 0.5,即概率小于 0.5 的我们都认为是好用户,而大于 0.5 都认为是坏用户。因此,对于阈值为 0.5 的情况下,我们可以得到相应的一对查准率和查全率。

但问题是:这个阈值是我们随便定义的,我们并不知道这个阈值是否符合我们的要求。 因此,为了找到一个最合适的阈值满足我们的要求,我们就必须遍历 0 到 1 之间所有的阈值,而每个阈值下都对应着一对查准率和查全率,从而我们就得到了 PR 曲线。

最后如何找到最好的阈值点呢? 首先,需要说明的是我们对于这两个指标的要求:我们希望查准率和查全率同时都非常高。 但实际上这两个指标是一对矛盾体,无法做到双高。图中明显看到,如果其中一个非常高,另一个肯定会非常低。选取合适的阈值点要根据实际需求,比如我们想要高的查全率,那么我们就会牺牲一些查准率,在保证查全率最高的情况下,查准率也不那么低。。

1.5,ROC 曲线与 AUC 面积
PR 曲线是以 Recall 为横轴,Precision 为纵轴;而 ROC 曲线则是以 FPR 为横轴,TPR 为纵轴。P-R 曲线越靠近右上角性能越好**。PR 曲线的两个指标都聚焦于正例
PR 曲线展示的是 Precision vs Recall 的曲线,ROC 曲线展示的是 FPR(x 轴:False positive rate) vs TPR(True positive rate, TPR)曲线。

ROC 曲线

AUC 面积
二,AP 与 mAP
2.1,AP 与 mAP 指标理解
AP 衡量的是训练好的模型在每个类别上的好坏,mAP 衡量的是模型在所有类别上的好坏,得到 AP 后 mAP 的计算就变得很简单了,就是取所有 AP 的平均值。AP 的计算公式比较复杂(所以单独作一章节内容),详细内容参考下文。

mAP 这个术语有不同的定义。此度量指标通常用于信息检索、图像分类和目标检测领域。然而这两个领域计算 mAP 的方式却不相同。这里我们只谈论目标检测中的 mAP 计算方法。

mAP 常作为目标检测算法的评价指标,具体来说就是,对于每张图片检测模型会输出多个预测框(远超真实框的个数),我们使用 IoU (Intersection Over Union,交并比)来标记预测框是否预测准确。标记完成后,随着预测框的增多,查全率 R 总会上升,在不同查全率 R 水平下对准确率 P 做平均,即得到 AP,最后再对所有类别按其所占比例做平均,即得到 mAP 指标。

2.2,近似计算AP
分类问题的PR曲线图

知道了AP 的定义,下一步就是理解AP计算的实现,理论上可以通过积分来计算AP,公式如下:

但通常情况下都是使用近似或者插值的方法来计算 。

近似计算 (approximated average precision),这种计算方式是 approximated 形式的;
很显然位于一条竖直线上的点对计算 没有贡献;
这里 为数据总量, 为每个样本点的索引, 。
近似计算 AP 和绘制 PR 曲线代码如下:

import numpy as np
import matplotlib.pyplot as plt

class_names = [“car”, “pedestrians”, “bicycle”]

def draw_PR_curve(predict_scores, eval_labels, name, cls_idx=1):
“”“calculate AP and draw PR curve, there are 3 types
Parameters:
@all_scores: single test dataset predict scores array, (-1, 3)
@all_labels: single test dataset predict label array, (-1, 3)
@cls_idx: the serial number of the AP to be calculated, example: 0,1,2,3…
“””
# print(‘sklearn Macro-F1-Score:’, f1_score(predict_scores, eval_labels, average=‘macro’))
global class_names
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(15, 10))
# Rank the predicted scores from large to small, extract their corresponding index(index number), and generate an array
idx = predict_scores[:, cls_idx].argsort()[::-1]
eval_labels_descend = eval_labels[idx]
pos_gt_num = np.sum(eval_labels == cls_idx) # number of all gt

predict_results = np.ones_like(eval_labels)
tp_arr = np.logical_and(predict_results == cls_idx, eval_labels_descend == cls_idx) # ndarray
fp_arr = np.logical_and(predict_results == cls_idx, eval_labels_descend != cls_idx)tp_cum = np.cumsum(tp_arr).astype(float) # ndarray, Cumulative sum of array elements.
fp_cum = np.cumsum(fp_arr).astype(float)precision_arr = tp_cum / (tp_cum + fp_cum) # ndarray
recall_arr = tp_cum / pos_gt_num
ap = 0.0
prev_recall = 0
for p, r in zip(precision_arr, recall_arr):ap += p * (r - prev_recall)# pdb.set_trace()prev_recall = r
print("------%s, ap: %f-----" % (name, ap))fig_label = '[%s, %s] ap=%f' % (name, class_names[cls_idx], ap)
ax.plot(recall_arr, precision_arr, label=fig_label)ax.legend(loc="lower left")
ax.set_title("PR curve about class: %s" % (class_names[cls_idx]))
ax.set(xticks=np.arange(0., 1, 0.05), yticks=np.arange(0., 1, 0.05))
ax.set(xlabel="recall", ylabel="precision", xlim=[0, 1], ylim=[0, 1])fig.savefig("./pr-curve-%s.png" % class_names[cls_idx])
plt.close(fig)

2.3,插值计算 AP
插值计算(Interpolated average precision) 的公式的演变过程这里不做讨论,详情可以参考这篇文章,我这里的公式和图也是参考此文章的。11 点插值计算方式计算 公式如下:

11点插值计算方式计算AP公式

这是通常意义上的 11 points_Interpolated 形式的 AP,选取固定的 11 个阈值,这个在 PASCAL2007 中使用
这里因为参与计算的只有 11 个点,所以 ,称为 11 points_Interpolated, 为阈值索引
取第 个阈值所对应的样本点之后的样本中的最大值,只不过这里的阈值被限定在了 范围内。
插值计算方式计算AP的PR曲线图

从曲线上看,真实 AP< approximated AP < Interpolated AP,11-points Interpolated AP 可能大也可能小,当数据量很多的时候会接近于 Interpolated AP,与 Interpolated AP 不同,前面的公式中计算 AP 时都是对 PR 曲线的面积估计,PASCAL 的论文里给出的公式就更加简单粗暴了,直接计算11 个阈值处的 precision 的平均值。PASCAL 论文给出的 11 点计算 AP 的公式如下。

PASCAL论文给出的11点计算AP公式

1, 在给定 recal 和 precision 的条件下计算 AP:

def voc_ap(rec, prec, use_07_metric=False):
“”"
ap = voc_ap(rec, prec, [use_07_metric])
Compute VOC AP given precision and recall.
If use_07_metric is true, uses the
VOC 07 11 point method (default:False).
“”"
if use_07_metric:
# 11 point metric
ap = 0.
for t in np.arange(0., 1.1, 0.1):
if np.sum(rec >= t) == 0:
p = 0
else:
p = np.max(prec[rec >= t])
ap = ap + p / 11.
else:
# correct AP calculation
# first append sentinel values at the end
mrec = np.concatenate(([0.], rec, [1.]))
mpre = np.concatenate(([0.], prec, [0.]))

    # compute the precision envelopefor i in range(mpre.size - 1, 0, -1):mpre[i - 1] = np.maximum(mpre[i - 1], mpre[i])# to calculate area under PR curve, look for points# where X axis (recall) changes valuei = np.where(mrec[1:] != mrec[:-1])[0]# and sum (\Delta recall) * precap = np.sum((mrec[i + 1] - mrec[i]) * mpre[i + 1])
return ap

2,给定目标检测结果文件和测试集标签文件 xml 等计算 AP:

def parse_rec(filename):
“”" Parse a PASCAL VOC xml file
Return : list, element is dict.
“”"
tree = ET.parse(filename)
objects = []
for obj in tree.findall(‘object’):
obj_struct = {}
obj_struct[‘name’] = obj.find(‘name’).text
obj_struct[‘pose’] = obj.find(‘pose’).text
obj_struct[‘truncated’] = int(obj.find(‘truncated’).text)
obj_struct[‘difficult’] = int(obj.find(‘difficult’).text)
bbox = obj.find(‘bndbox’)
obj_struct[‘bbox’] = [int(bbox.find(‘xmin’).text),
int(bbox.find(‘ymin’).text),
int(bbox.find(‘xmax’).text),
int(bbox.find(‘ymax’).text)]
objects.append(obj_struct)

return objects

def voc_eval(detpath,
annopath,
imagesetfile,
classname,
cachedir,
ovthresh=0.5,
use_07_metric=False):
“”“rec, prec, ap = voc_eval(detpath,
annopath,
imagesetfile,
classname,
[ovthresh],
[use_07_metric])
Top level function that does the PASCAL VOC evaluation.
detpath: Path to detections result file
detpath.format(classname) should produce the detection results file.
annopath: Path to annotations file
annopath.format(imagename) should be the xml annotations file.
imagesetfile: Text file containing the list of images, one image per line.
classname: Category name (duh)
cachedir: Directory for caching the annotations
[ovthresh]: Overlap threshold (default = 0.5)
[use_07_metric]: Whether to use VOC07’s 11 point AP computation
(default False)
“””
# assumes detections are in detpath.format(classname)
# assumes annotations are in annopath.format(imagename)
# assumes imagesetfile is a text file with each line an image name
# cachedir caches the annotations in a pickle file

# first load gt
if not os.path.isdir(cachedir):os.mkdir(cachedir)
cachefile = os.path.join(cachedir, '%s_annots.pkl' % imagesetfile)
# read list of images
with open(imagesetfile, 'r') as f:lines = f.readlines()
imagenames = [x.strip() for x in lines]if not os.path.isfile(cachefile):# load annotationsrecs = {}for i, imagename in enumerate(imagenames):recs[imagename] = parse_rec(annopath.format(imagename))if i % 100 == 0:print('Reading annotation for {:d}/{:d}'.format(i + 1, len(imagenames)))# saveprint('Saving cached annotations to {:s}'.format(cachefile))with open(cachefile, 'wb') as f:pickle.dump(recs, f)
else:# loadwith open(cachefile, 'rb') as f:try:recs = pickle.load(f)except:recs = pickle.load(f, encoding='bytes')# extract gt objects for this class
class_recs = {}
npos = 0
for imagename in imagenames:R = [obj for obj in recs[imagename] if obj['name'] == classname]bbox = np.array([x['bbox'] for x in R])difficult = np.array([x['difficult'] for x in R]).astype(np.bool)det = [False] * len(R)npos = npos + sum(~difficult)class_recs[imagename] = {'bbox': bbox,'difficult': difficult,'det': det}# read dets
detfile = detpath.format(classname)
with open(detfile, 'r') as f:lines = f.readlines()splitlines = [x.strip().split(' ') for x in lines]
image_ids = [x[0] for x in splitlines]
confidence = np.array([float(x[1]) for x in splitlines])
BB = np.array([[float(z) for z in x[2:]] for x in splitlines])nd = len(image_ids)
tp = np.zeros(nd)
fp = np.zeros(nd)if BB.shape[0] > 0:# sort by confidencesorted_ind = np.argsort(-confidence)sorted_scores = np.sort(-confidence)BB = BB[sorted_ind, :]image_ids = [image_ids[x] for x in sorted_ind]# go down dets and mark TPs and FPsfor d in range(nd):R = class_recs[image_ids[d]]bb = BB[d, :].astype(float)ovmax = -np.infBBGT = R['bbox'].astype(float)if BBGT.size > 0:# compute overlaps# intersectionixmin = np.maximum(BBGT[:, 0], bb[0])iymin = np.maximum(BBGT[:, 1], bb[1])ixmax = np.minimum(BBGT[:, 2], bb[2])iymax = np.minimum(BBGT[:, 3], bb[3])iw = np.maximum(ixmax - ixmin + 1., 0.)ih = np.maximum(iymax - iymin + 1., 0.)inters = iw * ih# unionuni = ((bb[2] - bb[0] + 1.) * (bb[3] - bb[1] + 1.) +(BBGT[:, 2] - BBGT[:, 0] + 1.) *(BBGT[:, 3] - BBGT[:, 1] + 1.) - inters)overlaps = inters / uniovmax = np.max(overlaps)jmax = np.argmax(overlaps)if ovmax > ovthresh:if not R['difficult'][jmax]:if not R['det'][jmax]:tp[d] = 1.R['det'][jmax] = 1else:fp[d] = 1.else:fp[d] = 1.# compute precision recall
fp = np.cumsum(fp)
tp = np.cumsum(tp)
rec = tp / float(npos)
# avoid divide by zero in case the first detection matches a difficult
# ground truth
prec = tp / np.maximum(tp + fp, np.finfo(np.float64).eps)
ap = voc_ap(rec, prec, use_07_metric)return rec, prec, ap

2.4,mAP 计算方法
因为 值的计算是对数据集中所有类别的 值求平均,所以我们要计算 ,首先得知道某一类别的 值怎么求。不同数据集的某类别的 计算方法大同小异,主要分为三种:

(1)在 VOC2007,只需要选取当 共 11 个点时的 Precision 最大值,然后 就是这 11 个 Precision 的平均值, 就是所有类别 值的平均。VOC 数据集中计算 的代码(用的是插值计算方法,代码出自py-faster-rcnn仓库)

(2)在 VOC2010 及以后,需要针对每一个不同的 Recall 值(包括 0 和 1),选取其大于等于这些 Recall 值时的 Precision 最大值,然后计算 PR 曲线下面积作为 值, 就是所有类别 值的平均。

(3)COCO 数据集,设定多个 IOU 阈值(0.5-0.95, 0.05 为步长),在每一个 IOU 阈值下都有某一类别的 AP 值,然后求不同 IOU 阈值下的 AP 平均,就是所求的最终的某类别的 AP 值。

三,目标检测度量标准汇总
目标检测指标汇总

评价指标 定义及理解
mAP mean Average Precision, 即各类别 AP 的平均值
AP PR 曲线下面积,后文会详细讲

Android rtmp 推流(RtmLivePrj)源码相关推荐

  1. 【Android RTMP】RTMPDumb 源码导入 Android Studio ( 交叉编译 | 配置 CMakeList.txt 构建脚本 )

    文章目录 安卓直播推流专栏博客总结 一. RTMP 协议 二. RTMP 协议使用 三. RTMPDump 源码下载 四. RTMPDump 源码交叉编译 五. RTMPDump 源码导入 Andro ...

  2. android硬编码用rtmp,Android RTMP推流之MediaCodec硬编码二(RTMPDump推流)

    简介 在前面的两篇文章中:Android RTMP推流之MediaCodec硬编码一(H.264进行flv封装)介绍了如何MediaCodec进行H264硬编码,然后将编码后的数据封装到flv文件中. ...

  3. 搭建直播平台过程中Android端直播APP源码是如何实现连麦功能的?

    直播平台强大的变现能力是大家有目共睹的,很多开发商在搭建直播平台时为了增加用户黏性,纷纷将直播中加入连麦功能. 目前市场上通用的有两种连麦方案:本地混流和云端混流.本地混流即主播和连麦观众分别推一路流 ...

  4. Android实用应用程序源码

    andriod闹钟源代码 http://www.apkbus.com/android-20974-1-1.html android源码分享之指南针程序 http://www.apkbus.com/an ...

  5. 【转】Ubuntu 14.04.3上配置并成功编译Android 6.0 r1源码

    http://www.linuxidc.com/Linux/2016-01/127292.htm 终于成功把Android 6.0 r1源码的源码编译.先上图,这是在Ubuntu中运行的Android ...

  6. android intent 源码,Android 基础之 IntentService 源码

    Android 基础之 IntentService 源码 Android,IntentService,源码 IntentService 位于 android.app 包下面,是 Service 的一个 ...

  7. android 修改编译内核源码 对抗反调试

    0×00  写在前面 攻防对立.程序调试与反调试之间的对抗是一个永恒的主题.在安卓逆向工程实践中,通过修改和编译安卓内核源码来对抗反调试是一种常见的方法.但网上关于此类的资料比较少,且都是基于AOSP ...

  8. Android Camera 系统架构源码分析

    Android Camera 系统架构源码分析(1)---->Camera的初始化 Android Camera 系统架构源码分析(2)---->Camera的startPreview和s ...

  9. Android -- 带你从源码角度领悟Dagger2入门到放弃(一)

    1,以前的博客也写了两篇关于Dagger2,但是感觉自己使用的时候还是云里雾里的,更不谈各位来看博客的同学了,所以今天打算和大家再一次的入坑试试,最后一次了,保证最后一次了. 2,接入项目 在项目的G ...

最新文章

  1. 在线作图|你不知道的绘制带聚类树的堆叠柱状图的方法
  2. linux增加自定义path和manpath
  3. python软件开发的一般流程-Python各个岗位的开发流程
  4. Living life over 假如生活重头再来
  5. MySQL数据库引擎快速指导
  6. 使用Data Profile进行数据剖析
  7. java 创建string对象机制 字符串缓冲池 字符串拼接机制 字符串中intern()方法...
  8. 让linux服务器支持安全http协议(https)
  9. Nginx正、反向代理以及负载均衡介绍
  10. tomcat 加载js 中文乱码
  11. 路由型交换机建立VSF及删除VSF
  12. Java 实现 pdf 和 Excel 的生成及数据动态插入、导出
  13. 分布式架构网络通信——netty
  14. linux中buff/cache占用高
  15. pcode.linq
  16. 电脑数据没有了怎么恢复?笔记本电脑数据丢失怎样恢复
  17. webpy中使用session
  18. 基于idea-SSM班级管理系统(javaweb-php-asp.netC#-j2ee)包含学生日常信息管理学生会选举投票管理
  19. 动力节点Maven课程笔记
  20. 自然语言处理实战-基于LSTM的藏头诗和古诗自动生成

热门文章

  1. 为什么 NanoID 会取代 UUID
  2. iPhone 5将近引发清货猜疑
  3. Java多线程碎碎念
  4. 【安全知识分享】2021年安全生产月宣讲课件-交通安全(附下载)
  5. 高速缓存cache详解
  6. 上海周边学校计算机一本,上海这所211实力很强悍,但因太低调而被忽视,中等生快来捡漏...
  7. 【自适应波束形成算法】 ---- 线性约束最小方差准则(公式推导)
  8. 超强1000个jquery极品插件!(转)
  9. python与新媒体专业就业前景_新媒体行业的发展前景如何?
  10. php云服务器域名绑定域名,云服务器使用WordPress搭建个人博客并绑定域名全记录...