crop_face.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #!/usr/bin/env python
  2. # Software License Agreement (BSD License)
  3. #
  4. # Copyright (c) 2012, Philipp Wagner
  5. # All rights reserved.
  6. #
  7. # Redistribution and use in source and binary forms, with or without
  8. # modification, are permitted provided that the following conditions
  9. # are met:
  10. #
  11. # * Redistributions of source code must retain the above copyright
  12. # notice, this list of conditions and the following disclaimer.
  13. # * Redistributions in binary form must reproduce the above
  14. # copyright notice, this list of conditions and the following
  15. # disclaimer in the documentation and/or other materials provided
  16. # with the distribution.
  17. # * Neither the name of the author nor the names of its
  18. # contributors may be used to endorse or promote products derived
  19. # from this software without specific prior written permission.
  20. #
  21. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  22. # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  23. # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  24. # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  25. # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  26. # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  27. # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  28. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  29. # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  30. # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  31. # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  32. # POSSIBILITY OF SUCH DAMAGE.
  33. import sys, math, Image
  34. def Distance(p1,p2):
  35. dx = p2[0] - p1[0]
  36. dy = p2[1] - p1[1]
  37. return math.sqrt(dx*dx+dy*dy)
  38. def ScaleRotateTranslate(image, angle, center = None, new_center = None, scale = None, resample=Image.BICUBIC):
  39. if (scale is None) and (center is None):
  40. return image.rotate(angle=angle, resample=resample)
  41. nx,ny = x,y = center
  42. sx=sy=1.0
  43. if new_center:
  44. (nx,ny) = new_center
  45. if scale:
  46. (sx,sy) = (scale, scale)
  47. cosine = math.cos(angle)
  48. sine = math.sin(angle)
  49. a = cosine/sx
  50. b = sine/sx
  51. c = x-nx*a-ny*b
  52. d = -sine/sy
  53. e = cosine/sy
  54. f = y-nx*d-ny*e
  55. return image.transform(image.size, Image.AFFINE, (a,b,c,d,e,f), resample=resample)
  56. def CropFace(image, eye_left=(0,0), eye_right=(0,0), offset_pct=(0.2,0.2), dest_sz = (70,70)):
  57. # calculate offsets in original image
  58. offset_h = math.floor(float(offset_pct[0])*dest_sz[0])
  59. offset_v = math.floor(float(offset_pct[1])*dest_sz[1])
  60. # get the direction
  61. eye_direction = (eye_right[0] - eye_left[0], eye_right[1] - eye_left[1])
  62. # calc rotation angle in radians
  63. rotation = -math.atan2(float(eye_direction[1]),float(eye_direction[0]))
  64. # distance between them
  65. dist = Distance(eye_left, eye_right)
  66. # calculate the reference eye-width
  67. reference = dest_sz[0] - 2.0*offset_h
  68. # scale factor
  69. scale = float(dist)/float(reference)
  70. # rotate original around the left eye
  71. image = ScaleRotateTranslate(image, center=eye_left, angle=rotation)
  72. # crop the rotated image
  73. crop_xy = (eye_left[0] - scale*offset_h, eye_left[1] - scale*offset_v)
  74. crop_size = (dest_sz[0]*scale, dest_sz[1]*scale)
  75. image = image.crop((int(crop_xy[0]), int(crop_xy[1]), int(crop_xy[0]+crop_size[0]), int(crop_xy[1]+crop_size[1])))
  76. # resize it
  77. image = image.resize(dest_sz, Image.ANTIALIAS)
  78. return image
  79. def readFileNames():
  80. try:
  81. inFile = open('path_to_created_csv_file.csv')
  82. except:
  83. raise IOError('There is no file named path_to_created_csv_file.csv in current directory.')
  84. return False
  85. picPath = []
  86. picIndex = []
  87. for line in inFile.readlines():
  88. if line != '':
  89. fields = line.rstrip().split(';')
  90. picPath.append(fields[0])
  91. picIndex.append(int(fields[1]))
  92. return (picPath, picIndex)
  93. if __name__ == "__main__":
  94. [images, indexes]=readFileNames()
  95. if not os.path.exists("modified"):
  96. os.makedirs("modified")
  97. for img in images:
  98. image = Image.open(img)
  99. CropFace(image, eye_left=(252,364), eye_right=(420,366), offset_pct=(0.1,0.1), dest_sz=(200,200)).save("modified/"+img.rstrip().split('/')[1]+"_10_10_200_200.jpg")
  100. CropFace(image, eye_left=(252,364), eye_right=(420,366), offset_pct=(0.2,0.2), dest_sz=(200,200)).save("modified/"+img.rstrip().split('/')[1]+"_20_20_200_200.jpg")
  101. CropFace(image, eye_left=(252,364), eye_right=(420,366), offset_pct=(0.3,0.3), dest_sz=(200,200)).save("modified/"+img.rstrip().split('/')[1]+"_30_30_200_200.jpg")
  102. CropFace(image, eye_left=(252,364), eye_right=(420,366), offset_pct=(0.2,0.2)).save("modified/"+img.rstrip().split('/')[1]+"_20_20_70_70.jpg")