3D点云检测网络训练踩坑记录(看这一篇就够了)

3D点云KITTI数据集及其格式 KITTI数据集由德国卡尔斯鲁厄理工学院和丰田美国技术研究院联合创办,是目前国际上最大的自动驾驶场景下的计算机视觉算法评测数据集。该数据集用于评测立体图像(stereo),光流(optical flow),视觉测距(visual odometry),3D物体检测(object detection)和3D跟踪(tracking)等计算机视觉技术在车载环境下的性能。KITTI包含市区、乡村和高速公路等场景采集的真实图像数据,每张图像中最多达15辆车和30个行人,还有各种程度的遮挡与截断。 阅读详情

1. 数据

数据集链接:The KITTI Vision Benchmark Suite(官网)
简介:KITTI是自动驾驶领域最重要的数据集之一,提供了大量的真实场景数据,用来更好的度量和测试算法的表现。除3D目标检测外,KITTI数据集还可用于评测立体图像,光流,视觉测距,3D跟踪等计算机视觉技术在车载环境下的性能。每张图像中最多达15辆车和30个行人目标,同时包含了各种程度的遮挡与截断。

KITTI数据迅雷下载地址
图片下载:https://s3.eu-central-1.amazonaws.com/avg-kitti/data_object_image_2.zip
点云下载:https://s3.eu-central-1.amazonaws.com/avg-kitti/data_object_velodyne.zip
标签下载:https://s3.eu-central-1.amazonaws.com/avg-kitti/data_object_label_2.zip
校正文件下载:https://s3.eu-central-1.amazonaws.com/avg-kitti/data_object_calib.zip

2. 依赖库

2.1 spconv安装

windows系统下安装稀疏卷积库spconv
确定环境中的cuda版本

import torch
print(torch.version.cuda) #11.6
pip install spconv-cu116

参考https://zhuanlan.zhihu.com/p/650809788?utm_id=0

2.2 SharedArray安装

windows系统下SharedArray

1.官网下载https://github.com/imaginary-friend94/Shared-Array-for-Windows
在这里插入图片描述
2.修改setup.py

from setuptools import setup, find_packages, Extension
import numpy as np
import sys
 
if sys.platform == "linux" or sys.platform == "linux2":
    libraries_ext = ["rt"]
elif sys.platform == "win32":
    libraries_ext = []
 
 
ext_modules = [
    Extension('SharedArray',
    #extra_compile_args=["-std=c++11"],  #这里更改了c++ 11,我这里使用这种方法会报错,故而取消这个
    sources = ['shared_memory_python.cpp'],
    libraries = libraries_ext,
    language="c++")    #增加了编译语言
]
 
setup(
        name = 'SharedArray',
        version = '1.2',
        include_dirs = [np.get_include()], #Add Include path of numpy
        ext_modules = ext_modules
      )

3修改 shared_memory_python.cpp

#if defined(_WIN64) || defined(_WIN32) || defined(__CYGWIN__)
#define WIN
#include <Windows.h>
#include <winbase.h>
#include <sddl.h>
#pragma comment(lib, "advapi32.lib")
#elif defined(__linux__)
#define LINUX
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <semaphore.h>
 
struct sem_wrapper
{
    sem_t * sem;
    bool is_locked;
};
 
#endif
 
#include "Python.h"
#include "numpy/arrayobject.h"
#include <iostream>
#include <cstdio>
#include <cstring>
 
#define WIN_SMEM "WINDOWS SHARED MEMORY"
#define ARRAY_STRUCT_SIZE sizeof(PyArrayObject)
#define ARRAY_FULL_SIZE(arr) (size_data_array(arr) + sizeof(int) + arr->nd * sizeof(npy_intp) * 3 + sizeof(int))
 
 
#if defined(WIN)
 
BOOL CreateMyDACL(SECURITY_ATTRIBUTES * pSA)
{
     TCHAR * szSD = TEXT("D:")       // Discretionary ACL
        TEXT("(D;OICI;GA;;;BG)")     // Deny access to 
                                     // built-in guests
        TEXT("(D;OICI;GA;;;AN)")     // Deny access to 
                                     // anonymous logon
        TEXT("(A;OICI;GRGWGX;;;AU)") // Allow 
                                     // read/write/execute 
                                     // to authenticated 
                                     // users
        TEXT("(A;OICI;GA;;;BA)");    // Allow full control 
                                     // to administrators
 
    if (NULL == pSA)
        return FALSE;
 
     return ConvertStringSecurityDescriptorToSecurityDescriptor(
                szSD,
                SDDL_REVISION_1,
                &(pSA->lpSecurityDescriptor),
                NULL);
}
#endif
 
/*
 * copy_from_pointer_array
 * the method returns the number of bytes copied
 */
template <typename ObjectType>
std::size_t copy_from_pointer_array(ObjectType * buffer_dist, ObjectType * buffer_src, size_t len) {
    for (int i = 0; i < len; i++) {
        *buffer_dist = *buffer_src;
        buffer_dist++;
        buffer_src++;
    }
    return len * sizeof(ObjectType);
}
 
std::size_t size_data_array(PyArrayObject *arr) {
    if (arr->nd == 0)
        return 0;
 
    std::size_t size = 1;
    for (int i = 0; i < arr->nd; ++i) {
        size *= (int) PyArray_DIM(arr, i);
    }
    size *= PyArray_ITEMSIZE(arr);
    return size;
}
 
void copy_from_numpy_array_to_buffer(PyArrayObject * array, char * buffer) {
    char * current_pointer = buffer;
    *((int *) current_pointer) = array->nd;
    current_pointer += sizeof(int);
    // dimensions copy
    current_pointer += copy_from_pointer_array(
        (npy_intp * ) current_pointer, 
        (npy_intp * ) array->dimensions, 
        array->nd
    );
    // strides copy
    current_pointer += copy_from_pointer_array(
        (npy_intp * ) current_pointer, 
        (npy_intp * ) array->strides, 
        array->nd
    );
    *((int *) current_pointer) = array->descr->type_num; 
    current_pointer += sizeof(int);
 
    size_t size_data = size_data_array(array);
    /* Copy data from heap to mmap memory */
    std::memcpy((char *) (current_pointer), (char *) array->data, size_data);
}
 
PyArrayObject * copy_from_buffer_to_numpy_array(char * buffer) {
    char * current_pointer = buffer;
    int nd = *((int *) current_pointer);
    current_pointer += sizeof(int);
    npy_intp * dims = new npy_intp[nd];
 
    current_pointer += copy_from_pointer_array(
        (npy_intp * ) dims, 
        (npy_intp * ) current_pointer, 
        nd
    );
    npy_intp * strides = new npy_intp[nd];
    current_pointer += copy_from_pointer_array(
        (npy_intp * ) strides, 
        (npy_intp * ) current_pointer, 
        nd
    );
    int type_num = *((int *) current_pointer);
    current_pointer += sizeof(int);
 
    PyArrayObject * array = (PyArrayObject *) PyArray_SimpleNewFromData(nd, 
        dims, 
        type_num, 
        (void *) current_pointer
    );
    return array;
}
 
 
/*
 * Create a buffer in shared memory
 */
char * create_shared_memory(char * string_shm, int max_buffer_size) {
    bool error_open_file_flag = false;
#if defined(WIN)
    SECURITY_ATTRIBUTES sa;
    if (!CreateMyDACL(&sa))
    {
         // Error encountered; generate message and exit.
        PyErr_SetString(PyExc_RuntimeError, "create_mutex: failed CreateMyDACL");
        return nullptr;
    }
    HANDLE hMapFile;
    hMapFile = CreateFileMapping(
        INVALID_HANDLE_VALUE,
        &sa,
        PAGE_READWRITE,
        0,
        max_buffer_size,
        string_shm);
    if (hMapFile == NULL) error_open_file_flag = true;
#elif defined(LINUX)
    int hMapFile = shm_open(string_shm, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
    if (hMapFile < 0){ 
        error_open_file_flag = true; 
    } else {
        if (ftruncate(hMapFile, max_buffer_size) == -1) error_open_file_flag = true;
    }
#endif
 
    if (error_open_file_flag) {
        PyErr_SetString(PyExc_RuntimeError, "create file is failed");
        return nullptr;
    }
 
#if defined(WIN)
    char * pBuf = (char *) MapViewOfFile(hMapFile,
                        FILE_MAP_ALL_ACCESS,
                        0,
                        0,
                        max_buffer_size);
#elif defined(LINUX)
    char * pBuf = (char *) mmap(NULL, max_buffer_size, PROT_WRITE | PROT_READ, MAP_SHARED, hMapFile, 0);
#endif
 
    if (pBuf == nullptr) {
        PyErr_SetString(PyExc_RuntimeError, "memory not allocated");
        return nullptr;
    }
 
    return pBuf;
}
/*
 * Del a buffer in shared memory
 */
bool delete_shared_memory(char * string_shm) {
#if defined(WIN)
    return true;
#elif defined(LINUX)
    if (shm_unlink(string_shm) == 0) return true;
#endif
}
 
/*
 * Attach a buffer in shared memory
 */
char * attach_shared_memory(char * string_shm) {
    bool error_open_file_flag = false;
#if defined(WIN)
    HANDLE hMapFile = OpenFileMapping(
        FILE_MAP_ALL_ACCESS,
        FALSE,
        string_shm); 
    if (hMapFile == NULL) error_open_file_flag = true;
#elif defined(LINUX)
    int hMapFile = shm_open(string_shm, O_RDWR, 0);
    if (hMapFile == -1) error_open_file_flag = true;
#endif
 
    if (error_open_file_flag) {
        PyErr_SetString(PyExc_RuntimeError, "memory not attached");
        return nullptr;
    }
 
#if defined(WIN)
    char * pBuf = (char *) MapViewOfFile(hMapFile,
                        FILE_MAP_ALL_ACCESS,
                        0,
                        0,
                        sizeof(size_t));
#elif defined(LINUX)
    char * pBuf = (char *) mmap(0, sizeof(size_t), PROT_WRITE | PROT_READ, MAP_SHARED, hMapFile, 0);
#endif
 
    size_t full_array_size = *((size_t *) pBuf);
 
#if defined(WIN)
    UnmapViewOfFile((LPCVOID) pBuf);
    pBuf = (char *) MapViewOfFile(hMapFile,
                        FILE_MAP_ALL_ACCESS,
                        0,
                        0,
                        full_array_size);
#elif defined(LINUX)
    munmap(pBuf, sizeof(size_t));
    pBuf = (char *) mmap(0, full_array_size, PROT_WRITE | PROT_READ, MAP_SHARED, hMapFile, 0);
#endif
 
    pBuf += sizeof(size_t);
 
    if (pBuf == nullptr) {
        PyErr_SetString(PyExc_RuntimeError, "memory not attached");
        return nullptr;
    }
 
    return pBuf;
}
 
static PyObject *
check_mem_sh(PyObject *self, PyObject *args) 
{
    char * string_shm;
    if (!PyArg_ParseTuple(args, "s", &string_shm)) {
        PyErr_SetString(PyExc_RuntimeError, "set_mem_sh: parse except");
    }
    bool error_open_file_flag = false;
 
#if defined(WIN)
    HANDLE hMapFile = OpenFileMapping(
        FILE_MAP_ALL_ACCESS,
        FALSE,
        string_shm);
    if (hMapFile == NULL) error_open_file_flag = true;
#elif defined(LINUX)
    int hMapFile = shm_open(string_shm, O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO);
    if (hMapFile == -1) error_open_file_flag = true;
#endif    
    if (error_open_file_flag) {
        Py_INCREF(Py_False);
        return Py_False;
    }
    Py_INCREF(Py_True);
    return Py_True;
 
}
 
static PyObject *
create_mem_sh(PyObject *self, PyObject *args)
{
    PyObject * pyobj_for_shrdmem = nullptr;
    char * string_shm;
    if (!PyArg_ParseTuple(args, "sO", &string_shm, &pyobj_for_shrdmem)) {
        PyErr_SetString(PyExc_RuntimeError, "set_mem_sh: parse except");
    }
    PyArrayObject * array_for_shrdmem = (PyArrayObject *) pyobj_for_shrdmem;
    array_for_shrdmem = PyArray_GETCONTIGUOUS(array_for_shrdmem);
    if (array_for_shrdmem->base != nullptr) {
        PyErr_SetString(PyExc_RuntimeError, "set_mem_sh: array is not homogeneous");
    }
    /* Аrray size calculation */ 
    char * shBuf = create_shared_memory(string_shm, ARRAY_FULL_SIZE(array_for_shrdmem));
    if (shBuf == nullptr) {
        Py_INCREF(Py_None);
        return Py_None;
    }
    /* Copy array struct from heap to shared memory */
    *((size_t *) shBuf) = ARRAY_FULL_SIZE(array_for_shrdmem);
    shBuf += sizeof(size_t);
    copy_from_numpy_array_to_buffer(array_for_shrdmem, shBuf);
    Py_INCREF(Py_True);
    return Py_True;
}
 
static PyObject *
attach_mem_sh(PyObject *self, PyObject *args)
{
    char * string_shm;
    if (!PyArg_ParseTuple(args, "s", &string_shm)) {
        PyErr_SetString(PyExc_RuntimeError, "get_mem_sh: parse except");
    }
    char * shBuf = attach_shared_memory(string_shm);
    if (shBuf == nullptr) {
        Py_INCREF(Py_None);
        return Py_None;
    }
 
    PyArrayObject * array_for_shrdmem = (PyArrayObject *) shBuf;
    array_for_shrdmem = copy_from_buffer_to_numpy_array(shBuf);
    Py_INCREF((PyObject *) array_for_shrdmem);
    return (PyObject *) array_for_shrdmem;
}
 
static PyObject *
delete_mem_sh(PyObject *self, PyObject *args) {
    char * string_shm;
    if (!PyArg_ParseTuple(args, "s", &string_shm)) {
        PyErr_SetString(PyExc_RuntimeError, "get_mem_sh: parse except");
    }
    if (delete_shared_memory(string_shm)) {
        Py_INCREF(Py_True);
        return Py_True;
    }
    Py_INCREF(Py_False);
    return Py_False;
}
 
void mutex_destructor(PyObject * m_obj) {
#if defined(WIN)
    const char * name = PyCapsule_GetName(m_obj);
    HANDLE mut = (HANDLE) PyCapsule_GetPointer(m_obj, PyCapsule_GetName(m_obj));
    delete name;
#elif defined(LINUX)
    const char * name = PyCapsule_GetName(m_obj);
    sem_wrapper * mut = (sem_wrapper *) PyCapsule_GetPointer(m_obj, name);
    if (name != NULL) {
        if (mut->is_locked) {
            sem_post(mut->sem);
            mut->is_locked = false;
        }
        if (name != NULL) {
            delete name;
        }
        delete mut;
    }
#endif
}
 
static PyObject *
create_mutex(PyObject *self, PyObject *args) {
    bool error_open_file_flag = false;
    char * string_smp;
    if (!PyArg_ParseTuple(args, "s", &string_smp)) {
        PyErr_SetString(PyExc_RuntimeError, "create_mutex: parse except");
        return nullptr;
    }
    char * string_shm_new = new char[strlen(string_smp) + 1];
    strcpy(string_shm_new, string_smp);
#if defined(WIN)
    SECURITY_ATTRIBUTES sa;
    if (!CreateMyDACL(&sa))
    {
         // Error encountered; generate message and exit.
        PyErr_SetString(PyExc_RuntimeError, "create_mutex: failed CreateMyDACL");
        return nullptr;
    }
    HANDLE mut = CreateMutex(
        &sa, 
        FALSE, 
        string_shm_new
    );
    if (mut == nullptr) {
        error_open_file_flag = true;
    }
#elif defined(LINUX)
    sem_wrapper * mut = new sem_wrapper{
        sem_open(string_shm_new, O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO, 1), 
        false
    };
    if (mut->sem == SEM_FAILED) {
        error_open_file_flag = true;
    }
#endif
    if (error_open_file_flag) {
        Py_INCREF(Py_None);
        return Py_None;
    }
    return PyCapsule_New((void *) mut, string_shm_new, (PyCapsule_Destructor) mutex_destructor);
}
 
static PyObject *
open_mutex(PyObject *self, PyObject *args) {
    bool error_open_file_flag = false;
    char * string_smp;
    if (!PyArg_ParseTuple(args, "s", &string_smp)) {
        PyErr_SetString(PyExc_RuntimeError, "open_mutex: parse except");
        return nullptr;
    }
    char * string_shm_new = new char[strlen(string_smp) + 1];
    strcpy(string_shm_new, string_smp);
#if defined(WIN)
    HANDLE mut = OpenMutex(
        MUTEX_ALL_ACCESS, 
        TRUE, 
        string_shm_new
    );
    if (mut == nullptr) error_open_file_flag = true;
#elif defined(LINUX)
    sem_wrapper * mut = new sem_wrapper{
        sem_open(string_shm_new, 0), 
        false
    };
    if (mut->sem == SEM_FAILED) error_open_file_flag = true;
#endif
 
    if (error_open_file_flag) {
        Py_INCREF(Py_None);
        return Py_None;
    }
    return PyCapsule_New((void *) mut, string_shm_new, (PyCapsule_Destructor) mutex_destructor);
}
 
static PyObject *
release_mutex(PyObject *self, PyObject *args) {
    PyObject * caps_mutex;
    if (!PyArg_ParseTuple(args, "O", &caps_mutex)) {
        PyErr_SetString(PyExc_RuntimeError, "release_mutex: parse except");
        return nullptr;
    }
#if defined(WIN)
    HANDLE mut = (HANDLE) PyCapsule_GetPointer(caps_mutex, PyCapsule_GetName(caps_mutex));
    ReleaseMutex(mut);
#elif defined(LINUX)
    sem_wrapper * mut = (sem_wrapper *) PyCapsule_GetPointer(caps_mutex, PyCapsule_GetName(caps_mutex));
    if (mut->is_locked) {
        sem_post(mut->sem);
        mut->is_locked = false;
    }
#endif
    Py_INCREF(Py_True);
    return Py_True;
}
 
static PyObject *
close_mutex(PyObject *self, PyObject *args) {
    PyObject * caps_mutex;
    if (!PyArg_ParseTuple(args, "O", &caps_mutex)) {
        PyErr_SetString(PyExc_RuntimeError, "close_mutex: parse except");
        return nullptr;
    }
    if (caps_mutex != Py_None) {
        mutex_destructor(caps_mutex);
        Py_INCREF(Py_True);
        return Py_True;
    } else {
        Py_INCREF(Py_False);
        return Py_False;    
    }
}
 
static PyObject *
remove_mutex(PyObject *self, PyObject *args) {
    PyObject * caps_mutex;
    if (!PyArg_ParseTuple(args, "O", &caps_mutex)) {
        PyErr_SetString(PyExc_RuntimeError, "close_mutex: parse except");
        return nullptr;
    }
#if defined(WIN)
    Py_INCREF(Py_True);
    return Py_True;
#elif defined(LINUX)
    sem_wrapper * mut = (sem_wrapper *) PyCapsule_GetPointer(caps_mutex, PyCapsule_GetName(caps_mutex));
    const char * name = PyCapsule_GetName(caps_mutex);
    if (sem_unlink(name) == -1) {
        Py_INCREF(Py_False);
        return Py_False;
    }
    if (name != NULL) {
        delete name;
    }
    delete mut;
    PyCapsule_SetName(caps_mutex, NULL);
    Py_INCREF(Py_True);
    return Py_True;
#endif    
}
 
static PyObject * _try_capture_mutex(PyObject * caps_mutex, int msec) {
#if defined(WIN)
    HANDLE mut = (HANDLE) PyCapsule_GetPointer(caps_mutex, PyCapsule_GetName(caps_mutex));
    DWORD out;
    if (msec == -1) {
        out = WaitForSingleObject(mut, INFINITE);
    } else {
        out = WaitForSingleObject(mut, (DWORD) msec);
    }
#elif defined(LINUX)
    sem_wrapper * mut = (sem_wrapper *) PyCapsule_GetPointer(caps_mutex, PyCapsule_GetName(caps_mutex));
    int out;
    if (msec == 0) {
        out = sem_trywait(mut->sem);
    } else if (msec != -1) {
        timespec ts;
        ts.tv_nsec = msec * 1000;
        out = sem_timedwait(mut->sem, &ts);
    } else {
        out = sem_wait(mut->sem);
    }
    if (out == 0) mut->is_locked = true;
#endif
 
    if (out == 0) {
        Py_INCREF(Py_True);
        return Py_True;
    }
    Py_INCREF(Py_False);
    return Py_False;
}
 
static PyObject *
try_capture_mutex(PyObject *self, PyObject *args) {
    PyObject * caps_mutex;
    int timeout;
    if (!PyArg_ParseTuple(args, "Oi", &caps_mutex, &timeout)) {
        PyErr_SetString(PyExc_RuntimeError, "try_capture_mutex: parse except");
        return nullptr;
    }
    return _try_capture_mutex(caps_mutex, timeout);
}
 
static PyObject *
capture_mutex(PyObject *self, PyObject *args) {
    PyObject * caps_mutex;
    if (!PyArg_ParseTuple(args, "O", &caps_mutex)) {
        PyErr_SetString(PyExc_RuntimeError, "capture_mutex: parse except");
        return nullptr;
    }
    return _try_capture_mutex(caps_mutex, -1);
}
 
static PyObject *
get_last_error(PyObject *self, PyObject *args) {
#if defined(WIN)
    PyObject * py_err = Py_BuildValue("i", (unsigned int) GetLastError());
#elif defined(LINUX)
    PyObject * py_err = Py_BuildValue("i", (unsigned int) errno);
#endif
    Py_INCREF(py_err);
    return py_err;
}
 
// static PyObject *
// test_function(PyObject *self, PyObject *args) {
//     int fd = shm_open("/test_sh_m", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
//     return Py_None;
// }
 
static PyMethodDef SharedArrayMethods[] = {
 
    {"create_mem_sh",  create_mem_sh, METH_VARARGS,
     "method for create shared memory named."},
    {"attach_mem_sh",  attach_mem_sh, METH_VARARGS,
     "method for get shared memory named."},
    {"delete_mem_sh",  delete_mem_sh, METH_VARARGS,
     "method for del shared memory named."},
    {"check_mem_sh",  check_mem_sh, METH_VARARGS,
     "method for check shared memory named."},
    {"create_mutex",  create_mutex, METH_VARARGS,
     ""},
    {"open_mutex",  open_mutex, METH_VARARGS,
     ""},
    {"release_mutex",  release_mutex, METH_VARARGS,
     ""},
    {"close_mutex",  close_mutex, METH_VARARGS,
     ""},
    {"try_capture_mutex",  try_capture_mutex, METH_VARARGS,
      ""},
    {"close_mutex",  close_mutex, METH_VARARGS,
     ""},
    {"remove_mutex",  remove_mutex, METH_VARARGS,
     ""},
 
    {"capture_mutex",  capture_mutex, METH_VARARGS,
     "capture mutex"},
    {"get_last_error",  get_last_error, METH_VARARGS,
     "returns the result of the call GetLastError() function"},
    {NULL, NULL, 0, NULL}
};
 
static struct PyModuleDef wsamodule = {
    PyModuleDef_HEAD_INIT,
    "SharedArray", 
    NULL, 
    -1,    
    SharedArrayMethods
};
 
PyMODINIT_FUNC
PyInit_SharedArray(void)
{
    import_array();
    return PyModule_Create(&wsamodule);
}

4.最后安装目录下执行 python setup.py develop

参考https://blog.youkuaiyun.com/qq_61981718/article/details/130719188

2.3 OpenPCDet安装

windows系统下安装OpenPCDet

  1. OpenPCDet项目官网下载 https://github.com/open-mmlab/OpenPCDet.git
    在这里插入图片描述
  2. conda环境下安装依赖 pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
    在这里插入图片描述
  3. 代码修改
    .\pcdet\ops\iou3d_nms\src目录下
    iou3d_nms.cpp
/*
3D IoU Calculation and Rotated NMS(modified from 2D NMS written by others)
Written by Shaoshuai Shi
All Rights Reserved 2019-2020.
*/
 
#include <torch/serialize/tensor.h>
#include <torch/extension.h>
#include <vector>
#include <cuda.h>
#include <cuda_runtime_api.h>
#include <stdint.h>
#include "iou3d_nms.h"
 
#define CHECK_CUDA(x) do { \
  if (!x.type().is_cuda()) { \
    fprintf(stderr, "%s must be CUDA tensor at %s:%d\n", #x, __FILE__, __LINE__); \
    exit(-1); \
  } \
} while (0)
#define CHECK_CONTIGUOUS(x) do { \
  if (!x.is_contiguous()) { \
    fprintf(stderr, "%s must be contiguous tensor at %s:%d\n", #x, __FILE__, __LINE__); \
    exit(-1); \
  } \
} while (0)
#define CHECK_INPUT(x) CHECK_CUDA(x);CHECK_CONTIGUOUS(x)
 
#define DIVUP(m,n) ((m) / (n) + ((m) % (n) > 0))
 
#define CHECK_ERROR(ans) { gpuAssert((ans), __FILE__, __LINE__); }
inline void gpuAssert(cudaError_t code, const char *file, int line, bool abort=true)
{
   if (code != cudaSuccess)
   {
      fprintf(stderr,"GPUassert: %s %s %d\n", cudaGetErrorString(code), file, line);
      if (abort) exit(code);
   }
}
 
const int THREADS_PER_BLOCK_NMS = sizeof(uint64_t) * 8;
 
void boxesoverlapLauncher(const int num_a, const float *boxes_a, const int num_b, const float *boxes_b, float *ans_overlap);
void boxesioubevLauncher(const int num_a, const float *boxes_a, const int num_b, const float *boxes_b, float *ans_iou);
void nmsLauncher(const float *boxes, uint64_t * mask, int boxes_num, float nms_overlap_thresh);
void nmsNormalLauncher(const float *boxes, uint64_t * mask, int boxes_num, float nms_overlap_thresh);
 
 
int boxes_overlap_bev_gpu(at::Tensor boxes_a, at::Tensor boxes_b, at::Tensor ans_overlap){
    // params boxes_a: (N, 7) [x, y, z, dx, dy, dz, heading]
    // params boxes_b: (M, 7) [x, y, z, dx, dy, dz, heading]
    // params ans_overlap: (N, M)
 
    CHECK_INPUT(boxes_a);
    CHECK_INPUT(boxes_b);
    CHECK_INPUT(ans_overlap);
 
    int num_a = boxes_a.size(0);
    int num_b = boxes_b.size(0);
 
    const float * boxes_a_data = boxes_a.data<float>();
    const float * boxes_b_data = boxes_b.data<float>();
    float * ans_overlap_data = ans_overlap.data<float>();
 
    boxesoverlapLauncher(num_a, boxes_a_data, num_b, boxes_b_data, ans_overlap_data);
 
    return 1;
}
 
int boxes_iou_bev_gpu(at::Tensor boxes_a, at::Tensor boxes_b, at::Tensor ans_iou){
    // params boxes_a: (N, 7) [x, y, z, dx, dy, dz, heading]
    // params boxes_b: (M, 7) [x, y, z, dx, dy, dz, heading]
    // params ans_overlap: (N, M)
    CHECK_INPUT(boxes_a);
    CHECK_INPUT(boxes_b);
    CHECK_INPUT(ans_iou);
 
    int num_a = boxes_a.size(0);
    int num_b = boxes_b.size(0);
 
    const float * boxes_a_data = boxes_a.data<float>();
    const float * boxes_b_data = boxes_b.data<float>();
    float * ans_iou_data = ans_iou.data<float>();
 
    boxesioubevLauncher(num_a, boxes_a_data, num_b, boxes_b_data, ans_iou_data);
 
    return 1;
}
 
int nms_gpu(at::Tensor boxes, at::Tensor keep, float nms_overlap_thresh){
    // params boxes: (N, 7) [x, y, z, dx, dy, dz, heading]
    // params keep: (N)
    CHECK_INPUT(boxes);
    CHECK_CONTIGUOUS(keep);
 
    int boxes_num = boxes.size(0);
    const float * boxes_data = boxes.data<float>();
    long long * keep_data = keep.data<long long>();
 
    const int col_blocks = DIVUP(boxes_num, THREADS_PER_BLOCK_NMS);
 
    uint64_t *mask_data = NULL;
    CHECK_ERROR(cudaMalloc((void**)&mask_data, boxes_num * col_blocks * sizeof(uint64_t)));
    nmsLauncher(boxes_data, mask_data, boxes_num, nms_overlap_thresh);
 
    // uint64_t mask_cpu[boxes_num * col_blocks];
    // uint64_t *mask_cpu = new uint64_t [boxes_num * col_blocks];
    std::vector<uint64_t> mask_cpu(boxes_num * col_blocks);
 
//    printf("boxes_num=%d, col_blocks=%d\n", boxes_num, col_blocks);
    CHECK_ERROR(cudaMemcpy(&mask_cpu[0], mask_data, boxes_num * col_blocks * sizeof(uint64_t),
                           cudaMemcpyDeviceToHost));
 
    cudaFree(mask_data);
 
    //uint64_t remv_cpu(col_blocks);
    std::vector<uint64_t> remv_cpu(col_blocks);
    memset(&remv_cpu[0], 0, col_blocks * sizeof(uint64_t));
 
    int num_to_keep = 0;
 
    for (int i = 0; i < boxes_num; i++){
        int nblock = i / THREADS_PER_BLOCK_NMS;
        int inblock = i % THREADS_PER_BLOCK_NMS;
 
        if (!(remv_cpu[nblock] & (1ULL << inblock))){
            keep_data[num_to_keep++] = i;
            uint64_t *p = &mask_cpu[0] + i * col_blocks;
            for (int j = nblock; j < col_blocks; j++){
                remv_cpu[j] |= p[j];
            }
        }
    }
    if ( cudaSuccess != cudaGetLastError() ) printf( "Error!\n" );
 
    return num_to_keep;
}
 
 
int nms_normal_gpu(at::Tensor boxes, at::Tensor keep, float nms_overlap_thresh){
    // params boxes: (N, 7) [x, y, z, dx, dy, dz, heading]
    // params keep: (N)
 
    CHECK_INPUT(boxes);
    CHECK_CONTIGUOUS(keep);
 
    int boxes_num = boxes.size(0);
    const float * boxes_data = boxes.data<float>();
    long long * keep_data = keep.data<long long>();
 
    const int col_blocks = DIVUP(boxes_num, THREADS_PER_BLOCK_NMS);
 
    uint64_t *mask_data = NULL;
    CHECK_ERROR(cudaMalloc((void**)&mask_data, boxes_num * col_blocks * sizeof(uint64_t)));
    nmsNormalLauncher(boxes_data, mask_data, boxes_num, nms_overlap_thresh);
 
    // uint64_t mask_cpu[boxes_num * col_blocks];
    // uint64_t *mask_cpu = new uint64_t [boxes_num * col_blocks];
    std::vector<uint64_t> mask_cpu(boxes_num * col_blocks);
 
//    printf("boxes_num=%d, col_blocks=%d\n", boxes_num, col_blocks);
    CHECK_ERROR(cudaMemcpy(&mask_cpu[0], mask_data, boxes_num * col_blocks * sizeof(uint64_t),
                           cudaMemcpyDeviceToHost));
 
    cudaFree(mask_data);
 
    std::vector<uint64_t> remv_cpu(col_blocks);
    memset(&remv_cpu[0], 0, col_blocks * sizeof(uint64_t));
 
    int num_to_keep = 0;
 
    for (int i = 0; i < boxes_num; i++){
        int nblock = i / THREADS_PER_BLOCK_NMS;
        int inblock = i % THREADS_PER_BLOCK_NMS;
 
        if (!(remv_cpu[nblock] & (1ULL << inblock))){
            keep_data[num_to_keep++] = i;
            uint64_t *p = &mask_cpu[0] + i * col_blocks;
            for (int j = nblock; j < col_blocks; j++){
                remv_cpu[j] |= p[j];
            }
        }
    }
    if ( cudaSuccess != cudaGetLastError() ) printf( "Error!\n" );
 
    return num_to_keep;
}

iou3d_nms_kernel.cu

/*
3D IoU Calculation and Rotated NMS(modified from 2D NMS written by others)
Written by Shaoshuai Shi
All Rights Reserved 2019-2020.
*/
 
 
#include <stdio.h>
#include <stdint.h>
#define THREADS_PER_BLOCK 16
#define DIVUP(m, n) ((m) / (n) + ((m) % (n) > 0))
 
// #define DEBUG
const int THREADS_PER_BLOCK_NMS = sizeof(unsigned long long) * 8;
//const float EPS = 1e-8;
struct Point {
    float x, y;
    __device__ Point() {}
    __device__ Point(double _x, double _y){
        x = _x, y = _y;
    }
 
    __device__ void set(float _x, float _y){
        x = _x; y = _y;
    }
 
    __device__ Point operator +(const Point &b)const{
        return Point(x + b.x, y + b.y);
    }
 
    __device__ Point operator -(const Point &b)const{
        return Point(x - b.x, y - b.y);
    }
};
 
__device__ inline float cross(const Point &a, const Point &b){
    return a.x * b.y - a.y * b.x;
}
 
__device__ inline float cross(const Point &p1, const Point &p2, const Point &p0){
    return (p1.x - p0.x) * (p2.y - p0.y) - (p2.x - p0.x) * (p1.y - p0.y);
}
 
__device__ int check_rect_cross_cuda(const Point &p1, const Point &p2, const Point &q1, const Point &q2){
    int ret = min(p1.x,p2.x) <= max(q1.x,q2.x)  &&
              min(q1.x,q2.x) <= max(p1.x,p2.x) &&
              min(p1.y,p2.y) <= max(q1.y,q2.y) &&
              min(q1.y,q2.y) <= max(p1.y,p2.y);
    return ret;
}
 
__device__ inline int check_in_box2d(const float *box, const Point &p){
    //params: (7) [x, y, z, dx, dy, dz, heading]
    const float MARGIN = 1e-2;
 
    float center_x = box[0], center_y = box[1];
    float angle_cos = cos(-box[6]), angle_sin = sin(-box[6]);  // rotate the point in the opposite direction of box
    float rot_x = (p.x - center_x) * angle_cos + (p.y - center_y) * (-angle_sin);
    float rot_y = (p.x - center_x) * angle_sin + (p.y - center_y) * angle_cos;
 
    return (fabs(rot_x) < box[3] / 2 + MARGIN && fabs(rot_y) < box[4] / 2 + MARGIN);
}
 
__device__ inline int intersection(const Point &p1, const Point &p0, const Point &q1, const Point &q0, Point &ans){
    // fast exclusion
    if (check_rect_cross_cuda(p0, p1, q0, q1) == 0) return 0;
 
    // check cross standing
    float s1 = cross(q0, p1, p0);
    float s2 = cross(p1, q1, p0);
    float s3 = cross(p0, q1, q0);
    float s4 = cross(q1, p1, q0);
 
    if (!(s1 * s2 > 0 && s3 * s4 > 0)) return 0;
 
    // calculate intersection of two lines
    float s5 = cross(q1, p1, p0);
    if(fabs(s5 - s1) > 1e-8){
        ans.x = (s5 * q0.x - s1 * q1.x) / (s5 - s1);
        ans.y = (s5 * q0.y - s1 * q1.y) / (s5 - s1);
 
    }
    else{
        float a0 = p0.y - p1.y, b0 = p1.x - p0.x, c0 = p0.x * p1.y - p1.x * p0.y;
        float a1 = q0.y - q1.y, b1 = q1.x - q0.x, c1 = q0.x * q1.y - q1.x * q0.y;
        float D = a0 * b1 - a1 * b0;
 
        ans.x = (b0 * c1 - b1 * c0) / D;
        ans.y = (a1 * c0 - a0 * c1) / D;
    }
 
    return 1;
}
 
__device__ inline void rotate_around_center(const Point &center, const float angle_cos, const float angle_sin, Point &p){
    float new_x = (p.x - center.x) * angle_cos + (p.y - center.y) * (-angle_sin) + center.x;
    float new_y = (p.x - center.x) * angle_sin + (p.y - center.y) * angle_cos + center.y;
    p.set(new_x, new_y);
}
 
__device__ inline int point_cmp(const Point &a, const Point &b, const Point &center){
    return atan2(a.y - center.y, a.x - center.x) > atan2(b.y - center.y, b.x - center.x);
}
 
__device__ inline float box_overlap(const float *box_a, const float *box_b){
    // params box_a: [x, y, z, dx, dy, dz, heading]
    // params box_b: [x, y, z, dx, dy, dz, heading]
 
    float a_angle = box_a[6], b_angle = box_b[6];
    float a_dx_half = box_a[3] / 2, b_dx_half = box_b[3] / 2, a_dy_half = box_a[4] / 2, b_dy_half = box_b[4] / 2;
    float a_x1 = box_a[0] - a_dx_half, a_y1 = box_a[1] - a_dy_half;
    float a_x2 = box_a[0] + a_dx_half, a_y2 = box_a[1] + a_dy_half;
    float b_x1 = box_b[0] - b_dx_half, b_y1 = box_b[1] - b_dy_half;
    float b_x2 = box_b[0] + b_dx_half, b_y2 = box_b[1] + b_dy_half;
 
    Point center_a(box_a[0], box_a[1]);
    Point center_b(box_b[0], box_b[1]);
 
#ifdef DEBUG
    printf("a: (%.3f, %.3f, %.3f, %.3f, %.3f), b: (%.3f, %.3f, %.3f, %.3f, %.3f)\n", a_x1, a_y1, a_x2, a_y2, a_angle,
           b_x1, b_y1, b_x2, b_y2, b_angle);
    printf("center a: (%.3f, %.3f), b: (%.3f, %.3f)\n", center_a.x, center_a.y, center_b.x, center_b.y);
#endif
 
    Point box_a_corners[5];
    box_a_corners[0].set(a_x1, a_y1);
    box_a_corners[1].set(a_x2, a_y1);
    box_a_corners[2].set(a_x2, a_y2);
    box_a_corners[3].set(a_x1, a_y2);
 
    Point box_b_corners[5];
    box_b_corners[0].set(b_x1, b_y1);
    box_b_corners[1].set(b_x2, b_y1);
    box_b_corners[2].set(b_x2, b_y2);
    box_b_corners[3].set(b_x1, b_y2);
 
    // get oriented corners
    float a_angle_cos = cos(a_angle), a_angle_sin = sin(a_angle);
    float b_angle_cos = cos(b_angle), b_angle_sin = sin(b_angle);
 
    for (int k = 0; k < 4; k++){
#ifdef DEBUG
        printf("before corner %d: a(%.3f, %.3f), b(%.3f, %.3f) \n", k, box_a_corners[k].x, box_a_corners[k].y, box_b_corners[k].x, box_b_corners[k].y);
#endif
        rotate_around_center(center_a, a_angle_cos, a_angle_sin, box_a_corners[k]);
        rotate_around_center(center_b, b_angle_cos, b_angle_sin, box_b_corners[k]);
#ifdef DEBUG
        printf("corner %d: a(%.3f, %.3f), b(%.3f, %.3f) \n", k, box_a_corners[k].x, box_a_corners[k].y, box_b_corners[k].x, box_b_corners[k].y);
#endif
    }
 
    box_a_corners[4] = box_a_corners[0];
    box_b_corners[4] = box_b_corners[0];
 
    // get intersection of lines
    Point cross_points[16];
    Point poly_center;
    int cnt = 0, flag = 0;
 
    poly_center.set(0, 0);
    for (int i = 0; i < 4; i++){
        for (int j = 0; j < 4; j++){
            flag = intersection(box_a_corners[i + 1], box_a_corners[i], box_b_corners[j + 1], box_b_corners[j], cross_points[cnt]);
            if (flag){
                poly_center = poly_center + cross_points[cnt];
                cnt++;
#ifdef DEBUG
                printf("Cross points (%.3f, %.3f): a(%.3f, %.3f)->(%.3f, %.3f), b(%.3f, %.3f)->(%.3f, %.3f) \n",
                    cross_points[cnt - 1].x, cross_points[cnt - 1].y,
                    box_a_corners[i].x, box_a_corners[i].y, box_a_corners[i + 1].x, box_a_corners[i + 1].y,
                    box_b_corners[i].x, box_b_corners[i].y, box_b_corners[i + 1].x, box_b_corners[i + 1].y);
#endif
            }
        }
    }
 
    // check corners
    for (int k = 0; k < 4; k++){
        if (check_in_box2d(box_a, box_b_corners[k])){
            poly_center = poly_center + box_b_corners[k];
            cross_points[cnt] = box_b_corners[k];
            cnt++;
#ifdef DEBUG
                printf("b corners in a: corner_b(%.3f, %.3f)", cross_points[cnt - 1].x, cross_points[cnt - 1].y);
#endif
        }
        if (check_in_box2d(box_b, box_a_corners[k])){
            poly_center = poly_center + box_a_corners[k];
            cross_points[cnt] = box_a_corners[k];
            cnt++;
#ifdef DEBUG
                printf("a corners in b: corner_a(%.3f, %.3f)", cross_points[cnt - 1].x, cross_points[cnt - 1].y);
#endif
        }
    }
 
    poly_center.x /= cnt;
    poly_center.y /= cnt;
 
    // sort the points of polygon
    Point temp;
    for (int j = 0; j < cnt - 1; j++){
        for (int i = 0; i < cnt - j - 1; i++){
            if (point_cmp(cross_points[i], cross_points[i + 1], poly_center)){
                temp = cross_points[i];
                cross_points[i] = cross_points[i + 1];
                cross_points[i + 1] = temp;
            }
        }
    }
 
#ifdef DEBUG
    printf("cnt=%d\n", cnt);
    for (int i = 0; i < cnt; i++){
        printf("All cross point %d: (%.3f, %.3f)\n", i, cross_points[i].x, cross_points[i].y);
    }
#endif
 
    // get the overlap areas
    float area = 0;
    for (int k = 0; k < cnt - 1; k++){
        area += cross(cross_points[k] - cross_points[0], cross_points[k + 1] - cross_points[0]);
    }
 
    return fabs(area) / 2.0;
}
 
__device__ inline float iou_bev(const float *box_a, const float *box_b){
    // params box_a: [x, y, z, dx, dy, dz, heading]
    // params box_b: [x, y, z, dx, dy, dz, heading]
    float sa = box_a[3] * box_a[4];
    float sb = box_b[3] * box_b[4];
    float s_overlap = box_overlap(box_a, box_b);
    return s_overlap / fmaxf(sa + sb - s_overlap, 1e-8);
}
 
__global__ void boxes_overlap_kernel(const int num_a, const float *boxes_a, const int num_b, const float *boxes_b, float *ans_overlap){
    // params boxes_a: (N, 7) [x, y, z, dx, dy, dz, heading]
    // params boxes_b: (M, 7) [x, y, z, dx, dy, dz, heading]
    const int a_idx = blockIdx.y * THREADS_PER_BLOCK + threadIdx.y;
    const int b_idx = blockIdx.x * THREADS_PER_BLOCK + threadIdx.x;
 
    if (a_idx >= num_a || b_idx >= num_b){
        return;
    }
    const float * cur_box_a = boxes_a + a_idx * 7;
    const float * cur_box_b = boxes_b + b_idx * 7;
    float s_overlap = box_overlap(cur_box_a, cur_box_b);
    ans_overlap[a_idx * num_b + b_idx] = s_overlap;
}
 
__global__ void boxes_iou_bev_kernel(const int num_a, const float *boxes_a, const int num_b, const float *boxes_b, float *ans_iou){
    // params boxes_a: (N, 7) [x, y, z, dx, dy, dz, heading]
    // params boxes_b: (M, 7) [x, y, z, dx, dy, dz, heading]
    const int a_idx = blockIdx.y * THREADS_PER_BLOCK + threadIdx.y;
    const int b_idx = blockIdx.x * THREADS_PER_BLOCK + threadIdx.x;
 
    if (a_idx >= num_a || b_idx >= num_b){
        return;
    }
 
    const float * cur_box_a = boxes_a + a_idx * 7;
    const float * cur_box_b = boxes_b + b_idx * 7;
    float cur_iou_bev = iou_bev(cur_box_a, cur_box_b);
    ans_iou[a_idx * num_b + b_idx] = cur_iou_bev;
}
 
__global__ void nms_kernel(const int boxes_num, const float nms_overlap_thresh,
                           const float *boxes, uint64_t*mask){
    //params: boxes (N, 7) [x, y, z, dx, dy, dz, heading]
    //params: mask (N, N/THREADS_PER_BLOCK_NMS)
 
    const int row_start = blockIdx.y;
    const int col_start = blockIdx.x;
 
    // if (row_start > col_start) return;
 
    const int row_size = fminf(boxes_num - row_start * THREADS_PER_BLOCK_NMS, THREADS_PER_BLOCK_NMS);
    const int col_size = fminf(boxes_num - col_start * THREADS_PER_BLOCK_NMS, THREADS_PER_BLOCK_NMS);
 
    __shared__ float block_boxes[THREADS_PER_BLOCK_NMS * 7];
 
    if (threadIdx.x < col_size) {
        block_boxes[threadIdx.x * 7 + 0] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 0];
        block_boxes[threadIdx.x * 7 + 1] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 1];
        block_boxes[threadIdx.x * 7 + 2] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 2];
        block_boxes[threadIdx.x * 7 + 3] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 3];
        block_boxes[threadIdx.x * 7 + 4] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 4];
        block_boxes[threadIdx.x * 7 + 5] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 5];
        block_boxes[threadIdx.x * 7 + 6] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 6];
    }
    __syncthreads();
 
    if (threadIdx.x < row_size) {
        const int cur_box_idx = THREADS_PER_BLOCK_NMS * row_start + threadIdx.x;
        const float *cur_box = boxes + cur_box_idx * 7;
 
        int i = 0;
        uint64_t t = 0;
        int start = 0;
        if (row_start == col_start) {
          start = threadIdx.x + 1;
        }
        for (i = start; i < col_size; i++) {
            if (iou_bev(cur_box, block_boxes + i * 7) > nms_overlap_thresh){
                t |= 1ULL << i;
            }
        }
        const int col_blocks = DIVUP(boxes_num, THREADS_PER_BLOCK_NMS);
        mask[cur_box_idx * col_blocks + col_start] = t;
    }
}
 
 
__device__ inline float iou_normal(float const * const a, float const * const b) {
    //params: a: [x, y, z, dx, dy, dz, heading]
    //params: b: [x, y, z, dx, dy, dz, heading]
 
    float left = fmaxf(a[0] - a[3] / 2, b[0] - b[3] / 2), right = fminf(a[0] + a[3] / 2, b[0] + b[3] / 2);
    float top = fmaxf(a[1] - a[4] / 2, b[1] - b[4] / 2), bottom = fminf(a[1] + a[4] / 2, b[1] + b[4] / 2);
    float width = fmaxf(right - left, 0.f), height = fmaxf(bottom - top, 0.f);
    float interS = width * height;
    float Sa = a[3] * a[4];
    float Sb = b[3] * b[4];
    return interS / fmaxf(Sa + Sb - interS, 1e-8);
}
 
 
__global__ void nms_normal_kernel(const int boxes_num, const float nms_overlap_thresh,
                           const float *boxes, uint64_t*mask){
    //params: boxes (N, 7) [x, y, z, dx, dy, dz, heading]
    //params: mask (N, N/THREADS_PER_BLOCK_NMS)
 
    const int row_start = blockIdx.y;
    const int col_start = blockIdx.x;
 
    // if (row_start > col_start) return;
 
    const int row_size = fminf(boxes_num - row_start * THREADS_PER_BLOCK_NMS, THREADS_PER_BLOCK_NMS);
    const int col_size = fminf(boxes_num - col_start * THREADS_PER_BLOCK_NMS, THREADS_PER_BLOCK_NMS);
 
    __shared__ float block_boxes[THREADS_PER_BLOCK_NMS * 7];
 
    if (threadIdx.x < col_size) {
        block_boxes[threadIdx.x * 7 + 0] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 0];
        block_boxes[threadIdx.x * 7 + 1] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 1];
        block_boxes[threadIdx.x * 7 + 2] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 2];
        block_boxes[threadIdx.x * 7 + 3] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 3];
        block_boxes[threadIdx.x * 7 + 4] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 4];
        block_boxes[threadIdx.x * 7 + 5] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 5];
        block_boxes[threadIdx.x * 7 + 6] = boxes[(THREADS_PER_BLOCK_NMS * col_start + threadIdx.x) * 7 + 6];
    }
    __syncthreads();
 
    if (threadIdx.x < row_size) {
        const int cur_box_idx = THREADS_PER_BLOCK_NMS * row_start + threadIdx.x;
        const float *cur_box = boxes + cur_box_idx * 7;
 
        int i = 0;
        uint64_t t = 0;
        int start = 0;
        if (row_start == col_start) {
          start = threadIdx.x + 1;
        }
        for (i = start; i < col_size; i++) {
            if (iou_normal(cur_box, block_boxes + i * 7) > nms_overlap_thresh){
                t |= 1ULL << i;
            }
        }
        const int col_blocks = DIVUP(boxes_num, THREADS_PER_BLOCK_NMS);
        mask[cur_box_idx * col_blocks + col_start] = t;
    }
}
 
void boxesoverlapLauncher(const int num_a, const float *boxes_a, const int num_b, const float *boxes_b, float *ans_overlap){
 
    dim3 blocks(DIVUP(num_b, THREADS_PER_BLOCK), DIVUP(num_a, THREADS_PER_BLOCK));  // blockIdx.x(col), blockIdx.y(row)
    dim3 threads(THREADS_PER_BLOCK, THREADS_PER_BLOCK);
 
    boxes_overlap_kernel<<<blocks, threads>>>(num_a, boxes_a, num_b, boxes_b, ans_overlap);
#ifdef DEBUG
    cudaDeviceSynchronize();  // for using printf in kernel function
#endif
}
 
void boxesioubevLauncher(const int num_a, const float *boxes_a, const int num_b, const float *boxes_b, float *ans_iou){
 
    dim3 blocks(DIVUP(num_b, THREADS_PER_BLOCK), DIVUP(num_a, THREADS_PER_BLOCK));  // blockIdx.x(col), blockIdx.y(row)
    dim3 threads(THREADS_PER_BLOCK, THREADS_PER_BLOCK);
 
    boxes_iou_bev_kernel<<<blocks, threads>>>(num_a, boxes_a, num_b, boxes_b, ans_iou);
#ifdef DEBUG
    cudaDeviceSynchronize();  // for using printf in kernel function
#endif
}
 
 
void nmsLauncher(const float *boxes, uint64_t* mask, int boxes_num, float nms_overlap_thresh){
    dim3 blocks(DIVUP(boxes_num, THREADS_PER_BLOCK_NMS),
                DIVUP(boxes_num, THREADS_PER_BLOCK_NMS));
    dim3 threads(THREADS_PER_BLOCK_NMS);
    nms_kernel<<<blocks, threads>>>(boxes_num, nms_overlap_thresh, boxes, mask);
}
 
 
void nmsNormalLauncher(const float *boxes, uint64_t* mask, int boxes_num, float nms_overlap_thresh){
    dim3 blocks(DIVUP(boxes_num, THREADS_PER_BLOCK_NMS),
                DIVUP(boxes_num, THREADS_PER_BLOCK_NMS));
    dim3 threads(THREADS_PER_BLOCK_NMS);
    nms_normal_kernel<<<blocks, threads>>>(boxes_num, nms_overlap_thresh, boxes, mask);
}

iou3d_nms.h

#ifndef IOU3D_NMS_H
#define IOU3D_NMS_H
 
#include <torch/serialize/tensor.h>
#include <vector>
#include <assert.h>
#include <cuda.h>
#include <cuda_runtime_api.h>
 
//int boxes_aligned_overlap_bev_gpu(at::Tensor boxes_a, at::Tensor boxes_b, at::Tensor ans_overlap);
int boxes_overlap_bev_gpu(at::Tensor boxes_a, at::Tensor boxes_b, at::Tensor ans_overlap);
int boxes_iou_bev_gpu(at::Tensor boxes_a, at::Tensor boxes_b, at::Tensor ans_iou);
int nms_gpu(at::Tensor boxes, at::Tensor keep, float nms_overlap_thresh);
int nms_normal_gpu(at::Tensor boxes, at::Tensor keep, float nms_overlap_thresh);
 
#endif

iou3d_nms_api.cpp

#include <torch/serialize/tensor.h>
#include <torch/extension.h>
#include <vector>
#include <cuda.h>
#include <cuda_runtime_api.h>
 
#include "iou3d_cpu.h"
#include "iou3d_nms.h"
 
 
PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) {
    //m.def("boxes_aligned_overlap_bev_gpu", &boxes_aligned_overlap_bev_gpu, "aligned oriented boxes overlap");
    m.def("boxes_overlap_bev_gpu", &boxes_overlap_bev_gpu, "oriented boxes overlap");
    m.def("boxes_iou_bev_gpu", &boxes_iou_bev_gpu, "oriented boxes iou");
    m.def("nms_gpu", &nms_gpu, "oriented nms gpu");
    m.def("nms_normal_gpu", &nms_normal_gpu, "nms gpu");
    m.def("boxes_aligned_iou_bev_cpu", &boxes_aligned_iou_bev_cpu, "aligned oriented boxes iou");
    m.def("boxes_iou_bev_cpu", &boxes_iou_bev_cpu, "oriented boxes iou");
}
  1. 编译 python setup.py develop
    ![在这里插入图片描述](https://img-blog.csdnimg.cn/
    可能出现的坑
    问题1(已解决)
无法打开输入文件“F:\OpenPCDet\OpenPCDet\build\temp.win-amd64-3.8\Release\pcdet\ops\iou3d_nms\src\iou3d_cpu.obj”

error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2017\\BuildTools\\VC\\Tools\\MSVC\\14.16.27023\\bin\\HostX86\\x64\\link.exe' failed with exit status 1181

将setup.py中的cmdclass={'build_ext': BuildExtension}”修改为cmdclass={'build_ext': BuildExtension.with_options(use_ninja=False)},然后重新编译;
参考https://blog.youkuaiyun.com/qq_61981718/article/details/130741276

问题2(已解决)

安装过程中报错:fatal error: THC/THC.h: No such file or directory

主要是pytorch版本太高导致,可将版本降低至1.11以下,或者更改./OpenPCDet/pcdet/ops/pointnet2/pointnet2_batch/src和./OpenPCDet/pcdet/ops/pointnet2/pointnet2_stack/src文件夹下的几个cpp文件

//#include <THC/THC.h>
...
//extern THCState *state

将这两行注释掉之后重新编译

3D点云目标检测算法综述 3D点云目标检测综述,从 pointnet到centernet,介绍各种深度学习点云检测算法 阅读详情

相关推荐

3D点云学习:SECOND目标检测①论文阅读

论文: 论文链接. 源码: 源码链接. 由于本来是准备研究PV-RCNN网络的,可是发现源码还没有开源。但是在PCDet.上发现包含了SECOND等几个网络 源码2: 源码链接2. 1 摘要 基于LiDAR或基于RGB-D的目标检测被用于从自动驾驶到机器人视觉的众多应用中。 在处理点云LiDAR数据时,基于Voxel的3D卷积网络已经使用了一段时间,体素方法能够在处理雷达点云数据时的保留更多的信息。 但是,仍然存在问题,包括推理速度慢和方向估计性能低。因此,我们研究了一种改进的稀疏卷积方法用于这种网络,这显

themasterbi的博客 7632

制作PointNet以及PointNet++点云训练样本

Pointnet或Pointnet++分类数据集制作,制作自己的三维深度学习点云训练数据集

CC047964的博客 9314

手把手教学基于简单神经网络的激光雷达点云车辆检测(附代码)

准备工作 python matlab KITTI数据集激光雷达部分 参考文献(本文基本按照该文献方式处理):邓淇天. 基于激光雷达和视觉传感器融合的障碍物识别技术研究[D]. 南京: 东南大学, 2019. 1. KITTI数据读入 我在https://blog.youkuaiyun.com/weixin_43145941/article/details/119513491一文中已经给出了matlab代码用于得到KITTI点云图。当然,可以假想现在已经获得了一个点云: points_cloud.shape=(n,4

ZYunfei的博客 8318

三维点云数据库

深度学习算法研究与开发离不开数据库,在这里对较为常用的点云三维数据库作整理,以便后续研究使用过程。这里将开源点云三维数据库分为两类:室外三维数据集和室内三维数据集。

qq_47818101的博客 1608

多视图3D目标检测学习笔记

参加滴滴无人驾驶算法大赛,在多方面参考了几篇目标检测和多视角检测融合等文献,最终团队确定了一下两篇论文作为比赛的参考: A Unified Multi-scale Deep Convolutional Neural Network for Fast Object Detection Multi-View 3D Object Detection Network for Autonomous

神秘少年的博客 1万+

【点云缺陷检测】IMRNet阅读记录

基于重建的异常检测模型IMRNET阅读记录

yuemingneu的博客 1090

【3D点云】目标检测总结(持续汇总)

3D点云目标检测的算法汇总,部分重要论文附带代码讲解

qq_45752541的博客 1万+

3D异常检测最新论文《Complementary Pseudo Multimodal Feature for Point Cloud Anomaly Detection》阅读笔记

在BTF这篇文章中指出,点云的特征提取至关重要,但因为预训练点云特征网络的训练与使用的域差异,导致这些网络的性能甚至不如手工制作的特征提取方法。因此,作者产生了将二者结合起来的思路。之后,根据投影过程的对应关系,可以将每个像素的2D特征赋给对应的3D点,并使用平均值池化进行聚合,也就是一个3D点的特征是它对应的不同视角下所得到的这些2D特征的平均。另外对于在MVTec 3D-AD上进行3D异常检测的算法,其评判标准有失偏颇,因为一些缺陷是仅能通过RGB判断的,这对统计3D异常检测算法的性能是不充分的。

gaooolianggg的专栏 1712

点云 3D 目标检测 - PointPillars(CVPR 2019)

点云 3D 目标检测 - PointPillars1. 文章信息2. PointPillars 简介2.1 算法特点2.2 模型结构2.2.1 Pillar Feature Net2.2.2 Backbone (2D CNN)2.2.3 Detection Head (SSD) 1. 文章信息 文章标题 PointPillars: Fast Encoders for Object Detection from Point Clouds (2019) 文章链接 https://arxiv.org/ab

77wpa的博客 1万+

生成点云网络:使用深度学习生成逼真的三维点云数据

在训练过程中,我们使用生成器生成虚假的点云数据,并使用判别器对生成的点云数据和真实的点云数据进行分类。将点云数据预处理为网络可接受的输入格式是必要的,一种常见的方法是将点云转换为体素网格表示或投影到二维平面。接下来,我们定义生成器和判别器的网络架构。生成器负责生成逼真的点云数据,而判别器则负责区分生成的点云和真实的点云数据。此外,生成点云网络的训练通常需要大量的计算资源和时间,因此在实际应用中需要进行合理的调参和训练策略。总结起来,生成点云网络是使用深度学习方法生成逼真的三维点云数据的重要工具。

FqLibrary的博客 805

点云数据集大全(附官网地址和下载链接)

点云数据集大全(附官网地址和下载链接)持续更新

qq_56233492的博客 8931

3D点云目标检测网络简介

划分成体素格子后,由于点云密度不一致,有些格子里面点云可能比较多,对超出给定数量T的格子,需要进行随机采样,保证每个格子点不超过T个,少于T个的在实现中采用补0的方式。

datian1234的博客 2314

手把手调试Altera FPGA远程升级:从ASMI扇区擦除到Remote Update IP配置的避坑实录

本文详细解析了Altera FPGA远程升级的全流程,重点介绍了Cyclone IV系列FPGA的ASMI扇区擦除和Remote Update IP配置的实战技巧。通过双镜像架构设计、ASMI IP核优化配置及Remote Update IP的隐藏参数设置,帮助开发者避免常见陷阱,提升远程升级的可靠性和效率。

weixin_30872499的博客 447

3D点云目标检测:MPPNet网络训练waymo数据集

注意事项,要求内存大于100G,使用gt_sampling策略,不要使用share_memory策略。注意:验证集的版本要新一点,旧的的验证集合没有目标的点数,无法区分level1和level2。在这里记录一下MPPNet网络训练waymo数据的过程。三、训练centerpoint网络。一、waymo数据集介绍。二、waymo数据预处理。四、训练mppnet网络。

zhaoguanhua的博客 6052

Bellhop水声信道模型的仿真

Bellhop是一种基于射线追踪的水声信道模型,广泛用于预测水下环境中的声压场。它通过模拟声波在水中的传播路径,计算声场分布,适用于复杂的水下通信场景。

yt94832的博客 1313

Ubuntu中 vsftpd 的安装与配置 (详细介绍)

简介 vsftpd 是一个 UNIX 类操作系统上运行的服务器的名字,它可以运行在诸如 Linux, BSD, Solaris, HP-UX 以及 IRIX 上面。它支持很多其他的 FTP 服务器不支持的特征。 vsftpd是 UNIX 操作系统中的一个开源的、免费的 FTP 服务软件。具有以下特点: 安全性高 轻小易用 支持系统用户匿名用户和虚拟用户的权限验证和相关操作 安装步骤如下: 1.将此命令复制到终端 sudo apt-get install vsftpd 2.安装完成后启动VSFTP

qq_43299421的博客 1万+

点云 3D 目标检测 - VoxelNet(CVPR 2018)

精确检测3D点云中的物体是许多应用中的中心问题,例如自主导航、家政机器人和增强/虚拟现实。为了将高度稀疏的LiDAR点云与区域提案网络(RPN)连接起来,大多数现有工作都集中在手工制作的特征表示上,例如鸟瞰投影。在这项工作中,我们消除了对3D点云的手动特征工程的需求,并提出了VoxelNet,这是一种通用的3D检测网络,它将特征提取和边界框预测统一到单个阶段、端到端可训练的深度网络中。

77wpa的博客 4382

AxMath行间公式转化为office公式求和符号以及编号显示问题

AxMath行间公式转化为office公式求和符号以及编号显示问题问题描述解决方法 问题描述 首先打出axmath公式,如下: 转换后的OfficeMath公式: 字体先不说,word公式字体默认cambria math且无法编辑。比较难受的一点是求和符号与后面的 ai+bi2a_i+b_i^2ai​+bi2​比例不匹配啊!正常的比例应该是: (虽然也不太正常,将就下) 解决方法 点击变换后的office公式右侧,选择更改为"显示" 可以看到,多了一些软回车符号(⬇),如果你想删除它,不要直接选中

weixin_43543177的博客 4649

3D点云 (Lidar)检测入门篇 : PointPillars PyTorch实现

作者丨千百度@知乎来源丨https://zhuanlan.zhihu.com/p/521277176编辑丨3D视觉工坊基于Lidar的object检测模型包括Point-based [PointRCNN(CVPR19),IA-SSD(CVPR22)等], Voxel-based [PointPillars(CVPR19),CenterPoint(CVPR21)等],P...

3D视觉工坊 4382

2025使用VM虚拟机安装配置Macos苹果系统下Flutter开发环境保姆级教程--下篇

我们可以看到,目前配置基本完成了,现在有两个错,一个是Chrome没安装,这个自己安装就可以了,如果不需要WEB测试也不影响开发,另一个是Simulator还没安装,这个主要是安装的时间太长了,也就是上面的这一步。这里要注意,这个下载安装会比较慢,有的载会特别卡造成安装失败,最好的办法是挂一个VPN,保证安装完成,不过这个可以在以后单独进行安装。至此,基本的安装完毕,好多人会以为Xcode就OK了,其实还没有,我们还缺少命令行工具包,这个在安装完Flutter以后进行设置。

weixin_48803304的博客 1412

YOLO模型轻量化实战:剪枝、量化与知识蒸馏三大技术落地详解

这篇文章结合我自己的实战经验,从原理、操作、效果、避坑四个方面,给大家讲清楚了YOLO模型轻量化的三大核心技术:剪枝、量化、知识蒸馏。先明确应用场景,再选择合适的技术组合,不要盲目追求极致压缩,要在“大小、速度、精度”之间找平衡。实战才是最好的学习方式——大家可以先拿自己的数据集试试剪枝和量化,感受一下效果,有问题可以在评论区留言。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 592

点云 3D 目标检测 - SECOND(Sensors 2018)

基于LiDAR或RGB-D的目标检测被用于从自动驾驶到机器人视觉的许多应用中。基于体素的3D卷积网络已被用于在处理点云LiDAR数据时增强信息的保留。然而,问题仍然存在,包括推理速度慢和方向估计性能低。因此,我们研究了一种用于此类网络的改进的稀疏卷积方法,该方法显著提高了训练和推理的速度。我们还引入了一种新的角度损失回归形式来提高方向估计性能,并引入了一个新的数据增强方法来提高收敛速度和性能。所提出的网络在KITTI 3D目标检测基准上产生最先进的结果,同时保持快速推断速度。

77wpa的博客 3453

[系统安全] 十七.Windows PE病毒概念、分类及感染方式详解

作者前文介绍了PE文件格式,熟悉各种PE编辑查看工具,针对目标EXE程序新增对话框等;这篇文章将介绍Windows PE病毒, 包括PE病毒原理、分类及感染方式详解,并通过案例进行介绍。这些基础性知识不仅和系统安全相关,同样与我们身边的APP、常用软件及操作系统紧密联系,希望这些知识对您有所帮助,更希望大家提高安全意识,安全保障任重道远。本文参考了《软件安全》视频、安全网站和参考文献中的文章,并结合自己的经验和实践进行撰写,也推荐大家阅读参考文献。

杨秀璋的专栏 1万+

3D点云 (Lidar)检测入门篇 - PointPillars PyTorch实现

3D点云 (Lidar)检测入门篇 - PointPillars PyTorch实现 完整代码:https://github.com/zhulf0804/PointPillars。 自动驾驶中基于Lidar的object检测,简单的说,就是从3D点云数据中定位到object的框和类别。具体地,输入是点云X∈RN×c\mathbf X \in \mathbb R^{N \times c}X∈RN×c (一般c=4c=4c=4),输出是nnn个检测框bboxes, 以第iii个检测框bbox为例, 它包括位姿信

zhulf0804的博客 2931

⑩电子产品拆解分析-家用无线遥控开关433Mhz

①免布线随意贴,装上就能使用解决单线开关烦恼;②遥控配对简单,无线通讯距离长,信号可穿墙;

a6662580的博客 4693

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

上一篇: python-pcl+Windows10+anaconda安装
下一篇: 基于OnnxRuntime在C++端部署YOLOV5
WD-ss
博客等级 码龄7年 44粉丝 18原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值