1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
| <span></span><code><span id="__span-0-1"><span>from</span> <span>PySide6</span> <span>import</span> <span>QtWidgets</span><span>,</span> <span>QtCore</span><span>,</span> <span>QtGui</span> </span><span id="__span-0-2"><span>import</span> <span>cv2</span><span>,</span> <span>os</span><span>,</span> <span>time</span> </span><span id="__span-0-3"><span>from</span> <span>threading</span> <span>import</span> <span>Thread</span> </span><span id="__span-0-4"> </span><span id="__span-0-5"><span># 不然每次YOLO处理都会输出调试信息</span> </span><span id="__span-0-6"><span>os</span><span>.</span><span>environ</span><span>[</span><span>'YOLO_VERBOSE'</span><span>]</span> <span>=</span> <span>'False'</span> </span><span id="__span-0-7"><span>from</span> <span>ultralytics</span> <span>import</span> <span>YOLO</span> </span><span id="__span-0-8"> </span><span id="__span-0-9"><span>class</span> <span>MWindow</span><span>(</span><span>QtWidgets</span><span>.</span><span>QMainWindow</span><span>):</span> </span><span id="__span-0-10"> </span><span id="__span-0-11"> <span>def</span> <span>__init__</span><span>(</span><span>self</span><span>):</span> </span><span id="__span-0-12"> </span><span id="__span-0-13"> <span>super</span><span>()</span><span>.</span><span>__init__</span><span>()</span> </span><span id="__span-0-14"> </span><span id="__span-0-15"> <span># 设置界面</span> </span><span id="__span-0-16"> <span>self</span><span>.</span><span>setupUI</span><span>()</span> </span><span id="__span-0-17"> </span><span id="__span-0-18"> <span>self</span><span>.</span><span>camBtn</span><span>.</span><span>clicked</span><span>.</span><span>connect</span><span>(</span><span>self</span><span>.</span><span>startCamera</span><span>)</span> </span><span id="__span-0-19"> <span>self</span><span>.</span><span>stopBtn</span><span>.</span><span>clicked</span><span>.</span><span>connect</span><span>(</span><span>self</span><span>.</span><span>stop</span><span>)</span> </span><span id="__span-0-20"> </span><span id="__span-0-21"> <span># 定义定时器,用于控制显示视频的帧率</span> </span><span id="__span-0-22"> <span>self</span><span>.</span><span>timer_camera</span> <span>=</span> <span>QtCore</span><span>.</span><span>QTimer</span><span>()</span> </span><span id="__span-0-23"> <span># 定时到了,回调 self.show_camera</span> </span><span id="__span-0-24"> <span>self</span><span>.</span><span>timer_camera</span><span>.</span><span>timeout</span><span>.</span><span>connect</span><span>(</span><span>self</span><span>.</span><span>show_camera</span><span>)</span> </span><span id="__span-0-25"> </span><span id="__span-0-26"> <span># 加载 YOLO nano 模型,第一次比较耗时,要20秒左右</span> </span><span id="__span-0-27"> <span>self</span><span>.</span><span>model</span> <span>=</span> <span>YOLO</span><span>(</span><span>'yolov8n.pt'</span><span>)</span> </span><span id="__span-0-28"> </span><span id="__span-0-29"> <span># 要处理的视频帧图片队列,目前就放1帧图片</span> </span><span id="__span-0-30"> <span>self</span><span>.</span><span>frameToAnalyze</span> <span>=</span> <span>[]</span> </span><span id="__span-0-31"> </span><span id="__span-0-32"> <span># 启动处理视频帧独立线程</span> </span><span id="__span-0-33"> <span>Thread</span><span>(</span><span>target</span><span>=</span><span>self</span><span>.</span><span>frameAnalyzeThreadFunc</span><span>,</span><span>daemon</span><span>=</span><span>True</span><span>)</span><span>.</span><span>start</span><span>()</span> </span><span id="__span-0-34"> </span><span id="__span-0-35"> <span>def</span> <span>setupUI</span><span>(</span><span>self</span><span>):</span> </span><span id="__span-0-36"> </span><span id="__span-0-37"> <span>self</span><span>.</span><span>resize</span><span>(</span><span>1200</span><span>,</span> <span>800</span><span>)</span> </span><span id="__span-0-38"> </span><span id="__span-0-39"> <span>self</span><span>.</span><span>setWindowTitle</span><span>(</span><span>'白月黑羽 YOLO-Qt 演示'</span><span>)</span> </span><span id="__span-0-40"> </span><span id="__span-0-41"> <span># central Widget</span> </span><span id="__span-0-42"> <span>centralWidget</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QWidget</span><span>(</span><span>self</span><span>)</span> </span><span id="__span-0-43"> <span>self</span><span>.</span><span>setCentralWidget</span><span>(</span><span>centralWidget</span><span>)</span> </span><span id="__span-0-44"> </span><span id="__span-0-45"> <span># central Widget 里面的 主 layout</span> </span><span id="__span-0-46"> <span>mainLayout</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QVBoxLayout</span><span>(</span><span>centralWidget</span><span>)</span> </span><span id="__span-0-47"> </span><span id="__span-0-48"> <span># 界面的上半部分 : 图形展示部分</span> </span><span id="__span-0-49"> <span>topLayout</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QHBoxLayout</span><span>()</span> </span><span id="__span-0-50"> <span>self</span><span>.</span><span>label_ori_video</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QLabel</span><span>(</span><span>self</span><span>)</span> </span><span id="__span-0-51"> <span>self</span><span>.</span><span>label_treated</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QLabel</span><span>(</span><span>self</span><span>)</span> </span><span id="__span-0-52"> <span>self</span><span>.</span><span>label_ori_video</span><span>.</span><span>setMinimumSize</span><span>(</span><span>520</span><span>,</span><span>400</span><span>)</span> </span><span id="__span-0-53"> <span>self</span><span>.</span><span>label_treated</span><span>.</span><span>setMinimumSize</span><span>(</span><span>520</span><span>,</span><span>400</span><span>)</span> </span><span id="__span-0-54"> <span>self</span><span>.</span><span>label_ori_video</span><span>.</span><span>setStyleSheet</span><span>(</span><span>'border:1px solid #D7E2F9;'</span><span>)</span> </span><span id="__span-0-55"> <span>self</span><span>.</span><span>label_treated</span><span>.</span><span>setStyleSheet</span><span>(</span><span>'border:1px solid #D7E2F9;'</span><span>)</span> </span><span id="__span-0-56"> </span><span id="__span-0-57"> <span>topLayout</span><span>.</span><span>addWidget</span><span>(</span><span>self</span><span>.</span><span>label_ori_video</span><span>)</span> </span><span id="__span-0-58"> <span>topLayout</span><span>.</span><span>addWidget</span><span>(</span><span>self</span><span>.</span><span>label_treated</span><span>)</span> </span><span id="__span-0-59"> </span><span id="__span-0-60"> <span>mainLayout</span><span>.</span><span>addLayout</span><span>(</span><span>topLayout</span><span>)</span> </span><span id="__span-0-61"> </span><span id="__span-0-62"> <span># 界面下半部分: 输出框 和 按钮</span> </span><span id="__span-0-63"> <span>groupBox</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QGroupBox</span><span>(</span><span>self</span><span>)</span> </span><span id="__span-0-64"> </span><span id="__span-0-65"> <span>bottomLayout</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QHBoxLayout</span><span>(</span><span>groupBox</span><span>)</span> </span><span id="__span-0-66"> <span>self</span><span>.</span><span>textLog</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QTextBrowser</span><span>()</span> </span><span id="__span-0-67"> <span>bottomLayout</span><span>.</span><span>addWidget</span><span>(</span><span>self</span><span>.</span><span>textLog</span><span>)</span> </span><span id="__span-0-68"> </span><span id="__span-0-69"> <span>mainLayout</span><span>.</span><span>addWidget</span><span>(</span><span>groupBox</span><span>)</span> </span><span id="__span-0-70"> </span><span id="__span-0-71"> <span>btnLayout</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QVBoxLayout</span><span>()</span> </span><span id="__span-0-72"> <span>self</span><span>.</span><span>videoBtn</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QPushButton</span><span>(</span><span>'🎞️视频文件'</span><span>)</span> </span><span id="__span-0-73"> <span>self</span><span>.</span><span>camBtn</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QPushButton</span><span>(</span><span>'📹摄像头'</span><span>)</span> </span><span id="__span-0-74"> <span>self</span><span>.</span><span>stopBtn</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QPushButton</span><span>(</span><span>'🛑停止'</span><span>)</span> </span><span id="__span-0-75"> <span>btnLayout</span><span>.</span><span>addWidget</span><span>(</span><span>self</span><span>.</span><span>videoBtn</span><span>)</span> </span><span id="__span-0-76"> <span>btnLayout</span><span>.</span><span>addWidget</span><span>(</span><span>self</span><span>.</span><span>camBtn</span><span>)</span> </span><span id="__span-0-77"> <span>btnLayout</span><span>.</span><span>addWidget</span><span>(</span><span>self</span><span>.</span><span>stopBtn</span><span>)</span> </span><span id="__span-0-78"> <span>bottomLayout</span><span>.</span><span>addLayout</span><span>(</span><span>btnLayout</span><span>)</span> </span><span id="__span-0-79"> </span><span id="__span-0-80"> </span><span id="__span-0-81"> <span>def</span> <span>startCamera</span><span>(</span><span>self</span><span>):</span> </span><span id="__span-0-82"> </span><span id="__span-0-83"> <span># 参考 https://docs.opencv.org/3.4/dd/d43/tutorial_py_video_display.html</span> </span><span id="__span-0-84"> </span><span id="__span-0-85"> <span># 在 windows上指定使用 cv2.CAP_DSHOW 会让打开摄像头快很多, </span> </span><span id="__span-0-86"> <span># 在 Linux/Mac上 指定 V4L, FFMPEG 或者 GSTREAMER</span> </span><span id="__span-0-87"> <span>self</span><span>.</span><span>cap</span> <span>=</span> <span>cv2</span><span>.</span><span>VideoCapture</span><span>(</span><span>0</span><span>,</span> <span>cv2</span><span>.</span><span>CAP_DSHOW</span><span>)</span> </span><span id="__span-0-88"> <span>if</span> <span>not</span> <span>self</span><span>.</span><span>cap</span><span>.</span><span>isOpened</span><span>():</span> </span><span id="__span-0-89"> <span>print</span><span>(</span><span>"1号摄像头不能打开"</span><span>)</span> </span><span id="__span-0-90"> <span>return</span><span>()</span> </span><span id="__span-0-91"> </span><span id="__span-0-92"> <span>if</span> <span>self</span><span>.</span><span>timer_camera</span><span>.</span><span>isActive</span><span>()</span> <span>==</span> <span>False</span><span>:</span> <span># 若定时器未启动</span> </span><span id="__span-0-93"> <span>self</span><span>.</span><span>timer_camera</span><span>.</span><span>start</span><span>(</span><span>50</span><span>)</span> </span><span id="__span-0-94"> </span><span id="__span-0-95"> </span><span id="__span-0-96"> <span>def</span> <span>show_camera</span><span>(</span><span>self</span><span>):</span> </span><span id="__span-0-97"> </span><span id="__span-0-98"> <span>ret</span><span>,</span> <span>frame</span> <span>=</span> <span>self</span><span>.</span><span>cap</span><span>.</span><span>read</span><span>()</span> <span># 从视频流中读取</span> </span><span id="__span-0-99"> <span>if</span> <span>not</span> <span>ret</span><span>:</span> </span><span id="__span-0-100"> <span>return</span> </span><span id="__span-0-101"> </span><span id="__span-0-102"> <span># 把读到的16:10帧的大小重新设置 </span> </span><span id="__span-0-103"> <span>frame</span> <span>=</span> <span>cv2</span><span>.</span><span>resize</span><span>(</span><span>frame</span><span>,</span> <span>(</span><span>520</span><span>,</span> <span>400</span><span>))</span> </span><span id="__span-0-104"> <span># 视频色彩转换回RGB,OpenCV images as BGR</span> </span><span id="__span-0-105"> <span>frame</span> <span>=</span> <span>cv2</span><span>.</span><span>cvtColor</span><span>(</span><span>frame</span><span>,</span> <span>cv2</span><span>.</span><span>COLOR_BGR2RGB</span><span>)</span> </span><span id="__span-0-106"> <span>qImage</span> <span>=</span> <span>QtGui</span><span>.</span><span>QImage</span><span>(</span><span>frame</span><span>.</span><span>data</span><span>,</span> <span>frame</span><span>.</span><span>shape</span><span>[</span><span>1</span><span>],</span> <span>frame</span><span>.</span><span>shape</span><span>[</span><span>0</span><span>],</span> </span><span id="__span-0-107"> <span>QtGui</span><span>.</span><span>QImage</span><span>.</span><span>Format_RGB888</span><span>)</span> <span># 变成QImage形式</span> </span><span id="__span-0-108"> <span># 往显示视频的Label里 显示QImage</span> </span><span id="__span-0-109"> <span>self</span><span>.</span><span>label_ori_video</span><span>.</span><span>setPixmap</span><span>(</span><span>QtGui</span><span>.</span><span>QPixmap</span><span>.</span><span>fromImage</span><span>(</span><span>qImage</span><span>))</span> </span><span id="__span-0-110"> </span><span id="__span-0-111"> <span># 如果当前没有处理任务</span> </span><span id="__span-0-112"> <span>if</span> <span>not</span> <span>self</span><span>.</span><span>frameToAnalyze</span><span>:</span> </span><span id="__span-0-113"> <span>self</span><span>.</span><span>frameToAnalyze</span><span>.</span><span>append</span><span>(</span><span>frame</span><span>)</span> </span><span id="__span-0-114"> </span><span id="__span-0-115"> <span>def</span> <span>frameAnalyzeThreadFunc</span><span>(</span><span>self</span><span>):</span> </span><span id="__span-0-116"> </span><span id="__span-0-117"> <span>while</span> <span>True</span><span>:</span> </span><span id="__span-0-118"> <span>if</span> <span>not</span> <span>self</span><span>.</span><span>frameToAnalyze</span><span>:</span> </span><span id="__span-0-119"> <span>time</span><span>.</span><span>sleep</span><span>(</span><span>0.01</span><span>)</span> </span><span id="__span-0-120"> <span>continue</span> </span><span id="__span-0-121"> </span><span id="__span-0-122"> <span>frame</span> <span>=</span> <span>self</span><span>.</span><span>frameToAnalyze</span><span>.</span><span>pop</span><span>(</span><span>0</span><span>)</span> </span><span id="__span-0-123"> </span><span id="__span-0-124"> <span>results</span> <span>=</span> <span>self</span><span>.</span><span>model</span><span>(</span><span>frame</span><span>)[</span><span>0</span><span>]</span> </span><span id="__span-0-125"> </span><span id="__span-0-126"> <span>img</span> <span>=</span> <span>results</span><span>.</span><span>plot</span><span>(</span><span>line_width</span><span>=</span><span>1</span><span>)</span> </span><span id="__span-0-127"> </span><span id="__span-0-128"> <span>qImage</span> <span>=</span> <span>QtGui</span><span>.</span><span>QImage</span><span>(</span><span>img</span><span>.</span><span>data</span><span>,</span> <span>img</span><span>.</span><span>shape</span><span>[</span><span>1</span><span>],</span> <span>img</span><span>.</span><span>shape</span><span>[</span><span>0</span><span>],</span> </span><span id="__span-0-129"> <span>QtGui</span><span>.</span><span>QImage</span><span>.</span><span>Format_RGB888</span><span>)</span> <span># 变成QImage形式</span> </span><span id="__span-0-130"> </span><span id="__span-0-131"> <span>self</span><span>.</span><span>label_treated</span><span>.</span><span>setPixmap</span><span>(</span><span>QtGui</span><span>.</span><span>QPixmap</span><span>.</span><span>fromImage</span><span>(</span><span>qImage</span><span>))</span> <span># 往显示Label里 显示QImage</span> </span><span id="__span-0-132"> </span><span id="__span-0-133"> <span>time</span><span>.</span><span>sleep</span><span>(</span><span>0.5</span><span>)</span> </span><span id="__span-0-134"> </span><span id="__span-0-135"> <span>def</span> <span>stop</span><span>(</span><span>self</span><span>):</span> </span><span id="__span-0-136"> <span>self</span><span>.</span><span>timer_camera</span><span>.</span><span>stop</span><span>()</span> <span># 关闭定时器</span> </span><span id="__span-0-137"> <span>self</span><span>.</span><span>cap</span><span>.</span><span>release</span><span>()</span> <span># 释放视频流</span> </span><span id="__span-0-138"> <span>self</span><span>.</span><span>label_ori_video</span><span>.</span><span>clear</span><span>()</span> <span># 清空视频显示区域 </span> </span><span id="__span-0-139"> <span>self</span><span>.</span><span>label_treated</span><span>.</span><span>clear</span><span>()</span> <span># 清空视频显示区域</span> </span><span id="__span-0-140"> </span><span id="__span-0-141"> </span><span id="__span-0-142"><span>app</span> <span>=</span> <span>QtWidgets</span><span>.</span><span>QApplication</span><span>()</span> </span><span id="__span-0-143"><span>window</span> <span>=</span> <span>MWindow</span><span>()</span> </span><span id="__span-0-144"><span>window</span><span>.</span><span>show</span><span>()</span> </span><span id="__span-0-145"><span>app</span><span>.</span><span>exec</span><span>()</span> </span></code>
|