代码拉取完成,页面将自动刷新
同步操作将从 卑微小韩/旋转图处理器 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
import os
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap, QMouseEvent, QKeySequence, QTransform, QImage
from mainFrame import Ui_MainWindow
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QFileDialog, QMessageBox, QAction, QMenu, QInputDialog, \
QShortcut, QTableWidgetItem, QGraphicsScene
from PyQt5 import QtGui, QtWidgets, QtCore
import cv2
import numpy as np
onnx = None
if os.path.exists('models/circle_model.onnx'):
import onnxruntime as ort
class Onnx:
def __init__(self, root):
self.ort_session = ort.InferenceSession(root)
def to_rgb(self, im):
"""
图片转 RGB
:param im: 图片 np.array
:return: 图片 np.array
"""
if len(im.shape) == 2: # 灰度
return cv2.cvtColor(im, cv2.COLOR_GRAY2RGB)
elif im.shape[2] == 4: # PNG (RGBA)
return cv2.cvtColor(im, cv2.COLOR_BGRA2RGB)
assert len(im.shape) == 3 and im.shape[2] == 3 # 如果 Channel 不为3, 肯定出问题了
return cv2.cvtColor(im, cv2.COLOR_BGR2RGB)
def normalize(self, img):
"""
使用 OpenCV 对图像进行归一化
:param img: 图片 np.array
:return: 归一化后的图片 np.array
"""
mean = np.array([0.485, 0.456, 0.406], dtype=np.float32)
std = np.array([0.229, 0.224, 0.225], dtype=np.float32)
img = img.astype(np.float32) / 255.0 # 确保图像是 float32 类型
img = (img - mean) / std
return img
def __call__(self, img):
img = cv2.resize(img, (128, 128))
img = self.to_rgb(img)
mask = np.zeros((128, 128), dtype=np.uint8)
cv2.circle(mask, (64, 64), 62, 255, -1)
img[mask != 255] = 0
img = self.normalize(img)
img = img.transpose(2, 0, 1) # 将 Channel 放在前面
img = np.expand_dims(img, axis=0)
loc = self.ort_session.run(None, {'input': img})[0]
loc = np.array(loc)
angle = int(loc.argmax(1)[0])
print('angle:', angle)
return angle
onnx = Onnx('models/circle_model.onnx')
def img_resize(image):
height, width = image.shape[0], image.shape[1]
# 设置新的图片分辨率框架
width_new = 128
height_new = 128
# 判断图片的长宽比率
if width / height >= width_new / height_new:
img_new = cv2.resize(image, (width_new, int(height * width_new / width)))
else:
img_new = cv2.resize(image, (int(width * height_new / height), height_new))
return img_new
class MainFrameShow(Ui_MainWindow):
def __init__(self, main_window):
super(MainFrameShow, self).setupUi(main_window)
self.MainWindow = main_window
self.import_path = None
self.save_path = None
# 已经保存的文件列表
self.save_file_list = []
self.graphicsView_list = []
self.rotation_degree = 2
self.col_num = 6
self.row_num = 30
self.init_ui_event()
def init_ui_event(self):
"""
初始化UI事件
:return:
"""
# 设置菜单栏
# self.init_menu()
# 设置快捷键
self.init_shortcut()
# 设置按钮事件
self.init_button_event()
# 设置滚动条事件
# self.init_scroll_event()
# 设置鼠标事件
self.init_mouse_event()
# 设置表格事件
self.init_tabel_event()
# 设置graphicsView事件
self.init_horizontal_slider_event()
def init_horizontal_slider_event(self):
"""
设置horizontal_slider事件
:return:
"""
self.horizontalSlider.valueChanged.connect(self.horizontal_slider_value_changed)
# 鼠标抬起事件
self.horizontalSlider.sliderReleased.connect(self.horizontal_slider_released)
def horizontal_slider_value_changed(self):
"""
horizontal_slider值改变事件,主要是展示图片
:return:
"""
# 计算点击图片的度数
degree = int(self.horizontalSlider.value())
# 获取选中的行
selected_items = self.files_table.selectedItems()
if len(selected_items) == 0:
return
# 取文件名
row = selected_items[0].row()
file_name = self.files_table.item(row, 0).text()
# 把图片旋转
pic_path = os.path.join(self.import_path, file_name)
self.show_pic_to_rotate(pic_path, degree)
self.degree_label.setText(f"{degree}")
def horizontal_slider_released(self):
"""
horizontal_slider鼠标抬起事件
:return:
"""
self.save_pic_with_degree()
def save_pic_with_degree(self):
"""
带度数保存图片
:return:
"""
# 计算点击图片的度数
degree = int(self.horizontalSlider.value())
# 获取选中的行
selected_items = self.files_table.selectedItems()
if len(selected_items) == 0:
return
# 取文件名
row = selected_items[0].row()
file_name = self.files_table.item(row, 0).text()
# 保存的文件名为原文件名+度数.原后缀
save_file_name = f'{file_name.split(".")[0]}|{degree}.{file_name.split(".")[-1]}'
# 删除这张图片已经处理好的图片,命名规则为原文件名+度数.原后缀,度数不确定
for save_file in self.save_file_list:
if file_name.split('.')[0] in save_file:
os.remove(os.path.join(self.save_path, save_file))
self.save_file_list.remove(save_file)
break
# 把图片旋转
pic_path = os.path.join(self.import_path, file_name)
# pic = QPixmap(pic_path)
# pixmap = pic.transformed(QTransform().rotate(degree))
# # 保存图片
save_pic_path = os.path.join(self.save_path, save_file_name)
# # 保存图片
# pixmap.save(save_pic_path)
img = cv2.imread(pic_path)
# 顺时针旋转degree度
M = cv2.getRotationMatrix2D((img.shape[1] / 2, img.shape[0] / 2), -degree, 1)
img = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]))
cv2.imwrite(save_pic_path, img)
# 更新表格
self.files_table.setItem(row, 1, QTableWidgetItem("已处理"))
self.files_table.item(row, 1).setBackground(QtGui.QColor(0, 255, 0))
# 更新已经保存的文件列表
self.save_file_list.append(save_file_name)
def init_shortcut(self):
"""
设置快捷键
:return:
"""
# 设置热键s
# self.hot_key_s = QAction()
sq = QShortcut(QKeySequence('s'), self.MainWindow) # 通过QShortcut控件设置快捷方式,触发槽函数
sq.activated.connect(self.next_img)
# 设置热键w
wq = QShortcut(QKeySequence('w'), self.MainWindow) # 通过QShortcut控件设置快捷方式,触发槽函数
wq.activated.connect(self.prev_img)
def init_button_event(self):
"""
设置按钮事件
:return:
"""
self.import_pics_btn.clicked.connect(self.import_pics)
self.set_pics_save_path_btn.clicked.connect(self.set_pics_save_path)
def init_mouse_event(self):
"""
设置鼠标事件
:return:
"""
pass
def init_tabel_event(self):
"""
设置表格事件
:return:
"""
# 设置选中内容改变事件
self.files_table.itemSelectionChanged.connect(self.table_item_selected)
def next_img(self):
"""
下一张图片
:return:
"""
# 获取选中的行
selected_items = self.files_table.selectedItems()
if len(selected_items) == 0:
return
# 获取选中的行号
row = selected_items[0].row()
# 下一行
row += 1
if row >= self.files_table.rowCount():
return
self.files_table.selectRow(row)
def prev_img(self):
"""
上一张图片
:return:
"""
# 获取选中的行
selected_items = self.files_table.selectedItems()
if len(selected_items) == 0:
return
# 获取选中的行号
row = selected_items[0].row()
# 上一行
row -= 1
if row < 0:
return
self.files_table.selectRow(row)
def table_item_selected(self):
"""
表格选中内容改变事件
:return:
"""
# 获取选中的行
selected_items = self.files_table.selectedItems()
if len(selected_items) == 0:
return
# 度数轨道设置为 0
self.horizontalSlider.setValue(0)
# 度数标签设置为 0
self.degree_label.setText(f"{0}")
# 获取选中的行号
row = selected_items[0].row()
# 获取文件名
file_name = self.files_table.item(row, 0).text()
# 获取文件路径
file_path = os.path.join(self.import_path, file_name)
degree = 0
# 检查保存文件中是否有
for save_file in self.save_file_list:
if file_name.split('.')[0] in save_file:
# 获取度数
degree = int(save_file.split('|')[1].split('.')[0])
self.horizontalSlider.setValue(degree)
break
# 显示图片
if degree == 0:
if onnx is not None:
# 会进行一次初次推理
img = np.fromfile(file_path, np.uint8)
img = cv2.imdecode(img, cv2.IMREAD_COLOR)
degree = onnx(img)
self.horizontalSlider.setValue(degree)
# 保存图片
self.save_pic_with_degree()
self.show_pic_to_rotate(file_path, degree)
def convert_cv2_to_qt(self, cv_img):
""" Convert from an opencv image to QPixmap """
# Convert the image from BGR to RGB format
rgb_image = cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB)
# Get the shape of the image
height, width, channels = rgb_image.shape
# Create QImage from the numpy array
bytes_per_line = channels * width
qt_image = QImage(rgb_image.data, width, height, bytes_per_line, QImage.Format_RGB888)
# Convert QImage to QPixmap
qt_pixmap = QPixmap.fromImage(qt_image)
return qt_pixmap
def show_pic_to_rotate(self, pic_path, degree=0):
"""
显示图片旋转后的样子
:param pic_path: 图片路径
:param degree: 旋转度数
:return:
"""
self.degree_label.setText(f"{degree}")
# 旋转图片
img = cv2.imread(pic_path)
# 顺时针旋转degree度
M = cv2.getRotationMatrix2D((img.shape[1] / 2, img.shape[0] / 2), -degree, 1)
img = cv2.warpAffine(img, M, (img.shape[1], img.shape[0]))
pixmap = self.convert_cv2_to_qt(img)
# pixmap = pic.transformed(QTransform().rotate(degree))
# 设置图片
scene = QGraphicsScene()
# graphicsView.setScene(scene)
pixmap_item = scene.addPixmap(pixmap)
self.graphicsView.setScene(scene)
self.graphicsView.fitInView(pixmap_item, Qt.KeepAspectRatio)
QApplication.processEvents()
# self.pic_label.setPixmap(pic)
# self.pic_label.setAlignment(Qt.AlignCenter)
# QApplication.processEvents()
def import_pics(self):
"""
导入图片
:return:
"""
if not self.save_path:
QMessageBox.information(self.MainWindow, "提示", "请先设置图片保存路径")
return
dir_path = QFileDialog.getExistingDirectory(self.MainWindow, "选择图片读取目录", "./")
if dir_path:
self.import_path = dir_path
# 加入文件表格
self.init_files_table()
def init_files_table(self):
"""
初始化文件列表表格
:return:
"""
# 清空表格
self.files_table.clearContents()
self.files_table.setRowCount(0)
files = os.listdir(self.import_path)
files.sort()
for file in files:
if not (file.endswith(".jpg") or file.endswith(".png") or file.endswith(".jpeg") or file.endswith(".bmp")):
continue
# 添加到表格最后一行
row = self.files_table.rowCount()
self.files_table.insertRow(row)
# 添加一行 文件名和未处理
self.files_table.setItem(row, 0, QTableWidgetItem(file))
# 判断是否已经处理,即file是否在save_file_list中,名字中包含即可
self.files_table.setItem(row, 1, QTableWidgetItem("未处理"))
for save_file in self.save_file_list:
if file.split('.')[0] in save_file:
self.files_table.setItem(row, 1, QTableWidgetItem("已处理"))
# 设置当前行为绿色
self.files_table.item(row, 1).setBackground(QtGui.QColor(0, 255, 0))
break
def set_pics_save_path(self):
"""
设置图片保存路径
:return:
"""
save_path = QFileDialog.getExistingDirectory(self.MainWindow, "选择图片保存目录", "./")
if save_path:
self.save_path = save_path
# 读取已经保存的文件列表
self.read_save_file_list()
def read_save_file_list(self):
"""
读取已经保存的文件列表
:return:
"""
self.save_file_list = []
save_file_list = os.listdir(self.save_path)
for file in save_file_list:
print(file)
if not (file.endswith(".jpg") or file.endswith(".png") or file.endswith(".jpeg") or file.endswith(".bmp")):
continue
self.save_file_list.append(file)
if __name__ == '__main__':
app = QApplication(sys.argv)
MainWindow = QMainWindow()
# 设置MainWindow不能调整大小
MainWindow.setFixedSize(1024, 768)
ui = MainFrameShow(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。