Need to share screen under special circumstances? Microscreen sharing server based on flash (can realize screen sharing)

Keywords: Python OpenCV

Preface:

Today, I'd like to share an interesting little project with you. I need to make a report a long time ago. There was something wrong with the original screen sharing software, so I temporarily wrote this program to deal with the emergency. The effect is good. Today, I'd like to share it with you. In case of some special circumstances, it can be used to deal with the emergency

1, Use environment
Pillow 6.0.0
Opencv-Python 4.1.1.26
flask 1.1.1
2, Project introduction

In fact, it's not very difficult. Before I used the UDP broadcast shared screen, now we have a library in python with pilot to get the screen, which can realize the screenshot effect and convert the picture into a byte stream. But pilot has a disadvantage. If the screen is scaled, it's scaled, which means that the screen picture you get is not a complete picture. Next, I will introduce How to use Python to capture a screen and convert it to a byte stream:

  • Pillow
from PIL import ImageGrab

img = ImageGrab.grab()
img.save("a.png")

Pilot can't capture full screen in case of screen zooming

  • pyautogui
import pyautogui

img = pyautogui.screenshot()
img.save("a.png")

pyautogui can also get full screen when the screen is zoomed

  • Picture to byte stream
import pyautogui
from io import BytesIO

img = pyautogui.screenshot()
output_buffer = BytesIO()  # Creating binary objects
img.save(output_buffer, format='JPEG', quality=100)  # quality improves image resolution
frame = output_buffer.getvalue()  # Get binary data
print(frame)

2, Hands on practice

  • Create a new folder (do it with me)
  • Create another templates folder in the folder
  • Create an index.html in templates
  • Create three empty Python files app.py camera.py pil.py base ABCD camera.py
  • After creation, paste the following code into index.html
<html>
<head>
    <title>Screen sharing</title>
</head>
<body>
<h4>Screen sharing</h4>
<img src="{{ url_for('video_feed') }}">
</body>
</html>
  • Then paste the following code into: base? Camera.py
import time
import threading
try:
    from greenlet import getcurrent as get_ident
except ImportError:
    try:
        from thread import get_ident
    except ImportError:
        from _thread import get_ident


class CameraEvent(object):
    def __init__(self):
        self.events = {}

    def wait(self):
        ident = get_ident()
        if ident not in self.events:
            self.events[ident] = [threading.Event(), time.time()]
        return self.events[ident][0].wait()

    def set(self):
        now = time.time()
        remove = None
        for ident, event in self.events.items():
            if not event[0].isSet():
                event[0].set()
                event[1] = now
            else:
                if now - event[1] > 5:
                    remove = ident
        if remove:
            del self.events[remove]

    def clear(self):
        self.events[get_ident()][0].clear()


class BaseCamera(object):
    thread = None
    frame = None
    last_access = 0
    event = CameraEvent()

    def __init__(self):
        if BaseCamera.thread is None:
            BaseCamera.last_access = time.time()

            BaseCamera.thread = threading.Thread(target=self._thread)
            BaseCamera.thread.start()

            while self.get_frame() is None:
                time.sleep(0)

    def get_frame(self):
        BaseCamera.last_access = time.time()

        BaseCamera.event.wait()
        BaseCamera.event.clear()

        return BaseCamera.frame

    @staticmethod
    def frames():
        raise RuntimeError('Must be implemented by subclasses.')

    @classmethod
    def _thread(cls):
        print('Starting camera thread.')
        frames_iterator = cls.frames()
        for frame in frames_iterator:
            BaseCamera.frame = frame
            BaseCamera.event.set()
            time.sleep(0)
            if time.time() - BaseCamera.last_access > 10:
                frames_iterator.close()
                print('Stopping camera thread due to inactivity.')
                break
        BaseCamera.thread = None
  • Then paste the following code into: camera_pil.py
from io import BytesIO
import cv2
from PIL import ImageGrab, Image
from base_camera import BaseCamera


class Camera(BaseCamera):
    video_source = 0

    @staticmethod
    def set_video_source(source):
        Camera.video_source = source

    @staticmethod
    def frames():
        camera = cv2.VideoCapture(Camera.video_source)
        if not camera.isOpened():
            raise RuntimeError('Error')

        while True:
            image = ImageGrab.grab()  # Get screen data
            # w, h = image.size
            image = image.resize((1366, 750), Image.ANTIALIAS)  # Picture zoom
            output_buffer = BytesIO()  # Creating binary objects
            image.save(output_buffer, format='JPEG', quality=100)  # quality improves image resolution
            frame = output_buffer.getvalue()  # Get binary data
            yield frame  # Generator returns binary data of a picture
  • Then paste the following code into: apps.py
import os
from importlib import import_module
from flask import Flask, render_template, Response

if os.environ.get('CAMERA'):
    Camera = import_module('camera_' + os.environ['CAMERA']).Camera
else:
    from camera_pil import Camera

app = Flask(__name__)


@app.route('/')
def index():
    """
    //View function
    :return:
    """
    return render_template('index.html')


def gen(camera):
    """
    //Streaming generator
    """
    while True:
        frame = camera.get_frame()

        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')


@app.route('/video_feed')
def video_feed():
    """Streaming data"""
    return Response(gen(Camera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')


if __name__ == '__main__':
    app.run(threaded=True, host="127.0.0.1", port=80)
  • Run app.py, then open your browser and type: http://127.0.0.1/ try it!
  • If you want to use it, please change the host = "127.0.0.1" to host = "0.0.0.0" and run the screen sharing server. Check the ip address of your Ethernet and tell the receiver to let them access your ip address using the browser. Then you can realize the screen sharing. You will find that your CPU will be crazy (not so exaggerated) after all, it is an emergency
Published 21 original articles, won praise 35, visited 5101
Private letter follow

Posted by eyespark on Thu, 13 Feb 2020 07:30:15 -0800