У меня есть скрипт на рассбери. import io
import logging
import socketserver
from http import server
from threading import Condition
import json
import cv2
import numpy as np
import os
from picamera2 import Picamera2
from picamera2.encoders import JpegEncoder
from picamera2.outputs import FileOutput

# Загружаем эталонные изображения
CARDS_DIR = 'carts'
reference_images = []
for filename in os.listdir(CARDS_DIR):
    if filename.endswith(('.jpg', '.jpeg', '.png')):
        img_path = os.path.join(CARDS_DIR, filename)
        img = cv2.imread(img_path)
        if img is not None:
            reference_images.append({
                'name': filename,
                'image': img
            })

# Функция для поиска объекта на изображении
def find_object(frame):
    frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
    for ref in reference_images:
        ref_gray = cv2.cvtColor(ref['image'], cv2.COLOR_BGR2GRAY)
        
        # Используем SIFT для поиска ключевых точек и дескрипторов
        sift = cv2.SIFT_create()
        kp1, des1 = sift.detectAndCompute(ref_gray, None)
        kp2, des2 = sift.detectAndCompute(frame_gray, None)
        
        if des1 is not None and des2 is not None:
            # Создаем матчер FLANN
            FLANN_INDEX_KDTREE = 1
            index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
            search_params = dict(checks=50)
            flann = cv2.FlannBasedMatcher(index_params, search_params)
            
            # Находим соответствия
            matches = flann.knnMatch(des1, des2, k=2)
            
            # Применяем фильтр Лоу
            good_matches = []
            for m, n in matches:
                if m.distance < 0.75 * n.distance:
                    good_matches.append(m)
            
            # Если достаточно хороших совпадений
            if len(good_matches) > 10:
                match_percent = len(good_matches) / len(matches) * 100
                if match_percent > 75:
                    # Получаем координаты точек
                    src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
                    dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
                    
                    # Находим матрицу гомографии
                    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
                    
                    if M is not None:
                        # Получаем углы объекта
                        h, w = ref_gray.shape
                        pts = np.float32([[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)
                        dst = cv2.perspectiveTransform(pts, M)
                        
                        # Рисуем зеленый прямоугольник
                        frame = cv2.polylines(frame, [np.int32(dst)], True, (0, 255, 0), 3, cv2.LINE_AA)
                        
    return frame

class StreamingOutput(io.BufferedIOBase):
    def __init__(self):
        self.frame = None
        self.condition = Condition()

    def write(self, buf):
        # Преобразуем буфер в numpy массив
        data = np.frombuffer(buf, dtype=np.uint8)
        img = cv2.imdecode(data, cv2.IMREAD_COLOR)
        
        if img is not None:
            # Применяем распознавание объектов
            processed_img = find_object(img)
            
            # Кодируем обратно в JPEG
            _, buf = cv2.imencode('.jpg', processed_img)
            
            with self.condition:
                self.frame = buf.tobytes()
                self.condition.notify_all()

class StreamingHandler(server.BaseHTTPRequestHandler):
    def do_GET(self):
        if self.path == '/':
            self.send_response(301)
            self.send_header('Location', '/index.html')
            self.end_headers()
        elif self.path == '/index.html':
            try:
                with open('templates/index.html', 'rb') as f:
                    content = f.read()
                self.send_response(200)
                self.send_header('Content-Type', 'text/html')
                self.send_header('Content-Length', len(content))
                self.end_headers()
                self.wfile.write(content)
            except:
                self.send_error(404)
                self.end_headers()
        elif self.path.startswith('/static/'):
            try:
                with open('.' + self.path, 'rb') as f:
                    content = f.read()
                self.send_response(200)
                if self.path.endswith('.css'):
                    self.send_header('Content-Type', 'text/css')
                elif self.path.endswith('.js'):
                    self.send_header('Content-Type', 'application/javascript')
                self.send_header('Content-Length', len(content))
                self.end_headers()
                self.wfile.write(content)
            except:
                self.send_error(404)
                self.end_headers()
        elif self.path == '/stream.mjpg':
            self.send_response(200)
            self.send_header('Age', 0)
            self.send_header('Cache-Control', 'no-cache, private')
            self.send_header('Pragma', 'no-cache')
            self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
            self.end_headers()
            try:
                while True:
                    with output.condition:
                        output.condition.wait()
                        frame = output.frame
                    self.wfile.write(b'--FRAME\r\n')
                    self.send_header('Content-Type', 'image/jpeg')
                    self.send_header('Content-Length', len(frame))
                    self.end_headers()
                    self.wfile.write(frame)
                    self.wfile.write(b'\r\n')
            except Exception as e:
                logging.warning(
                    'Removed streaming client %s: %s',
                    self.client_address, str(e))
        else:
            self.send_error(404)
            self.end_headers()

    def do_POST(self):
        if self.path == '/update_camera':
            content_length = int(self.headers['Content-Length'])
            post_data = self.rfile.read(content_length)
            try:
                data = json.loads(post_data.decode('utf-8'))
                setting = data['setting']
                value = data['value']
                
                if setting == 'resolution':
                    w, h = map(int, value.split('x'))
                    picam2.stop_recording()
                    picam2.configure(picam2.create_video_configuration(main={"size": (w, h)}))
                    picam2.start_recording(JpegEncoder(), FileOutput(output))
                elif setting == 'brightness':
                    # Преобразуем значение от 0 до 10 в значение от 0 до 1
                    brightness = float(value) / 10
                    picam2.set_controls({'Brightness': brightness})
                elif setting == 'contrast':
                    # Преобразуем значение от 0 до 100 в значение от 0 до 2
                    contrast = (float(value) / 50)  # 50 станет 1, 0 станет 0, 100 станет 2
                    picam2.set_controls({'Contrast': contrast})
                elif setting == 'framerate':
                    # Устанавливаем частоту кадров
                    fps = int(value)
                    picam2.set_controls({'FrameDurationLimits': (int(1e6 / fps), int(1e6 / fps))})
                elif setting == 'rotation':
                    # Устанавливаем поворот камеры
                    rotation = int(value)
                    picam2.set_controls({'Rotate': rotation})
                elif setting == 'autofocus':
                    # True = 2 (continuous), False = 0 (manual)
                    picam2.set_controls({'AfMode': 2 if value else 0})
                
                self.send_response(200)
                self.send_header('Content-Type', 'application/json')
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
                self.wfile.write(json.dumps({'success': True}).encode())
            except Exception as e:
                self.send_response(400)
                self.send_header('Content-Type', 'application/json')
                self.send_header('Access-Control-Allow-Origin', '*')
                self.end_headers()
                self.wfile.write(json.dumps({'success': False, 'error': str(e)}).encode())

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
    allow_reuse_address = True
    daemon_threads = True

# Инициализация камеры
picam2 = Picamera2()
picam2.configure(picam2.create_video_configuration(main={"size": (1280, 720)}))
output = StreamingOutput()
picam2.start_recording(JpegEncoder(), FileOutput(output))

try:
    address = ('', 8000)
    server = StreamingServer(address, StreamingHandler)
    server.serve_forever()
finally:
    picam2.stop_recording() - он транслирует видео поток с рассбери. Как мне сделать так, чтобы к этой трансляции можно было подключиться с любой точки мира?