nonogamer9

CC-CAM Flask Script

Aug 1st, 2026
103
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.51 KB | Source Code | 0 0
  1. import os
  2. import cv2
  3. import time
  4. import threading
  5. import numpy as np
  6. from flask import Flask, Response, request
  7.  
  8. os.environ["OPENCV_LOG_LEVEL"] = "FATAL"
  9.  
  10. app = Flask(__name__)
  11. cap = None
  12.  
  13. TERM_WIDTH = 51
  14. TERM_HEIGHT = 19
  15. PIXEL_WIDTH = TERM_WIDTH * 6
  16. PIXEL_HEIGHT = TERM_HEIGHT * 9
  17.  
  18. latest_frame = None
  19. frame_lock = threading.Lock()
  20. capture_running = False
  21.  
  22. CC_16_COLORS = np.array([
  23.     [240, 240, 240],
  24.     [242, 178, 51],
  25.     [229, 127, 216],
  26.     [153, 178, 242],
  27.     [222, 222, 108],
  28.     [127, 204, 25],
  29.     [242, 178, 204],
  30.     [76, 76, 76],
  31.     [153, 153, 153],
  32.     [76, 153, 178],
  33.     [127, 63, 178],
  34.     [51, 51, 178],
  35.     [102, 76, 51],
  36.     [102, 127, 51],
  37.     [153, 51, 51],
  38.     [25, 25, 25]
  39. ], dtype=np.float32)
  40.  
  41. BAYER_4X4 = np.array([
  42.     [0, 8, 2, 10],
  43.     [12, 4, 14, 6],
  44.     [3, 11, 1, 9],
  45.     [15, 7, 13, 5]
  46. ], dtype=np.float32) / 16.0 - 0.5
  47.  
  48. def get_dither_matrix(h, w):
  49.     tiled = np.tile(BAYER_4X4, (int(np.ceil(h / 4)), int(np.ceil(w / 4))))
  50.     return tiled[:h, :w, np.newaxis]
  51.  
  52. def get_available_cameras():
  53.     available_cameras = []
  54.     backend = cv2.CAP_DSHOW if os.name == 'nt' else cv2.CAP_ANY
  55.     for i in range(2):
  56.         temp_cap = cv2.VideoCapture(i, backend)
  57.         if temp_cap.isOpened():
  58.             success, _ = temp_cap.read()
  59.             if success:
  60.                 available_cameras.append(i)
  61.             temp_cap.release()
  62.     return available_cameras
  63.  
  64. def resize_with_aspect_ratio(frame, target_w, target_h):
  65.     src_h, src_w = frame.shape[:2]
  66.     scale = min(target_w / src_w, target_h / src_h)
  67.     new_w = max(1, round(src_w * scale))
  68.     new_h = max(1, round(src_h * scale))
  69.  
  70.     resized = cv2.resize(frame, (new_w, new_h), interpolation=cv2.INTER_AREA)
  71.  
  72.     canvas = np.zeros((target_h, target_w, 3), dtype=np.uint8)
  73.     x_off = (target_w - new_w) // 2
  74.     y_off = (target_h - new_h) // 2
  75.     canvas[y_off:y_off + new_h, x_off:x_off + new_w] = resized
  76.     return canvas
  77.  
  78. def capture_loop():
  79.     global latest_frame, capture_running
  80.     dither = get_dither_matrix(PIXEL_HEIGHT, PIXEL_WIDTH) * 24
  81.     while capture_running and cap and cap.isOpened():
  82.         success, frame = cap.read()
  83.         if not success:
  84.             time.sleep(0.01)
  85.             continue
  86.         resized = resize_with_aspect_ratio(frame, PIXEL_WIDTH, PIXEL_HEIGHT)
  87.         dithered = np.clip(resized.astype(np.float32) + dither, 0, 255).astype(np.uint8)
  88.  
  89.         with frame_lock:
  90.             latest_frame = dithered
  91.         time.sleep(0.02)
  92.  
  93. def generate_video_stream(mode):
  94.     cube_size = 5
  95.     while capture_running:
  96.         with frame_lock:
  97.             frame = None if latest_frame is None else latest_frame.copy()
  98.  
  99.         if frame is None:
  100.             time.sleep(0.01)
  101.             continue
  102.  
  103.         pixels = frame.reshape((-1, 3)).astype(np.float32)
  104.  
  105.         if mode == 1:
  106.             b_val = pixels[:, 0]
  107.             g_val = pixels[:, 1]
  108.             r_val = pixels[:, 2]
  109.  
  110.             r_idx = (r_val * (cube_size - 1)) // 255
  111.             g_idx = (g_val * (cube_size - 1)) // 255
  112.             b_idx = (b_val * (cube_size - 1)) // 255
  113.  
  114.             color_indices = 16 + r_idx * (cube_size * cube_size) + g_idx * cube_size + b_idx
  115.         else:
  116.             distances = np.sqrt(np.sum((pixels[:, np.newaxis, :] - CC_16_COLORS[np.newaxis, :, :]) ** 2, axis=2))
  117.             color_indices = np.argmin(distances, axis=1)
  118.  
  119.         yield color_indices.astype(np.uint8).tobytes()
  120.         time.sleep(0.03)
  121.  
  122. @app.route('/stream')
  123. def stream():
  124.     mode = int(request.args.get('mode', 1))
  125.     return Response(generate_video_stream(mode), mimetype='application/octet-stream')
  126.  
  127. if __name__ == '__main__':
  128.     devices = get_available_cameras()
  129.     if not devices:
  130.         print("Error: No active cameras found!")
  131.         exit(1)
  132.  
  133.     selected_index = devices[0]
  134.     cap = cv2.VideoCapture(selected_index, cv2.CAP_DSHOW if os.name == 'nt' else cv2.CAP_ANY)
  135.     cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
  136.     cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG'))
  137.  
  138.     if not cap.isOpened():
  139.         print(f"Error: Could not open device {selected_index}.")
  140.         exit(1)
  141.  
  142.     capture_running = True
  143.     capture_thread = threading.Thread(target=capture_loop, daemon=True)
  144.     capture_thread.start()
  145.  
  146.     print("Flask server running on http://0.0.0.0:5000/stream ...")
  147.     try:
  148.         app.run(host='0.0.0.0', port=5000, threaded=True)
  149.     finally:
  150.         capture_running = False
  151.         capture_thread.join(timeout=2)
  152.         if cap:
  153.             cap.release()
Advertisement
Comments
  • User was banned
Add Comment
Please, Sign In to add comment