Paullux

Untitled

Jun 11th, 2023
47
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.75 KB | None | 0 0
  1. import sys
  2. import os
  3. import platform
  4. import time
  5. import threading
  6. import queue
  7. import random
  8. import curses
  9.  
  10. import cv2
  11. import numpy as np
  12. import pyvirtualcam
  13.  
  14. from PIL import Image, ImageDraw, ImageFont
  15.  
  16. if sys.platform == 'win32':
  17. import ctypes
  18. winVer = platform.win32_ver(release='')[0]
  19. try:
  20. if int(winVer) >= 10:
  21. ctypes.windll.shcore.SetProcessDpiAwareness(2)
  22. elif int(winVer) == 8:
  23. ctypes.windll.shcore.SetProcessDpiAwareness(1)
  24. else:
  25. ctypes.windll.user32.SetProcessDPIAware()
  26. except (ImportError, AttributeError, OSError):
  27. pass
  28.  
  29. class Matrix:
  30. def __init__(self):
  31. curses.initscr()
  32. # Initialisez les variables globales ici
  33. self.running = True
  34. self.ascii_image = ""
  35.  
  36. # dimention camera et affichage
  37. self.width = 1280
  38. self.height = 720
  39.  
  40. self.camera = 0
  41. # Ouverture de la caméra
  42. if platform.system() == 'Windows':
  43. self.capture = cv2.VideoCapture(self.camera,cv2.CAP_DSHOW)
  44. elif platform.system() == 'Linux':
  45. self.capture = cv2.VideoCapture(self.camera)
  46.  
  47. self.capture.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
  48. self.capture.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)
  49.  
  50. # Lecture de la frame
  51. ret, frame = self.capture.read()
  52.  
  53. # Définition des caractères à utiliser pour l'ASCII art
  54. self.characters = ' ú.ù,:öøýü×Öų·ÈØÙÍб´¶¹º¼Â²ÇËÒÓ¾Ú'
  55. self.wd = sys._MEIPASS if getattr(sys, 'frozen', False) else ''
  56. self.logo = cv2.imread(os.path.join(self.wd, '.', 'MatrixLogo.png'))
  57. self.size1, self.size2 = 1280, 301
  58. self.logo = cv2.resize(self.logo, (self.size1, self.size2))
  59.  
  60. self.camera = 0 # À modifier si ne fonctionne pas
  61. self.frame_lock = threading.Lock()
  62. self.ascii_image_lock = threading.Lock()
  63.  
  64. self.rain_intensity = 0.5
  65. self.last_ascii_image, rain_ascii_image = "", ""
  66. self.columns_to_erase_queue = queue.Queue()
  67. self.columns_launched_queue = queue.Queue()
  68. self.image_updated = ""
  69.  
  70. self.ascii_font_size_width = 20
  71. self.ascii_font_size_height = self.ascii_font_size_width * 9 / 16
  72.  
  73. self.width = 1280
  74. self.height = 720
  75. self.font_path = os.path.join(self.wd, 'mtx.ttf')
  76. self.canvas_image = Image.new('RGB', (self.width, self.height), 'black')
  77. self.draw = ImageDraw.Draw(self.canvas_image)
  78. self.font = ImageFont.truetype(self.font_path, self.ascii_font_size_width)
  79.  
  80. self.frame, self.ascii_image, self.rain_ascii_image, self.rain_ascii_image_result, self.drop_of_water_image_ascii, self.erase_rain_ascii_image = None, "", "", "", "", ""
  81. self.ascii_column = 0
  82. self.ascii_row = 0
  83.  
  84. if getattr(sys, 'frozen', False):
  85. import pyi_splash
  86. # Fermeture du splash screen
  87. pyi_splash.update_text('UI Loaded ...')
  88. pyi_splash.close()
  89.  
  90. # Variables partagées entre les threads
  91. self.frame = None
  92. self.ascii_image = ""
  93.  
  94. # Affichage de l'image
  95. cv2.namedWindow("Matrix rain", cv2.WINDOW_NORMAL)
  96. cv2.resizeWindow("Matrix rain", 1280, 720)
  97. cv2.imshow("Matrix rain", frame)
  98.  
  99. self.threads = []
  100.  
  101. # initialisation des ascii art
  102. for line in range(0, 106):
  103. for column in range(0, 106):
  104. self.ascii_image += ' '
  105. self.rain_ascii_image += ' '
  106. self.rain_ascii_image_result += ' '
  107. self.drop_of_water_image_ascii += ' '
  108. self.erase_rain_ascii_image += ' '
  109. self.ascii_image += '\n'
  110. self.rain_ascii_image += '\n'
  111. self.rain_ascii_image_result += '\n'
  112. self.drop_of_water_image_ascii += '\n'
  113. self.erase_rain_ascii_image += '\n'
  114.  
  115. def start_all_thread(self):
  116. # Lancement des threads
  117. self.capture_thread = threading.Thread(target=self.capture_frame)
  118. self.ascii_thread = threading.Thread(target=self.update_ascii_image)
  119. self.image_fusion_thread = threading.Thread(target=self.image_fusion)
  120.  
  121. resized_image = np.zeros((720, 1280), dtype=np.uint8)
  122. self.drop_of_water_image = resized_image
  123. self.erase_rain_image = resized_image
  124. self.virtual_frame = cv2.cvtColor(np.array(resized_image), cv2.COLOR_RGB2BGR)
  125. self.drop_positions = np.zeros(1280, dtype=int)
  126.  
  127. self.create_rain_drops_thread = threading.Thread(target=self.create_rain_drops)
  128. self.create_rain_drop_of_water_thread = threading.Thread(target=self.create_rain_drop_of_water)
  129. self.erase_rain_columns_thread = threading.Thread(target=self.erase_rain_columns)
  130.  
  131. self.image_updated = False
  132. self.buffer = None
  133.  
  134. self.send_virtual_camera_thread = threading.Thread(target=self.send_to_virtual_camera)
  135. self.create_virtual_camera_thread = threading.Thread(target=self.create_virtual_camera)
  136.  
  137. self.threads = [self.capture_thread,
  138. self.ascii_thread,
  139. self.image_fusion_thread,
  140. self.create_rain_drops_thread,
  141. self.create_rain_drop_of_water_thread,
  142. self.erase_rain_columns_thread,
  143. self.send_virtual_camera_thread,
  144. self.create_virtual_camera_thread
  145. ]
  146.  
  147. for thread in self.threads:
  148. thread.daemon = True
  149. thread.start()
  150.  
  151. def stop(self):
  152. # Libération des ressources
  153. self.capture.release()
  154. cv2.destroyAllWindows()
  155. # Arrêt propre du programme
  156. self.running = False
  157. curses.endwin()
  158. for thread in self.threads:
  159. thread.join(timeout=1.0)
  160. time.sleep(1.001)
  161. sys.exit(0)
  162.  
  163. def run(self):
  164. # Capturez le premier frame en dehors de la boucle principale
  165. self.capture_frame()
  166.  
  167. # Initialisez la variable 'running'
  168. running = True
  169.  
  170. while running:
  171. if not self.capture_frame():
  172. break
  173.  
  174. # Temporisation pour ralentir la boucle
  175. time.sleep(0.1)
  176.  
  177. # Capturez un nouveau frame avant la prochaine itération
  178. self.capture_frame()
  179. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  180. self.running = False
  181. break
  182. if cv2.waitKey(1) & 0xFF == ord('q'):
  183. self.running = False
  184. break
  185. self.capture.release()
  186. cv2.destroyAllWindows()
  187.  
  188. # Fonction pour convertir une intensité en caractère ASCII
  189. def get_character(self, intensity):
  190. characters = self.characters
  191. num_levels = len(characters)
  192. level = intensity * (num_levels - 1) // 255
  193. print(characters[level])
  194. return characters[level]
  195.  
  196. # Fonction pour convertir une image en ASCII art
  197. def image_to_ascii(self, image):
  198. ascii_font_size_width = self.ascii_font_size_width
  199. ascii_font_size_height = self.ascii_font_size_height
  200. if len(image.shape) > 2 and image.shape[2] == 3:
  201. gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
  202. else:
  203. gray_image = image
  204. resized_image = cv2.resize(gray_image, (int(gray_image.shape[1] / (0.88 * ascii_font_size_height)), int(gray_image.shape[0] / (0.88 * ascii_font_size_width))))
  205. ascii_image = ""
  206. for i in range(resized_image.shape[0]):
  207. for j in range(resized_image.shape[1]):
  208. intensity = resized_image[i][j]
  209. ascii_image += self.get_character(intensity)
  210. ascii_image += "\n"
  211. print(ascii_image)
  212. return ascii_image
  213.  
  214. #créer l'effets de pluie
  215. def create_rain_drops(self):
  216. resized_image = np.zeros((720, 1280), dtype=np.uint8)
  217. columns_to_erase_queue = self.columns_to_erase_queue
  218. drop_columns = []
  219. drop_positions = np.zeros(1280, dtype=int)
  220. while self.running:
  221. # Générer une nouvelle goutte de pluie
  222. if len(drop_columns) < 80:
  223. column = random.randint(0, resized_image.shape[1] - 1) # Choix aléatoire de la colonne
  224. drop_columns.append(column)
  225. drop_positions[column] = 0 # Initialiser la position de la goutte à la ligne supérieure
  226. # Mettre à jour les positions des gouttes de pluie
  227. for column in drop_columns:
  228. row = drop_positions[column]
  229. # Réinitialiser la colonne à zéro pour effacer la goutte précédente
  230. if row >= resized_image.shape[0] - 1:
  231. drop_columns.remove(column)
  232. columns_to_erase_queue.put((column, row)) # Ajouter la colonne à effacer à la liste
  233. for row_to_erase in range(0, drop_positions[column]):
  234. resized_image[row_to_erase][column] = 0
  235. else:
  236. row += 1 # Descendre la goutte d'une ligne
  237. drop_positions[column] = row # Mettre à jour la position de la goutte
  238. # Mettre à jour l'image avec la goutte de pluie
  239. resized_image[row][column] = 255 # Intensité maximale
  240. # Ajouter uniquement les colonnes dans la queue
  241. self.columns_launched_queue.put((column, row))
  242. # Mettre à jour l'affichage de l'ASCII art dans la fenêtre tkinter
  243. self.resized_image = resized_image
  244. a_image = self.image_to_ascii(resized_image)
  245. with self.ascii_image_lock:
  246. self.rain_ascii_image = a_image
  247. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  248. self.running = False
  249. break
  250. if cv2.waitKey(1) & 0xFF == ord('q'):
  251. self.running
  252.  
  253. def create_rain_drop_of_water(self):
  254. max_rows = {}
  255. while running:
  256. while not self.columns_launched_queue.empty():
  257. # Mettre à jour les positions des gouttes de pluie
  258. column, row = self.columns_launched_queue.get()
  259. if column in max_rows:
  260. max_rows[column] = max(max_rows[column], row)
  261. else:
  262. max_rows[column] = row
  263.  
  264. # Initialiser drop_of_water_image avec des zéros
  265. drop_of_water_image = np.zeros_like(drop_of_water_image)
  266.  
  267. with self.ascii_image_lock:
  268. for column, row in max_rows.items():
  269. drop_of_water_image[row][column] = 255
  270. # Mettre à jour l'affichage de l'ASCII art dans la fenêtre tkinter
  271. self.drop_of_water_image_ascii = self.image_to_ascii(drop_of_water_image)
  272. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  273. running = False
  274. break
  275. if cv2.waitKey(1) & 0xFF == ord('q'):
  276. running = False
  277. break
  278.  
  279. # Effacer progressivement la pluie
  280. def erase_rain_columns(self):
  281. erase_rain_image = np.zeros((720, 1280), dtype=np.uint8)
  282. while self.running:
  283. if not self.columns_to_erase_queue.empty():
  284. while not self.columns_to_erase_queue.empty():
  285. column, row = self.columns_to_erase_queue.get()
  286. for row_to_erase in range(0, self.height):
  287. erase_rain_image[row_to_erase][column] = self.resized_image[row_to_erase][column]
  288. with self.ascii_image_lock:
  289. self.erase_rain_ascii_image = self.image_to_ascii(erase_rain_image)
  290. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  291. self.running = False
  292. break
  293. if cv2.waitKey(1) & 0xFF == ord('q'):
  294. self.running = False
  295. break
  296.  
  297. # Fonction pour mettre à jour l'image capturée
  298. def capture_frame(self):
  299. while self.running:
  300. ret, f = self.capture.read()
  301. cv2.waitKey(0)
  302. if ret:
  303. # Redimensionner l'image capturée pour qu'elle s'adapte aux dimensions du canevas
  304. resized_frame = cv2.resize(f, (self.width, self.height))
  305. # Créer un canevas vide
  306. canvas = np.zeros((self.height, self.width, 3), dtype=np.uint8)
  307. # Calculer les coordonnées pour placer le logo au centre du canevas
  308. logo_x = int((self.width - self.size1) / 2)
  309. logo_y = 0
  310. # Dessiner le logo sur le canevas
  311. canvas[logo_y:logo_y+self.size2, logo_x:logo_x+self.size1] = self.logo
  312. # Combiner le canevas avec l'image capturée redimensionnée
  313. combined_frame = cv2.addWeighted(resized_frame, .5, canvas, 1, 0)
  314. with self.frame_lock:
  315. self.frame = combined_frame
  316. cv2.imshow("Matrix rain", self.frame) #test
  317. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  318. self.running = False
  319. break
  320. if cv2.waitKey(1) & 0xFF == ord('q'):
  321. self.running = False
  322. break
  323.  
  324. # Fonction pour mettre à jour l'image ASCII
  325. def update_ascii_image(self):
  326. while self.running:
  327. with self.frame_lock:
  328. f = self.frame
  329. if f is not None:
  330. self.y_image = self.image_to_ascii(f)
  331. with self.ascii_image_lock:
  332. self.ascii_image = self.y_image
  333. time.sleep(0.001) # Temps d'attente arbitraire
  334. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  335. self.running = False
  336. break
  337. if cv2.waitKey(1) & 0xFF == ord('q'):
  338. self.running = False
  339. break
  340.  
  341. def image_fusion(self):
  342. while self.running:
  343. with self.ascii_image_lock:
  344. ascii_image_cut = self.ascii_image.split("\n")
  345. rain_ascii_image_cut = self.rain_ascii_image.split("\n")
  346. drop_of_water_ascii_image_cut = self.drop_of_water_image_ascii.split("\n")
  347. erase_rain_ascii_image_cut = self.erase_rain_ascii_image.split("\n")
  348. ascii_image_intermediate = []
  349. rain_ascii_image_intermediate = []
  350. for i in range(len(ascii_image_cut)):
  351. ascii_image_cut_line = list(ascii_image_cut[i])
  352. rain_ascii_image_cut_line = list(rain_ascii_image_cut[i])
  353. drop_of_water_ascii_image_cut_line = list(drop_of_water_ascii_image_cut[i])
  354. erase_rain_ascii_image_cut_line = list(erase_rain_ascii_image_cut)
  355. for j in range(len(rain_ascii_image_cut_line)):
  356. if j < len(ascii_image_cut_line) and j < len(rain_ascii_image_cut_line) and j < len(drop_of_water_ascii_image_cut_line) and j < len(erase_rain_ascii_image_cut_line):
  357. if (rain_ascii_image_cut_line[j] != ' ' and rain_ascii_image_cut_line[j] in self.characters):
  358. if drop_of_water_ascii_image_cut_line[j] != ' ':
  359. ascii_image_cut_line[j] = ' '
  360. else:
  361. rain_ascii_image_cut_line[j] = self.ascii_image_cut_line[j]
  362. ascii_image_cut_line[j] = ' '
  363. ascii_image_intermediate.append("".join(ascii_image_cut_line))
  364. rain_ascii_image_intermediate.append("".join(rain_ascii_image_cut_line))
  365. self.ascii_image_result = "\n".join(ascii_image_intermediate)
  366. self.rain_ascii_image_result = "\n".join(rain_ascii_image_intermediate)
  367. time.sleep(0.001)
  368. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  369. self.running = False
  370. break
  371. if cv2.waitKey(1) & 0xFF == ord('q'):
  372. self.running = False
  373. break
  374.  
  375. def send_to_virtual_camera(self):
  376. while self.running:
  377. # Capture the content of the canvas as an image
  378. canvas_image = Image.new('RGB', (self.width, self.height), 'black')
  379. draw = ImageDraw.Draw(canvas_image)
  380. font = ImageFont.truetype(self.font_path, self.ascii_font_size_width)
  381. draw.text((0, 0), self.ascii_image_result, fill='#008800', font=font)
  382. draw.text((0, 0), self.rain_ascii_image_result, fill='#00ff00', font=font)
  383. hex_vars = ['f', 'e', 'd', 'c', 'b', 'a', '9', '8']
  384. for hex_var in hex_vars:
  385. draw.text((0, 0), self.erase_rain_ascii_image, fill='#00'+ hex_var + hex_var + '00', font=font)
  386. time.sleep(0.01)
  387. draw.text((0, 0), self.drop_of_water_image_ascii, fill='white', font=font)
  388. self.virtual_frame = cv2.cvtColor(np.array(canvas_image), cv2.COLOR_RGB2BGR)
  389.  
  390. # Affichez la miniature dans la fenêtre créée précédemment
  391. cv2.imshow("Matrix rain", self.virtual_frame)
  392.  
  393. # Vérifiez si la fenêtre a été fermée en utilisant le bouton en croix
  394. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  395. self.running = False
  396. break
  397.  
  398. # Attendez une touche pour quitter
  399. if cv2.waitKey(1) & 0xFF == ord('q'):
  400. self.running = False
  401. break
  402.  
  403. # Fermez la fenêtre et libérez les ressources
  404. cv2.destroyAllWindows()
  405.  
  406. def create_virtual_camera(self):
  407. with pyvirtualcam.Camera(self.width, self.height, 30) as cam:
  408. while self.running:
  409. # Redimensionne l'image pour qu'elle corresponde à la taille de la caméra virtuelle
  410. cam.send(self.virtual_frame)
  411. cam.sleep_until_next_frame()
  412. if cv2.getWindowProperty("Matrix rain", cv2.WND_PROP_VISIBLE) < 1:
  413. self.running = False
  414. break
  415. if cv2.waitKey(1) & 0xFF == ord('q'):
  416. self.running = False
  417. break
  418.  
  419. # Boucle principale
  420. if __name__ == "__main__":
  421. matrix = Matrix()
  422. thread_run = matrix.run()
Advertisement
Add Comment
Please, Sign In to add comment