MTCNN中生成positive,negative,part样本python代码解读

最近跑通了MTCNN的训练代码,对其中生成positive,negative,part样本gen_48net_data2.py代码进行解读。

项目地址:https://github.com/dlunion/mtcnn

对应代码地址:https://github.com/dlunion/mtcnn/blob/master/train/gen_48net_data2.py



   
   
  1. import sys
  2. sys.path.append( ‘D:\\Anaconda2\\libs’) # 在windows系统上,导入python库目录
  3. import numpy as np
  4. import cv2
  5. import os
  6. import numpy.random as npr
  7. from utils import IoU
  8. # stdsize:随机crop的窗口大小,positive,negative,part样本都对应此大小
  9. stdsize = 48
  10. anno_file = “E:/face_alignment/data/CelebA/Anno/mtcnn_train_label_2.txt”
  11. im_dir = “E:/face_alignment/data/CelebA/Img/img_celeba.7z/img_celeba/”
  12. pos_save_dir = str(stdsize) + “/positive”
  13. part_save_dir = str(stdsize) + “/part”
  14. neg_save_dir = str(stdsize) + ‘/negative’
  15. save_dir = “./” + str(stdsize)
  16. # 生成文件夹函数
  17. def mkr(dr):
  18. if not os.path.exists(dr):
  19. os.mkdir(dr)
  20. mkr(save_dir)
  21. mkr(pos_save_dir)
  22. mkr(part_save_dir)
  23. mkr(neg_save_dir)
  24. # 打开保存pos,neg,part文件名、标签的txt文件,这三个是生成文件
  25. f1 = open(os.path.join(save_dir, ‘pos_’ + str(stdsize) + ‘.txt’), ‘w’)
  26. f2 = open(os.path.join(save_dir, ‘neg_’ + str(stdsize) + ‘.txt’), ‘w’)
  27. f3 = open(os.path.join(save_dir, ‘part_’ + str(stdsize) + ‘.txt’), ‘w’)
  28. # 打开原始图片标注txt文件
  29. with open(anno_file, ‘r’) as f:
  30. annotations = f.readlines()
  31. num = len(annotations)
  32. print “%d pics in total” % num
  33. p_idx = 0 # positive
  34. n_idx = 0 # negative
  35. d_idx = 0 # part
  36. idx = 0
  37. box_idx = 0
  38. # 原始图片根据标注的bbox,生成negative,posotive,part图片,标注形式也做相应变化
  39. for annotation in annotations: #逐行读取,按作者的方式,每行为一个原图
  40. annotation = annotation.strip().split( ’ ‘) #对读取的每一行,按空格进行切片
  41. im_path = annotation[ 0] # 第1个为图片名
  42. bbox = map(float, annotation[ 1: -10]) #第2个~~倒数第11个为bbox
  43. # pts = map(float, annotation[5:])
  44. pts = map(float, annotation[ -10:]) #倒数第10个~~倒数第1个为landmark
  45. # 对bbox进行reshape,4个一列
  46. boxes = np.array(bbox, dtype=np.float32).reshape( -1, 4)
  47. im_path = im_dir + im_path #图片地址拼接
  48. img = cv2.imread(im_path) #读取图片
  49. idx += 1
  50. if idx % 100 == 0:
  51. print idx, “images done”
  52. height, width, channel = img.shape
  53. neg_num = 0
  54. # 生成nagative,每个原图生成100个negative sample
  55. while neg_num < 100:
  56. # size表示neg样本大小,在40和min(width, height)/2之间随机取一个整数
  57. size = npr.randint( 40, min(width, height) / 2)
  58. # neg的左上角坐标(x1,y1),在0和(width - size)之间随机取一个整数
  59. nx = npr.randint( 0, width - size)
  60. ny = npr.randint( 0, height - size)
  61. # 随机生成的bbox位置(x1,y1),(x2,y2)
  62. crop_box = np.array([nx, ny, nx + size, ny + size])
  63. # 计算随机生成的bbox和原图中所有标注bboxs的交并比
  64. Iou = IoU(crop_box, boxes)
  65. # 在原图中crop对应的区域图片,作为negative sample
  66. cropped_im = img[ny : ny + size, nx : nx + size, :]
  67. # 对crop的图像进行resize,大小为stdsize*stdsize
  68. resized_im = cv2.resize(cropped_im, (stdsize, stdsize), interpolation=cv2.INTER_LINEAR)
  69. # 如果crop_box与所有boxes的Iou都小于0.3,那么认为它是nagative sample
  70. if np.max(Iou) < 0.3:
  71. # Iou with all gts must below 0.3
  72. # 保存图片的地址和图片名
  73. save_file = os.path.join(neg_save_dir, “%s.jpg”%n_idx)
  74. # 往neg_48.txt文件中写入该negative样本的图片地址和名字,分类标签
  75. f2.write(str(stdsize)+ “/negative/%s”%n_idx + ’ 0\n’)
  76. # 保存该负样本图片
  77. cv2.imwrite(save_file, resized_im)
  78. n_idx += 1
  79. neg_num += 1
  80. backupPts = pts[:] # 该列表用于landmark
  81. for box in boxes: #逐行读取,每次循环处理一个box
  82. # box (x_left, y_top, x_right, y_bottom)
  83. x1, y1, x2, y2 = box
  84. w = x2 - x1 + 1
  85. h = y2 - y1 + 1
  86. # 忽略小脸
  87. # in case the ground truth boxes of small faces are not accurate
  88. if max(w, h) < 12 or x1 < 0 or y1 < 0:
  89. continue
  90. # 生成 positive examples and part faces
  91. # 每个box随机生成50个box,Iou>=0.65的作为positive examples,0.4<=Iou<0.65的作为part faces,其他忽略
  92. for i in range( 50):
  93. pts = backupPts[:]
  94. # size表示随机生成样本的大小,在int(min(w, h) * 0.8) 和 np.ceil(1.25 * max(w, h)) 之间
  95. size = npr.randint(int(min(w, h) * 0.8), np.ceil( 1.25 * max(w, h)))
  96. # delta 表示相对于标注box center的偏移量
  97. delta_x = npr.randint(-w * 0.2, w * 0.2)
  98. delta_y = npr.randint(-h * 0.2, h * 0.2)
  99. # nx,ny表示偏移后的box坐标位置
  100. nx1 = max(x1 + w / 2 + delta_x - size / 2, 0)
  101. ny1 = max(y1 + h / 2 + delta_y - size / 2, 0)
  102. nx2 = nx1 + size
  103. ny2 = ny1 + size
  104. # 去掉超出原图的box
  105. if nx2 > width or ny2 > height:
  106. continue
  107. crop_box = np.array([nx1, ny1, nx2, ny2])
  108. #bbox偏移量的计算,由 x1 = nx1 + float(size)*offset_x1 推导而来,可以参考bounding box regression博客
  109. offset_x1 = (x1 - nx1) / float(size)
  110. offset_y1 = (y1 - ny1) / float(size)
  111. offset_x2 = (x2 - nx1) / float(size)
  112. offset_y2 = (y2 - ny1) / float(size)
  113. # landmark偏移量的计算,即landmark相对于随机生成bbox的归一化相对位置。
  114. for k in range(len(pts) / 2):
  115. pts[k* 2] = (pts[k* 2] - nx1) / float(size);
  116. pts[k* 2+ 1] = (pts[k* 2+ 1] - ny1) / float(size);
  117. cropped_im = img[int(ny1) : int(ny2), int(nx1) : int(nx2), :]
  118. resized_im = cv2.resize(cropped_im, (stdsize, stdsize), interpolation=cv2.INTER_LINEAR)
  119. # 将box reshape为一行
  120. box_ = box.reshape( 1, -1)
  121. # Iou>=0.65的作为positive examples
  122. if IoU(crop_box, box_) >= 0.65:
  123. save_file = os.path.join(pos_save_dir, “%s.jpg”%p_idx)
  124. # 将图片路径,类别,偏移量写入到positive_48.txt文件中
  125. f1.write(str(stdsize)+ “/positive/%s”%p_idx + ’ 1 %f %f %f %f’%(offset_x1, offset_y1, offset_x2, offset_y2))
  126. # 将landmark写入到positive_48.txt文件中
  127. for k in range(len(pts)):
  128. f1.write( ” %f” % pts[k])
  129. f1.write( “\n”)
  130. cv2.imwrite(save_file, resized_im)
  131. p_idx += 1
  132. # 0.4<=Iou<0.65的作为part faces
  133. elif IoU(crop_box, box_) >= 0.4:
  134. save_file = os.path.join(part_save_dir, “%s.jpg”%d_idx)
  135. f3.write(str(stdsize)+ “/part/%s”%d_idx + ’ -1 %f %f %f %f’%(offset_x1, offset_y1, offset_x2, offset_y2))
  136. for k in range(len(pts)):
  137. f3.write( ” %f” % pts[k])
  138. f3.write( “\n”)
  139. cv2.imwrite(save_file, resized_im)
  140. d_idx += 1
  141. box_idx += 1
  142. print “%s images done, pos: %s part: %s neg: %s”%(idx, p_idx, d_idx, n_idx)
  143. f1.close()
  144. f2.close()
  145. f3.close()


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值