传统目标跟踪——MeanShift算法

news2024/12/26 11:57:35

目录

一、均值漂移(MeanShift)

二、流程

三、代码

3.1 meanshift+固定框的代码

3.2 优化:meanshift+鼠标选择

3.3 meanshift+自己实现函数

四、补充知识

4.1 直方图

4.2 归一化

4.3 直方图反投影


一、均值漂移(MeanShift)

        该算法寻找离散样本的最大密度,并且重新计算下一帧的最大密度,这个算法的特点就是可以给出目标移动的方向。

         meanshift算法的原理很简单。假设你有一堆点集,还有一个小的窗口,这个窗口可能是圆形的,现在你可能要移动这个窗口到点集密度最大的区域当中。 

        最开始的窗口是蓝色圆环的区域,命名为C1。蓝色圆环的圆心用一个蓝色的矩形标注,命名为C1_o。
        而窗口中所有点的点集构成的质心在蓝色圆形点C1_r处,显然圆环的形心和质心并不重合。所以,移动蓝色的窗口,使得形心与之前得到的质心重合。在新移动后的圆环的区域当中再次寻找圆环当中所包围点集的质心,然后再次移动,通常情况下,形心和质心是不重合的。不断执行上面的移动过程,直到形心和质心大致重合结束。这样,最后圆形的窗口会落到像素分布最大的地方,也就是图中的绿色圈,命名为C2。
        meanshift算法除了应用在视频追踪当中,在聚类,平滑等等各种涉及到数据以及非监督学习的场合当中均有重要应用,是一个应用广泛的算法。

        如果不知道预先要跟踪的目标,就可以采用这种巧妙地办法,加设定条件,使能动态的开始跟踪(和停止跟踪)视频的某些区域,(如可以采用预先训练好的SVM进行目标的检测,然后开始使用均值漂移MeanShift跟踪检测到的目标)

        所以一般是分两个步骤:1.标记感兴趣区域 2.跟踪该区域

二、流程

         图像是一个矩阵信息,如何在一个视频当中使用meanshift算法来追踪一个运动的物体呢?大致流程如下:

meanshift流程
1.首先在图像上选定一个目标区域
2.计算选定区域的直方图分布,一般是HSV色彩空间的直方图
3.对下一帧图像 b 同样计算直方图分布
4.计算图像 b 当中与选定区域直方图分布最为相似的区域,使用meanshift算法将选定区域沿着最为相似的部分进行移动,直到找到最相似的区域,便完成了在图像b中的目标追踪。
5.重复3到4的过程,就完成整个视频目标追踪。
通常情况下我们使用直方图反向投影得到的图像和第一帧目标对象的起始位置,当目标对象的移动会反映到直方图反向投影图中,meanshift算法就把我们的窗口移动到反向投影图像中灰度密度最大的区域了。

                直方图反向投影

实现Meanshift的主要流程是︰

  1. 读取视频文件:cv.videoCapture()
  2. 感兴趣区域设置:获取第一帧图像,并设置目标区域,即感兴趣区域
  3. 计算直方图:计算感兴趣区域的HSV直方图,并进行归一化
  4. 目标追踪︰设置窗口搜索停止条件,直方图反向投影,进行目标追踪,并在目标位置绘制矩形框

三、代码

opencv API

cv2.meanShift(probImage, window, criteria)

参数:

  • probImage:ROI区域,即目标直方图的反向投影
  • window:初始搜索窗口,就是定义ROI的rect
  • criteria:确定窗口搜索停止的准则,主要有迭代次数达到设置的最大值,窗口中心的漂移值大于某个设定的限值等

(Python)从零开始,简单快速学机器仿人视觉Opencv---运用五:物体运动跟踪 - 古月居

3.1 meanshift+固定框的代码

import cv2 as cv

# 创建读取视频的对象
cap = cv.VideoCapture("E:\Python-Code/videodataset/enn.mp4")

# 获取第一帧位置,并指定目标位置
ret, frame = cap.read()
c, r, h, w = 530, 160, 300, 320
track_window = (c, r, h, w)
# 指定感兴趣区域
roi = frame[r:r + h, c:c + w]

# 计算直方图
# 转换色彩空间
hsv_roi = cv.cvtColor(roi, cv.COLOR_BGR2HSV)
# 计算直方图
roi_hist = cv.calcHist([hsv_roi], [0], None, [180], [0, 180])
# 归一化
cv.normalize(roi_hist, roi_hist, 0, 255, cv.NORM_MINMAX)

# 目标追踪
# 设置窗口搜索终止条件:最大迭代次数,窗口中心漂移最小值
term_crit = (cv.TermCriteria_EPS | cv.TERM_CRITERIA_COUNT, 10, 1)

while True:
    ret, frame = cap.read()
    if ret:
        # 计算直方图的反向投影
        hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
        dst = cv.calcBackProject([hsv], [0], roi_hist, [0, 180], 1)

        # 进行meanshift追踪
        ret, track_window = cv.meanShift(dst, track_window, term_crit)

        # 将追踪的位置绘制在视频上,并进行显示
        x, y, w, h = track_window
        img = cv.rectangle(frame, (x, y), (x + w, y + h), 255, 2)
        cv.imshow("frame", img)

        if cv.waitKey(20) & 0xFF == ord('q'):
            break

    else:
        break

# 资源释放
cap.release()
cv.destroyAllWindows()

 缺点:这种就是一开始设定了具体框的大小和位置,不能根据实际情况自己进行更改。

        初始框的位置很重要。以Meanshift为例,它的工作原理是根据概率密度来寻找最大的密度区域,但如果我们一开始将跟踪框放置在了一个直方图反向投影图中全黑的区域(密度为0),这会导致其无法正确向物体方向进行移动,从而导致卡死在那里。

        我们已追踪视频的初始帧(第一帧)为例,我们假设想要跟踪其中的一个物体,我们就得将跟踪框放置到跟踪物体周边的区域才能让程序正常运行,但我们其实很难知道一张图片中跟踪物体的具体位置。   举个简单的例子,比如我现在有一张图片,我们要跟踪图片右下角的一个物体,但是我不知道这个物体的坐标范围,所以我只能一次一次的去尝试(在代码中修改初始框的位置后,看看程序的运行情况)来保证代码能够正常运行,但这样代码的普适性很差,因为每当要更改跟踪对象的时候,都需要反复的修改,才能应对当前的情况,这样实在是有点麻烦。  

3.2 优化:meanshift+鼠标选择

        这里介绍一个函数,起名为:cv2.selectROI,使用这个函数,我们就能够实现手动画取我们的跟踪框,其函数语法如下所示: 

track_window=cv2.selectROI('frameName', frame)

参数:

  • framename:显示窗口的画布名
  • frame:具体的帧
import cv2
import numpy as np

# 读取视频
cap=cv2.VideoCapture('E:\Python-Code/videodataset/enn.mp4')
# 获取第一帧位置,参数ret 为True 或者False,代表有没有读取到图片 第二个参数frame表示截取到一帧的图片
ret,frame=cap.read()
#我这里画面太大了所以缩小点——但是缩小后我的就会报错
# frame=cv2.resize(frame,None,None,fx=1/2,fy=1/2,interpolation=cv2.INTER_CUBIC)

#跟踪框
track_window=cv2.selectROI('img', frame)

#获得绿色的直方图
# 转换色彩空间
hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
mask=cv2.inRange(hsv,np.array((35,43,46)),np.array((77,255,255)))
# 计算直方图
hist=cv2.calcHist([hsv],[0],mask,[181],[0,180])
# hist=cv2.calcHist([hsv],[0],[None],[180],[0,180])
# 归一化
cv2.normalize(hist,hist,0,255,cv2.NORM_MINMAX)

# 目标追踪
# 设置窗口搜索终止条件:最大迭代次数,窗口中心漂移最小值
term_crit=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT,10,1)

while True:
    ret,frame=cap.read()
    # frame = cv2.resize(frame, None, None, fx=1 / 2, fy=1 / 2, interpolation=cv2.INTER_CUBIC)
    if ret== True:
        # 计算直方图的反向投影
        hsv=cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
        dst=cv2.calcBackProject([hsv],[0],hist,[0,180],1)

        # 进行meanshift追踪
        ret,track_window=cv2.meanShift(dst,track_window,term_crit)

        # 将追踪的位置绘制在视频上,并进行显示
        x,y,w,h = track_window
        img = cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
        (x,y)=img.shape[:2]
        cv2.imshow('img',img)

        if cv2.waitKey(1)==ord('q'):
            break
    else:
        break

# 资源释放
cap.release()
cv2.destroyAllWindows()

          运行上面的代码,会跳出一个窗口,窗口上显示的就是我们载入的视频的第一帧,我们用鼠标拖动,画出我们要跟踪的物体的位置

        但是这里需要注意的是,这个函数每次调用只能画一个矩形(C++版本中的OpenCV可以一次画好多个),如果想画好多个矩形的话,可以使用while循环:

bboxes = []
colors = [] 
while 1:
    bbox = cv2.selectROI('MultiTracker', frame)
    bboxes.append(bbox)
    colors.append((randint(0, 255), randint(0, 255), randint(0, 255)))
    print("按下q键退出,按下其他键继续画下一个框")
    if cv2.waitKey(0) & 0xFF==ord('q'):
        break
print('选取的边框为{}'.format(bboxes))

但是完整的代码并没有跑通

3.3 meanshift+自己实现函数

这个效果最好,但是不懂为什么会这样?为什么调用库函数反而效果不好呢?

import math
import numpy as np
import cv2


def get_tr(img):
    # 定义需要返回的参数
    mouse_params = {'x': None, 'width': None, 'height': None,
                    'y': None, 'temp': None}
    cv2.namedWindow('image')
    # 鼠标框选操作函数
    cv2.setMouseCallback('image', on_mouse, mouse_params)
    cv2.imshow('image', img)
    cv2.waitKey(0)
    return [mouse_params['x'], mouse_params['y'], mouse_params['width'],
            mouse_params['height']], mouse_params['temp']


def on_mouse(event, x, y, flags, param):
    global img, point1
    img2 = img.copy()
    if event == cv2.EVENT_LBUTTONDOWN:  # 左键点击
        point1 = (x, y)
        cv2.circle(img2, point1, 10, (0, 255, 0), 5)
        cv2.imshow('image', img2)
    elif event == cv2.EVENT_MOUSEMOVE and (flags & cv2.EVENT_FLAG_LBUTTON):  # 按住左键拖曳
        cv2.rectangle(img2, point1, (x, y), (255, 0, 0), 5)
        cv2.imshow('image', img2)
    elif event == cv2.EVENT_LBUTTONUP:  # 左键释放
        point2 = (x, y)
        cv2.rectangle(img2, point1, point2, (0, 0, 255), 5)
        cv2.imshow('image', img2)
        # 返回框选矩形左上角点的坐标、矩形宽度、高度以及矩形包含的图像
        param['x'] = min(point1[0], point2[0])
        param['y'] = min(point1[1], point2[1])
        param['width'] = abs(point1[0] - point2[0])
        param['height'] = abs(point1[1] - point2[1])
        param['temp'] = img[param['y']:param['y'] + param['height'],
                        param['x']:param['x'] + param['width']]


def main():
    global img
    cap = cv2.VideoCapture("E:\Python-Code/videodataset/enn.mp4")
    # 获取视频第一帧
    ret, frame = cap.read()
    img = frame
    # 框选目标并返回相应信息:rect为四个信息,temp为框选出来的图像
    rect, temp = get_tr(img)
    print(temp)
    (a, b, c) = temp.shape
    y = [a / 2, b / 2]

    # 计算目标图像的权值矩阵
    m_wei = np.zeros((a, b))
    for i in range(a):
        for j in range(b):
            z = (i - y[0]) ** 2 + (j - y[1]) ** 2
            m_wei[i, j] = 1 - z / (y[0] ** 2 + y[1] ** 2)

    # 计算目标权值直方图
    C = 1 / sum(sum(m_wei))
    hist1 = np.zeros(16 ** 3)
    for i in range(a):
        for j in range(b):
            q_b = math.floor(float(temp[i, j, 0]) / 16)
            q_g = math.floor(float(temp[i, j, 1]) / 16)
            q_r = math.floor(float(temp[i, j, 2]) / 16)
            q_temp1 = q_r * 256 + q_g * 16 + q_b
            hist1[int(q_temp1)] = hist1[int(q_temp1)] + m_wei[i, j]
    hist1 = hist1 * C

    # 接着读取视频并进行目标跟踪
    while (1):
        ret, frame = cap.read()

        if ret == True:
            Img = frame
            num = 0
            Y = [1, 1]

            # mean shift迭代
            while (np.sqrt(Y[0] ** 2 + Y[1] ** 2) > 0.5) & (num < 20):
                num = num + 1

                # 计算候选区域直方图
                temp2 = Img[int(rect[1]):int(rect[1] + rect[3]), int(rect[0]):int(rect[0] + rect[2])]
                hist2 = np.zeros(16 ** 3)
                q_temp2 = np.zeros((a, b))
                for i in range(a):
                    for j in range(b):
                        q_b = math.floor(float(temp2[i, j, 0]) / 16)
                        q_g = math.floor(float(temp2[i, j, 1]) / 16)
                        q_r = math.floor(float(temp2[i, j, 2]) / 16)
                        q_temp2[i, j] = q_r * 256 + q_g * 16 + q_b
                        hist2[int(q_temp2[i, j])] = hist2[int(q_temp2[i, j])] + m_wei[i, j]
                hist2 = hist2 * C

                w = np.zeros(16 ** 3)
                for i in range(16 ** 3):
                    if hist2[i] != 0:
                        w[i] = math.sqrt(hist1[i] / hist2[i])
                    else:
                        w[i] = 0

                sum_w = 0
                sum_xw = [0, 0]
                for i in range(a):
                    for j in range(b):
                        sum_w = sum_w + w[int(q_temp2[i, j])]
                        sum_xw = sum_xw + w[int(q_temp2[i, j])] * np.array([i - y[0], j - y[1]])
                Y = sum_xw / sum_w

                # 位置更新
                rect[0] = rect[0] + Y[1]
                rect[1] = rect[1] + Y[0]

            v0 = int(rect[0])
            v1 = int(rect[1])
            v2 = int(rect[2])
            v3 = int(rect[3])
            pt1 = (v0, v1)
            pt2 = (v0 + v2, v1 + v3)

            # 画矩形
            IMG = cv2.rectangle(Img, pt1, pt2, (0, 0, 255), 2)
            cv2.imshow('IMG', IMG)
            k = cv2.waitKey(60) & 0xff
            if k == 27:
                break
        else:
            break


if __name__ == '__main__':
    main()

四、补充知识

4.1 直方图

构建图像的直方图需要使用到函数cv2.calcHist,其常用函数语法如下所示:  

hist=cv2.calcHist(images, channels, mask, histSize, ranges) 

images:输入的图像
channels:选择图像的通道,如果是三通道的话就可以是[0],[1],[2]
mask:掩膜,是一个大小和image一样的np数组,其中把需要处理的部分指定为1,不需要处理的部分指定为0,一般设置为None,如果有mask,会先对输入图像进行掩膜操作
histSize:使用多少个bin(柱子),一般为256,但如果是H值就是181
ranges:像素值的范围,一般为[0,255]表示0~255,对于H通道而言就是[0,180]

  需要注意的是,这里除了mask以外,其余的几个参数都要加上[],如下所示:  

hist=cv2.calcHist([img],[0],mask,[181],[0,180]) 

4.2 归一化

        这个时候我们还需要使用一种归一化的方法来对彩色直方图中的数量值进行规范化。   现有的直方图中的数值为对应像素的数量,其中图中出现数量最多的像素的数量值(最高的柱子对应的y轴数值)我们记为max的话,整个直方图y方向上的取值范围就是[0,max],我们需要把这个范围缩减到[0,255],

        这里我们需要使用到cv2.normalize函数,函数主要语法如下所示:  

cv2.normalize(src,dst, alpha,beta, norm_type)
·src-输入数组。
·dst-与SRC大小相同的输出数组。
·α-范数值在范围归一化的情况下归一化到较低的范围边界。
·β-上限范围在范围归一化的情况下;它不用于范数归一化。
·范式-规范化类型(见下面详细介绍)。

  这里我们需要注意的是范式-规范化类型,这里有以下几种选择。  

NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化。
NORM_INF:归一化数组的(切比雪夫距离)L∞范数(绝对值的最大值)
NORM_L1: 归一化数组的(曼哈顿距离)L1-范数(绝对值的和)
NORM_L2: 归一化数组的(欧几里德距离)L2-范数

  上面的名词看起来很高大上,其实是很简单,我们一一讲解下。(不是很感兴趣的只要看下第一个NORM_MINMAX即可,剩下的三个可以不看)

        首先是NORM_MINMAX,这个是我们最常用的一种归一化方法。举个例子,我们上面提到的最高的柱子对应的y轴坐标为max,如果我们使用这种方法,想要缩放到的指定的范围为[0,255],那么max就会直接被赋值为255,其余的柱子也会随之一样被压缩(类似于相似三角形那样的缩放感觉)。   没错,很简单得就介绍完了一种,不是很想了解其他几个的读者可以直接跳过本小节剩下来的内容了,因为剩下三种不是很常用。  

      这里有介绍剩下的几种

4.3 直方图反投影

        简单来说,它会输出与输入图像(待搜索)同样大小的图像,其中的每一个像素值代表了输入图像上对应点属于目标对象(我们需要跟踪的目标)的概率。用更简单的话来解释,输出图像中像素值越高(越白)的点就越可能代表我们要搜索的目标 (在输入图像所在的位置)。   而对于灰度图而言,其只有一个通道,取值范围为0到255,所以我们之前在归一化的时候将直方图的y轴坐标的取值范围压缩到了0-255的范围内,就是为了这里可以直接赋值。  

直方图反向投影1    直方图反向投影2

        越暗的地方说明属于跟踪部分的可能性越低,越亮的地方属于跟踪部分的可能性越高。   这里使用到的函数为cv2.calcBackProject,函数语法如下所示:  

dst=cv2.calcBackProject(image,channel,hist,range,scale)

image:输入图像
channel:用来计算反向投影的通道数,与产生直方图对应的通道应一致
hist:作为输入的直方图
range:直方图的取值范围
scale:输出图像的缩放比,一般为1,保持与输入图像一样的大小
dst:输出图像

注意:除了hist和scale外,其他的参数都要加上[]

  例如:  

dst=cv2.calcBackProject([hsv],[0],hist,[0,180],1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/126657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Maven 教程

Maven 教程 Maven 翻译为"专家"、“内行”&#xff0c;是 Apache 下的一个纯 Java 开发的开源项目。基于项目对象模型&#xff08;缩写&#xff1a;POM&#xff09;概念&#xff0c;Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。 Maven 是一…

手把手教你阿里云服务器的购买及环境搭建

1.服务器相关 程序员都需要一个自己的服务器! 用于发布自己的网站和项目&#xff01;用于操作系统的练习&#xff01;将自己的远程仓库、远程数据库、远程tomcat… 搭建在服务器上&#xff01;用于Linux进行任意的环境部署操作&#xff01; 服务器如何购买 若果你没超过24岁&am…

【Bp2Lua】多返回值和Out参数说明

【Bp2Lua】多返回值和Out参数说明 这块比较繁琐&#xff0c;有四部分需要了解&#xff1a; U蓝图LuaUnLua 最后再解释 Bp2Lua 如何处理&#xff0c;以及后续潜在的风险 Bp2Lua 如何处理 先说结论 统一当作多返回值返回特殊处理了 out参数 不在参数列表最后的情况&#xf…

分布式理论之分布式锁

写在前面 在分布式理论之分布式互斥 一文中我们分析了分布式环境中的分布式互斥问题,其中解决该问题有如下的三种方案&#xff1a; 1&#xff1a;集中式算法 2&#xff1a;分布式算法 3&#xff1a;令牌环算法而本文要分析的分布式锁&#xff0c;就是其中的算法1&#xff0c;…

折腾了我一周,原来Netty网络编程就是这么个破玩意儿!!!

1、阻塞 阻塞模式下&#xff0c;相关方法都会导致线程暂停 ServerSocketChannel.accept 会在没有连接建立时让线程暂停SocketChannel.read 会在通道中没有数据可读时让线程暂停阻塞的表现其实就是线程暂停了&#xff0c;暂停期间不会占用 cpu&#xff0c;但线程相当于闲置 单线…

flowable学习笔记(四):动态多实例

1.定义流程模板 【测试用户任务多实例】任务节点配置了以下属性&#xff1a; 集合(多实例)&#xff1a;userList。这个创建流程实例时入参需要加上这个参数。 元素变量(多实例)&#xff1a;user。工作流创建多实例时会将集合(多实例)的值拆分成元素变量(多实例)&#xff0c;这个…

Git复习,GitHub\Gitee的使用,IDEA集成Git

今天想把自己的课设上传到GitHub&#xff0c;因为长久不用&#xff0c;Git的命令忘得差不多了&#xff0c;所以今天把Git重新学一遍。 文章目录Git的介绍Git的安装Git的常用命令工作机制常用命令用户签名初始化本地库查看本地库状态添加暂存区提交本地库查看引用日志信息修改文…

Python常用函数笔记汇总2

1.分组汇总groupby 2.计算空值 # py计算空值 data.isnull().sum(axis0) data.notnull().sum(axis0)# py去重计数 data_op[id_num_op].value_counts().size data_op[id_num_op].size3.保留两位小数 # predict_proba保留两位小数 gnb GaussianNB() pre gnb.fit(X_train,y_tr…

pytest-日志配置

如果想要在run测试用例时&#xff0c;打印出由python的logging的日志&#xff0c;可以在pytest中进行相应的配置 pytest可以将日志输出到控制台或者文件中&#xff0c;分别对应不同的配置项 pytest的日志配置文件主要在pytest.ini文件中进行配置&#xff0c;包括配置日志的格式…

ARM64内存虚拟化分析(5)内存布局更新

1 添加MR 创建的MR需要通过函数memory_region_add_subregion()添加到系统中&#xff0c;提交MR&#xff0c;并最终往KVM提交内存的变化。 过程如下&#xff1a; 将mr设置为subregion的container&#xff1b;设置subregion在虚拟机中的物理地址&#xff1b;调用memory_region_t…

FOHEART H1数据手套_Unity3D SDK开发

本教程介绍使用FOHEART H1数据手套在Unity3D中&#xff0c;显示每段骨骼的位置与旋转信息。 需要准备的软硬件&#xff1a; 1、FOHEART H1数据手套 2、MotionVenus客户端 3、Unity3D软件 4、开发包MotionVenus_U3DPlugin_v2.0_H1GloveDev_SDKTest.unitypackage 1、连接数…

HFSS学习笔记

以下所有操作&#xff0c;都是基于2022版本的HFSS。一、HFSS solution模式选择位置&#xff1a;HFSS-Solution type类型表格。二、单位设置位置&#xff1a;Modeler-Units点击后&#xff0c;通常选用单位为&#xff1a;mm三、绘制物体点击红圈1的draw&#xff0c;右侧有些形状可…

MCU-51:单片机实时时钟

目录一、什么是时钟1.1 实时时钟1.2 时序二、DS1302实时时钟2.1 DS1302介绍2.2 引脚定义和应用电路三、代码演示3.1 数字时钟3.2 DS1302可调时钟注意&#xff1a;一定要看一、什么是时钟 1.1 实时时钟 real time clock&#xff0c;真实时间&#xff0c;就是所谓的xx年x月x日x…

我的统计学学习笔记(持续更新)

目录数据&#xff1a;变量和观测统计学描述统计数据的收集数据的可视化数据的规律性特征统计推断参数估计假设检验贝叶斯统计基础知识&#xff1a;概率论数据&#xff1a;变量和观测 变量(column)、观测(row)、测量(assign number to observation)。 统计学 描述统计 数据…

YOLO-V5 系列算法和代码解析(四)—— 网络结构

文章目录辅助工具网络配置文件网络构建网络推理绘制网络结构辅助工具 借助辅助工具可视化网络结构&#xff0c;达到辅助阅读代码&#xff0c;进而辅助手动绘制结构清晰的网络结构&#xff0c;最终理解整个网络架构的目的&#xff0c;为深入学习【yolo-v5】提供有效的保障。 ten…

阿里妈妈内容风控模型预估引擎的探索和建设

作者&#xff1a;徐雄飞、金禄旸、滑庆波、李治 内容作为营销的重要载体&#xff0c;能够促进信息的交流和传播。在营销场景中&#xff0c;广告高曝光的特性放大了风险外漏带来的一系列问题&#xff0c;因此对内容的风控审核就显得至关重要。本文将为大家分享阿里妈妈内容风控模…

DOM节点操作

节点操作 改变元素节点中的内容可以使用两个相关属性&#xff1a;innerHTML innerText 注意字符串不能换行 innerHTML属性能以HTML语法设置节点中的内容 innerText属性只能以纯文本的形式设置节点中的内容 节点创建 document.createElement()方法用于创建一个指定tagname…

android studio编译慢

前言 android studio编译慢一直就是一个问题&#xff0c;很久以前使用eclipse&#xff0c;编译速度很快&#xff0c;在还没开始正式工作的时候就开始使用android studio&#xff0c;那时候还是0.8 很原始&#xff0c;主要那时候还没开始工作&#xff0c;所以编译快慢没感觉&am…

TikTok Shop跨境服务市场上线;俄罗斯速卖通发布延误通知

让我们一起来看看今日都有哪些新鲜事吧&#xff01;01 TikTok Shop跨境服务市场上线 12月28日消息&#xff0c;服务商是助力商家在TikTok Shop成长非常重要的合作伙伴&#xff0c;TikTok Shop希望通过上线服务市场帮助商家快速了解服务商&#xff0c;筛选符合自身需求的服务商…

【JavaSE成神之路】Java面向对象(上)

哈喽&#xff0c;我是兔哥呀&#xff0c;今天就让我们继续这个JavaSE成神之路&#xff01; 这一节啊&#xff0c;咱们要学习的内容是Java的面向对象。 首先我们回顾一下&#xff0c;之前的章节我们学到了哪些东西。 我们学会了写一个类&#xff0c;然后里面弄一个main方法&am…