Browse Source

feat: 新增对树莓派摄像头的支持

SongZihuan 3 năm trước cách đây
mục cha
commit
48301096f4
9 tập tin đã thay đổi với 83 bổ sung39 xóa
  1. 1 0
      HGSSystem.conf.py
  2. 2 1
      conf/equipment.py
  3. 70 31
      equipment/scan.py
  4. 0 1
      equipment/scan_user.py
  5. 5 0
      init.py
  6. 2 2
      sql/db.py
  7. 1 1
      sql/mysql_db.py
  8. 1 2
      tk_ui/station.py
  9. 1 1
      tk_ui/station_event.py

+ 1 - 0
HGSSystem.conf.py

@@ -5,3 +5,4 @@ tk_manager_login_zoom = 1
 tk_ranking_zoom = 1
 
 capture_num = 0
+use_opencv = True

+ 2 - 1
conf/equipment.py

@@ -3,7 +3,8 @@ from .conf import conf_args
 
 class ConfigCaptureRelease:
     """ 摄像头相关配置 """
-    capture_num = tk_zoom = float(conf_args.get("capture_num", 1))  # 文字缩放  # 摄像头号
+    use_opencv = bool(conf_args.get("use_opencv", True))
+    capture_num = tk_zoom = float(conf_args.get("capture_num", 1))  # 摄像头号
     capture_arg = []
 
 

+ 70 - 31
equipment/scan.py

@@ -1,42 +1,82 @@
 import time
 import threading
 import cv2.cv2 as cv2
-from PIL.Image import Image
+from PIL.Image import Image, FLIP_LEFT_RIGHT, fromarray
+import io
+import numpy as np
 
 from conf import Config
 import qrcode
 from tool.typing import *
 
+if Config.use_opencv:
+    class HGSCapture:
+        """ 摄像头扫描 """
 
-class HGSCapture:
-    """ 摄像头扫描 """
-    def __init__(self, capnum: int = Config.capture_num, *args, **kwargs):
-        args = *args, *Config.capture_arg
-        if cv2.CAP_DSHOW not in args:
-            args = *args, cv2.CAP_DSHOW
-        self._capture = cv2.VideoCapture(int(capnum), *args, **kwargs)
-        self._frame = None
-        self._lock = threading.RLock()
+        def __init__(self, capnum: int = Config.capture_num, *args, **kwargs):
+            args = *args, *Config.capture_arg
+            if cv2.CAP_DSHOW not in args:
+                args = *args, cv2.CAP_DSHOW
+            self._capture = cv2.VideoCapture(int(capnum), *args, **kwargs)
+            self._frame = None
+            self._lock = threading.RLock()
 
-    def get_image(self):
-        """ 获取摄像头图像 """
-        try:
-            self._lock.acquire()
-            ret, frame = self._capture.read()
-            if ret:
-                self._frame = frame
-        finally:
-            self._lock.release()
-        return ret
+        def get_image(self) -> bool:
+            """ 获取摄像头图像 """
+            try:
+                self._lock.acquire()
+                ret, frame = self._capture.read()
+                if ret:
+                    self._frame = frame
+            finally:
+                self._lock.release()
+            return ret
+
+        def get_frame(self) -> Image:
+            """ 获取 frame """
+            try:
+                self._lock.acquire()
+                frame = fromarray(cv2.cvtColor(self._frame, cv2.COLOR_BGR2RGB)).transpose(FLIP_LEFT_RIGHT)
+            finally:
+                self._lock.release()
+            return frame
+else:
+    import picamera
 
-    def get_frame(self):
-        """ 获取 frame """
-        try:
-            self._lock.acquire()
-            frame = self._frame
-        finally:
-            self._lock.release()
-        return frame
+
+    class HGSCapture:
+        """ 摄像头扫描 """
+
+        def __init__(self):
+            self._frame = None
+            self._lock = threading.RLock()
+
+        def get_image(self) -> bool:
+            """ 获取摄像头图像 """
+            try:
+                self._lock.acquire()
+                stream = io.BytesIO()
+                with picamera.PiCamera() as camera:
+                    camera.start_preview()
+                    time.sleep(2)
+                    camera.capture(stream, format='jpeg')
+                # 将指针指向流的开始
+                stream.seek(0)
+                self._frame = Image.open(stream)
+            except:
+                return False
+            finally:
+                self._lock.release()
+            return True
+
+        def get_frame(self) -> Image:
+            """ 获取 frame """
+            try:
+                self._lock.acquire()
+                frame = self._frame
+            finally:
+                self._lock.release()
+            return frame
 
 
 class QRCode:
@@ -68,7 +108,6 @@ class QRCode:
     def make_img(self) -> Image:
         qr = qrcode.QRCode(
             version=None,
-            error_correction=qrcode.constants.ERROR_CORRECT_H,
             box_size=10,
             border=4
         )
@@ -101,8 +140,8 @@ class HGSQRCoder:
         try:
             self._lock.acquire()
 
-            frame = self._cap.get_frame()
-            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
+            frame: Image = self._cap.get_frame().transpose(FLIP_LEFT_RIGHT)
+            gray = cv2.cvtColor(cv2.cvtColor(np.asarray(frame), cv2.COLOR_RGB2BGR), cv2.COLOR_BGR2GRAY)
             coder = cv2.QRCodeDetector()
 
             try:

+ 0 - 1
equipment/scan_user.py

@@ -19,7 +19,6 @@ qr_img_info_font = ImageFont.truetype(font=Config.font_d["noto"], size=30, encod
 def scan_uid(code: QRCode) -> uid_t:
     data = code.get_data()
     res = re.match(qr_user_pattern, data)
-    print(data, res)
     if res is None:
         return ""
     else:

+ 5 - 0
init.py

@@ -48,6 +48,11 @@ def check_import(packages: Union[str, List[str]], pips: Union[str, List[str]]):
                 print(f"依赖 {packages}:{pip} 安装成功")
 
 
+print("是否安装可选的`picamera`支持?")
+res = input("[Y/n]")
+if res == "Y" or res == "y":
+    check_import("picamera", "opencv-python==4.5.3.56")
+
 check_import("cv2", "opencv-python==4.5.3.56")  # 图像处理
 check_import("qrcode", "qrcode")  # 二维码生成
 check_import("pymysql", "PyMySQL")  # 连接 MySQL服务器

+ 2 - 2
sql/db.py

@@ -5,12 +5,12 @@ if Config.database.upper() == 'MYSQL':
     try:
         from .mysql_db import MysqlDB
     except ImportError:
-        print("Can not import mysqlDB")
+        print("无法导入MysqlDB程序")
         raise
     else:
         DB = MysqlDB
 else:
-    print(f"Not support database: {Config.database}")
+    print(f"不支持的数据库类型: {Config.database}")
     raise Exception
 
 

+ 1 - 1
sql/mysql_db.py

@@ -143,7 +143,7 @@ class MysqlDB(HGSDatabase):
             self._cursor.execute(sql)
         except pymysql.MySQLError:
             self._db.rollback()
-            print(f"{sql}")
+            print(f"sql={sql}")
             traceback.print_exc()
             return None
         finally:

+ 1 - 2
tk_ui/station.py

@@ -1274,8 +1274,7 @@ class GarbageStation(GarbageStationBase):
             return
 
         # 需要存储一些数据 谨防被gc释放
-        _cap_img_info = (Image.fromarray(cv2.cvtColor(self.get_cap_img(), cv2.COLOR_BGR2RGB)).
-                         transpose(Image.FLIP_LEFT_RIGHT))
+        _cap_img_info: Image.Image = self.get_cap_img()
         self._cap_img = _cap_img_info
 
         img_width, img_height = _cap_img_info.size

+ 1 - 1
tk_ui/station_event.py

@@ -69,7 +69,7 @@ class ScanUserEvent(StationEventBase):
         if res is None:
             event = ScanGarbageEvent(self.station).start(self._qr_code)
             self.station.push_event(event)
-        if res:
+        elif res:
             self.station.switch_user(user)
             self.station.update_control()
         else: