You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

243 lines
7.9KB

  1. import math
  2. import cv2
  3. import logging
  4. import numpy as np
  5. import random as rd
  6. NO_MOD = 0
  7. FACE_GLITCH = 1
  8. FACE_DRAG = 2
  9. EYE_CENSOR = 3
  10. EYE_DRAG = 4
  11. EYES = 100
  12. FACE = 101
  13. DEGREES_PER_RADIAN = 57.296
  14. TOP_LEFT = 0
  15. TOP_RIGHT = 1
  16. BOTTOM_RIGHT = 2
  17. BOTTOM_LEFT = 3
  18. logger = logging.getLogger("mods")
  19. def sort_corners(corners):
  20. corners = sorted(corners, key=lambda x: x[0])
  21. top_left, bottom_left = sorted(corners[0:2], key=lambda x: x[1])
  22. top_right, bottom_right = sorted(corners[2:4], key=lambda x: [1])
  23. return top_left, top_right, bottom_right, bottom_left
  24. def unit_vector(vector):
  25. return vector / np.linalg.norm(vector)
  26. def angle(first, second, to_degrees=True):
  27. unit_first = unit_vector(first)
  28. unit_second = unit_vector(second)
  29. radians = np.arccos(np.clip(np.dot(unit_first, unit_second), -1.0, 1.0))
  30. return radians * DEGREES_PER_RADIAN if to_degrees else radians
  31. # The following function is used to determine the placement of
  32. # text, at the moment it is incomplete
  33. # function takes corners and text
  34. # and resturns top left corner that
  35. # centers text and the angle needed
  36. def pos_and_angle(pts):
  37. # find left top most coordinate
  38. left_upper = pts[TOP_LEFT]
  39. right_upper = pts[TOP_RIGHT]
  40. vector = np.array(left_upper - right_upper)
  41. y_axis = np.array(np.array([0, 0]) - np.array([1, 0]))
  42. return left_upper, angle(vector, y_axis)
  43. def determine_face_mod(eyes_present):
  44. function_list = [
  45. (lambda x, y: x, FACE),
  46. (face_glitch, FACE),
  47. (face_drag, FACE),
  48. (eye_censor, EYES),
  49. (eye_drag, EYES)
  50. ]
  51. function_index = rd.randint(0, 4) if eyes_present else rd.randint(0, 2)
  52. return function_list[function_index]
  53. def eye_drag(img, eyes):
  54. # make sure there are only two eyes per face
  55. if len(eyes) > 2:
  56. eye1 = eyes[0]
  57. eye2 = eyes[0]
  58. size = 0
  59. for itr in range(0, len(eyes)):
  60. if eyes[itr][2] * eyes[itr][3] > size:
  61. size = eyes[itr][2] * eyes[itr][3]
  62. eye1 = eyes[itr]
  63. size = 0
  64. for itr in range(0, len(eyes)):
  65. if eyes[itr][2] * eyes[itr][3] > size and not np.array_equal(eyes[itr], eye1):
  66. size = eyes[itr][2] * eyes[itr][3]
  67. eye2 = eyes[itr]
  68. eyes = [eye1, eye2]
  69. # there should only be two eyes now
  70. for eye in eyes:
  71. # find width of eye
  72. iwid = eye[2]
  73. strp = int(round(iwid / 20.))
  74. num_glitches = int(eye[2] / strp)
  75. line = rd.randint(1, eye[3])
  76. line += eye[1]
  77. line = int(eye[1] + eye[3] / 2)
  78. for itr in range(0, num_glitches):
  79. # edit the second parameter to change eye drop chance
  80. drop = rd.randint(10, 200)
  81. # if the line drop is too low, shorten it
  82. if line + drop > img.shape[0]:
  83. drop = img.shape[0] - line
  84. img[line:line + drop, eye[0] + itr * strp:eye[0] + itr * strp + strp] = \
  85. img[line, eye[0] + itr * strp:eye[0] + itr * strp + strp]
  86. def eye_censor(img, eyes):
  87. if len(eyes) < 2:
  88. logger.warning("Failed to generate censor, less than two eyes present")
  89. return
  90. # cenH = 40
  91. # get centroids of eyes
  92. centroid_right = np.array([eyes[0][0] + eyes[0][2] / 2.0, eyes[0][1] + eyes[0][3] / 2.0])
  93. centroid_left = np.array([eyes[1][0] + eyes[1][2] / 2.0, eyes[1][1] + eyes[1][3] / 2.0])
  94. # find the corners of the bar
  95. # find vector of the two centroids
  96. vec = centroid_right - centroid_left
  97. # unitize vector
  98. vec = vec / (vec[0] ** 2.0 + vec[1] ** 2.0) ** 0.5
  99. # perpendicular vector
  100. per_vec = np.array([vec[1], vec[0] * (-1)])
  101. # change these value to adjust height and width of
  102. # censor bar
  103. w_ex = 40
  104. mag = 75
  105. right_upper = per_vec * w_ex + centroid_right
  106. right_lower = centroid_right - per_vec * w_ex
  107. left_upper = per_vec * w_ex + centroid_left
  108. left_lower = centroid_left - per_vec * w_ex
  109. right_upper += vec * mag
  110. right_lower += vec * mag
  111. left_upper -= vec * mag
  112. left_lower -= vec * mag
  113. # round all values
  114. corners = sort_corners([right_upper, right_lower, left_lower, left_upper])
  115. print(corners)
  116. cv2.fillPoly(img, np.array([corners], dtype=np.int32), (0, 0, 0))
  117. should_render_text = rd.randint(0, 2)
  118. if should_render_text:
  119. with open("elements/censor.txt", "r") as text_file:
  120. allText = text_file.read()
  121. possText = allText.split(";")
  122. dec = rd.randint(0, len(possText) - 1)
  123. text = possText[dec]
  124. # calculate text position and angle
  125. return render_text(text, corners, img)
  126. def render_text(text, corners, img):
  127. left_upper, right_upper, right_lower, left_lower = corners
  128. corner, rotation_angle = pos_and_angle(corners)
  129. text_image = np.ones(img.shape)
  130. text_img_rows, text_img_cols, _ = text_image.shape
  131. font = cv2.FONT_HERSHEY_SIMPLEX
  132. text_size = cv2.getTextSize(text, font, 1, 1)
  133. (text_width, text_height), _ = text_size
  134. text_corner_x = left_upper[0] + (right_upper[0] - left_upper[0]) / 2.0 - text_width / 2.0
  135. text_corner_y = left_upper[1] + (left_lower[1] - left_upper[1]) / 2.0 - text_height / 2.0
  136. corner_coords = (int(text_corner_x), int(text_corner_y))
  137. rotation_matrix = cv2.getRotationMatrix2D(corner_coords, rotation_angle, 1)
  138. cv2.putText(text_image, text, corner_coords, font, 1, (255, 255, 255), 2, cv2.LINE_AA)
  139. text_image = cv2.warpAffine(text_image, rotation_matrix, (text_img_cols, text_img_rows))
  140. img = text_image + img
  141. cv2.imshow("pic", img)
  142. return img
  143. def face_drag(img, face):
  144. h, w, d = img.shape
  145. # 0 is horizontal 1 is veritical
  146. ornt = rd.randint(0, 2)
  147. if ornt == 0:
  148. line = rd.randint(face[1] + 25, face[1] + face[3] - 25)
  149. # 0 is up 1 is down
  150. direction = rd.randint(0, 2)
  151. if direction == 0:
  152. img[0:line, face[0]:face[0] + face[2]] = img[line, face[0]:face[0] + face[2]]
  153. else:
  154. img[line:h, face[0]:face[0] + face[2]] = img[line, face[0]:face[0] + face[2]]
  155. else:
  156. line = rd.randint(face[0] + 25, face[0] + face[2] - 25)
  157. # 0 is left 1 is right
  158. direction = rd.randint(0, 2)
  159. if direction == 0:
  160. img[face[1]:face[1] + face[3], 0:line] = img[face[1]:face[1] + face[3], line:line + 1]
  161. else:
  162. img[face[1]:face[1] + face[3], line:w] = img[face[1]:face[1] + face[3], line:line + 1]
  163. def face_glitch(img, face):
  164. height, width, d = img.shape
  165. # pixels segments of 40
  166. div = rd.randint(10, 100)
  167. strp = int(round(face[3] / (div * 1.0)))
  168. num_glitches = face[3] / strp
  169. if type(num_glitches) == np.float64:
  170. num_glitches = math.floor(num_glitches)
  171. for itr in range(0, num_glitches):
  172. #set limits of y-axis
  173. st_y = face[1] + (itr * strp)
  174. end_y = face[1] + (itr * strp + strp)
  175. # play with the second parameter to increase "glitchiness"
  176. rng = rd.randint(15, 100)
  177. #randomize direction face is glitched in
  178. dec = rd.randint(1, 2)
  179. #if length modifications need to be made, this value is changed
  180. diff = 0
  181. #1 shifts image left 2 shifts it right
  182. if dec % 2 == 0:
  183. #check to make sure in bounds
  184. if face[0] + face[2] + rng >= width:
  185. diff = face[0] + face[2] + rng - width
  186. #set rng in bounds if its too big
  187. rng = width - (face[0] + face[2])
  188. # perform glitch effect
  189. img[st_y:end_y, (face[0] + rng):face[0] + face[2] + rng] = \
  190. img[st_y:end_y, face[0]:face[0] + face[2] - diff]
  191. else:
  192. #check if range leaves the images size
  193. if face[0] - rng < 0:
  194. diff = abs(face[0] - rng)
  195. #set rng in bounds if too small
  196. rng = face[0]
  197. # perform glitch effect
  198. img[st_y:end_y, (face[0] - rng):face[0] + face[2] - rng] = \
  199. img[st_y:end_y, face[0]:face[0] + face[2] - diff]