Advertisement
Paullux

Untitled

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