英文:
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.
import sys
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtMultimedia import QCameraInfo
import cv2
from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget, QStatusBar, QLabel
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtGui import QPixmap
import numpy as np
from Process import Ui_MainWindow
import skimage.exposure
class VideoThread(QThread):
change_pixmap_signal = pyqtSignal(np.ndarray)
def __init__(self):
super().__init__()
self._run_flag = True
def run(self):
# capture from webcam
self._run_flag = True
self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
while self._run_flag:
ret, cv_img = self.cap.read()
if ret:
self.change_pixmap_signal.emit(cv_img)
# shut down capture system
self.cap.release()
def stop(self):
"""Sets run flag to False and waits for thread to finish"""
self._run_flag = False
class MyWindow(QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.available_cameras = QCameraInfo.availableCameras() # Getting available cameras
cent = QDesktopWidget().availableGeometry().center() # Finds the center of the screen
self.setStyleSheet("background-color: white;")
self.resize(1400, 800)
self.frameGeometry().moveCenter(cent)
self.setWindowTitle('S L A I T')
self.initWindow()
########################################################################################################################
# Windows #
########################################################################################################################
def initWindow(self):
# create the video capture thread
self.thread = VideoThread()
# Button to start video
self.ss_video = QtWidgets.QPushButton(self)
self.ss_video.setText('Start video')
self.ss_video.move(769, 100)
self.ss_video.resize(300, 100)
self.ss_video.clicked.connect(self.ClickStartVideo)
#Slider to change max exposure
self.slider_expo = QtWidgets.QSlider(self)
self.slider_expo.setMinimum(52)
self.slider_expo.setMaximum(255)
self.slider_expo.setProperty("value",99)
self.slider_expo.resize(10, 501)
self.slider_expo.move(700, 0)
# Status bar
self.status = QStatusBar()
self.status.setStyleSheet("background : lightblue;") # Setting style sheet to the status bar
self.setStatusBar(self.status) # Adding status bar to the main window
self.status.showMessage('Ready to start')
self.image_label = QLabel(self)
self.disply_width = 669
self.display_height = 501
self.image_label.resize(self.disply_width, self.display_height)
self.image_label.setStyleSheet("background : black;")
self.image_label.move(0, 0)
########################################################################################################################
# Buttons #
########################################################################################################################
# Activates when Start/Stop video button is clicked to Start (ss_video
def ClickStartVideo(self):
# Change label color to light blue
self.ss_video.clicked.disconnect(self.ClickStartVideo)
self.status.showMessage('Video Running...')
# Change button to stop
self.ss_video.setText('Stop video')
self.thread = VideoThread()
self.thread.change_pixmap_signal.connect(self.update_image)
# start the thread
self.thread.start()
self.ss_video.clicked.connect(self.thread.stop) # Stop the video if button clicked
self.ss_video.clicked.connect(self.ClickStopVideo)
# Activates when Start/Stop video button is clicked to Stop (ss_video)
def ClickStopVideo(self):
self.thread.change_pixmap_signal.disconnect()
self.ss_video.setText('Start video')
self.status.showMessage('Ready to start')
self.ss_video.clicked.disconnect(self.ClickStopVideo)
self.ss_video.clicked.disconnect(self.thread.stop)
self.ss_video.clicked.connect(self.ClickStartVideo)
########################################################################################################################
# Actions #
########################################################################################################################
def update_image(self, cv_img):
"""Updates the image_label with a new opencv image"""
min_expo = 50
max_expo = self.slider_expo.value()
img_expo = skimage.exposure.rescale_intensity(cv_img, in_range=(min_expo, max_expo),
out_range=(0, 255)).astype(np.uint8)
qt_img = self.convert_cv_qt(img_expo)
self.image_label.setPixmap(qt_img)
def convert_cv_qt(self, cv_img):
"""Convert from an opencv image to QPixmap"""
rgb_image = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * w
convert_to_Qt_format = QtGui.QImage(rgb_image.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
p = convert_to_Qt_format.scaled(self.disply_width, self.display_height, Qt.KeepAspectRatio)
#p = convert_to_Qt_format.scaled(801, 801, Qt.KeepAspectRatio)
return QPixmap.fromImage(p)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
win.show()
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.
import sys
from PyQt5.QtCore import QThread, pyqtSignal, Qt
from PyQt5.QtMultimedia import QCameraInfo
import cv2
from PyQt5.QtWidgets import QApplication, QMainWindow, QDesktopWidget, QStatusBar, QLabel
from PyQt5 import QtWidgets, QtGui
from PyQt5.QtGui import QPixmap
import numpy as np
import skimage.exposure
class VideoThread(QThread):
change_pixmap_signal = pyqtSignal(np.ndarray)
def __init__(self):
super().__init__()
def run(self):
# capture from webcam
self._run_flag = True
self.cap = cv2.VideoCapture(2)
while self._run_flag:
ret, cv_img = self.cap.read()
if ret:
self.change_pixmap_signal.emit(cv_img)
# shut down capture system
self.cap.release()
def stop(self):
"""Sets run flag to False and waits for thread to finish"""
self._run_flag = False
class MyWindow(QMainWindow):
def __init__(self):
super(MyWindow, self).__init__()
self.available_cameras = QCameraInfo.availableCameras() # Getting available cameras
cent = QDesktopWidget().availableGeometry().center() # Finds the center of the screen
self.setStyleSheet("background-color: white;")
self.resize(1400, 800)
self.frameGeometry().moveCenter(cent)
self.setWindowTitle('S L A I T')
self.initWindow()
self.cv_img = None
########################################################################################################################
# Windows #
########################################################################################################################
def initWindow(self):
# create the video capture thread
self.thread = VideoThread()
# Button to start video
self.ss_video = QtWidgets.QPushButton(self)
self.ss_video.setText('Start video')
self.ss_video.move(769, 100)
self.ss_video.resize(300, 100)
self.ss_video.clicked.connect(self.ClickStartVideo)
# Slider to change max exposure
self.slider_expo = QtWidgets.QSlider(self)
self.max_expo = 99
self.slider_expo.setMinimum(52)
self.slider_expo.setMaximum(255)
self.slider_expo.setProperty("value", 99)
self.slider_expo.resize(10, 501)
self.slider_expo.move(700, 0)
# Status bar
self.status = QStatusBar()
self.status.setStyleSheet("background : lightblue;") # Setting style sheet to the status bar
self.setStatusBar(self.status) # Adding status bar to the main window
self.status.showMessage('Ready to start')
self.image_label = QLabel(self)
self.disply_width = 669
self.display_height = 501
self.image_label.resize(self.disply_width, self.display_height)
self.image_label.setStyleSheet("background : black;")
self.image_label.move(0, 0)
########################################################################################################################
# Buttons #
########################################################################################################################
# Activates when Start/Stop video button is clicked to Start (ss_video
def ClickStartVideo(self):
# Change label color to light blue
self.ss_video.clicked.disconnect(self.ClickStartVideo)
self.status.showMessage('Video Running...')
# Change button to stop
self.ss_video.setText('Stop video')
self.thread = VideoThread()
self.thread.change_pixmap_signal.connect(self.update_image)
# start the thread
self.thread.start()
self.ss_video.clicked.connect(self.thread.stop) # Stop the video if button clicked
self.ss_video.clicked.connect(self.ClickStopVideo)
# Disconnect updating image when slider is changed.
if self.cv_img is not None:
self.slider_expo.valueChanged.disconnect(self.update_image_when_video_paused)
# Activates when Start/Stop video button is clicked to Stop (ss_video)
def ClickStopVideo(self):
self.thread.change_pixmap_signal.disconnect()
self.ss_video.setText('Start video')
self.status.showMessage('Ready to start')
self.ss_video.clicked.disconnect(self.ClickStopVideo)
self.ss_video.clicked.disconnect(self.thread.stop)
self.ss_video.clicked.connect(self.ClickStartVideo)
# Connect the slider signal to update image
self.slider_expo.valueChanged.connect(self.update_image_when_video_paused)
########################################################################################################################
# Actions #
########################################################################################################################
def render_processed_image(self, cv_img, min_expo=50, max_expo=255):
if min_expo != 50:
print(min_expo)
if max_expo != self.max_expo:
print(f"max_expo changed to {max_expo}")
self.max_expo = max_expo
img_expo = skimage.exposure.rescale_intensity(cv_img, in_range=(min_expo, max_expo),
out_range=(0, 255)).astype(np.uint8)
qt_img = self.convert_cv_qt(img_expo)
self.image_label.setPixmap(qt_img)
def update_image(self, cv_img):
"""Updates the image_label with a new opencv image"""
self.cv_img = cv_img
self.render_processed_image(self.cv_img, max_expo=self.slider_expo.value())
def update_image_when_video_paused(self):
self.render_processed_image(self.cv_img, max_expo=self.slider_expo.value())
def convert_cv_qt(self, cv_img):
"""Convert from an opencv image to QPixmap"""
rgb_image = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * w
convert_to_Qt_format = QtGui.QImage(rgb_image.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
p = convert_to_Qt_format.scaled(self.disply_width, self.display_height, Qt.KeepAspectRatio)
# p = convert_to_Qt_format.scaled(801, 801, Qt.KeepAspectRatio)
return QPixmap.fromImage(p)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec())
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论