• 【含泪提速!】一文全解相似度算法、跟踪算法在各个AI场景的应用(附代码)


    大家好,我是cv君,大家是否为深度学习算法速度感到困扰?本次cv君倾力分享一个优秀的方法,通过相似度+跟踪方案优化速度问题,并提高了检测、分割算法稳定性,附带代码,一起肝起来吧~

    今天给大家全解一下图像相似度算法以及跟踪算法。简单说就是判断俩图片、视频、画面是否相似的算法。

    能做什么?

    1: 当你老板说你目标检测算法耗时、耗电、耗内存的时候:请务必加上相似度算法!超低能耗、超快速度,适用于部分场景:你的检测算法慢,功耗高时,实际上,并不需要每秒都检测,检测算法ok,那么你前几帧检测,后几十帧跟踪,都行。相似度过小:即画面变化过大后,就重新检测;或者时间过了几秒,重新检测,再跟踪,功耗大大降低。

    2: 判断画面是否变化,有人闯入你家,黑暗的时候,蒙面大盗是难以被目标检测、人脸识别的。

    3: 相机在预览时,画面是否改变:调焦,物体运动,画面是否被放大缩小,云台是否转动。

    4:画面是否稳定。

    5:图像之间谁最相似、最不相似。

    6:用作超分、去雾、去雨、去摩、图像修复、各种图像调试,以达到与你的GT最相似,用作损失计算。

    等等

    相似度算法全解

    1.余弦相似度计算

    把图片表示成一个向量,通过计算向量之间的余弦距离来表征两张图片的相似度。

    1. # -*- coding: utf-8 -*-
    2. # !/usr/bin/env python
    3. # 余弦相似度计算
    4. from PIL import Image
    5. from numpy import average, dot, linalg
    6. # 对图片进行统一化处理
    7. def get_thum(image, size=(64, 64), greyscale=False):
    8.    # 利用image对图像大小重新设置, Image.ANTIALIAS为高质量的
    9.    image = image.resize(size, Image.ANTIALIAS)
    10.    if greyscale:
    11.        # 将图片转换为L模式,其为灰度图,其每个像素用8个bit表示
    12.        image = image.convert('L')
    13.    return image
    14. # 计算图片的余弦距离
    15. def image_similarity_vectors_via_numpy(image1, image2):
    16.    image1 = get_thum(image1)
    17.    image2 = get_thum(image2)
    18.    images = [image1, image2]
    19.    vectors = []
    20.    norms = []
    21.    for image in images:
    22.        vector = []
    23.        for pixel_tuple in image.getdata():
    24.            vector.append(average(pixel_tuple))
    25.        vectors.append(vector)
    26.        # linalg=linear(线性)+algebra(代数),norm则表示范数
    27.        # 求图片的范数
    28.        norms.append(linalg.norm(vector, 2))
    29.    a, b = vectors
    30.    a_norm, b_norm = norms
    31.    # dot返回的是点积,对二维数组(矩阵)进行计算
    32.    res = dot(a / a_norm, b / b_norm)
    33.    return res
    34. image1 = Image.open('010.jpg')
    35. image2 = Image.open('011.jpg')
    36. cosin = image_similarity_vectors_via_numpy(image1, image2)
    37. print('图片余弦相似度', cosin)
    38. # 输出结果
    39. # 图片余弦相似度 0.9858416158253334

    2.哈希算法计算图片的相似度

    cv君简介一下Hash哈希算法是一类算法的总称,包括aHash、pHash、dHash。顾名思义,哈希不是以严格的方式计算Hash值,而是以更加相对的方式计算哈希值,因为“相似”与否,就是一种相对的判定。

    几种hash值的比较:

    • aHash:平均值哈希。速度比较快,但是常常不太精确。

    • pHash:感知哈希。精确度比较高,但是速度方面较差一些。

    • dHash:差异值哈希。精确度较高,且速度也非常快

    值哈希算法差值哈希算法感知哈希算法都是值越小,相似度越高,取值为0-64,即汉明距离中,64位的hash值有多少不同。三直方图单通道直方图的值为0-1,值越大,相似度越高。

     

    cv君把算法的时间也打印出来。我们把图像都缩放到8*8进行相似度的计算,此时余弦相似度要花16.9ms,而Hash算法都接近0ms,3通道直方图需要 5ms,单通道直方图需要1ms,我们可以看到,下面的两张图片,有几处不同,但整体相似,我们一眼看到就好主观会认为很相似,但细细看,会发现,有几处不同,所以,相似度,几种方法都不太相同。

    不过,我们需要一种稳定的算法,该相似的相似,不该相似的不相似。

    cv君通过广泛实验,建议大家使用单通道直方图方案。或者感知哈希。

     

    代码

    1. # -*- coding: utf-8 -*-
    2. # !/usr/bin/env python
    3. # 余弦相似度计算
    4. from PIL import Image
    5. from numpy import average, dot, linalg
    6. import time
    7. # 对图片进行统一化处理
    8. def get_thum(image, size=(8, 8), greyscale=False):
    9.    # 利用image对图像大小重新设置, Image.ANTIALIAS为高质量的
    10.    image = image.resize(size, Image.ANTIALIAS)
    11.    if greyscale:
    12.        # 将图片转换为L模式,其为灰度图,其每个像素用8个bit表示
    13.        image = image.convert('L')
    14.    return image
    15. # 计算图片的余弦距离
    16. def image_similarity_vectors_via_numpy(image1, image2):
    17.    image1 = get_thum(image1)
    18.    image2 = get_thum(image2)
    19.    images = [image1, image2]
    20.    vectors = []
    21.    norms = []
    22.    for image in images:
    23.        vector = []
    24.        for pixel_tuple in image.getdata():
    25.            vector.append(average(pixel_tuple))
    26.        vectors.append(vector)
    27.        # linalg=linear(线性)+algebra(代数),norm则表示范数
    28.        # 求图片的范数
    29.        norms.append(linalg.norm(vector, 2))
    30.    a, b = vectors
    31.    a_norm, b_norm = norms
    32.    # dot返回的是点积,对二维数组(矩阵)进行计算
    33.    res = dot(a / a_norm, b / b_norm)
    34.    return res
    35. image1 = Image.open('1.jpg')
    36. image2 = Image.open('2.jpg')
    37. time1 = time.time()
    38. cosin = image_similarity_vectors_via_numpy(image1, image2)
    39. print('图片余弦相似度', cosin, '时间:', time.time() - time1)
    40. import cv2
    41. import numpy as np
    42. from PIL import Image
    43. import requests
    44. from io import BytesIO
    45. import matplotlib
    46. matplotlib.use('TkAgg')
    47. import matplotlib.pyplot as plt
    48. def aHash(img):
    49.    # 均值哈希算法
    50.    # 缩放为8*8
    51.    img = cv2.resize(img, (8, 8))
    52.    # 转换为灰度图
    53.    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    54.    # s为像素和初值为0,hash_str为hash值初值为''
    55.    s = 0
    56.    hash_str = ''
    57.    # 遍历累加求像素和
    58.    for i in range(8):
    59.        for j in range(8):
    60.            s = s + gray[i, j]
    61.    # 求平均灰度
    62.    avg = s / 64
    63.    # 灰度大于平均值为1相反为0生成图片的hash值
    64.    for i in range(8):
    65.        for j in range(8):
    66.            if gray[i, j] > avg:
    67.                hash_str = hash_str + '1'
    68.            else:
    69.                hash_str = hash_str + '0'
    70.    return hash_str
    71. def dHash(img):
    72.    # 差值哈希算法
    73.    # 缩放8*8
    74.    img = cv2.resize(img, (9, 8))
    75.    # 转换灰度图
    76.    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    77.    hash_str = ''
    78.    # 每行前一个像素大于后一个像素为1,相反为0,生成哈希
    79.    for i in range(8):
    80.        for j in range(8):
    81.            if gray[i, j] > gray[i, j + 1]:
    82.                hash_str = hash_str + '1'
    83.            else:
    84.                hash_str = hash_str + '0'
    85.    return hash_str
    86. def pHash(img):
    87.    # 感知哈希算法
    88.    # 缩放32*32
    89.    img = cv2.resize(img, (32, 32))  # , interpolation=cv2.INTER_CUBIC
    90.    # 转换为灰度图
    91.    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    92.    # 将灰度图转为浮点型,再进行dct变换
    93.    dct = cv2.dct(np.float32(gray))
    94.    # opencv实现的掩码操作
    95.    dct_roi = dct[0:8, 0:8]
    96.    hash = []
    97.    avreage = np.mean(dct_roi)
    98.    for i in range(dct_roi.shape[0]):
    99.        for j in range(dct_roi.shape[1]):
    100.            if dct_roi[i, j] > avreage:
    101.                hash.append(1)
    102.            else:
    103.                hash.append(0)
    104.    return hash
    105. def calculate(image1, image2):
    106.    # 灰度直方图算法
    107.    # 计算单通道的直方图的相似值
    108.    hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
    109.    hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
    110.    # 计算直方图的重合度
    111.    degree = 0
    112.    for i in range(len(hist1)):
    113.        if hist1[i] != hist2[i]:
    114.            degree = degree + \
    115.                     (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
    116.        else:
    117.            degree = degree + 1
    118.    degree = degree / len(hist1)
    119.    return degree
    120. def classify_hist_with_split(image1, image2, size=(256, 256)):
    121.    # RGB每个通道的直方图相似度
    122.    # 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值
    123.    image1 = cv2.resize(image1, size)
    124.    image2 = cv2.resize(image2, size)
    125.    sub_image1 = cv2.split(image1)
    126.    sub_image2 = cv2.split(image2)
    127.    sub_data = 0
    128.    for im1, im2 in zip(sub_image1, sub_image2):
    129.        sub_data += calculate(im1, im2)
    130.    sub_data = sub_data / 3
    131.    return sub_data
    132. def cmpHash(hash1, hash2):
    133.    # Hash值对比
    134.    # 算法中1和0顺序组合起来的即是图片的指纹hash。顺序不固定,但是比较的时候必须是相同的顺序。
    135.    # 对比两幅图的指纹,计算汉明距离,即两个64位的hash值有多少是不一样的,不同的位数越小,图片越相似
    136.    # 汉明距离:一组二进制数据变成另一组数据所需要的步骤,可以衡量两图的差异,汉明距离越小,则相似度越高。汉明距离为0,即两张图片完全一样
    137.    n = 0
    138.    # hash长度不同则返回-1代表传参出错
    139.    if len(hash1) != len(hash2):
    140.        return -1
    141.    # 遍历判断
    142.    for i in range(len(hash1)):
    143.        # 不相等则n计数+1,n最终为相似度
    144.        if hash1[i] != hash2[i]:
    145.            n = n + 1
    146.    return n
    147. def getImageByUrl(url):
    148.    # 根据图片url 获取图片对象
    149.    html = requests.get(url, verify=False)
    150.    image = Image.open(BytesIO(html.content))
    151.    return image
    152. def PILImageToCV():
    153.    # PIL Image转换成OpenCV格式
    154.    path = "/Users/waldenz/Documents/Work/doc/TestImages/t3.png"
    155.    img = Image.open(path)
    156.    plt.subplot(121)
    157.    plt.imshow(img)
    158.    print(isinstance(img, np.ndarray))
    159.    img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
    160.    print(isinstance(img, np.ndarray))
    161.    plt.subplot(122)
    162.    plt.imshow(img)
    163.    plt.show()
    164. def CVImageToPIL():
    165.    # OpenCV图片转换为PIL image
    166.    path = "/Users/waldenz/Documents/Work/doc/TestImages/t3.png"
    167.    img = cv2.imread(path)
    168.    # cv2.imshow("OpenCV",img)
    169.    plt.subplot(121)
    170.    plt.imshow(img)
    171.    img2 = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    172.    plt.subplot(122)
    173.    plt.imshow(img2)
    174.    plt.show()
    175. def bytes_to_cvimage(filebytes):
    176.    # 图片字节流转换为cv image
    177.    image = Image.open(filebytes)
    178.    img = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
    179.    return img
    180. def runAllImageSimilaryFun(para1, para2):
    181.    # 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
    182.    # 三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1
    183.    # t1,t2   14;19;10; 0.70;0.75
    184.    # t1,t3   39 33 18   0.58 0.49
    185.    # s1,s2 7 23 11     0.83 0.86 挺相似的图片
    186.    # c1,c2 11 29 17   0.30 0.31
    187.    if para1.startswith("http"):
    188.        # 根据链接下载图片,并转换为opencv格式
    189.        img1 = getImageByUrl(para1)
    190.        img1 = cv2.cvtColor(np.asarray(img1), cv2.COLOR_RGB2BGR)
    191.        img2 = getImageByUrl(para2)
    192.        img2 = cv2.cvtColor(np.asarray(img2), cv2.COLOR_RGB2BGR)
    193.    else:
    194.        # 通过imread方法直接读取物理路径
    195.        img1 = cv2.imread(para1)
    196.        img2 = cv2.imread(para2)
    197.    time1 = time.time()
    198.    hash1 = aHash(img1)
    199.    hash2 = aHash(img2)
    200.    n1 = cmpHash(hash1, hash2)
    201.    print('均值哈希算法相似度aHash:', n1, '时间:', time.time() - time1)
    202.    time1 = time.time()
    203.    hash1 = dHash(img1)
    204.    hash2 = dHash(img2)
    205.    n2 = cmpHash(hash1, hash2)
    206.    print('差值哈希算法相似度dHash:', n2, '时间:', time.time() - time1)
    207.    time1 = time.time()
    208.    hash1 = pHash(img1)
    209.    hash2 = pHash(img2)
    210.    n3 = cmpHash(hash1, hash2)
    211.    print('感知哈希算法相似度pHash:', n3, '时间:', time.time() - time1)
    212.    time1 = time.time()
    213.    n4 = classify_hist_with_split(img1, img2)
    214.    print('三直方图算法相似度:', n4, '时间:', time.time() - time1)
    215.    time1 = time.time()
    216.    n5 = calculate(img1, img2)
    217.    print("单通道的直方图", n5, '时间:', time.time() - time1)
    218.    print("%d %d %d %.2f %.2f " % (n1, n2, n3, round(n4[0], 2), n5[0]))
    219.    print("相似概率|均值: %.2f 差值: %.2f 感知: %.2f 三直方图: %.2f 单通道: %.2f " % (1 - float(n1 / 64), 1 -
    220.                                         float(n2 / 64), 1 - float(n3 / 64), round(n4[0], 2), n5[0]))
    221.    plt.subplot(121)
    222.    plt.imshow(Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)))
    223.    plt.subplot(122)
    224.    plt.imshow(Image.fromarray(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)))
    225.    plt.show()
    226. if __name__ == "__main__":
    227.    p1 = "1.jpg"
    228.    p2 = "2.jpg"
    229.    runAllImageSimilaryFun(p1, p2)

    3.直方图计算图片的相似度

    利用直方图计算图片的相似度时,是按照颜色的全局分布情况来看待的,无法对局部的色彩进行分析,同一张图片如果转化成为灰度图时,在计算其直方图时差距就更大了。对于灰度图可以将图片进行等分,然后在计算图片的相似度。

    代码在上面也有哦,这里是多了个size(64,64)

    1. # 将图片转化为RGB
    2. def make_regalur_image(img, size=(64, 64)):
    3.    gray_image = img.resize(size).convert('RGB')
    4.    return gray_image
    5. # 计算直方图
    6. def hist_similar(lh, rh):
    7.    assert len(lh) == len(rh)
    8.    hist = sum(1 - (0 if l == r else float(abs(l - r)) / max(l, r)) for l, r in zip(lh, rh)) / len(lh)
    9.    return hist
    10. # 计算相似度
    11. def calc_similar(li, ri):
    12.    calc_sim = hist_similar(li.histogram(), ri.histogram())
    13.    return calc_sim
    14. if __name__ == '__main__':
    15.    image1 = Image.open('123.jpg')
    16.    image1 = make_regalur_image(image1)
    17.    image2 = Image.open('456.jpg')
    18.    image2 = make_regalur_image(image2)
    19.    print("图片间的相似度为", calc_similar(image1, image2))

    4.SSIM(结构相似度度量)计算图片的相似度 (重点)

    这是图像修复很重要的方法,经常用在损失函数中

    SSIM是一种全参考的图像质量评价指标,分别从亮度、对比度、结构三个方面度量图像相似性。SSIM取值范围[0, 1],值越大,表示图像失真越小。在实际应用中,可以利用滑动窗将图像分块,令分块总数为N,考虑到窗口形状对分块的影响,采用高斯加权计算每一窗口的均值、方差以及协方差,然后计算对应块的结构相似度SSIM,最后将平均值作为两图像的结构相似性度量,即平均结构相似性SSIM。

    1. import numpy
    2. import numpy as np
    3. import math
    4. import cv2
    5. import torch
    6. import pytorch_ssim
    7. from torch.autograd import Variable
    8. original = cv2.imread("1.jpg")     # numpy.adarray
    9. original = cv2.resize(original, (256, 256))
    10. contrast = cv2.imread("2.jpg",1)
    11. contrast = cv2.resize(contrast, (256, 256))
    12. def psnr(img1, img2):
    13.    mse = numpy.mean( (img1 - img2) ** 2 )
    14.    if mse == 0:
    15.        return 100
    16.    PIXEL_MAX = 255.0
    17.    return 20 * math.log10(PIXEL_MAX / math.sqrt(mse))
    18. def ssim_2(img1, img2):
    19.    """Calculate SSIM (structural similarity) for one channel images.
    20.   It is called by func:`calculate_ssim`.
    21.   Args:
    22.       img1 (ndarray): Images with range [0, 255] with order 'HWC'.
    23.       img2 (ndarray): Images with range [0, 255] with order 'HWC'.
    24.   Returns:
    25.       float: ssim result.
    26.   """
    27.    C1 = (0.01 * 255)**2
    28.    C2 = (0.03 * 255)**2
    29.    img1 = img1.astype(np.float64)
    30.    img2 = img2.astype(np.float64)
    31.    kernel = cv2.getGaussianKernel(11, 1.5)
    32.    window = np.outer(kernel, kernel.transpose())
    33.    mu1 = cv2.filter2D(img1, -1, window)[5:-5, 5:-5]
    34.    mu2 = cv2.filter2D(img2, -1, window)[5:-5, 5:-5]
    35.    mu1_sq = mu1**2
    36.    mu2_sq = mu2**2
    37.    mu1_mu2 = mu1 * mu2
    38.    sigma1_sq = cv2.filter2D(img1**2, -1, window)[5:-5, 5:-5] - mu1_sq
    39.    sigma2_sq = cv2.filter2D(img2**2, -1, window)[5:-5, 5:-5] - mu2_sq
    40.    sigma12 = cv2.filter2D(img1 * img2, -1, window)[5:-5, 5:-5] - mu1_mu2
    41. # 公式二计算
    42.    ssim_map = ((2 * mu1_mu2 + C1) *
    43.               (2 * sigma12 + C2)) / ((mu1_sq + mu2_sq + C1) *
    44.                                       (sigma1_sq + sigma2_sq + C2))
    45.    return ssim_map.mean()
    46. psnrValue = psnr(original,contrast)
    47. ssimValue = ssim_2(original,contrast)
    48. print('PSNR: ', psnrValue)
    49. print('SSIM: ',ssimValue)

    SSIM当做Pytorch损失函数代码:基于pytorch计算ssim和ms-ssim_是依韵阿的博客-CSDN博客_pytorch计算ssim

    psnr 和ssim,大家可以看网上参考哦,这个经常用在损失函数里面,大家可以看看Pytorch版SSIM 和PSNR

     

    PSNR 是越大越相似,一般到30以上就没有什么很大的意义了,肉眼已经快看不出差别了。这时候就需要其他指标了。

    SSIM 是越接近1 越相似。一半是用于去噪等修复任务中,我们这:找不同的任务,偏差较大~后续写写图像修复领域的文章~

    互信息

    互信息(Mutual Information)是信息论里一种有用的信息度量,它可以看成是一个随机变量中包含的关于另一个随机变量的信息量,或者说是一个随机变量由于已知另一个随机变量而减少的不肯定性

    归一化互信息(NMI),就是将互信息放在[0,1]之间

    1. from sklearn import metrics as mr
    2. img1 = cv2.imread('1.jpg')
    3. img2 = cv2.imread('2.jpg')
    4. img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0]))
    5. nmi = mr.normalized_mutual_info_score(img1.reshape(-1), img2.reshape(-1))
    6. print('nmi: ', nmi)

    nmi接近1为满分。

    pixelmatch

    利用像素之间的匹配来计算相似度,速度的话,下面例子7ms,还是比较慢的,但是比较准,能够知道两张图片哪些像素不太相似,然后标注出来,结果如图:

     

    上图是两图相同的,显示出来就是浅色,说明完全相同;如果有不同处,会勾勒出来,下图是下面代码的结果,:

     

    1. #第一步:
    2. # pip install pixelmatch
    3. #第二步:
    4. from PIL import Image
    5. from pixelmatch.contrib.PIL import pixelmatch
    6. img_a = Image.open("1.jpg").resize((64, 64))
    7. img_b = Image.open("2.jpg").resize((64, 64))
    8. img_diff = Image.new("RGBA", img_a.size)
    9. # note how there is no need to specify dimensions
    10. time1 = time.time()
    11. mismatch = pixelmatch(img_a, img_b, img_diff, includeAA=True)
    12. print('pixelmatch Time: ', time.time() - time1)
    13. img_diff.save("diff1.png")

    md5

    粗暴的md5比较 返回是否完全相同,用的哈希方法,只能得到是否完全相同。

    1. def md5_similarity(img1_path, img2_path):
    2.    file1 = open(img1_path, "rb")
    3.    file2 = open(img2_path, "rb")
    4.    md = hashlib.md5()
    5.    md.update(file1.read())
    6.    res1 = md.hexdigest()
    7.    md = hashlib.md5()
    8.    md.update(file2.read())
    9.    res2 = md.hexdigest()
    10. if __name__ == "__main__":
    11.    p1 = "1.jpg"
    12.    p2 = "2.jpg"
    13.    print('md5_similarity:', md5_similarity(p1, p2))

    还有一些,比如基于布隆过滤器的图像相似度算法,这本质也是一种基于Hash改版的算法,实现起来还是有点复杂的,因为它本质是实现对数据搜索的过滤。在搜索中加速。

    2.深度学习方法

    思路:深度特征提取+特征向量相似度计算

    cv君简述:就是换到Feature Map层去做相似度计算比对。没什么亮点。

    参考:

    2.1 论文1

    2.2 论文2

    论文提出感知相似度度量方法

     

    跟踪有十多种,原理和代码,我们下一章说,和这个配套使用,妙哉。

    相似度算法总结

    • 单通道直方图计算结果与直观视觉不符合,但准确率和速度很不错。推荐

    • 余弦相似度准确度较高,但太耗时。不推荐。

    • 互信息的方法从耗时和准确度上粗略观察,介于直方图和余弦相似度之间,次推荐。

    • 感知哈希算法耗时较为可接受,且比对结果较有区分度且符合直观视觉。推荐。

    • SSIM 和PSNR,深度学习修复任务推荐使用loss ,需要多个loss组合使用

    • 互信息的方法从耗时和准确度上粗略观察,介于直方图和余弦相似度之间,次推荐。

    跟踪

    跟踪算法普遍比较耗时,距今有几十年历史了。有2D,3D跟踪算法;

    2D又快准又稳的跟踪方法介绍

    2D像Sort ,匈牙利,Deepsort,Iou 追踪,光流估计,STC跟踪器,KF、KCF,CSRT,mosse,medianflow, tld, mil, boosting, 还有今年新出的ByteTrack。

    上面的话,Sort就不说了,巨快(256输入估计只需要3-4ms),比较准(给7分),但物体离开视野或者被遮挡就寄了!和sort有同样的问题:STC跟踪器,KF、KCF,CSRT,mosse,medianflow, tld, mil, boosting , (并且这些更慢(当然有个别比较快,但准确率只能6-7分)),这些都是不需要保存、读取模型的,可以随插即用。仅支持单目标追踪;

    传统跟踪可以看我这篇文章,附带代码(源码用的跟踪):【效率提高10倍项目原创发布!】深度学习数据自动标注器开源 目标检测和图像分类(高精度高效率)_cv君的博客-CSDN博客

    Deepsort深度学习发方法做了特征提取后用改进版sort追踪,速度的话10-20ms,准确率9分,看输入尺寸, 追踪得比较准,抗遮挡,缺点是速度慢,需要保存、读取模型;

    Deepsort可以看我文章:【AI全栈二】视频流多目标多类别无延迟高精度高召回目标追踪 YOLO+Deepsort 全解_cv君的博客-CSDN博客

    光流估计方法追踪,是我想重点说的,速度比较快,8-13ms 256输入,准确率很高,9分;支持多目标追踪

    原本被用在运动点的估计,可以更改代码改成:任何物体追踪,任何形状跟踪:以上所有2D方法都只能追踪矩形,不能接受倾斜四边形(因为有的是旋转目标检测)、不接受:三角形、随机四边形、圆形、点状物体识别与追踪,

    而光流追踪统统可以实现(也不需要模型)

    cv君已经改成了目标检测版本的跟踪,由于涉密,给出一个网上参考版本给大家学习~

    官方思路:

    步骤一:基于角点检测算法检测到第一帧的关键点;

    步骤二:LK稀疏光流跟踪这些关键点;

    于是就实现了点的追踪

    矩形目标检测 + 光流追踪思路:

    由于矩形目标检测边界框和物体之间有一些空隙,而光流点估计,我们需要得到运动点,因为目标检测直接有空隙,所以若是点落在了空隙处,那么跟踪结果将有偏差:某几个点跟踪的是背景 ,某几个点跟踪了物体,所以下一帧,你的目标框就会有偏差了。

    所以使用光流很困难,这就是业界没人使用的原因

    我的建议方案:

    步骤一:将矩形中心点替换掉上一步骤一;

    步骤二:一样走LK算法;

    步骤三:根据先前四周点到中心点(由于运动而改变)的距离,算出新的跟踪框位置;

    多边形、倾斜目标检测+光流跟踪思路:

    这种多边形的检测结果,基本上box边界就落在运动物体上,或者偏外几个像素,我们就可以:

    方案:

    步骤一,将边界点当做特征点;

    后续步骤同上

    图像分割+光流追踪:

    分割结果就是物体边缘,那么也是直接将边界点当做特征点,后续步骤一样;

    1. # -*- coding:utf-8 -*-
    2. __author__ = 'Microcosm'
    3. import cv2
    4. import numpy as np
    5. cap = cv2.VideoCapture("E:/python/Python Project/opencv_showimage/videos/visionface.avi")
    6. # 设置 ShiTomasi 角点检测的参数
    7. feature_params = dict( maxCorners=100,
    8.                       qualityLevel=0.3,
    9.                       minDistance=7,
    10.                       blockSize=7 )
    11. # 设置 lucas kanade 光流场的参数
    12. # maxLevel 为使用图像金字塔的层数
    13. lk_params = dict( winSize=(15,15),
    14.                  maxLevel=2,
    15.                  criteria=(cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 0.03))
    16. # 产生随机的颜色值
    17. color = np.random.randint(0,255,(100,3))
    18. # 获取第一帧,并寻找其中的角点
    19. ret, old_frame = cap.read()
    20. old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY)
    21. p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
    22. # 创建一个掩膜为了后面绘制角点的光流轨迹
    23. mask = np.zeros_like(old_frame)
    24. while(1):
    25.    ret, frame = cap.read()
    26.    if ret:
    27.        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    28.        # 计算能够获取到的角点的新位置
    29.        p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
    30.        # 选取好的角点,并筛选出旧的角点对应的新的角点
    31.        good_new = p1[st == 1]
    32.        good_old = p0[st == 1]
    33.        # 绘制角点的轨迹
    34.        for i,(new,old) in enumerate(zip(good_new,good_old)):
    35.            a,b = new.ravel()
    36.            c,d = old.ravel()
    37.            cv2.line(mask, (a,b), (c,d), color[i].tolist(), 2)
    38.            cv2.circle(frame, (a,b), 5, color[i].tolist(), -1)
    39.        img = cv2.add(frame, mask)
    40.        cv2.imshow("frame", img)
    41.        k = cv2.waitKey(30) & 0xff
    42.        if k == 27:
    43.            break
    44.        # 更新当前帧和当前角点的位置
    45.        old_gray = frame_gray.copy()
    46.        p0 = good_new.reshape(-1,1,2)
    47.    else:
    48.        break
    49. cv2.destroyAllWindows()
    50. cap.release()

    3D跟踪算法

    3D的话,可以查一下KIITI数据集的排行榜,找一些高排名的:

     

     

    像速度比较快的就是第二幅图里的AB3DMOT,GPU 5ms,很快了,毕竟是多点追踪,维度比2D多很多;

    单目准稠密三维目标跟踪(QD-3DT)是一个在线框架,使用二维图像中的准稠密目标方案检测和跟踪三维目标

    根据在移动平台上捕获的二维图像序列估计其完整的三维边界框信息。对象关联利用准密集相似性学习来识别仅具有外观线索的各种姿势和视点中的对象。在初始2D关联之后,我们进一步利用3D边界盒深度排序启发式算法进行鲁棒实例关联,并利用基于运动的3D轨迹预测进行遮挡车辆的重新识别。最后,一个基于LSTM的目标速度学习模块聚合长期轨迹信息,以进行更精确的运动外推。在我们提出的模拟数据和真实基准(包括KITTI、nuScenes和Waymo数据集)上的实验表明,我们的跟踪框架在城市驾驶场景中提供了鲁棒的对象关联和跟踪。在Waymo开放基准上,我们在3D跟踪和3D检测挑战中建立了第一条仅限摄像头的基线。我们的准密集3D跟踪管道在nuScenes 3D跟踪基准上实现了令人印象深刻的改进,在所有已发布的方法中,其跟踪精度是best vision only submission的近五倍。

    跳转中...

    总结

    相似度算法+跟踪算法辅助目标检测、图像分割,规则设计好,既可以无痛提速,又可以提高稳定性(跟踪稳定),何乐而不为呢?cv君提供技术帮助,可以免费随便咨询我,我的联系方式在下面啦~欢迎订阅博主专栏~没钱恰饭啦。哈哈哈

  • 相关阅读:
    太空射击第16课: 道具(Part 2)
    项目开发中使用Date和LocalDateTime处理日期
    uniapp - 微信小程序新版本发布之后用户端如何手动更新
    ISPRS2021/云检测:一种地理信息驱动的方法和一种新的大规模遥感云/雪检测数据集
    WSL2环境下Debian 12的Docker安装与配置
    map和set容器
    点云从入门到精通技术详解100篇-基于 Kinect v2 相机的柑橘点云分割与配准
    httpprompt.ml靶场练习
    【Java 基础篇】Java网络编程基础知识详解
    Python课程设计之俄罗斯方块
  • 原文地址:https://blog.csdn.net/qq_46098574/article/details/126619249