detect_face_v1.m 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. % MIT License
  2. %
  3. % Copyright (c) 2016 Kaipeng Zhang
  4. %
  5. % Permission is hereby granted, free of charge, to any person obtaining a copy
  6. % of this software and associated documentation files (the "Software"), to deal
  7. % in the Software without restriction, including without limitation the rights
  8. % to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. % copies of the Software, and to permit persons to whom the Software is
  10. % furnished to do so, subject to the following conditions:
  11. %
  12. % The above copyright notice and this permission notice shall be included in all
  13. % copies or substantial portions of the Software.
  14. %
  15. % THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. % IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. % FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. % AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. % LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. % OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. % SOFTWARE.
  22. function [total_boxes, points] = detect_face_v1(img,minsize,PNet,RNet,ONet,threshold,fastresize,factor)
  23. %im: input image
  24. %minsize: minimum of faces' size
  25. %pnet, rnet, onet: caffemodel
  26. %threshold: threshold=[th1 th2 th3], th1-3 are three steps's threshold
  27. %fastresize: resize img from last scale (using in high-resolution images) if fastresize==true
  28. factor_count=0;
  29. total_boxes=[];
  30. points=[];
  31. h=size(img,1);
  32. w=size(img,2);
  33. minl=min([w h]);
  34. img=single(img);
  35. if fastresize
  36. im_data=(single(img)-127.5)*0.0078125;
  37. end
  38. m=12/minsize;
  39. minl=minl*m;
  40. %creat scale pyramid
  41. scales=[];
  42. while (minl>=12)
  43. scales=[scales m*factor^(factor_count)];
  44. minl=minl*factor;
  45. factor_count=factor_count+1;
  46. end
  47. %first stage
  48. for j = 1:size(scales,2)
  49. scale=scales(j);
  50. hs=ceil(h*scale);
  51. ws=ceil(w*scale);
  52. if fastresize
  53. im_data=imResample(im_data,[hs ws],'bilinear');
  54. else
  55. im_data=(imResample(img,[hs ws],'bilinear')-127.5)*0.0078125;
  56. end
  57. PNet.blobs('data').reshape([hs ws 3 1]);
  58. out=PNet.forward({im_data});
  59. boxes=generateBoundingBox(out{2}(:,:,2),out{1},scale,threshold(1));
  60. %inter-scale nms
  61. pick=nms(boxes,0.5,'Union');
  62. boxes=boxes(pick,:);
  63. if ~isempty(boxes)
  64. total_boxes=[total_boxes;boxes];
  65. end
  66. end
  67. numbox=size(total_boxes,1);
  68. if ~isempty(total_boxes)
  69. pick=nms(total_boxes,0.7,'Union');
  70. total_boxes=total_boxes(pick,:);
  71. regw=total_boxes(:,3)-total_boxes(:,1);
  72. regh=total_boxes(:,4)-total_boxes(:,2);
  73. total_boxes=[total_boxes(:,1)+total_boxes(:,6).*regw total_boxes(:,2)+total_boxes(:,7).*regh total_boxes(:,3)+total_boxes(:,8).*regw total_boxes(:,4)+total_boxes(:,9).*regh total_boxes(:,5)];
  74. total_boxes=rerec(total_boxes);
  75. total_boxes(:,1:4)=fix(total_boxes(:,1:4));
  76. [dy edy dx edx y ey x ex tmpw tmph]=pad(total_boxes,w,h);
  77. end
  78. numbox=size(total_boxes,1);
  79. if numbox>0
  80. %second stage
  81. tempimg=zeros(24,24,3,numbox);
  82. for k=1:numbox
  83. tmp=zeros(tmph(k),tmpw(k),3);
  84. tmp(dy(k):edy(k),dx(k):edx(k),:)=img(y(k):ey(k),x(k):ex(k),:);
  85. if size(tmp,1)>0 && size(tmp,2)>0 || size(tmp,1)==0 && size(tmp,2)==0
  86. tempimg(:,:,:,k)=imResample(tmp,[24 24],'bilinear');
  87. else
  88. total_boxes = [];
  89. return;
  90. end;
  91. end
  92. tempimg=(tempimg-127.5)*0.0078125;
  93. RNet.blobs('data').reshape([24 24 3 numbox]);
  94. out=RNet.forward({tempimg});
  95. score=squeeze(out{2}(2,:));
  96. pass=find(score>threshold(2));
  97. total_boxes=[total_boxes(pass,1:4) score(pass)'];
  98. mv=out{1}(:,pass);
  99. if size(total_boxes,1)>0
  100. pick=nms(total_boxes,0.7,'Union');
  101. total_boxes=total_boxes(pick,:);
  102. total_boxes=bbreg(total_boxes,mv(:,pick)');
  103. total_boxes=rerec(total_boxes);
  104. end
  105. numbox=size(total_boxes,1);
  106. if numbox>0
  107. %third stage
  108. total_boxes=fix(total_boxes);
  109. [dy edy dx edx y ey x ex tmpw tmph]=pad(total_boxes,w,h);
  110. tempimg=zeros(48,48,3,numbox);
  111. for k=1:numbox
  112. tmp=zeros(tmph(k),tmpw(k),3);
  113. tmp(dy(k):edy(k),dx(k):edx(k),:)=img(y(k):ey(k),x(k):ex(k),:);
  114. if size(tmp,1)>0 && size(tmp,2)>0 || size(tmp,1)==0 && size(tmp,2)==0
  115. tempimg(:,:,:,k)=imResample(tmp,[48 48],'bilinear');
  116. else
  117. total_boxes = [];
  118. return;
  119. end;
  120. end
  121. tempimg=(tempimg-127.5)*0.0078125;
  122. ONet.blobs('data').reshape([48 48 3 numbox]);
  123. out=ONet.forward({tempimg});
  124. score=squeeze(out{3}(2,:));
  125. points=out{2};
  126. pass=find(score>threshold(3));
  127. points=points(:,pass);
  128. total_boxes=[total_boxes(pass,1:4) score(pass)'];
  129. mv=out{1}(:,pass);
  130. w=total_boxes(:,3)-total_boxes(:,1)+1;
  131. h=total_boxes(:,4)-total_boxes(:,2)+1;
  132. points(1:5,:)=repmat(w',[5 1]).*points(1:5,:)+repmat(total_boxes(:,1)',[5 1])-1;
  133. points(6:10,:)=repmat(h',[5 1]).*points(6:10,:)+repmat(total_boxes(:,2)',[5 1])-1;
  134. if size(total_boxes,1)>0
  135. total_boxes=bbreg(total_boxes,mv(:,:)');
  136. pick=nms(total_boxes,0.7,'Min');
  137. total_boxes=total_boxes(pick,:);
  138. points=points(:,pick);
  139. end
  140. end
  141. end
  142. end
  143. function [boundingbox] = bbreg(boundingbox,reg)
  144. %calibrate bouding boxes
  145. if size(reg,2)==1
  146. reg=reshape(reg,[size(reg,3) size(reg,4)])';
  147. end
  148. w=[boundingbox(:,3)-boundingbox(:,1)]+1;
  149. h=[boundingbox(:,4)-boundingbox(:,2)]+1;
  150. boundingbox(:,1:4)=[boundingbox(:,1)+reg(:,1).*w boundingbox(:,2)+reg(:,2).*h boundingbox(:,3)+reg(:,3).*w boundingbox(:,4)+reg(:,4).*h];
  151. end
  152. function [boundingbox reg] = generateBoundingBox(map,reg,scale,t)
  153. %use heatmap to generate bounding boxes
  154. stride=2;
  155. cellsize=12;
  156. boundingbox=[];
  157. map=map';
  158. dx1=reg(:,:,1)';
  159. dy1=reg(:,:,2)';
  160. dx2=reg(:,:,3)';
  161. dy2=reg(:,:,4)';
  162. [y x]=find(map>=t);
  163. a=find(map>=t);
  164. if size(y,1)==1
  165. y=y';x=x';score=map(a)';dx1=dx1';dy1=dy1';dx2=dx2';dy2=dy2';
  166. else
  167. score=map(a);
  168. end
  169. reg=[dx1(a) dy1(a) dx2(a) dy2(a)];
  170. if isempty(reg)
  171. reg=reshape([],[0 3]);
  172. end
  173. boundingbox=[y x];
  174. boundingbox=[fix((stride*(boundingbox-1)+1)/scale) fix((stride*(boundingbox-1)+cellsize-1+1)/scale) score reg];
  175. end
  176. function pick = nms(boxes,threshold,type)
  177. %NMS
  178. if isempty(boxes)
  179. pick = [];
  180. return;
  181. end
  182. x1 = boxes(:,1);
  183. y1 = boxes(:,2);
  184. x2 = boxes(:,3);
  185. y2 = boxes(:,4);
  186. s = boxes(:,5);
  187. area = (x2-x1+1) .* (y2-y1+1);
  188. [vals, I] = sort(s);
  189. pick = s*0;
  190. counter = 1;
  191. while ~isempty(I)
  192. last = length(I);
  193. i = I(last);
  194. pick(counter) = i;
  195. counter = counter + 1;
  196. xx1 = max(x1(i), x1(I(1:last-1)));
  197. yy1 = max(y1(i), y1(I(1:last-1)));
  198. xx2 = min(x2(i), x2(I(1:last-1)));
  199. yy2 = min(y2(i), y2(I(1:last-1)));
  200. w = max(0.0, xx2-xx1+1);
  201. h = max(0.0, yy2-yy1+1);
  202. inter = w.*h;
  203. if strcmp(type,'Min')
  204. o = inter ./ min(area(i),area(I(1:last-1)));
  205. else
  206. o = inter ./ (area(i) + area(I(1:last-1)) - inter);
  207. end
  208. I = I(find(o<=threshold));
  209. end
  210. pick = pick(1:(counter-1));
  211. end
  212. function [dy edy dx edx y ey x ex tmpw tmph] = pad(total_boxes,w,h)
  213. %compute the padding coordinates (pad the bounding boxes to square)
  214. tmpw=total_boxes(:,3)-total_boxes(:,1)+1;
  215. tmph=total_boxes(:,4)-total_boxes(:,2)+1;
  216. numbox=size(total_boxes,1);
  217. dx=ones(numbox,1);dy=ones(numbox,1);
  218. edx=tmpw;edy=tmph;
  219. x=total_boxes(:,1);y=total_boxes(:,2);
  220. ex=total_boxes(:,3);ey=total_boxes(:,4);
  221. tmp=find(ex>w);
  222. edx(tmp)=-ex(tmp)+w+tmpw(tmp);ex(tmp)=w;
  223. tmp=find(ey>h);
  224. edy(tmp)=-ey(tmp)+h+tmph(tmp);ey(tmp)=h;
  225. tmp=find(x<1);
  226. dx(tmp)=2-x(tmp);x(tmp)=1;
  227. tmp=find(y<1);
  228. dy(tmp)=2-y(tmp);y(tmp)=1;
  229. end
  230. function [bboxA] = rerec(bboxA)
  231. %convert bboxA to square
  232. bboxB=bboxA(:,1:4);
  233. h=bboxA(:,4)-bboxA(:,2);
  234. w=bboxA(:,3)-bboxA(:,1);
  235. l=max([w h]')';
  236. bboxA(:,1)=bboxA(:,1)+w.*0.5-l.*0.5;
  237. bboxA(:,2)=bboxA(:,2)+h.*0.5-l.*0.5;
  238. bboxA(:,3:4)=bboxA(:,1:2)+repmat(l,[1 2]);
  239. end