Я хотел добавить изображение захвата с помощью веб-камеры в окно графического интерфейса PyQt, и изображение веб-камеры появится в окне графического интерфейса - PullRequest
0 голосов
/ 24 сентября 2018

Я хотел добавить изображение с веб-камеры в главное окно графического интерфейса, и оно будет отправлено на электронный адрес.Если это невозможно, я также хочу сохранить это изображение, и это сохраненное изображение будет отправлено на мой адрес электронной почты. В обратном отсчете до 3,2,1, улыбнитесь, оно щелкнет изображение по веб-камере.Вот мой код:

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_()

1 Ответ

0 голосов
/ 24 сентября 2018

Прежде всего вам не нужно использовать cv2.imshow() внутри PyQt, поскольку он блокирует цикл событий Python. Если вы хотите показать изображение opencv в PyQt, вам нужно преобразовать его в QImage или QPixmap, следующий класс реализуетсбор данных opencv, и он позволяет получить QImage, но он должен выполняться в потоке.

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)

С помощью вышеизложенногопоказать камеру в QLabel, с другой стороны мы должны преобразовать QImage в байты, для этого мы используем QByteArray с QBuffer.Другая проблема, которая возникает, заключается в том, что отправка электронной почты занимает некоторое время, поэтому графический интерфейс пользователя может быть заблокирован, поэтому он должен выполняться в потоке.И, наконец, я добавил 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_())
...