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