Centernet genera mapas de calor gaussianos

palabras escritas delante

Recientemente, la escuela está cerrada y el dormitorio está cerrado. La red del dormitorio no es buena y el experimento no se puede ejecutar de forma remota. Escribiré una interpretación del código fuente de CenterNet. El trabajo que quedó desde el momento en que escribí la tesis. , ¡respeto!

Este artículo es principalmente para analizar parte del código que genera el núcleo gaussiano en CenterNet. El principio específico no se explicará en detalle, pero este artículo agrega un código Puede ejecutarlo usted mismo y puede entenderlo cuando depura el significado del autor, espero que sea útil para los lectores.

Enlace de descarga de código visual: https://download.csdn.net/download/weixin_42899627/87157112

Ubicación del código fuente de Centernet
El código central de este artículo se puede encontrar en CenterNet/src/lib/utils/image.py

La fórmula para la función gaussiana bidimensional

inserte la descripción de la imagen aquí

La función gaussiana bidimensional en el código fuente de CenterNet se implementa de la siguiente manera:

consejo: falta algo en la fórmula de comparación, pero no afecta las características de la función gaussiana. La clave aquí es observar el cálculo del radio del núcleo gaussiano

def gaussian2D(shape, sigma=1):
    m, n = [(ss - 1.) / 2. for ss in shape]
    y, x = np.ogrid[-m:m + 1, -n:n + 1]#np.orgin 生成二维网格坐标

    h = np.exp(-(x * x + y * y) / (2 * sigma * sigma))
    h[h < np.finfo(h.dtype).eps * h.max()] = 0 #np.finfo()常用于生成一定格式,数值较小的偏置项eps,以避免分母或对数变量为零
    return h

Cálculo del radio del núcleo gaussiano

Desde el punto de vista del código, es la fórmula para encontrar la raíz de la ecuación cuadrática en una variable

Cabe señalar aquí que el cálculo del radio gaussiano en el código se basa en los puntos de las esquinas del marco, mientras que en Centernet, lo que se necesita calcular es el radio gaussiano del punto central del marco. la razón es la misma. El desplazamiento de los puntos de las esquinas del marco de la red central se puede aproximar para el desplazamiento del punto central de la caja

Caso 1: Ambas esquinas están dentro del cuadro de verdad
Caso 2: Ambas esquinas están fuera del cuadro de verdad
Caso 3: Una esquina está dentro del cuadro de verdad y la otra esquina está fuera del cuadro de verdad

Artículo de referencia:
radio guassiano de CornerNet Determinación del radio gaussiano: fórmula matemática
punto de explicación detallada Código de Cornernet/Centernet dentro del mapa de calor GT cómo aplicar el kernel de dispersión gaussiana

def gaussian_radius(det_size, min_overlap=0.7):
    height, width = det_size

    a1 = 1
    b1 = (height + width)
    c1 = width * height * (1 - min_overlap) / (1 + min_overlap)
    sq1 = np.sqrt(b1 ** 2 - 4 * a1 * c1)
    r1 = (b1 + sq1) / 2

    a2 = 4
    b2 = 2 * (height + width)
    c2 = (1 - min_overlap) * width * height
    sq2 = np.sqrt(b2 ** 2 - 4 * a2 * c2)
    r2 = (b2 + sq2) / 2

    a3 = 4 * min_overlap
    b3 = -2 * min_overlap * (height + width)
    c3 = (min_overlap - 1) * width * height
    sq3 = np.sqrt(b3 ** 2 - 4 * a3 * c3)
    r3 = (b3 + sq3) / 2
    return min(r1, r2, r3)

La función draw_umich_gaussian en el código fuente de CenterNet se implementa de la siguiente manera:

Consejo: No hay una operación especial, principalmente para colocar un kernel gaussiano bidimensional generado (tamaño de fotograma de destino) en la posición correspondiente de la imagen original (tamaño de imagen)

def draw_umich_gaussian(heatmap, center, radius, k=1):
    diameter = 2 * radius + 1
    gaussian = gaussian2D((diameter, diameter), sigma=diameter / 6)

    x, y = int(center[0]), int(center[1])

    height, width = heatmap.shape[0:2]

    left, right = min(x, radius), min(width - x, radius + 1)
    top, bottom = min(y, radius), min(height - y, radius + 1)

    masked_heatmap = heatmap[y - top:y + bottom, x - left:x + right]
    masked_gaussian = gaussian[radius - top:radius + bottom, radius - left:radius + right]
    if min(masked_gaussian.shape) > 0 and min(masked_heatmap.shape) > 0:  # TODO debug
        np.maximum(masked_heatmap, masked_gaussian * k, out=masked_heatmap)#逐个元素比较大小,保留大的值
    return heatmap

inserte la descripción de la imagen aquí

import numpy as np
import math
import xml.etree.ElementTree as ET
import glob
from image import draw_dense_reg, draw_msra_gaussian, draw_umich_gaussian
from image import get_affine_transform, affine_transform, gaussian_radius

data_dir = r"*.jpg"
a_file = glob.glob(data_dir)[0]
print(a_file, a_file.replace(".jpg", ".xml"))

tree = ET.parse(a_file.replace(".jpg", ".xml"))
root = tree.getroot()
size = root.find('size')
width = int(size.find('width').text)
height = int(size.find('height').text)
print(f"原图宽:{
      
      width} 高:{
      
      height}")

num_classes = 3
output_h = height
output_w = width
hm = np.zeros((num_classes, output_h, output_w), dtype=np.float32)

anns = []
for obj in root.iter('object'):
    bbox = obj.find('bndbox')
    cate = obj.find('name').text
    # print(cate, bbox.find("xmin").text, bbox.find("xmax").text,
    #       bbox.find("ymin").text, bbox.find("ymax").text)
    xyxy = [int(bbox.find("xmin").text), int(bbox.find("ymin").text),
          int(bbox.find("xmax").text),int(bbox.find("ymax").text)]
    anns.append({
    
    "bbox" : xyxy,'category_id':int(cate)})

num_objs = len(anns)
flipped = False #是否经过全图翻转

import matplotlib.pyplot as plt
plt.figure(figsize=(19, 6))
plt.ion()
plt.subplot(131)
img = plt.imread(a_file)
plt.title('Origin_img')
plt.imshow(img)

for k in range(num_objs):
    ann = anns[k]
    bbox = ann['bbox']
    cls_id = ann['category_id']
    if flipped:
        bbox[[0, 2]] = width - bbox[[2, 0]] - 1
    # bbox[:2] = affine_transform(bbox[:2], trans_output)# 仿射变换
    # bbox[2:] = affine_transform(bbox[2:], trans_output)
    # bbox[[0, 2]] = np.clip(bbox[[0, 2]], 0, output_w - 1)#裁剪
    # bbox[[1, 3]] = np.clip(bbox[[1, 3]], 0, output_h - 1)
    h, w = bbox[3] - bbox[1], bbox[2] - bbox[0]
    if h > 0 and w > 0:
        radius = gaussian_radius((math.ceil(h), math.ceil(w)))
        radius = max(0, int(radius))
        # radius = self.opt.hm_gauss if self.opt.mse_loss else radius
        ct = np.array(
            [(bbox[0] + bbox[2]) / 2, (bbox[1] + bbox[3]) / 2], dtype=np.float32)
        ct_int = ct.astype(np.int32)
        plt.subplot(133)
        hm_out, gaussian = draw_umich_gaussian(hm[cls_id], ct_int, radius)
        plt.title('Umich Heatmap')
        # hm_out = draw_msra_gaussian(hm[cls_id], ct_int, radius)
        # print(hm_out.shape)
        # plt.title("Mara Heatmap")
        plt.text(ct[0], ct[1], f"(class:{
      
      cls_id})", c='white')
        plt.plot([bbox[0], bbox[2], bbox[2], bbox[0], bbox[0]], [bbox[1], bbox[1], bbox[3], bbox[3], bbox[1]])
        plt.imshow(hm_out)
        plt.subplot(132)
        plt.title(f'Gaussian: bbox_h={
      
      h},bbox_w={
      
      w}, radius={
      
      radius}')
        plt.imshow(gaussian)
        plt.pause(2)


inserte la descripción de la imagen aquí

artículo de referencia

1. Uso de np.ogrid y np.mgrid
2. Funciones gaussianas unidimensionales y bidimensionales y sus primeras y segundas derivadas

Supongo que te gusta

Origin blog.csdn.net/weixin_42899627/article/details/128042986
Recomendado
Clasificación