qml_puthon_user
Dec. 6, 2019, 6:10 p.m.

подружить qml и opencv

OpenCV, qml, Python 3, QML

Доброго времени суток.
Пытаюсь сделать отображение с веб-камеры в графическом интерфейсе написанном на qml.
Код программы:

  1. #системные библиотеки
  2. import cv2
  3. import numpy as np
  4. import sys
  5. import threading
  6.  
  7. #PyQt библиотеки
  8. from PyQt5.QtCore import *
  9. from PyQt5.QtGui import *
  10. from PyQt5.QtQml import *
  11. from PyQt5.QtQuick import *
  12.  
  13.  
  14. class MyImageProvider(QQuickImageProvider):
  15. def __init__(self):
  16. super(MyImageProvider, self).__init__(QQuickImageProvider.Image)
  17.  
  18. def requestImage(self, p_str, size):
  19. cap = cv2.VideoCapture(0)
  20. while True:
  21. ret, frame = cap.read()
  22. #image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
  23. height, width, channel = frame.shape
  24. #step = channel * width
  25. img = QImage(frame, width, height, QImage.Format_RGB888)
  26. #img.fill(Qt.green)
  27. return img, img.size()
  28. cv2.waitKey(1)
  29.  
  30. if __name__ == '__main__':
  31. app = QGuiApplication(sys.argv)
  32. MyImageProvider()
  33. engine = QQmlApplicationEngine()
  34. engine.addImageProvider("myprovider", MyImageProvider())
  35. engine.load(QUrl.fromLocalFile("tst.qml"))
  36. if len(engine.rootObjects()) == -1:
  37. sys.exit(-1)
  38. sys.exit(app.exec_())

Вот код формы:

  1. import QtQuick 2.12
  2. import QtQuick.Window 2.12
  3.  
  4. Window{
  5. visible: true
  6. width: 800
  7. height: 600
  8. title: ("QML OPENCV")
  9. color: "green"
  10. Image
  11. {
  12. //anchors.fill : parent
  13. source: "image://myprovider/test.png"
  14. }
  15. }

Читал статью про слоты и сигналы в python , но пока не могу сообразить, как это всё складывается воедино.
Представленный код отображает окно с веб-камерой и окно qml интерфейста.

Есть на C++ образец... Я в нём не силён, подсобите перевести на python3. :)
Утечка памяти (OpenCV + QML)

Нашёл пример с изображением:
QQuickImageProvider PyQt5
С помощью этого примера почти получилось добиться желаемого результата. Получается, что отображается только последний снятый кадр веб-камерой, а не поток. Есть идеи, как сделать поток из кадров в форму qml?

Спасибо!

Вот такой набросок пока что получился.

3

Do you like it? Share on social networks!

21
Evgenii Legotckoi
  • Dec. 9, 2019, 2:21 p.m.

Добрый день.
Да... OpenCV, конечно, интересная тема. Но вот я от неё далёк.
QQuickImageProvider использутеся для предоставления изображений, но точно не для потока этих самых изображений. В каком-то смысле все те примеры выглядят как костыли, поскольку QQuickImageProvider используется не по своему прямому назначению. Но тем не менее это должно работать.

Обратите своё внимание на то, что в примере с утечкой памяти имеется сигнал, который сообщает об изменении изображения на каждый новый кадр. Вам нужно сделать тоже самое. Вам нуэно использовать сигналы и слоты для этого. Не помню, вы уже кажется смотрели ту статью по сигналам и слотам PyQt5 - Урок 007. Работаем с QML QtQuick (Сигналы и слоты)

    qml_puthon_user
    • Dec. 9, 2019, 2:27 p.m.

    Добрый.
    Да, я пытался связаться через сигналы и слоты, но у меня не выходит перевести программу с плюсов на питон. Если не затруднит помочь в переводе, то есть вероятность, что получится написать конечный результат. :)

      Evgenii Legotckoi
      • Dec. 9, 2019, 2:45 p.m.

      Думаю, что в QQuickImageProvider следует добавить сигнал, что-то вроде такого

      1. class MyImageProvider(QQuickImageProvider):
      2. frameChanged = pyqtSignal()

      А потом как минимум подключить к этому сигналу обработчик в QML и посмотреть, сыпется ли что-то нибудь в консоль QML

      1. Window
      2. {
      3. visible: true
      4. width: 640
      5. height: 480
      6. title: ("QML OPENCV")
      7. color: "green"
      8. id: root
      9.  
      10. // ...
      11.  
      12. Connections
      13. {
      14. target: myprovider
      15. property int frameCounter: 0
      16.  
      17. onFrameChanged:
      18. {
      19. frameCounter ^= 1;
      20. console.log(frameCounter); // проверяем здесь изменение счётчика
      21. }
      22. }
      23. }

      Тогда уже можно будет пытаться сообразить что-нибудь дальше

        qml_puthon_user
        • Dec. 9, 2019, 3:06 p.m.

        А через "console.log" Вы куда выводите сообщения? В PyCharm? Я работаю в основном в стандартной IDLE Python. Такое не срабатывает в стандартной IDLE. PyCharm у меня стоит.

          Evgenii Legotckoi
          • Dec. 9, 2019, 3:12 p.m.

          вообще - это тоже должно сыпаться в консоль и без разницы, какую IDE использовать. К IDE это не должно иметь никакого отношения. Если вывода нет, то скорее всего не работает.

          А да, ещё этот сигнал нужно вызывать

          1. class MyImageProvider(QQuickImageProvider):
          2. frameChanged = pyqtSignal()
          3.  
          4. def __init__(self):
          5. super(MyImageProvider, self).__init__(QQuickImageProvider.Image)
          6.  
          7. def requestImage(self, p_str, size):
          8. cap = cv2.VideoCapture(0)
          9. while True:
          10. ret, frame = cap.read()
          11. #image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
          12. height, width, channel = frame.shape
          13. #step = channel * width
          14. img = QImage(frame, width, height, QImage.Format_RGB888)
          15. #img.fill(Qt.green)
          16. self.frameChanged.emit() # вызвать сигнал
          17. return img, img.size() # а вот из-за этого у вас выполняется выход из функции,
          18. cv2.waitKey(1) # до выполнения этого кода метод никогда не доходит

          И кстати сам запрос изображения у вас как-то странно написан

            qml_puthon_user
            • Dec. 9, 2019, 3:18 p.m.

            Вы сейчас разбираете некий костыль, посоветовали с сигналами и слотами поработать, вот и хочу с ними разобраться, если так имеет место быть более правильное решение.) Я могу по-новому написать, чтобы было понятнее работать.

              Evgenii Legotckoi
              • Dec. 9, 2019, 3:21 p.m.

              что предоставлено, с тем и работаю. не писать же мне с нуля ваш проект ))

                qml_puthon_user
                • Dec. 9, 2019, 3:33 p.m.
                • (edited)

                Это понятное дело.)
                Я сделал вот так, чтобы проверить, работает ли счётчик.
                Код программы:

                1. # системные библиотеки
                2. import cv2
                3. import numpy as np
                4. import sys
                5. import threading
                6.  
                7. # PyQt библиотеки
                8. from PyQt5.QtCore import *
                9. from PyQt5.QtGui import *
                10. from PyQt5.QtQml import *
                11. from PyQt5.QtQuick import *
                12.  
                13.  
                14. class MyImageProvider(QQuickImageProvider):
                15. def __init__(self):
                16. super(MyImageProvider, self).__init__(QQuickImageProvider.Image)
                17.  
                18. frameChanged = pyqtSignal()
                19.  
                20. def reauestSignal(self):
                21.  
                22. self.frameChanged.emit() #вызываю сигнал
                23.  
                24. if __name__ == '__main__':
                25.  
                26. # создаём экземпляр приложения
                27. app = QGuiApplication(sys.argv)
                28. # создаём QML движок
                29. engine = QQmlApplicationEngine()
                30. # создаём объект vision
                31. videoProvider = MyImageProvider()
                32. # и регистрируем его в контексте QML
                33. engine.rootContext().setContextProperty("myprovider", videoProvider)
                34. #engine.addImageProvider("myprovider", videoProvider)
                35. # загружаем файл qml в движок
                36. engine.load("test.qml")
                37.  
                38. engine.quit.connect(app.quit)
                39. sys.exit(app.exec_())

                Код формы:

                1. import QtQuick 2.12
                2. import QtQuick.Window 2.12
                3. import QtQuick.Controls 2.12
                4.  
                5. Window
                6. {
                7. visible: true
                8. width: 640
                9. height: 480
                10. title: ("QML OPENCV")
                11. color: "green"
                12. id: root
                13.  
                14. // ...
                15.  
                16. TextArea
                17. {
                18. id: debug_area
                19. x: 183
                20. y: 361
                21. width: 275
                22. height: 145
                23. text: qsTr("Debug\n")
                24. selectByMouse: true
                25. }
                26.  
                27. Connections
                28. {
                29. target: myprovider
                30. property int frameCounter: 0
                31.  
                32. onFrameChanged:
                33. {
                34. frameCounter ^= 1;
                35. debug_area.text += frameCounter; // проверяем здесь изменение счётчика
                36. }
                37. }
                38. }

                Не хочет работать.

                  qml_puthon_user
                  • Dec. 9, 2019, 6:16 p.m.

                  Я сделал простой вывод текста по испусканию сигнала...
                  Чего не хватает программе?)
                  Python:

                  1. # системные библиотеки
                  2. import cv2
                  3. import numpy as np
                  4. import sys
                  5. import threading
                  6.  
                  7. # PyQt библиотеки
                  8. from PyQt5.QtCore import *
                  9. from PyQt5.QtGui import *
                  10. from PyQt5.QtQml import *
                  11. from PyQt5.QtQuick import *
                  12.  
                  13.  
                  14. class MyImageProvider(QObject):
                  15. def __init__(self):
                  16. QObject.__init__(self)
                  17.  
                  18. frameChanged = pyqtSignal()
                  19.  
                  20.  
                  21. if __name__ == '__main__':
                  22.  
                  23. # создаём экземпляр приложения
                  24. app = QGuiApplication(sys.argv)
                  25. # создаём QML движок
                  26. engine = QQmlApplicationEngine()
                  27. # создаём объект vision
                  28. videoProvider = MyImageProvider()
                  29. # и регистрируем его в контексте QML
                  30. engine.rootContext().setContextProperty("myprovider", videoProvider)
                  31. #engine.addImageProvider("myprovider", videoProvider)
                  32. # загружаем файл qml в движок
                  33. engine.load("test.qml")
                  34.  
                  35. engine.quit.connect(app.quit)
                  36. sys.exit(app.exec_())
                  37.  

                  QML:

                  1. import QtQuick 2.12
                  2. import QtQuick.Window 2.12
                  3. import QtQuick.Controls 2.12
                  4.  
                  5. Window
                  6. {
                  7. visible: true
                  8. width: 640
                  9. height: 480
                  10. title: ("QML OPENCV")
                  11. color: "green"
                  12. id: root
                  13.  
                  14. //здесь увидим информацию
                  15. TextArea
                  16. {
                  17. id: debug_area
                  18. x: 183
                  19. y: 10
                  20. width: 200
                  21. height: 400
                  22. text: qsTr("Debug\n")
                  23. selectByMouse: true
                  24. }
                  25. Button
                  26. {
                  27. x: 10
                  28. y: 10
                  29. width: 100
                  30. height: 50
                  31. text: qsTr("Debug Btn")
                  32. onClicked:
                  33. {
                  34. debug_area.text += "BTN is WORK\n"
                  35. }
                  36. }
                  37. Connections
                  38. {
                  39. target: myprovider
                  40. property int frameCounter: 0
                  41.  
                  42. onFrameChanged:
                  43. {
                  44. debug_area.text = "Signal is work"
                  45. //frameCounter += 1;
                  46. //debug_area.text = frameCounter; // проверяем здесь изменение счётчика
                  47. }
                  48. }
                  49. }
                    qml_puthon_user
                    • Dec. 12, 2019, 10:05 p.m.

                    Есть на qml что-то типа window.onload? Чтобы при загрузке формы срабатывал сигнал. По нажатию кнопки всё прекрасно работает... А вот при загрузке формы нет...

                      qml_puthon_user
                      • Dec. 12, 2019, 10:49 p.m.

                      Да, с console.log() я разобрался, счётчик ничего не показывает

                        Evgenii Legotckoi
                        • Dec. 13, 2019, 2:42 p.m.

                        У всех компонентов есть встраиваемый обработчик Component.onCompleted, который выполняется, когда объект полностью создан

                        1. Window {
                        2. Component.onCompleted: {
                        3. console.log("Window Completed Running!")
                        4. }
                        5. }
                          Evgenii Legotckoi
                          • Dec. 13, 2019, 2:43 p.m.

                          Наверное сигнал всё-таки не вызывается правильно

                            qml_puthon_user
                            • Dec. 13, 2019, 2:53 p.m.

                            А не подскажете, как вызвать правильно? :)

                              qml_puthon_user
                              • Dec. 16, 2019, 6:42 p.m.
                              • (edited)

                              Сделал вот такой вариант и он работает, только мне непонятно, почему в консоли пишется undefined...
                              Форма:

                              1. import QtQuick 2.12
                              2. import QtQuick.Window 2.12
                              3. import QtQuick.Controls 2.12
                              4.  
                              5. Window
                              6. {
                              7. visible: true
                              8. width: 640
                              9. height: 480
                              10. title: ("QML OPENCV")
                              11. color: "green"
                              12. id: root
                              13.  
                              14. Component.onCompleted:
                              15. {
                              16. console.log("onload")
                              17. console.log(myprovider.say())
                              18. }
                              19.  
                              20. Connections
                              21. {
                              22. target: myprovider
                              23.  
                              24. /*onFrameChanged:
                              25. {
                              26. }*/
                              27. }
                              28. }

                              Скрипт:

                              1. # системные библиотеки
                              2. import cv2
                              3. import numpy as np
                              4. import sys
                              5. import threading
                              6.  
                              7. # PyQt библиотеки
                              8. from PyQt5.QtCore import *
                              9. from PyQt5.QtGui import *
                              10. from PyQt5.QtQml import *
                              11. from PyQt5.QtQuick import *
                              12.  
                              13.  
                              14. class MyImageProvider(QObject):
                              15.  
                              16. def __init__(self):
                              17. QObject.__init__(self)
                              18.  
                              19. #frameChanged = pyqtSignal()
                              20.  
                              21. @pyqtSlot()
                              22. def say(self):
                              23. print("blablabla")
                              24.  
                              25. if __name__ == '__main__':
                              26.  
                              27. # создаём экземпляр приложения
                              28. app = QGuiApplication(sys.argv)
                              29. # создаём QML движок
                              30. engine = QQmlApplicationEngine()
                              31. # создаём объект vision
                              32. videoProvider = MyImageProvider()
                              33. # и регистрируем его в контексте QML
                              34. engine.rootContext().setContextProperty("myprovider", videoProvider)
                              35. #engine.addImageProvider("myprovider", videoProvider)
                              36. # загружаем файл qml в движок
                              37. engine.load("test.qml")
                              38.  
                              39. engine.quit.connect(app.quit)
                              40. sys.exit(app.exec_())
                              41.  

                                Evgenii Legotckoi
                                • Dec. 17, 2019, 1:40 p.m.

                                undefined пишет потому, что метод сам по себе ничего не возвращает, то есть void, напишите так

                                1. Component.onCompleted:
                                2. {
                                3. console.log("onload")
                                4. console.log(myprovider)
                                5. }
                                  qml_puthon_user
                                  • Dec. 17, 2019, 2:07 p.m.

                                  Вернул код инструкции, если я правильно понял.

                                    Evgenii Legotckoi
                                    • Dec. 17, 2019, 2:10 p.m.

                                    Вернулся указатель на ваш объект. Ну слот срабатывает. Вам теперь нужно дальше развить вашу задачу. У меня к сожалению нет времени разбираться с opencv, поэтому не могу ответить на некоторые вопросы.

                                      qml_puthon_user
                                      • Dec. 17, 2019, 2:16 p.m.

                                      С opencv я разберусь. :) У меня пока только вопросы по сигналам и слотам.)

                                        Михаиллл
                                        • Dec. 28, 2019, 7:46 p.m.
                                        • (edited)

                                        На сколько мне известно в opencv с камеры подпются картинки через определенное время и так выходит видео. По идее можно по получении этой картинки передавать ее в qml. Прикрепить сигнал к получению картинки или таймеру и так подовать сигнал в qml об необходимости обновления.

                                          qml_puthon_user
                                          • Dec. 28, 2019, 8:28 p.m.

                                          Если смотреть глубже, то там подаётся массив байтов(bytes в питоне). Ну, а по простому, то да. Я пока не разобрался как переменную передавать в qml форму. В этой самой переменной, пускай будет frame, как раз хранится поток с веб-камеры. Как только я передам её на форму, то по идее, элемент в котором будет "отображаться" данная переменная, нужно же перерисовывать, чтобы кадры обновлялись.

                                            Comments

                                            Only authorized users can post comments.
                                            Please, Log in or Sign up
                                            • Last comments
                                            • AK
                                              April 1, 2025, 11:41 a.m.
                                              Добрый день. В данный момент работаю над проектом, где необходимо выводить звук из программы в определенное аудиоустройство (колонки, наушники, виртуальный кабель и т.д). Пишу на Qt5.12.12 поско…
                                            • Evgenii Legotckoi
                                              March 9, 2025, 9:02 p.m.
                                              К сожалению, я этого подсказать не могу, поскольку у меня нет необходимости в обходе блокировок и т.д. Поэтому я и не задавался решением этой проблемы. Ну выглядит так, что вам действитель…
                                            • VP
                                              March 9, 2025, 4:14 p.m.
                                              Здравствуйте! Я устанавливал Qt6 из исходников а также Qt Creator по отдельности. Все компоненты, связанные с разработкой для Android, установлены. Кроме одного... Когда пытаюсь скомпилиров…
                                            • ИМ
                                              Nov. 22, 2024, 9:51 p.m.
                                              Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
                                            • Evgenii Legotckoi
                                              Oct. 31, 2024, 11:37 p.m.
                                              Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup