pyQT + OpenCV 的三个练习
一、创建一个 PyQt 应用程序,该应用程序能够:
- 使用 OpenCV 加载一张图像。
- 在 PyQt 的窗口中显示这张图像。
- 提供四个按钮(QPushButton):
- 一个用于将图像转换为灰度图
- 一个用于将图像恢复为原始彩色图
- 一个用于将图像进行翻转
- 一个用于将图像进行旋转
- 当用户点击按钮时,相应地更新窗口中显示的图像。
思路分析
- 加载图像:
- 使用 OpenCV 加载一张图像,并将其存储为类的一个属性,以便在后续操作中访问。
- 显示图像:
- 使用 PyQt6 的
QLabel
来显示图像。 - 将图像转换为
QPixmap
,然后设置为QLabel
的图像。
- 使用 PyQt6 的
- 创建按钮:
- 使用 PyQt6 的
QPushButton
创建四个按钮,每个按钮对应一个图像处理功能。
- 使用 PyQt6 的
- 实现图像处理功能:
- 灰度图:使用 OpenCV 的
cv2.cvtColor
函数将图像转换为灰度图。 - 恢复原始图像:重新加载或存储原始图像,并在需要时恢复。
- 翻转图像:使用 OpenCV 的
cv2.flip
函数进行水平翻转。 - 旋转图像:使用 OpenCV 的
cv2.getRotationMatrix2D
和cv2.warpAffine
函数进行旋转。
- 灰度图:使用 OpenCV 的
- 更新显示:
- 每当用户点击按钮时,调用相应的图像处理函数,更新存储的图像,并刷新
QLabel
上的显示。
- 每当用户点击按钮时,调用相应的图像处理函数,更新存储的图像,并刷新
涉及到的函数方法
cv2.imread(filepath)
: 加载图像。cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
: 将图像转换为灰度图。cv2.flip(image, 1)
: 水平翻转图像。cv2.getRotationMatrix2D(center, angle, scale)
: 获取旋转矩阵。cv2.warpAffine(image, rotation_matrix, (width, height))
: 使用旋转矩阵旋转图像。QImage(data, width, height, format)
: 将图像数据转换为QImage
。QPixmap.fromImage(image)
: 将QImage
转换为QPixmap
。QLabel.setPixmap(pixmap)
: 设置QLabel
的图像。
代码实现
import sys
import cv2
from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget
from PyQt6.QtGui import QImage, QPixmap
from PyQt6.QtCore import Qt
import numpy as np
class ImageProcessor(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Image Processor")
self.setGeometry(100, 100, 800, 600)
self.original_image = cv2.imread('path_to_your_image.jpg')
self.current_image = self.original_image.copy()
self.qimage = self.convert_cv_qt(self.current_image)
self.image_label = QLabel(self)
self.image_label.setPixmap(QPixmap.fromImage(self.qimage))
self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.gray_button = QPushButton('Gray Scale')
self.restore_button = QPushButton('Restore Original')
self.flip_button = QPushButton('Flip Image')
self.rotate_button = QPushButton('Rotate Image')
self.gray_button.clicked.connect(self.convert_to_gray)
self.restore_button.clicked.connect(self.restore_original)
self.flip_button.clicked.connect(self.flip_image)
self.rotate_button.clicked.connect(self.rotate_image)
layout = QVBoxLayout()
layout.addWidget(self.image_label)
layout.addWidget(self.gray_button)
layout.addWidget(self.restore_button)
layout.addWidget(self.flip_button)
layout.addWidget(self.rotate_button)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def convert_cv_qt(self, cv_img):
rgb_image = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * w
convert_to_Qt_format = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format.Format_RGB888)
return convert_to_Qt_format
def update_image_display(self):
self.qimage = self.convert_cv_qt(self.current_image)
self.image_label.setPixmap(QPixmap.fromImage(self.qimage))
def convert_to_gray(self):
self.current_image = cv2.cvtColor(self.current_image, cv2.COLOR_BGR2GRAY)
# Convert back to BGR for compatibility (if needed)
self.current_image = cv2.cvtColor(self.current_image, cv2.COLOR_GRAY2BGR)
self.update_image_display()
def restore_original(self):
self.current_image = self.original_image.copy()
self.update_image_display()
def flip_image(self):
"""Flip the image horizontally"""
self.current_image = cv2.flip(self.current_image, 1)
self.update_image_display()
def rotate_image(self):
"""Rotate the image by 90 degrees"""
(h, w) = self.current_image.shape[:2]
center = (w // 2, h // 2)
rotation_matrix = cv2.getRotationMatrix2D(center, 90, 1.0)
self.current_image = cv2.warpAffine(self.current_image, rotation_matrix, (w, h))
self.update_image_display()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = ImageProcessor()
window.show()
sys.exit(app.exec())
效果展示
QQ20241228-94934-HD
二、创建一个 PyQt 应用程序,该应用程序能够:
- 使用 OpenCV 加载一张彩色图像,并在 PyQt 的窗口中显示它。
- 提供一个滑动条(QSlider),允许用户调整图像的亮度。
- 当用户调整滑动条时,实时更新窗口中显示的图像亮度。
- 添加另一个滑动条(QSlider),允许用户调整图像的对比度。
- 当用户调整滚动条时,实时更新窗口中显示的图像对比度。
- 提供一个按钮(QPushButton),允许用户将图像保存为新的文件。
- 当用户点击保存按钮时,将调整后的图像保存到指定的路径,OpenCV中使用cv2.imwrite()来保存图片。
思路分析
- 创建 PyQt 应用程序:
- 使用
QApplication
创建应用程序实例。 - 使用
QMainWindow
或QWidget
创建主窗口。
- 使用
- 加载和显示图像:
- 使用 OpenCV (
cv2.imread()
) 加载彩色图像。 - 将 OpenCV 图像(NumPy 数组)转换为 QImage,以便在 PyQt 中显示。
- 使用
QLabel
来显示 QImage。
- 使用 OpenCV (
- 实现亮度调整:
- 添加一个
QSlider
用于亮度调整。 - 连接滑动条的
valueChanged
信号到一个槽函数,该槽函数根据滑动条的值调整图像的亮度。 - 亮度调整可以通过将每个像素值加上一个偏移量来实现。
- 添加一个
- 实现对比度调整:
- 添加另一个
QSlider
用于对比度调整。 - 连接滑动条的
valueChanged
信号到一个槽函数,该槽函数根据滑动条的值调整图像的对比度。 - 对比度调整可以通过线性变换(如
new_pixel = alpha * (old_pixel - 127) + 127
)来实现,其中alpha
是对比度因子。
- 添加另一个
- 保存图像:
- 添加一个
QPushButton
用于保存图像。 - 连接按钮的
clicked
信号到一个槽函数,该槽函数使用 OpenCV 的cv2.imwrite()
保存调整后的图像。
- 添加一个
设计到的函数方法
cv2.imread()
: 加载图像。cv2.cvtColor()
: 转换图像颜色空间(如从 BGR 到 RGB)。QImage()
: 创建 QImage 对象。QSlider()
: 创建滑动条。QPushButton()
: 创建按钮。QLabel()
: 创建标签用于显示图像。QVBoxLayout()
/QHBoxLayout()
: 布局管理器。valueChanged
信号: 捕捉滑动条值的变化。clicked
信号: 捕捉按钮点击事件。cv2.imwrite()
: 保存图像。
代码实现
import sys
import cv2
from PyQt6.QtWidgets import QApplication, QMainWindow, QSlider, QVBoxLayout, QWidget, QPushButton, QLabel
from PyQt6.QtGui import QImage, QPixmap
from PyQt6.QtCore import Qt
class ImageProcessor(QMainWindow):
def __init__(self):
super().__init__()
# 加载图像
self.image_path = 'C:\\Users\\lilba\\Desktop\\1228.jpg'
self.image = cv2.imread(self.image_path)
if self.image is None:
print(f"Error: Unable to load image at {self.image_path}")
sys.exit(1)
self.brightness = 0
self.contrast = 1
self.initUI()
def initUI(self):
self.setWindowTitle('Image Processor')
self.setGeometry(100, 100, 800, 600)
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout = QVBoxLayout()
self.central_widget.setLayout(self.layout)
self.image_label = QLabel()
self.layout.addWidget(self.image_label)
self.brightness_slider = QSlider()
self.brightness_slider.setOrientation(Qt.Orientation.Vertical)
self.brightness_slider.setMinimum(-100)
self.brightness_slider.setMaximum(100)
self.brightness_slider.setValue(0)
self.brightness_slider.valueChanged.connect(self.updateBrightness)
self.layout.addWidget(self.brightness_slider)
self.contrast_slider = QSlider()
self.contrast_slider.setOrientation(Qt.Orientation.Vertical)
self.contrast_slider.setMinimum(1)
self.contrast_slider.setMaximum(10)
self.contrast_slider.setValue(1)
self.contrast_slider.valueChanged.connect(self.updateContrast)
self.layout.addWidget(self.contrast_slider)
self.save_button = QPushButton('保存图像')
self.save_button.clicked.connect(self.saveImage)
self.layout.addWidget(self.save_button)
self.updateImageLabel()
def updateImageLabel(self):
# 调整图像亮度和对比度
adjusted_image = cv2.convertScaleAbs(self.image, alpha=self.contrast, beta=self.brightness)
adjusted_image = cv2.cvtColor(adjusted_image, cv2.COLOR_BGR2RGB)
# 将 OpenCV 图像转换为 QImage
height, width, channel = adjusted_image.shape
bytes_per_line = 3 * width
q_image = QImage(adjusted_image.data, width, height, bytes_per_line, QImage.Format.Format_RGB888)
# 确保 QImage 不在调整后被释放
q_image = q_image.copy()
# 将 QImage 转换为 QPixmap
pixmap = QPixmap.fromImage(q_image)
# 在 QLabel 上显示 QPixmap
self.image_label.setPixmap(pixmap)
def updateBrightness(self, value):
self.brightness = value
self.updateImageLabel()
def updateContrast(self, value):
self.contrast = value / 5.0 * 4 + 1
self.updateImageLabel()
def saveImage(self):
adjusted_image = cv2.convertScaleAbs(self.image, alpha=self.contrast, beta=self.brightness)
cv2.imwrite('adjusted_image.jpg', adjusted_image)
print("Image saved as adjusted_image.jpg")
if __name__ == '__main__':
app = QApplication(sys.argv)
window = ImageProcessor()
window.show()
sys.exit(app.exec())
效果展示
QQ20241228-103924
三、创建一个 PyQt 应用程序,该应用程序能够:
- 使用 OpenCV 加载一张图像。
- 在 PyQt 的窗口中显示这张图像。
- 提供一个下拉列表(QComboBox),对图像做(模糊、锐化、边缘检测)处理:
- 模糊——使用cv2.GaussianBlur()实现
- 锐化——使用cv2.Laplacian()、cv2.Sobel()实现
- 边缘检测——使用cv2.Canny()实现
- 当用户点击下拉列表选项时,相应地更新窗口中显示的图像。
- 提供一个按钮,当用户点击按钮时,能保存调整后的图像。
思路分析
- 初始化 PyQt 应用程序:
- 创建一个基本的 PyQt 应用程序窗口。
- 设置窗口标题和大小。
- 加载图像:
- 使用 OpenCV 加载图像。
- 将图像从 BGR 格式转换为 RGB 格式(因为 PyQt 使用 RGB 格式)。
- 显示图像:
- 使用 QLabel 来显示图像。
- 将图像转换为 QPixmap 格式以便在 QLabel 中显示。
- 创建下拉列表(QComboBox):
- 添加选项:“模糊”、“锐化”、“边缘检测”。
- 连接 QComboBox 的信号(currentIndexChanged)到槽函数,以便在用户选择选项时更新图像。
- 图像处理:
- 根据用户选择的选项,使用 OpenCV 对图像进行相应处理。
- 更新 QLabel 中显示的图像。
- 保存图像:
- 提供一个 QPushButton,当用户点击时,保存当前显示的图像。
- 使用 QFileDialog 让用户选择保存路径。
设计到的函数方法
cv2.imread()
:加载图像。cv2.cvtColor()
:转换图像颜色格式。cv2.GaussianBlur()
:对图像进行高斯模糊。cv2.Laplacian()
和cv2.Sobel()
:对图像进行锐化。cv2.Canny()
:进行边缘检测。QImage()
和QPixmap()
:在 PyQt 中处理和显示图像。QComboBox()
:创建下拉列表。QPushButton()
:创建按钮。QFileDialog()
:打开文件保存对话框。
代码实现
import sys
import cv2
from PyQt6.QtWidgets import QApplication, QMainWindow, QComboBox, QVBoxLayout, QWidget, QPushButton, QLabel, QFileDialog
from PyQt6.QtGui import QImage, QPixmap
class ImageProcessor(QMainWindow):
def __init__(self):
super().__init__()
# 加载图像,确保图像路径正确或添加错误处理
self.image_path = 'C:\\Users\\lilba\\Desktop\\1228.jpg'
self.image = cv2.imread(self.image_path)
if self.image is None:
print(f"Error: Unable to load image at {self.image_path}")
sys.exit(1)
self.initUI()
def initUI(self):
self.setWindowTitle('Image Processor')
self.setGeometry(100, 100, 800, 600)
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout = QVBoxLayout()
self.central_widget.setLayout(self.layout)
self.image_label = QLabel()
self.layout.addWidget(self.image_label)
self.processing_combobox = QComboBox()
self.processing_combobox.addItems(['模糊', '锐化', '边缘检测'])
self.processing_combobox.currentIndexChanged.connect(self.updateImage)
self.layout.addWidget(self.processing_combobox)
self.save_button = QPushButton('保存图像')
self.save_button.clicked.connect(self.saveImage)
self.layout.addWidget(self.save_button)
self.updateImageLabel()
def updateImageLabel(self):
# 根据下拉列表选项处理图像
processing_option = self.processing_combobox.currentText()
processed_image = self.image.copy() # 从原始图像复制,避免修改原始数据
if processing_option == '模糊':
processed_image = cv2.GaussianBlur(processed_image, (5, 5), 0)
elif processing_option == '锐化':
processed_image = cv2.Laplacian(processed_image, cv2.CV_64F)
processed_image = cv2.convertScaleAbs(processed_image)
elif processing_option == '边缘检测':
processed_image = cv2.Canny(processed_image, 100, 200)
# 将 OpenCV 图像转换为 QImage
processed_image = cv2.cvtColor(processed_image, cv2.COLOR_BGR2RGB)
height, width, channel = processed_image.shape
bytes_per_line = 3 * width
q_image = QImage(processed_image.data, width, height, bytes_per_line, QImage.Format.Format_RGB888)
# 将 QImage 转换为 QPixmap
pixmap = QPixmap.fromImage(q_image)
# 在 QLabel 上显示 QPixmap
self.image_label.setPixmap(pixmap)
def updateImage(self, index):
self.updateImageLabel()
def saveImage(self):
# 保存调整后的图像
processing_option = self.processing_combobox.currentText()
processed_image = self.image.copy() # 从原始图像复制
if processing_option == '模糊':
processed_image = cv2.GaussianBlur(processed_image, (5, 5), 0)
elif processing_option == '锐化':
processed_image = cv2.Laplacian(processed_image, cv2.CV_64F)
processed_image = cv2.convertScaleAbs(processed_image)
elif processing_option == '边缘检测':
processed_image = cv2.Canny(processed_image, 100, 200)
# 使用文件对话框选择保存路径
options = QFileDialog.Options()
file_path, _ = QFileDialog.getSaveFileName(self, "保存图像", "", "JPEG Files (*.jpg);;PNG Files (*.png)",
options=options)
if file_path:
cv2.imwrite(file_path, processed_image)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = ImageProcessor()
window.show()
sys.exit(app.exec())
效果展示
QQ20241228-112315