detect_face_v2.m 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288
  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_v2(img,minsize,PNet,RNet,ONet,LNet,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. bbw=total_boxes(:,3)-total_boxes(:,1);
  72. bbh=total_boxes(:,4)-total_boxes(:,2);
  73. total_boxes=[total_boxes(:,1)+total_boxes(:,6).*bbw total_boxes(:,2)+total_boxes(:,7).*bbh total_boxes(:,3)+total_boxes(:,8).*bbw total_boxes(:,4)+total_boxes(:,9).*bbh 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. tempimg(:,:,:,k)=imResample(tmp,[24 24],'bilinear');
  86. end
  87. tempimg=(tempimg-127.5)*0.0078125;
  88. RNet.blobs('data').reshape([24 24 3 numbox]);
  89. out=RNet.forward({tempimg});
  90. score=squeeze(out{2}(2,:));
  91. pass=find(score>threshold(2));
  92. total_boxes=[total_boxes(pass,1:4) score(pass)'];
  93. mv=out{1}(:,pass);
  94. if size(total_boxes,1)>0
  95. pick=nms(total_boxes,0.7,'Union');
  96. total_boxes=total_boxes(pick,:);
  97. total_boxes=bbreg(total_boxes,mv(:,pick)');
  98. total_boxes=rerec(total_boxes);
  99. end
  100. numbox=size(total_boxes,1);
  101. if numbox>0
  102. %third stage
  103. total_boxes=fix(total_boxes);
  104. [dy edy dx edx y ey x ex tmpw tmph]=pad(total_boxes,w,h);
  105. tempimg=zeros(48,48,3,numbox);
  106. for k=1:numbox
  107. tmp=zeros(tmph(k),tmpw(k),3);
  108. tmp(dy(k):edy(k),dx(k):edx(k),:)=img(y(k):ey(k),x(k):ex(k),:);
  109. tempimg(:,:,:,k)=imResample(tmp,[48 48],'bilinear');
  110. end
  111. tempimg=(tempimg-127.5)*0.0078125;
  112. ONet.blobs('data').reshape([48 48 3 numbox]);
  113. out=ONet.forward({tempimg});
  114. score=squeeze(out{3}(2,:));
  115. points=out{2};
  116. pass=find(score>threshold(3));
  117. points=points(:,pass);
  118. total_boxes=[total_boxes(pass,1:4) score(pass)'];
  119. mv=out{1}(:,pass);
  120. bbw=total_boxes(:,3)-total_boxes(:,1)+1;
  121. bbh=total_boxes(:,4)-total_boxes(:,2)+1;
  122. points(1:5,:)=repmat(bbw',[5 1]).*points(1:5,:)+repmat(total_boxes(:,1)',[5 1])-1;
  123. points(6:10,:)=repmat(bbh',[5 1]).*points(6:10,:)+repmat(total_boxes(:,2)',[5 1])-1;
  124. if size(total_boxes,1)>0
  125. total_boxes=bbreg(total_boxes,mv(:,:)');
  126. pick=nms(total_boxes,0.7,'Min');
  127. total_boxes=total_boxes(pick,:);
  128. points=points(:,pick);
  129. end
  130. end
  131. numbox=size(total_boxes,1);
  132. %extended stage
  133. if numbox>0
  134. tempimg=zeros(24,24,15,numbox);
  135. patchw=max([total_boxes(:,3)-total_boxes(:,1)+1 total_boxes(:,4)-total_boxes(:,2)+1]');
  136. patchw=fix(0.25*patchw);
  137. tmp=find(mod(patchw,2)==1);
  138. patchw(tmp)=patchw(tmp)+1;
  139. pointx=ones(numbox,5);
  140. pointy=ones(numbox,5);
  141. for k=1:5
  142. tmp=[points(k,:);points(k+5,:)];
  143. x=fix(tmp(1,:)-0.5*patchw);
  144. y=fix(tmp(2,:)-0.5*patchw);
  145. [dy edy dx edx y ey x ex tmpw tmph]=pad([x' y' x'+patchw' y'+patchw'],w,h);
  146. for j=1:numbox
  147. tmpim=zeros(tmpw(j),tmpw(j),3);
  148. tmpim(dy(j):edy(j),dx(j):edx(j),:)=img(y(j):ey(j),x(j):ex(j),:);
  149. tempimg(:,:,(k-1)*3+1:(k-1)*3+3,j)=imResample(tmpim,[24 24],'bilinear');
  150. end
  151. end
  152. LNet.blobs('data').reshape([24 24 15 numbox]);
  153. tempimg=(tempimg-127.5)*0.0078125;
  154. out=LNet.forward({tempimg});
  155. score=squeeze(out{3}(2,:));
  156. for k=1:5
  157. tmp=[points(k,:);points(k+5,:)];
  158. %do not make a large movement
  159. temp=find(abs(out{k}(1,:)-0.5)>0.35);
  160. if ~isempty(temp)
  161. l=length(temp);
  162. out{k}(:,temp)=ones(2,l)*0.5;
  163. end
  164. temp=find(abs(out{k}(2,:)-0.5)>0.35);
  165. if ~isempty(temp)
  166. l=length(temp);
  167. out{k}(:,temp)=ones(2,l)*0.5;
  168. end
  169. pointx(:,k)=(tmp(1,:)-0.5*patchw+out{k}(1,:).*patchw)';
  170. pointy(:,k)=(tmp(2,:)-0.5*patchw+out{k}(2,:).*patchw)';
  171. end
  172. for j=1:numbox
  173. points(:,j)=[pointx(j,:)';pointy(j,:)'];
  174. end
  175. end
  176. end
  177. end
  178. function [boundingbox] = bbreg(boundingbox,reg)
  179. %calibrate bouding boxes
  180. if size(reg,2)==1
  181. reg=reshape(reg,[size(reg,3) size(reg,4)])';
  182. end
  183. w=[boundingbox(:,3)-boundingbox(:,1)]+1;
  184. h=[boundingbox(:,4)-boundingbox(:,2)]+1;
  185. boundingbox(:,1:4)=[boundingbox(:,1)+reg(:,1).*w boundingbox(:,2)+reg(:,2).*h boundingbox(:,3)+reg(:,3).*w boundingbox(:,4)+reg(:,4).*h];
  186. end
  187. function [boundingbox reg] = generateBoundingBox(map,reg,scale,t)
  188. %use heatmap to generate bounding boxes
  189. stride=2;
  190. cellsize=12;
  191. boundingbox=[];
  192. map=map';
  193. dx1=reg(:,:,1)';
  194. dy1=reg(:,:,2)';
  195. dx2=reg(:,:,3)';
  196. dy2=reg(:,:,4)';
  197. [y x]=find(map>=t);
  198. a=find(map>=t);
  199. if size(y,1)==1
  200. y=y';x=x';score=map(a)';dx1=dx1';dy1=dy1';dx2=dx2';dy2=dy2';
  201. else
  202. score=map(a);
  203. end
  204. reg=[dx1(a) dy1(a) dx2(a) dy2(a)];
  205. if isempty(reg)
  206. reg=reshape([],[0 3]);
  207. end
  208. boundingbox=[y x];
  209. boundingbox=[fix((stride*(boundingbox-1)+1)/scale) fix((stride*(boundingbox-1)+cellsize-1+1)/scale) score reg];
  210. end
  211. function pick = nms(boxes,threshold,type)
  212. %NMS
  213. if isempty(boxes)
  214. pick = [];
  215. return;
  216. end
  217. x1 = boxes(:,1);
  218. y1 = boxes(:,2);
  219. x2 = boxes(:,3);
  220. y2 = boxes(:,4);
  221. s = boxes(:,5);
  222. area = (x2-x1+1) .* (y2-y1+1);
  223. [vals, I] = sort(s);
  224. pick = s*0;
  225. counter = 1;
  226. while ~isempty(I)
  227. last = length(I);
  228. i = I(last);
  229. pick(counter) = i;
  230. counter = counter + 1;
  231. xx1 = max(x1(i), x1(I(1:last-1)));
  232. yy1 = max(y1(i), y1(I(1:last-1)));
  233. xx2 = min(x2(i), x2(I(1:last-1)));
  234. yy2 = min(y2(i), y2(I(1:last-1)));
  235. w = max(0.0, xx2-xx1+1);
  236. h = max(0.0, yy2-yy1+1);
  237. inter = w.*h;
  238. if strcmp(type,'Min')
  239. o = inter ./ min(area(i),area(I(1:last-1)));
  240. else
  241. o = inter ./ (area(i) + area(I(1:last-1)) - inter);
  242. end
  243. I = I(find(o<=threshold));
  244. end
  245. pick = pick(1:(counter-1));
  246. end
  247. function [dy edy dx edx y ey x ex tmpw tmph] = pad(total_boxes,w,h)
  248. %compute the padding coordinates (pad the bounding boxes to square)
  249. tmpw=total_boxes(:,3)-total_boxes(:,1)+1;
  250. tmph=total_boxes(:,4)-total_boxes(:,2)+1;
  251. numbox=size(total_boxes,1);
  252. dx=ones(numbox,1);dy=ones(numbox,1);
  253. edx=tmpw;edy=tmph;
  254. x=total_boxes(:,1);y=total_boxes(:,2);
  255. ex=total_boxes(:,3);ey=total_boxes(:,4);
  256. tmp=find(ex>w);
  257. edx(tmp)=-ex(tmp)+w+tmpw(tmp);ex(tmp)=w;
  258. tmp=find(ey>h);
  259. edy(tmp)=-ey(tmp)+h+tmph(tmp);ey(tmp)=h;
  260. tmp=find(x<1);
  261. dx(tmp)=2-x(tmp);x(tmp)=1;
  262. tmp=find(y<1);
  263. dy(tmp)=2-y(tmp);y(tmp)=1;
  264. end
  265. function [bboxA] = rerec(bboxA)
  266. %convert bboxA to square
  267. bboxB=bboxA(:,1:4);
  268. h=bboxA(:,4)-bboxA(:,2);
  269. w=bboxA(:,3)-bboxA(:,1);
  270. l=max([w h]')';
  271. bboxA(:,1)=bboxA(:,1)+w.*0.5-l.*0.5;
  272. bboxA(:,2)=bboxA(:,2)+h.*0.5-l.*0.5;
  273. bboxA(:,3:4)=bboxA(:,1:2)+repmat(l,[1 2]);
  274. end