前面了解到Faster R-CNN在实验中的效果很不错,以及对论文做了一个大概的了解,对此有兴趣的伙伴们也可以先浏览前面两篇文章:
MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《1》
MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《2》
这节主要就是针对源代码,来具体看看有一些什么新的知识点以及加深对论文观点的认识。
python demo.py --dataset voc --network vgg16 --params model/vgg_voc07-0010.params --image hi.jpg
从这个参数来看,很关键的点就是用到已训练好的模型参数vgg_voc07_0010.params,这个好处大家都知道,大型的模型训练非常耗时,而且我们在计算机视觉之迁移学习中的微调(fine tuning)
有讲到可以应用已训练好的参数文件为我所用,我们可以先来加载看下这个参数文件里面有些什么键值对。
加载模型参数
import mxnet as mx
mydict=mx.nd.load('model/vgg_voc07-0010.params')
for k,v in mydict.items():
tp,name=k.split(":")
print(tp,name,end=',')
'''
arg conv3_2_weight,arg rpn_conv_3x3_weight,arg conv4_1_bias,arg conv5_3_bias,arg cls_score_weight,arg conv3_3_bias,arg fc7_bias,arg conv4_3_weight,arg conv1_2_bias,arg conv4_1_weight,arg bbox_pred_bias,arg bbox_pred_weight,arg fc7_weight,arg
conv2_1_bias,arg conv5_2_weight,arg conv1_1_bias,arg cls_score_bias,arg bbox_pred_weight_test,arg conv2_2_weight,arg conv4_3_bias,arg fc6_bias,arg bbox_pred_bias_test,arg conv3_1_bias,arg rpn_bbox_pred_bias,arg rpn_cls_score_bias,arg conv5_3_weight,arg conv1_2_weight,arg conv4_2_weight,arg rpn_cls_score_weight,arg conv3_1_weight,arg conv5_1_bias,arg conv4_2_bias,arg conv2_1_weight,arg conv2_2_bias,arg conv5_1_weight,arg conv1_1_weight,arg rpn_conv_3x3_bias,arg rpn_bbox_pred_weight,arg conv3_3_weight,arg fc6_weight,arg conv3_2_bias,arg conv5_2_bias,
'''
可以看到k有卷积层权重与偏置、rpn3x3的卷积层权重与偏置、类别分数权重与偏置、全连接层权重与偏置、边框预测权值与偏置、rpn边框预测权值与偏置、rpn类别分数权值与偏置等。
当然这个v值就是权值与偏置的值。这里就不必要贴了。
在这个模型源码当中,判别了tp是arg还是aux,分别放入到arg_params和aux_params字典中
可视化
python demo.py --dataset voc --network vgg16 --params model/vgg_voc07-0010.params --image hi.jpg --vis
加一个vis参数,可以将输入图片进行可视化,标注类别和锚框并显示分数,这个参数我们可以看到,如果存在将会调用一个vis_detection方法。我们单独列出来看下这个可视化的函数是怎么样的。
import cv2
def vis_detection(im_orig, detections, class_names, thresh=0.7):
"""visualize [cls, conf, x1, y1, x2, y2]"""
import matplotlib.pyplot as plt
import random
plt.imshow(im_orig)
colors = [(random.random(), random.random(), random.random())
for _ in class_names]
for [cls, conf, x1, y1, x2, y2] in detections:
cls = int(cls)
#类别索引大于0以及大于设定的阈值才显示锚框
if cls > 0 and conf > thresh:
rect = plt.Rectangle((x1, y1), x2 - x1, y2 - y1,
fill=False, edgecolor=colors[cls], linewidth=3.5)
plt.gca().add_patch(rect)
plt.gca().text(x1, y1 - 2, '{:s} {:.3f}'.format(class_names[cls], conf),
bbox=dict(facecolor=colors[cls], alpha=0.5), fontsize=12, color='white')
plt.show()
img = cv2.imread("hi.jpg")
img = img[:, :, (2, 1, 0)] # cv2出来的是BGR,需要转成RGB
# 里面6个元素分别表示类别索引、阈值(交并比IoU)、左上角xy坐标、右下角xy坐标
det = [[12, 0.999, 214, 0, 473, 473], [8, 0.997, 15, 175, 171, 453], [2, 0.25, 6, 74, 176, 458]]
clsname = ['__background__', 'aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow',
'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']
vis_detection(img, det, clsname, 0.7)
这里主要就是最后做可视化的一步,给图片加上锚框,这个模型包括背景一共是21个类:
感兴趣区域
感兴趣区域ROI(Region Of Interest),这个在代码中也是频繁出现,我们独立出来了解下:
感兴趣区域
import cv2 as cv
#感兴趣区域
def roi(imgpath):
src = cv.imread(imgpath)
cv.namedWindow("hi", cv.WINDOW_AUTOSIZE) # 创建一个自适应窗口
cv.imshow("hi", src)
roiImg = src[200:400, 0:300] # 感兴趣的区域(高、宽)
cv.imshow("roi", roiImg)
cv.waitKey()
roi("hi.png")
我们将看到左边那块,就是我们感兴趣的区域,其实就是将图片转成矩阵,然后可以选择几行几列的元素,这样就挑选出了ROI
还原图片
# 还原
def orig(imgpath):
src = cv.imread(imgpath)
cv.namedWindow("hi", cv.WINDOW_AUTOSIZE) # 创建一个自适应窗口
cv.imshow("hi", src)
roiImg = src[200:400, 0:300] # 感兴趣的区域(高、宽)
cv.imshow("roi", roiImg)
gray = cv.cvtColor(roiImg, cv.COLOR_BGR2GRAY) # 灰度单通道(200,300)
backface = cv.cvtColor(gray, cv.COLOR_GRAY2BGR) # 单通道转3通道(200,300,3)
src[200:400, 0:300] = backface
cv.imshow("newImg", src)
cv.waitKey(0)
cv.destroyAllWindows()
注意看感兴趣区域的那块颜色,成了灰色区域,然后这块区域cv.COLOR_BGR2GRAY灰色区域是单通道,要还原到原图,原图是三通道,所以需要cv.COLOR_GRAY2BGR转成三通道。
剪切区域
#剪切指定区域块到指定位置
def clipImg(imgarr):
src = imgarr[10:150, 200:380]
cv.imshow("clip", src)
imgarr[110:250, 300:480] = src #截取的块放入到指定位置,形状保持一样
cv.imshow("merge", imgarr)
imgarr = cv.imread("hi.jpg")
cv.imshow("orginal", imgarr)
clipImg(imgarr)
cv.waitKey(0)
orig("hi.jpg")
裁剪出来的区域,放入到原图中合并时,也需要保持大小一样,一个萝卜一个坑,不然形状转换就会报错。
泛洪填充
泛洪填充也叫漫水填充
FLOODFILL_FIXED_RANGE
import cv2 as cv
import numpy as np
def fillColor(image):
copyImg = image.copy()
h, w = image.shape[:2]
mask = np.zeros([h+2, w+2], image.dtype)
#图片、掩码、种子点、填充颜色、低于种子点的颜色范围、高于种子点的颜色范围、填充方法
cv.floodFill(copyImg, mask, (200, 10), (0, 0, 255), (100, 100, 100), (50, 50, 50), cv.FLOODFILL_FIXED_RANGE)
cv.imshow("fillcolor", copyImg)
cv.waitKey()
src = cv.imread("hi.jpg")
fillColor(src)
FLOODFILL_MASK_ONLY
def fillBinary(image):
image[100:300,100:300,:]=255
cv.imshow("fillbinary",image)
h,w=image.shape[:2]
mask=np.ones([h+2,w+2,1],np.uint8)
mask[101:301,101:301]=0 #为1不填充,为0才进行填充
#将这块mask进行填充
cv.floodFill(image,mask,(100,100),(0,255,0),cv.FLOODFILL_MASK_ONLY)
cv.imshow("filledbinary1",image)
cv.waitKey()
src = cv.imread("hi.jpg")
fillBinary(src)
FLOODFILL_FIXED_RANGE:改变图像,泛洪填充
FLOODFILL_MASK_ONLY:不会改变图像,只填充mask遮罩层本身
其中关键点就是选择一个种子点seedPoint,然后把邻近区域所有相似点填充上相同的颜色。
另外需要注意的就是cv出来的通道是BGR,平时看到的是RGB通道。