一、创建一个 PyQt 应用程序,该应用程序能够:
- 使用 OpenCV 加载一张图像。
- 在 PyQt 的窗口中显示这张图像。
- 提供四个按钮(QPushButton):
- 一个用于将图像转换为灰度图
- 一个用于将图像恢复为原始彩色图
- 一个用于将图像进行翻转
- 一个用于将图像进行旋转
- 4.当用户点击按钮时,相应地更新窗口中显示的图像。
import sys
import cv2
from PyQt6.QtGui import QImage, QPixmap
from PyQt6.QtWidgets import QWidget, QApplication, QLabel, QPushButton
from PyQt6 import uic
# 封装一个我的窗口类
class MyWidget(QWidget):
def __init__(self):
super().__init__()
# 通过 uic 将 ui 界面加载到程序中来
ui = uic.loadUi("./form.ui", self)
# 加载图像
self.original_image = cv2.imread("../images/lena.png")
if self.original_image is None:
print("无法加载图像,请检查图像路径。")
sys.exit(1)
self.current_image = self.original_image.copy()
self.label: QLabel = ui.label
self.btn1: QPushButton = ui.btn1
self.btn2: QPushButton = ui.btn2
self.btn3: QPushButton = ui.btn3
self.btn4: QPushButton = ui.btn4
# 显示原始图像
self.display_image(self.current_image)
self.label.setScaledContents(True)
# 连接按钮信号和槽函数
self.btn1.clicked.connect(self.convert_to_gray)
self.btn2.clicked.connect(self.restore_color)
self.btn3.clicked.connect(self.flip_image)
self.btn4.clicked.connect(self.rotate_image)
def display_image(self, image):
height, width, channel = image.shape
bytes_per_line = 3 * width
q_img = QImage(image.data, width, height, bytes_per_line, QImage.Format.Format_BGR888)
pixmap = QPixmap.fromImage(q_img)
self.label.setPixmap(pixmap)
def convert_to_gray(self):
self.current_image = cv2.cvtColor(self.current_image, cv2.COLOR_BGR2GRAY)
self.current_image = cv2.cvtColor(self.current_image, cv2.COLOR_GRAY2BGR)
self.display_image(self.current_image)
def restore_color(self):
self.current_image = self.original_image.copy()
self.display_image(self.current_image)
def flip_image(self):
self.current_image = cv2.flip(self.current_image, 1)
self.display_image(self.current_image)
def rotate_image(self):
self.current_image = cv2.rotate(self.current_image, cv2.ROTATE_90_CLOCKWISE)
self.display_image(self.current_image)
if __name__ == '__main__':
app = QApplication(sys.argv)
myWidget = MyWidget()
myWidget.show()
sys.exit(app.exec())
结果展示:
二、创建一个 PyQt 应用程序,该应用程序能够:
- 使用 OpenCV 加载一张彩色图像,并在 PyQt 的窗口中显示它。
- 提供一个滑动条(QSlider),允许用户调整图像的亮度。
- 当用户调整滑动条时,实时更新窗口中显示的图像亮度。
- 添加另一个滑动条(QSlider),允许用户调整图像的对比度。
- 当用户调整滚动条时,实时更新窗口中显示的图像对比度。
- 提供一个按钮(QPushButton),允许用户将图像保存为新的文件。
- 当用户点击保存按钮时,将调整后的图像保存到指定的路径,OpenCV中使用cv2.imwrite()来保存图片。
import sys
import cv2
from PyQt6.QtGui import QImage, QPixmap
from PyQt6.QtWidgets import QWidget, QApplication, QLabel, QPushButton, QSlider, QFileDialog
from PyQt6 import uic
class MyWidget(QWidget):
def __init__(self):
super().__init__()
# 通过 uic 将 ui 界面加载到程序中来
ui = uic.loadUi("./form1.ui", self)
self.original_image = cv2.imread("../images/lena.png")
if self.original_image is None:
print("无法加载图像,请检查图像路径。")
sys.exit(1)
self.current_image = self.original_image.copy()
self.label: QLabel = ui.label
self.Slider1: QSlider = ui.Slider1
self.Slider2: QSlider = ui.Slider2
self.pushButton: QPushButton = ui.pushButton
# 初始化滑动条范围
self.Slider1.setRange(-100, 100)
self.Slider2.setRange(0, 200)
self.Slider1.setValue(0)
self.Slider2.setValue(100)
# 连接信号和槽
self.Slider1.valueChanged.connect(self.adjust_brightness)
self.Slider2.valueChanged.connect(self.adjust_contrast)
self.pushButton.clicked.connect(self.save_image)
self.display_image(self.current_image)
self.label.setScaledContents(True)
def display_image(self, image):
height, width, channel = image.shape
bytes_per_line = 3 * width
q_img = QImage(image.data, width, height, bytes_per_line, QImage.Format.Format_BGR888)
pixmap = QPixmap.fromImage(q_img)
self.label.setPixmap(pixmap)
def adjust_brightness(self, value):
# 调整亮度
alpha = 1.0
beta = value
self.current_image = cv2.convertScaleAbs(self.original_image, alpha=alpha, beta=beta)
self.display_image(self.current_image)
def adjust_contrast(self, value):
# 调整对比度
alpha = value / 100.0
beta = 0
self.current_image = cv2.convertScaleAbs(self.original_image, alpha=alpha, beta=beta)
self.display_image(self.current_image)
def save_image(self):
# 选择保存路径
file_path, _ = QFileDialog.getSaveFileName(self, "保存图像", "", "图像文件 (*.png *.jpg *.jpeg)")
if file_path:
try:
cv2.imwrite(file_path, self.current_image)
print(f"图像已保存到 {file_path}")
except Exception as e:
print(f"保存图像时出错: {e}")
if __name__ == '__main__':
app = QApplication(sys.argv)
myWidget = MyWidget()
myWidget.show()
sys.exit(app.exec())
结果展示:
三、创建一个 PyQt 应用程序,该应用程序能够:
- 使用 OpenCV 加载一张图像。
- 在 PyQt 的窗口中显示这张图像。
- 提供一个下拉列表(QComboBox),对图像做(模糊、锐化、边缘检测)处理:
- 模糊——使用cv2.GaussianBlur()实现
- 锐化——使用cv2.Laplacian()、cv2.Sobel()实现
- 边缘检测——使用cv2.Canny()实现
- 当用户点击下拉列表选项时,相应地更新窗口中显示的图像。
- 提供一个按钮,当用户点击按钮时,能保存调整后的图像。
import sys
import cv2
from PyQt6.QtGui import QImage, QPixmap
from PyQt6.QtWidgets import QWidget, QApplication, QLabel, QPushButton, QSlider, QFileDialog, QComboBox
from PyQt6 import uic
# 封装一个我的窗口类
class MyWidget(QWidget):
def __init__(self):
super().__init__()
# 通过uic将ui界面加载到程序中来
ui = uic.loadUi("./form2.ui",self)
self.original_image = cv2.imread("../images/lena.png")
if self.original_image is None:
print("无法加载图像,请检查图像路径。")
sys.exit(1)
self.current_image = self.original_image.copy()
self.label: QLabel = ui.label
self.comboBox:QComboBox = ui.comboBox
self.pushButton:QPushButton = ui.pushButton
self.comboBox.addItems(["原始图像","模糊处理","锐化处理","边缘检测"])
self.display_image(self.current_image)
self.label.setScaledContents(True)
self.comboBox.currentIndexChanged.connect(self.comboBox_slot)
self.pushButton.clicked.connect(self.save_image)
def display_image(self, image):
height, width, channel = image.shape
bytes_per_line = 3 * width
q_img = QImage(image.data, width, height, bytes_per_line, QImage.Format.Format_BGR888)
pixmap = QPixmap.fromImage(q_img)
self.label.setPixmap(pixmap)
def comboBox_slot(self):
if self.comboBox.currentText() == "原始图像":
self.current_image = self.original_image.copy()
elif self.comboBox.currentText() == "模糊处理":
self.current_image = cv2.GaussianBlur(self.original_image,(5,5),0)
elif self.comboBox.currentText() == "锐化处理":
laplacian = cv2.Laplacian(self.original_image,cv2.CV_64F)
self.current_image = cv2.convertScaleAbs(laplacian)
elif self.comboBox.currentText() == "边缘检测":
# 使用 Canny 边缘检测
self.current_image = cv2.Canny(self.original_image, 100, 200)
# 转换为三通道图像以便显示
self.current_image = cv2.cvtColor(self.current_image, cv2.COLOR_GRAY2BGR)
self.display_image(self.current_image)
def save_image(self):
# 选择保存路径
file_path, _ = QFileDialog.getSaveFileName(self, "保存图像", "", "图像文件 (*.png *.jpg *.jpeg)")
if file_path:
try:
cv2.imwrite(file_path, self.current_image)
print(f"图像已保存到 {file_path}")
except Exception as e:
print(f"保存图像时出错: {e}")
if __name__ == '__main__':
app = QApplication(sys.argv)
myWidget = MyWidget()
myWidget.show()
sys.exit(app.exec())
结果展示:
四、请编写一段Python代码,实现以下功能:
- 读取一张二维码图片
- 进行二值化处理和形态学操作,获取二维码轮廓
- 通过轮廓外接特征检测或者多边形逼近等获取 二维码的四个点
- 进行透视变换,矫正二维码图像
import cv2
import numpy as np
def order_points(pts):
"""对四个点进行排序:左上,右上,右下,左下"""
rect = np.zeros((4, 2), dtype="float32")
s = pts.sum(axis=1)
rect[0] = pts[np.argmin(s)] # 左上(x+y最小)
rect[2] = pts[np.argmax(s)] # 右下(x+y最大)
diff = np.diff(pts, axis=1)
rect[1] = pts[np.argmin(diff)] # 右上(y-x最小)
rect[3] = pts[np.argmax(diff)] # 左下(y-x最大)
return rect
# 1. 读取图片
image = cv2.imread('../images/erwei.jpg')
image = cv2.resize(image,(0,0),fx=0.5,fy=0.5)
orig = image.copy()
# 2. 预处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)
_, thresh = cv2.threshold(blur, 127, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# 形态学操作(闭运算填充内部空隙)
kernel = np.ones((3, 3), np.uint8)
closed = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=2)
# 3. 轮廓检测
contours, _ = cv2.findContours(closed, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 筛选最大轮廓并进行多边形逼近
max_area = 0
screen_pts = None
for cnt in contours:
area = cv2.contourArea(cnt)
if area < 1000: # 过滤小面积噪声
continue
peri = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
if len(approx) == 4:
if area > max_area:
max_area = area
screen_pts = approx.reshape(4, 2)
if screen_pts is None:
raise ValueError("未检测到二维码轮廓")
# 4. 透视变换
rect = order_points(screen_pts)
(tl, tr, br, bl) = rect
# 计算目标图像尺寸
width_a = np.linalg.norm(br - bl)
width_b = np.linalg.norm(tr - tl)
max_width = max(int(width_a), int(width_b))
height_a = np.linalg.norm(tr - br)
height_b = np.linalg.norm(tl - bl)
max_height = max(int(height_a), int(height_b))
# 目标点坐标
dst = np.array([
[0, 0],
[max_width - 1, 0],
[max_width - 1, max_height - 1],
[0, max_height - 1]], dtype="float32")
# 计算变换矩阵并执行变换
M = cv2.getPerspectiveTransform(rect, dst)
warped = cv2.warpPerspective(orig, M, (max_width, max_height))
# 显示结果
cv2.imshow("Original", orig)
cv2.imshow("Corrected QR Code", warped)
cv2.waitKey(0)
cv2.destroyAllWindows()
五、 请编写一段Python代码,实现以下功能:
- 读取一张彩色图像
- 制作要提取颜色的掩膜
- 输出抠图后的前景图 和 背景图
import cv2
import numpy as np
def extract_colors(image_path):
# 1. 读取彩色图像
img = cv2.imread(image_path)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 2. 定义颜色范围(示例:提取红色系)
# 可根据需求修改阈值范围
lower_red1 = np.array([0, 43, 46]) # 红色HSV下限1
upper_red1 = np.array([10, 255, 255]) # 红色HSV上限1
lower_red2 = np.array([156, 43, 46]) # 红色HSV下限2(处理色相环闭合)
upper_red2 = np.array([180, 255, 255]) # 红色HSV上限2
# 生成掩膜
mask1 = cv2.inRange(hsv, lower_red1, upper_red1)
mask2 = cv2.inRange(hsv, lower_red2, upper_red2)
mask = cv2.bitwise_or(mask1, mask2)
# 形态学优化(填充空洞、去除噪声)
kernel = np.ones((5,5), np.uint8)
mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=2)
mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
# 3. 分割前景和背景
foreground = cv2.bitwise_and(img, img, mask=mask)
background = cv2.bitwise_and(img, img, mask=cv2.bitwise_not(mask))
# 4. 显示结果
# cv2.imshow("Original", img)
cv2.imshow("Foreground", foreground)
cv2.imshow("Background", background)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 执行函数(替换为你的图片路径)
extract_colors("../images/redflowers.png")
结果展示: