-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 936a287
Showing
5 changed files
with
243 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
fixedenv | ||
__pycache__ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
from typing import Optional | ||
from PIL import Image | ||
import shutil | ||
|
||
|
||
def image_to_ascii_art(img: Image.Image, rows: int = 0) -> str: | ||
"""Convert an Image to ASCII Art""" | ||
|
||
width, height = img.size | ||
aspect_ratio = height / width | ||
new_width = rows | ||
new_height = aspect_ratio * new_width * 0.55 | ||
img = img.resize((new_width, int(new_height))) | ||
|
||
pixels = img.getdata() | ||
|
||
chars = ["*", "S", "#", "&", "@", "$", "%", "*", "!", ":", "."] | ||
new_pixels = [chars[pixel // 25] for pixel in pixels] | ||
new_pixels = "".join(new_pixels) | ||
|
||
new_pixels_count = len(new_pixels) | ||
ascii_image = [ | ||
new_pixels[index : index + new_width] | ||
for index in range(0, new_pixels_count, new_width) | ||
] | ||
ascii_image = "\n".join(ascii_image) | ||
|
||
return ascii_image |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
colorama | ||
pywhatkit | ||
opencv-python | ||
numpy | ||
pillow | ||
setproctitle |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
from PIL import Image | ||
|
||
import numpy as np | ||
|
||
import os | ||
import pyautogui | ||
import Quartz | ||
import time | ||
import cv2 | ||
|
||
TERMINAL_COLUMN_WIDTH_CONSTANT = 9.028871391076116 | ||
TERMINAL_ROW_HEIGHT_CONSTANT = 17.142857142857142 | ||
|
||
|
||
def get_screen_size() -> tuple[int, int]: | ||
""" | ||
Obtiene el tamaño de la pantalla. | ||
Returns: | ||
tuple: Ancho y alto de la pantalla. | ||
""" | ||
return pyautogui.size() | ||
|
||
|
||
def get_frame_size(cap: cv2.VideoCapture) -> tuple[int, int]: | ||
""" | ||
Obtiene el tamaño del frame capturado por la webcam. | ||
Args: | ||
cap (cv2.VideoCapture): Objeto de captura de video. | ||
Returns: | ||
tuple: Ancho y alto del frame. | ||
""" | ||
return int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int( | ||
cap.get(cv2.CAP_PROP_FRAME_HEIGHT) | ||
) | ||
|
||
|
||
def get_terminal_size(window_number) -> tuple[int, int, int, int, int, int]: | ||
""" | ||
Obtiene el tamaño de la ventana de la terminal. | ||
Args: | ||
window_number (int): Número de la ventana de la terminal. | ||
Returns: | ||
tuple: Coordenadas x, y, ancho, alto, columnas y filas de la terminal. | ||
""" | ||
window_list = Quartz.CGWindowListCopyWindowInfo( | ||
Quartz.kCGWindowListOptionOnScreenOnly, Quartz.kCGNullWindowID | ||
) | ||
for window_info in window_list: | ||
if ( | ||
window_info["kCGWindowNumber"] == window_number | ||
): # Busca la ventana de la terminal | ||
terminal_window = window_info | ||
break | ||
|
||
x = int(terminal_window["kCGWindowBounds"]["X"]) | ||
y = int(terminal_window["kCGWindowBounds"]["Y"]) | ||
|
||
terminal_columns, terminal_rows = os.get_terminal_size() | ||
|
||
width = int(terminal_columns * TERMINAL_COLUMN_WIDTH_CONSTANT) | ||
height = int(terminal_rows * TERMINAL_ROW_HEIGHT_CONSTANT) | ||
|
||
return x, y, width, height, terminal_columns, terminal_rows | ||
|
||
|
||
def resize_frame(frame, frame_width, frame_height) -> np.ndarray: | ||
""" | ||
Redimensiona el frame para que se ajuste a la pantalla. | ||
Args: | ||
frame (np.ndarray): Frame capturado por la webcam. | ||
frame_width (int): Ancho del frame. | ||
frame_height (int): Alto del frame. | ||
Returns: | ||
np.ndarray: Frame redimensionado. | ||
""" | ||
screen_width, screen_height = get_screen_size() | ||
|
||
if frame_height > screen_height: | ||
adjusted_width = int(screen_height / frame_height * frame_width) | ||
adjusted_height = screen_height | ||
else: | ||
adjusted_width = int(screen_width) | ||
adjusted_height = int(screen_width / frame_width * frame_height) | ||
|
||
return cv2.resize(frame, (adjusted_width, adjusted_height)) | ||
|
||
|
||
def prepare_image(frame: np.ndarray) -> Image.Image: | ||
""" | ||
Prepara la imagen para la conversión a ASCII Art. | ||
Args: | ||
frame (np.ndarray): Frame capturado por la webcam. | ||
Returns: | ||
Image.Image: Imagen preparada para la conversión a ASCII Art. | ||
""" | ||
gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) | ||
normalized_frame = cv2.normalize(gray_frame, None, 0, 255, cv2.NORM_MINMAX) | ||
return Image.fromarray(normalized_frame.astype(np.uint8)) | ||
|
||
|
||
def lazy_print(ascii_art: str): | ||
""" | ||
Imprime el ASCII Art en la terminal con un pequeño retraso entre líneas. | ||
Args: | ||
ascii_art (str): ASCII Art a imprimir. | ||
""" | ||
lines = ascii_art.split("\n") | ||
for line in lines: | ||
print(line, end="\r\n") | ||
time.sleep(0.1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
from img2ascii import image_to_ascii_art | ||
from colorama import init, Fore | ||
from utils import ( | ||
get_frame_size, | ||
get_terminal_size, | ||
resize_frame, | ||
prepare_image, | ||
lazy_print, | ||
) | ||
|
||
import sys | ||
import cv2 | ||
|
||
|
||
class WebcamAscii: | ||
""" | ||
Clase que convierte la entrada de una webcam en ASCII Art | ||
y la muestra en multiples ventanas de la terminal | ||
""" | ||
|
||
# Inicializa colorama para imprimir colores en la terminal | ||
init(autoreset=True) | ||
|
||
def __init__(self, window_number): | ||
self.window_number = window_number | ||
|
||
def open_webcam(self): | ||
""" | ||
Abre la conexión con la webcam y verifica si la conexión fue exitosa. | ||
Returns: | ||
Objeto cv2.VideoCapture si la conexión fue exitosa. | ||
""" | ||
|
||
# Abre la conexión con la webcam | ||
cap = cv2.VideoCapture(0) | ||
# Verifica si la conexión fue exitosa | ||
exit() if not cap.isOpened() else print( | ||
Fore.GREEN + "Conexión exitosa con la cámara." | ||
) | ||
return cap | ||
|
||
def run(self): | ||
""" | ||
Inicia la captura de la webcam y la muestra en la terminal. | ||
""" | ||
|
||
cap = self.open_webcam() | ||
frame_width, frame_height = get_frame_size(cap) | ||
( | ||
terminal_x, | ||
terminal_y, | ||
terminal_width, | ||
terminal_height, | ||
terminal_columns, | ||
_, | ||
) = get_terminal_size(window_number) | ||
|
||
while True: | ||
ret, frame = cap.read() | ||
|
||
if not ret: # Verifica si la captura fue exitosa | ||
print(Fore.RED + "Error: No se puede leer el frame.") | ||
break | ||
|
||
resized_frame = resize_frame(frame, frame_width, frame_height) | ||
cutted_frame = resized_frame[ | ||
terminal_y : terminal_y + terminal_height, | ||
terminal_x : terminal_x + terminal_width, | ||
] | ||
pre_processed_image = prepare_image(cutted_frame) | ||
ascii_art = image_to_ascii_art(pre_processed_image, rows=terminal_columns) | ||
lazy_print(ascii_art) | ||
|
||
if cv2.waitKey(1) & 0xFF == ord("q"): | ||
break | ||
|
||
cap.release() | ||
|
||
# Libera la cámara y cierra la ventana | ||
cv2.destroyAllWindows() | ||
|
||
|
||
if __name__ == "__main__": | ||
window_number = int(sys.argv[1]) # Obtiene el número de la ventana de la terminal | ||
cam = WebcamAscii(window_number) | ||
cam.run() |