AidLux “3D对象检测”案例源码详解

“3D对象检测”案例源码详解 (Python)

objectron.py用于检测3D对象

  1. 检测峰值
  2. 解码函数
  3. 绘制三维空间中的盒子,以标识物体
  4. 指定模型路径和输入形状
  5. 设置相机并开始读图
  6. 启动模型,调用三个函数进行物体检测并绘制

打开objectron对象检测案例

1.在VScode中进入代码编辑状态。
AidLux “3D对象检测”案例源码详解_第1张图片
2.代码存在路径在/examples_gpu/objectron/objectron.py。

导入相关库

AidLux “3D对象检测”案例源码详解_第2张图片

1. cvs图形控件模块。
2. remi是一个用于python应用程序的gui库,它将应用程序的接口转换成html并在web浏览器中呈现。这消除了特定于平台的依赖关系,使用户可以轻松地在python中开发跨平台应用程序
3. sys模块包括了一组非常实用的服务,内含很多函数方法和变量,用来处理Python运行时配置以及资源,从而可以与前当程序之外的系统环境交互。 
4. NumPy(Numerical Python) 是 Python 语言的一个扩展程序库,支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。在机器学习算法中大部分都是调用Numpy库来完成基础数值计算的。
5. SciPy是一个开源的数学、科学和工程计算包
6. Scipy.ndimage---Multi-dimensional image processing(多维图像处理包)----该包包含用于多维图像处理的各种功能。7. 几个模块:Filters:过滤器
8. tflite_gpu,GPU加速代码由AID提供,TensorFlow Lite 支持多种硬件加速器。
9. GPU 是设计用来完成高吞吐量的大规模并行工作的。因此,它们非常适合用在包含大量运算符的神经网络上,
10. 一些输入张量可以容易的被划分为更小的工作负载且可以同时执行,通常这会导致更低的延迟。
11. 在最佳情况下,用 GPU 在实时应用程序上做推理运算已经可以运行的足够快,而这在以前是不可能的。

检测峰值函数

tflite = tflite_gpu.tflite()


#检测峰值,返回峰值索引
#传递的参数中要设置过滤器大小、级数(此处分别为5、0.5)
def detect_peak(image, filter_size=5, order=0.5):

    #local_max用于存放图像中诸像素的最大值
    
    #此处np.ones生成5行5列的值全为1的矩阵
    #footprint.ones(n,m)相当于size=(n,m),指定大小为n行m列
    local_max = maximum_filter(image, footprint=np.ones((filter_size, filter_size)), mode='constant')

    #掩码数组(np.ma.array),使用Mask遮挡掉某些不符合条件的数据,使其不参与后续运算
    #检测到的峰值是一个蒙板(mask)数列,蒙板(mask)设置为图像不为最大值的部分
    #"~"即取反
    detected_peaks = np.ma.array(image,mask=~(image == local_max))
    
    #掩码数组(np.ma.array),使用Mask遮挡掉某些不符合条件的数据,使其不参与后续运算
    #检测到的峰值是一个蒙板(mask)数列,蒙板(mask)设置为图像不为最大值的部分
    temp = np.ma.array(detected_peaks, mask=~(detected_peaks >= detected_peaks.max() * order))
    peaks_index = np.where((temp.mask != True))
    return peaks_index

解码函数(decode)

def transfer(image, mask):

    #将mask的像素矩阵(在python中是一个二维数组)改成与image同行数同列数
    mask = cv2.resize(mask, (image.shape[1], image.shape[0]))

    #np.zeros_like函数主要是想实现构造一个矩阵mask_n,其维度与矩阵image一致
    #并为其初始化为全0
    #这个函数方便的构造了新矩阵,无需参数指定shape大小
    mask_n = np.zeros_like(image)
    mask_n[:, :, 0] = mask

    alpha = 0.7 
     
    beta = (1.0 - alpha)

    #cv2.addWeighted是Python-OpenCV图像叠加or图像混合加权方法
    #其中image是第一个输入的数列
    #alpha是第一个数列诸元素的权重
    #mask_n是一个输入数列,它的大小和通道数与image必须相同
    #beta即第二个数列诸元素的权重
    #0.0处填入一个标量,需要加到每一个和值上
    dst = cv2.addWeighted(image, alpha, mask_n, beta, 0.0)

    return dst

绘制三维空间中的盒子

def draw_box(image, pts):

    #图像(在python中是一个二维矩阵)的行数、列数分别赋给变量scaleX、scaleY
    #属性shape[0],shape[1]分别是行数、列数
    scaleX = image.shape[1]
    scaleY = image.shape[0]

    #初始化一个线段集
    #(0,1)表示线段1,(1,3)表示线段2……
    lines = [(0,1), (1,3), (0,2), (3,2), (1,5), (0,4), (2,6), (3,7), (5,7), (6,7), (6,4), (4,5)]
	#遍历线集,对每条线段进行操作:
	for line in lines:
	    #获取点
	    pt0 = pts[line[0]]
	    pt1 = pts[line[1]]
	
	    #将每条线段的两个点进行缩放
	    #乘以之前确定的缩放系数scaleX、scaleY
	    pt0 = (int(pt0[0]*scaleX), int(pt0[1]*scaleY))
	    pt1 = (int(pt1[0]*scaleX), int(pt1[1]*scaleY))
	
	    #使用opencv2中的line方法绘制线
	    #(255,245,0)是线条颜色(RGB)
	    cv2.line(image, pt0, pt1, (255 ,245, 0))
	for i in range(8):
	    pt = pts[i]
	
	    #将每个点进行缩放
	    #乘以之前确定的缩放系数scaleX、scaleY
	    pt = (int(pt[0]*scaleX), int(pt[1]*scaleY))
	
	    #使用opencv2中的circle方法画圆
	    # circle(img, center, radius, color, thickness)
	    # img为源图像, center为画圆的圆心坐标, radius为圆的半径, color为设定圆的颜色,规则根据B(蓝)G(绿)R(红)
	    # thickness 如果是正数,表示组成圆的线条的粗细程度。否则,-1表示圆是否被填充
	    cv2.circle(image, pt, 1,(255 ,245, 0), -1)
	
	    #使用opencv2中的putText方法添加文字
	    #图片,添加的文字,左上角坐标,字体,字体大小,颜色,字体粗细
	    cv2.putText(image, str(i), pt,  cv2.FONT_HERSHEY_PLAIN, 2, (255,0,0), 2)

指定模型路径和输入形状

#指定模型路径
#指定输入形状(图像数目*像素行数*像素列数*通道数)

model_path = 'models/object_detection_3d_chair_1stage.tflite'
#img_path = 'imgs/chairs.jpg'
#img_path = '/sdcard/yoline/objectron-3d-object-detection-openvino/resources/output.jpg'

#输入图像数据量 [一副图像*(640*480)像素*rgb三通道*4字节]
#(1个float是32位也就是4字节,即每个数据4个字节)
inShape =[1*640*480*3*4,]


#输出图像数据量 [一副图像*40个框*每个框的置信度30*4个字节] 40指的是896个框, 30指的是每个框的置信度,具体这16个数表示什么、顺序怎样,只有看作者在训练的时候如何定义
outShape= [1*40*30*1*4, 1*40*30*16*4, 1*160*120*4*4]

print('gpu:',tflite.NNModel(model_path,inShape,outShape,4,0))

设置相机并开始读图

#cvs.VideoCapture(1)是调用手机前置摄像头,如果是cvs.VideoCapture(0)就是调用手机后置摄像头。
cap=cvs.VideoCapture(0)
while True:
    # img_org = cv2.imread(img_path)
    #直到读取到摄像头的图像为止
    img_ori=cvs.read()
    if img_ori is None:
        continue
    # img_ori=cv2.flip(img_ori,1)
	#cv2.cvtColor(p1,p2) 是颜色空间转换函数,p1是需要转换的图片,p2是转换成何种格式。
	#另外,cv2.COLOR_BGR2RGB 将BGR格式转换成RGB格式  
	#cv2.COLOR_BGR2GRAY 将BGR格式转换成灰度图片
	img = cv2.cvtColor(img_ori, cv2.COLOR_BGR2RGB)
	#opencv的resize方法在这里将图像转换为480*640像素
	#astype是类型转换,这里转换成np的三十二位浮点型
	img = cv2.resize(img, (480, 640)).astype(np.float32)
	img = img / 128.0 - 1.0
	img = img[None]
	
	#print(img.shape, img.dtype)

启动模型,调用三个函数进行物体检测并绘制

	#分配内存并传入数据
	tflite.setTensor_Fp32(img, 480, 640)
	
	#获取开始时间
	start_time = time.time()
	
	#启动tensorflow模型,使之开始运行
	tflite.invoke()
	
	#将经过的时间转换为毫秒
	gpuelapsed_ms = (time.time() - start_time) * 1000
	print('elapsed_ms invoke:',gpuelapsed_ms)
	cvs.setLbs('elapsed_ms invoke:'+str(gpuelapsed_ms))
	hm = tflite.getTensor_Fp32(0)
	#设定位移
	#由于fp16(16位浮点数)的值区间比fp32的值区间小很多,所以在计算过程中很容易出现上溢出(Overflow,>65504 )和下溢出(Underflow,<6x10^-8  )的错误,溢出之后就会出现“Nan”的问题
	#所以我们选择fp32
	displacements = tflite.getTensor_Fp32(1)
	#查看hm的形状(大小)、位移的形状
	print(hm.shape, displacements.shape)
	#对物体进行解码
	objs = decode(hm, displacements, threshold=0.7)
	
	#遍历物体列表,画三维盒子
	for obj in objs:
	    #画三维盒子需要传入两个参数:源图像、提取出的物体。
	    draw_box(img_ori, obj)
	    print(draw_box(img_ori, obj))
	#同时展示源图像
	cvs.imshow(img_ori)

你可能感兴趣的:(AidLux,opencv,python,tensorflow,深度学习)