[英]I wanted to add capturing image by using webcam to my PyQt gui window and webcam image will come on gui window
I wanted to add the webcam image to my main GUI window and that image will send to the email id.我想将网络摄像头图像添加到我的主 GUI 窗口,该图像将发送到电子邮件 ID。 If this is not Possible, I also want to save that image and that saved image will send to my email id and On the countdown to 3,2,1, smile it will click the image by webcam.如果这不可能,我还想保存该图像,保存的图像将发送到我的电子邮件 ID,在 3、2、1 倒计时,微笑它会通过网络摄像头单击图像。 Here, is my code:这是我的代码:
import sys
from PyQt5 import QtCore
from PyQt5 import QtWidgets, QtGui
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
import cv2, time
DURATION_INT = 5
class MyMainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.time_left_int = DURATION_INT
self.widget_counter_int = 0
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
vbox = QtWidgets.QVBoxLayout()
central_widget.setLayout(vbox)
self.pages_qsw = QtWidgets.QStackedWidget()
vbox.addWidget(self.pages_qsw)
self.time_passed_qll = QtWidgets.QLabel()
vbox.addWidget(self.time_passed_qll)
self.pushButton = QtWidgets.QPushButton()
self.pushButton.setText("Push to start")
self.yesbutton = QtWidgets.QToolButton()
self.yesbutton.setText("yes")
self.Nobutton = QtWidgets.QToolButton()
self.Nobutton.setText("No")
self.imageframe = QtWidgets.QLabel()
self.imageframe.setText("fghkfhh")
vbox.addWidget(self.Nobutton)
vbox.addWidget(self.yesbutton)
vbox.addWidget(self.pushButton)
vbox.addWidget(self.imageframe)
self.pushButton.clicked.connect(self.timer_start)
self.yesbutton.clicked.connect(self.capturing_image)
self.update_gui()
def gmail_alert(self):
email_user = 'user email_id'
email_send = 'receiver email_id'
subject = 'Alert system'
msg = MIMEMultipart()
msg['From'] = email_user
msg['To'] = email_send
msg['Subject'] = subject
msg.preamble = "test"
body = 'Hi there, sending this email from Python!'
msg.attach(MIMEText(body, 'plain'))
filename = 'alert.png'
attachment = open(filename, 'rb')
part = MIMEBase('application', 'octet-stream')
part.set_payload((attachment).read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', "attachment;
filename= " + filename)
msg.attach(part)
text = msg.as_string()
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(email_user, 'user email_id password')
server.sendmail(email_user, email_send, text)
server.quit()
def timer_start(self):
self.time_left_int = DURATION_INT
self.my_qtimer = QtCore.QTimer(self)
self.my_qtimer.timeout.connect(self.timer_timeout)
self.my_qtimer.start(1000)
self.update_gui()
def timer_timeout(self):
if self.time_left_int > 0:
self.time_left_int -= 1
else:
self.gmail_alert()
self.update_gui()
def update_gui(self):
self.time_passed_qll.setText((str(self.time_left_int) if self.time_left_int >=1 else "Smile..!"))
def capturing_image(self):
video =cv2.VideoCapture(0)
check, frame = video.read()
print(check)
print(frame)
cv2.imshow("capturing", frame)
video.release()
app = QtWidgets.QApplication(sys.argv)
main_window = MyMainWindow()
main_window.show()
sys.exit(app.exec_()
First of all you do not have to use cv2.imshow()
inside PyQt since it blocks the python event loop, if you want to show the image of opencv in PyQt you have to convert it to QImage or QPixmap, the next class implements the data acquisition of opencv and it allows to obtain the QImage but it must be executed in a thread.首先你不必在 PyQt 中使用cv2.imshow()
因为它会阻塞 python 事件循环,如果你想在 PyQt 中显示 opencv 的图像你必须将它转换为 QImage 或 QPixmap,下一个类实现opencv的数据采集,它允许获取QImage,但必须在线程中执行。
OpencvQt.py OpencvQt.py
import cv2
import numpy as np
from PyQt5 import QtCore, QtGui, QtWidgets
class Capture(QtCore.QObject):
started = QtCore.pyqtSignal()
frameReady = QtCore.pyqtSignal(np.ndarray)
def __init__(self, parent=None):
super(Capture, self).__init__(parent)
self._frame = None
self.m_timer = QtCore.QBasicTimer()
self.m_videoCapture = cv2.VideoCapture()
@QtCore.pyqtSlot()
def start(self, cam=0):
if self.m_videoCapture is not None:
self.m_videoCapture.release()
self.m_videoCapture = cv2.VideoCapture(cam)
if self.m_videoCapture.isOpened():
self.m_timer.start(0, self)
self.started.emit()
@QtCore.pyqtSlot()
def stop(self):
self.m_timer.stop()
def __del__(self):
self.m_videoCapture.release()
def frame(self):
return self.m_frame
def timerEvent(self, event):
if event.timerId() != self.m_timer.timerId():
return
ret, val = self.m_videoCapture.read()
if not ret:
self.m_timer.stop()
return
self.m_frame = val
self.frameReady.emit(self.m_frame)
frame = QtCore.pyqtProperty(np.ndarray, fget=frame, notify=frameReady, user=True)
class Converter(QtCore.QObject):
imageReady = QtCore.pyqtSignal(QtGui.QImage)
def __init__(self, parent=None):
super(Converter, self).__init__(parent)
self.m_frame = np.array([])
self.m_timer = QtCore.QBasicTimer()
self.m_processAll = True
self.m_image = QtGui.QImage()
def queue(self, frame):
self.m_frame = frame
if not self.m_timer.isActive():
self.m_timer.start(0, self)
def process(self, frame):
w, h, _ = frame.shape
rgbImage = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.m_image = QtGui.QImage(rgbImage.data, h, w, QtGui.QImage.Format_RGB888)
self.imageReady.emit(QtGui.QImage(self.m_image))
def timerEvent(self, event):
if event.timerId() != self.m_timer.timerId():
return
self.process(self.m_frame)
self.m_timer.stop()
def processAll(self):
return self.m_processAll
def setProcessAll(self, _all):
self.m_processAll = _all
def processFrame(self, frame):
if self.m_processAll:
self.process(frame)
else:
self.queue(frame)
def image(self):
return self.m_image
image = QtCore.pyqtProperty(QtGui.QImage, fget=image, notify=imageReady, user=True)
processAll = QtCore.pyqtProperty(bool, fget=processAll, fset=setProcessAll)
With the above we can show the camera in a QLabel, on the other hand we must convert the QImage to bytes for it we use QByteArray with QBuffer.有了上面我们可以在 QLabel 中显示相机,另一方面,我们必须将 QImage 转换为字节,因为我们使用 QByteArray 和 QBuffer。 Another problem that arises is that the sending of email takes a while so the GUI can be blocked so it must be executed in a thread.出现的另一个问题是电子邮件的发送需要一段时间,因此 GUI 可能会被阻塞,因此必须在线程中执行。 And finally I added a QDialog where you must enter the mail data.最后我添加了一个 QDialog,您必须在其中输入邮件数据。
main.py主文件
import sys
import threading
from PyQt5 import QtCore, QtGui, QtWidgets
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.base import MIMEBase
from email import encoders
from OpencvQt import Capture, Converter
config = {
"DURATION_INT": 5
}
def send_email(user, pwd, recipient, subject, body, image_payload):
msg = MIMEMultipart()
msg['From'] = user
msg['To'] = recipient
msg['Subject'] = subject
msg.attach(MIMEText(body, 'plain'))
part = MIMEBase('application', 'octet-stream')
part.set_payload(image_payload)
encoders.encode_base64(part)
filename = QtCore.QDateTime.currentDateTime().toString()+ '.png'
part.add_header('Content-Disposition', "attachment; filename= " + filename)
msg.attach(part)
text = msg.as_string()
server = smtplib.SMTP('smtp.gmail.com', 587)
server.starttls()
server.login(user, pwd)
server.sendmail(user, recipient, text)
server.quit()
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QVBoxLayout(central_widget)
self.view = QtWidgets.QLabel()
self.btn_start = QtWidgets.QPushButton("Start")
self.btn_stop = QtWidgets.QPushButton("Stop")
self.btn_send = QtWidgets.QPushButton("Send Email")
self.label_time = QtWidgets.QLabel()
lay.addWidget(self.view, alignment=QtCore.Qt.AlignCenter)
lay.addWidget(self.btn_start)
lay.addWidget(self.btn_stop)
lay.addWidget(self.btn_send)
lay.addWidget(self.label_time, alignment=QtCore.Qt.AlignCenter)
self.view.setFixedSize(640, 400)
self.show()
self.init_camera()
self.init_email()
def init_camera(self):
self.capture = Capture()
self.converter = Converter()
captureThread = QtCore.QThread(self)
converterThread = QtCore.QThread(self)
self.converter.setProcessAll(False)
captureThread.start()
converterThread.start()
self.capture.moveToThread(captureThread)
self.converter.moveToThread(converterThread)
self.capture.frameReady.connect(self.converter.processFrame)
self.converter.imageReady.connect(self.setImage)
self.capture.started.connect(lambda: print("started"))
self.btn_start.clicked.connect(self.capture.start)
self.btn_stop.clicked.connect(self.capture.stop)
@QtCore.pyqtSlot(QtGui.QImage)
def setImage(self, image):
self.view.setPixmap(QtGui.QPixmap.fromImage(image))
def init_email(self):
timeline = QtCore.QTimeLine(config["DURATION_INT"]*1000, self)
timeline.frameChanged.connect(self.onFrameChanged)
timeline.setFrameRange(0, config["DURATION_INT"])
timeline.setDirection(QtCore.QTimeLine.Backward)
self.btn_send.clicked.connect(timeline.start)
d = EmailDialog(self)
if d.exec_() == EmailDialog.Accepted:
self._info = d.get_data()
def onFrameChanged(self, frame):
if frame !=0:
self.label_time.setNum(frame)
else:
self.label_time.setText("Smile...!")
QtWidgets.QApplication.beep()
image = QtGui.QImage(self.converter.image)
ba = QtCore.QByteArray()
buff = QtCore.QBuffer(ba)
image.save(buff, "PNG")
th = threading.Thread(target=send_email, args=(*self._info, ba))
th.start()
def closeEvent(self, event):
self.capture.stop()
super(MainWindow, self).closeEvent(event)
class EmailDialog(QtWidgets.QDialog):
def __init__(self, parent=None):
super(EmailDialog, self).__init__(parent)
lay = QtWidgets.QFormLayout(self)
self.from_le = QtWidgets.QLineEdit()
self.pass_le = QtWidgets.QLineEdit(echoMode=QtWidgets.QLineEdit.Password)
self.to_le = QtWidgets.QLineEdit()
self.subject_le = QtWidgets.QLineEdit()
self.body_te = QtWidgets.QTextEdit()
self.buttonBox = QtWidgets.QDialogButtonBox()
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.accepted.connect(self.accept)
self.buttonBox.rejected.connect(self.reject)
lay.addRow("From: ", self.from_le)
lay.addRow("Password: ", self.pass_le)
lay.addRow("To: ", self.to_le)
lay.addRow("Subject: ", self.subject_le)
lay.addRow("Body: ", self.body_te)
lay.addRow(self.buttonBox)
self.from_le.textChanged.connect(self.enable_button)
self.pass_le.textChanged.connect(self.enable_button)
self.to_le.textChanged.connect(self.enable_button)
self.enable_button()
def enable_button(self):
disabled = self.from_le.text() == "" or self.pass_le.text() == "" or self.to_le.text() == ""
self.buttonBox.setDisabled(disabled)
def get_data(self):
return self.from_le.text(), self.pass_le.text(), self.to_le.text(), self.subject_le.text(), self.body_te.toPlainText()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec_())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.