如何调整显示图像的曝光(openCV / PyQT)?

huangapple go评论103阅读模式
英文:

How to adjust exposure of the displayed image (openCV / PyQT)?

问题

I use PyQT and OpenCV to get a thread from my webcam.
我使用PyQT和OpenCV从我的网络摄像头获取线程。

I use a slider to adjust the max exposure.
我使用滑块来调整最大曝光。

When I stop the thread, the last image stays displayed, but the slider doesn't adjust its exposure.
当我停止线程时,最后一幅图像仍然显示,但滑块不会调整曝光。

I guess I should connect it to a function
我猜我应该将它连接到一个函数

self.slider_expo.valueChanger['int'].connect(self.expo_value_change)

but it already works well when the thread is started. How can I make something specific to handle the last image displayed when the thread is stopped?
但是当线程启动时,它已经很好地工作了。当线程停止时,我如何制作一些特定的东西来处理最后显示的图像?

It's sometimes difficult to find the good value on a changing image; so I want to stop the thread to "pause" on a picture, adjust my value and then start the thread again.
在变化的图像上找到合适的值有时很困难;因此,我想停止线程以“暂停”在一张图片上,调整我的值,然后再次启动线程。

英文:

I use PyQT and OpenCV to get a thread from my webcam.
I use a slider to adjust the max exposure.
When I stop the thread, the last image stays displayed, but the slider doesn't adjust its exposure.
I guess I should connect it to a function

> self.slider_expo.valueChanger['int'].connect(self.expo_value_change)

but it already works well when the thread is started. How can I make something specific to handle the last image displayed when the thread is stopped?
It's sometimes difficult to find the good value on a changing image; so I want to stop the thread to "pause" on a picture, adjust my value and then start the thread again.

  1. import sys
  2. from PyQt5.QtCore import QThread, pyqtSignal, Qt
  3. from PyQt5.QtMultimedia import QCameraInfo
  4. import cv2
  5. from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget, QStatusBar, QLabel
  6. from PyQt5 import QtWidgets, QtGui
  7. from PyQt5.QtGui import QPixmap
  8. import numpy as np
  9. from Process import Ui_MainWindow
  10. import skimage.exposure
  11. class VideoThread(QThread):
  12. change_pixmap_signal = pyqtSignal(np.ndarray)
  13. def __init__(self):
  14. super().__init__()
  15. self._run_flag = True
  16. def run(self):
  17. # capture from webcam
  18. self._run_flag = True
  19. self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
  20. while self._run_flag:
  21. ret, cv_img = self.cap.read()
  22. if ret:
  23. self.change_pixmap_signal.emit(cv_img)
  24. # shut down capture system
  25. self.cap.release()
  26. def stop(self):
  27. """Sets run flag to False and waits for thread to finish"""
  28. self._run_flag = False
  29. class MyWindow(QMainWindow):
  30. def __init__(self):
  31. super(MyWindow, self).__init__()
  32. self.available_cameras = QCameraInfo.availableCameras() # Getting available cameras
  33. cent = QDesktopWidget().availableGeometry().center() # Finds the center of the screen
  34. self.setStyleSheet("background-color: white;")
  35. self.resize(1400, 800)
  36. self.frameGeometry().moveCenter(cent)
  37. self.setWindowTitle('S L A I T')
  38. self.initWindow()
  39. ########################################################################################################################
  40. # Windows #
  41. ########################################################################################################################
  42. def initWindow(self):
  43. # create the video capture thread
  44. self.thread = VideoThread()
  45. # Button to start video
  46. self.ss_video = QtWidgets.QPushButton(self)
  47. self.ss_video.setText('Start video')
  48. self.ss_video.move(769, 100)
  49. self.ss_video.resize(300, 100)
  50. self.ss_video.clicked.connect(self.ClickStartVideo)
  51. #Slider to change max exposure
  52. self.slider_expo = QtWidgets.QSlider(self)
  53. self.slider_expo.setMinimum(52)
  54. self.slider_expo.setMaximum(255)
  55. self.slider_expo.setProperty("value",99)
  56. self.slider_expo.resize(10, 501)
  57. self.slider_expo.move(700, 0)
  58. # Status bar
  59. self.status = QStatusBar()
  60. self.status.setStyleSheet("background : lightblue;") # Setting style sheet to the status bar
  61. self.setStatusBar(self.status) # Adding status bar to the main window
  62. self.status.showMessage('Ready to start')
  63. self.image_label = QLabel(self)
  64. self.disply_width = 669
  65. self.display_height = 501
  66. self.image_label.resize(self.disply_width, self.display_height)
  67. self.image_label.setStyleSheet("background : black;")
  68. self.image_label.move(0, 0)
  69. ########################################################################################################################
  70. # Buttons #
  71. ########################################################################################################################
  72. # Activates when Start/Stop video button is clicked to Start (ss_video
  73. def ClickStartVideo(self):
  74. # Change label color to light blue
  75. self.ss_video.clicked.disconnect(self.ClickStartVideo)
  76. self.status.showMessage('Video Running...')
  77. # Change button to stop
  78. self.ss_video.setText('Stop video')
  79. self.thread = VideoThread()
  80. self.thread.change_pixmap_signal.connect(self.update_image)
  81. # start the thread
  82. self.thread.start()
  83. self.ss_video.clicked.connect(self.thread.stop) # Stop the video if button clicked
  84. self.ss_video.clicked.connect(self.ClickStopVideo)
  85. # Activates when Start/Stop video button is clicked to Stop (ss_video)
  86. def ClickStopVideo(self):
  87. self.thread.change_pixmap_signal.disconnect()
  88. self.ss_video.setText('Start video')
  89. self.status.showMessage('Ready to start')
  90. self.ss_video.clicked.disconnect(self.ClickStopVideo)
  91. self.ss_video.clicked.disconnect(self.thread.stop)
  92. self.ss_video.clicked.connect(self.ClickStartVideo)
  93. ########################################################################################################################
  94. # Actions #
  95. ########################################################################################################################
  96. def update_image(self, cv_img):
  97. """Updates the image_label with a new opencv image"""
  98. min_expo = 50
  99. max_expo = self.slider_expo.value()
  100. img_expo = skimage.exposure.rescale_intensity(cv_img, in_range=(min_expo, max_expo),
  101. out_range=(0, 255)).astype(np.uint8)
  102. qt_img = self.convert_cv_qt(img_expo)
  103. self.image_label.setPixmap(qt_img)
  104. def convert_cv_qt(self, cv_img):
  105. """Convert from an opencv image to QPixmap"""
  106. rgb_image = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
  107. h, w, ch = rgb_image.shape
  108. bytes_per_line = ch * w
  109. convert_to_Qt_format = QtGui.QImage(rgb_image.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
  110. p = convert_to_Qt_format.scaled(self.disply_width, self.display_height, Qt.KeepAspectRatio)
  111. #p = convert_to_Qt_format.scaled(801, 801, Qt.KeepAspectRatio)
  112. return QPixmap.fromImage(p)
  113. if __name__ == '__main__':
  114. app = QApplication(sys.argv)
  115. win = MyWindow()
  116. win.show()
  117. sys.exit(app.exec())

答案1

得分: 0

以下是您要翻译的内容:

Your application updates image only when update_image is called. This method is only called when change_pixmap_signal signal is sent by the VideoThread. To update the image when the VideoThread is paused or stopped, you will have to first connect the slider with a new slot as you guessed. Next, you will need to save the last image received in update_image as a class member variable.

Also, make sure the slider value changed signal is not connected to a slot to update the image when the video is playing. Otherwise, you will have two different update methods running at the same time.

英文:

Your application updates image only when update_image is called. This method is only called when change_pixmap_signal signal is send by the VideoThread. To update image when the VideoThread is paused or stopped, you will have to first connect slider with a new slot as you guessed. Next, you will need to save the last image received in update_image as a class member variable.

Also, make sure the slider value changed signal is not connected to a slot to update image when video is playing. Otherwise, you will have two different update methods running at the same time.

  1. import sys
  2. from PyQt5.QtCore import QThread, pyqtSignal, Qt
  3. from PyQt5.QtMultimedia import QCameraInfo
  4. import cv2
  5. from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget, QStatusBar, QLabel
  6. from PyQt5 import QtWidgets, QtGui
  7. from PyQt5.QtGui import QPixmap
  8. import numpy as np
  9. import skimage.exposure
  10. class VideoThread(QThread):
  11. change_pixmap_signal = pyqtSignal(np.ndarray)
  12. def __init__(self):
  13. super().__init__()
  14. def run(self):
  15. # capture from webcam
  16. self._run_flag = True
  17. self.cap = cv2.VideoCapture(2)
  18. while self._run_flag:
  19. ret, cv_img = self.cap.read()
  20. if ret:
  21. self.change_pixmap_signal.emit(cv_img)
  22. # shut down capture system
  23. self.cap.release()
  24. def stop(self):
  25. """Sets run flag to False and waits for thread to finish"""
  26. self._run_flag = False
  27. class MyWindow(QMainWindow):
  28. def __init__(self):
  29. super(MyWindow, self).__init__()
  30. self.available_cameras = QCameraInfo.availableCameras() # Getting available cameras
  31. cent = QDesktopWidget().availableGeometry().center() # Finds the center of the screen
  32. self.setStyleSheet("background-color: white;")
  33. self.resize(1400, 800)
  34. self.frameGeometry().moveCenter(cent)
  35. self.setWindowTitle('S L A I T')
  36. self.initWindow()
  37. self.cv_img = None
  38. ########################################################################################################################
  39. # Windows #
  40. ########################################################################################################################
  41. def initWindow(self):
  42. # create the video capture thread
  43. self.thread = VideoThread()
  44. # Button to start video
  45. self.ss_video = QtWidgets.QPushButton(self)
  46. self.ss_video.setText('Start video')
  47. self.ss_video.move(769, 100)
  48. self.ss_video.resize(300, 100)
  49. self.ss_video.clicked.connect(self.ClickStartVideo)
  50. # Slider to change max exposure
  51. self.slider_expo = QtWidgets.QSlider(self)
  52. self.max_expo = 99
  53. self.slider_expo.setMinimum(52)
  54. self.slider_expo.setMaximum(255)
  55. self.slider_expo.setProperty("value", 99)
  56. self.slider_expo.resize(10, 501)
  57. self.slider_expo.move(700, 0)
  58. # Status bar
  59. self.status = QStatusBar()
  60. self.status.setStyleSheet("background : lightblue;") # Setting style sheet to the status bar
  61. self.setStatusBar(self.status) # Adding status bar to the main window
  62. self.status.showMessage('Ready to start')
  63. self.image_label = QLabel(self)
  64. self.disply_width = 669
  65. self.display_height = 501
  66. self.image_label.resize(self.disply_width, self.display_height)
  67. self.image_label.setStyleSheet("background : black;")
  68. self.image_label.move(0, 0)
  69. ########################################################################################################################
  70. # Buttons #
  71. ########################################################################################################################
  72. # Activates when Start/Stop video button is clicked to Start (ss_video
  73. def ClickStartVideo(self):
  74. # Change label color to light blue
  75. self.ss_video.clicked.disconnect(self.ClickStartVideo)
  76. self.status.showMessage('Video Running...')
  77. # Change button to stop
  78. self.ss_video.setText('Stop video')
  79. self.thread = VideoThread()
  80. self.thread.change_pixmap_signal.connect(self.update_image)
  81. # start the thread
  82. self.thread.start()
  83. self.ss_video.clicked.connect(self.thread.stop) # Stop the video if button clicked
  84. self.ss_video.clicked.connect(self.ClickStopVideo)
  85. # Disconnect updating image when slider is changed.
  86. if self.cv_img is not None:
  87. self.slider_expo.valueChanged.disconnect(self.update_image_when_video_paused)
  88. # Activates when Start/Stop video button is clicked to Stop (ss_video)
  89. def ClickStopVideo(self):
  90. self.thread.change_pixmap_signal.disconnect()
  91. self.ss_video.setText('Start video')
  92. self.status.showMessage('Ready to start')
  93. self.ss_video.clicked.disconnect(self.ClickStopVideo)
  94. self.ss_video.clicked.disconnect(self.thread.stop)
  95. self.ss_video.clicked.connect(self.ClickStartVideo)
  96. # Connect the slider signal to update image
  97. self.slider_expo.valueChanged.connect(self.update_image_when_video_paused)
  98. ########################################################################################################################
  99. # Actions #
  100. ########################################################################################################################
  101. def render_processed_image(self, cv_img, min_expo=50, max_expo=255):
  102. if min_expo != 50:
  103. print(min_expo)
  104. if max_expo != self.max_expo:
  105. print(f"max_expo changed to {max_expo}")
  106. self.max_expo = max_expo
  107. img_expo = skimage.exposure.rescale_intensity(cv_img, in_range=(min_expo, max_expo),
  108. out_range=(0, 255)).astype(np.uint8)
  109. qt_img = self.convert_cv_qt(img_expo)
  110. self.image_label.setPixmap(qt_img)
  111. def update_image(self, cv_img):
  112. """Updates the image_label with a new opencv image"""
  113. self.cv_img = cv_img
  114. self.render_processed_image(self.cv_img, max_expo=self.slider_expo.value())
  115. def update_image_when_video_paused(self):
  116. self.render_processed_image(self.cv_img, max_expo=self.slider_expo.value())
  117. def convert_cv_qt(self, cv_img):
  118. """Convert from an opencv image to QPixmap"""
  119. rgb_image = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
  120. h, w, ch = rgb_image.shape
  121. bytes_per_line = ch * w
  122. convert_to_Qt_format = QtGui.QImage(rgb_image.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
  123. p = convert_to_Qt_format.scaled(self.disply_width, self.display_height, Qt.KeepAspectRatio)
  124. # p = convert_to_Qt_format.scaled(801, 801, Qt.KeepAspectRatio)
  125. return QPixmap.fromImage(p)
  126. if __name__ == '__main__':
  127. app = QApplication(sys.argv)
  128. win = MyWindow()
  129. win.show()
  130. sys.exit(app.exec())

huangapple
  • 本文由 发表于 2023年6月13日 17:32:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76463500.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定