图片元信息Exif,给你详细讲讲 - 知乎 (zhihu.com)https://zhuanlan.zhihu.com/p/366726838在使用labelimg等开源的图像标注软件过程中发现,有时候一些图像数据集,比如从手机拍摄的照片可能会有一个图像的方向的选项供选择,拍出来的照片,也因此图像分辨率是会发生变化的。
关于使用opencv读取经过labelImg工具进行标注后的图像出现的框与图像旋转方向不一致的问题 [author: linkrain]_opencv读图与labelimg显示不一致-CSDN博客https://blog.csdn.net/xuan_xuan_/article/details/100295306
利用现有的一些比如WPS图片、360AI图片等等成熟的国产化的图像处理查看软件,是可以直接进行图像的旋转的。
测试发现,有些图像并不能成功修改其分辨率,而是修改了其图片的方向和Exif信息。
遂开发一个PyQT的小工具——名为——图像旋转器,修改图像的方向Exif的同时,修改其分辨率,实现正确地在labelimg软件中实现加载
import sys
import os
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QFileDialog, QVBoxLayout, QWidget
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import Qt
from PIL import Image
import cv2
import numpy as np
class ImageRotator(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("图像旋转与调整")
self.setGeometry(100, 100, 800, 600)
self.current_image_index = 0
self.image_paths = []
self.cv_image = None # OpenCV 格式的图像
self.original_size = (0, 0) # 原始图像的分辨率
self.initUI()
def initUI(self):
# 设置布局
self.label = QLabel(self)
self.label.setAlignment(Qt.AlignCenter)
self.btn_open_folder = QPushButton("打开文件夹", self)
self.btn_open_folder.clicked.connect(self.open_folder)
self.btn_prev = QPushButton("上一张", self)
self.btn_prev.clicked.connect(self.show_previous_image)
self.btn_prev.setEnabled(False)
self.btn_next = QPushButton("下一张", self)
self.btn_next.clicked.connect(self.show_next_image)
self.btn_next.setEnabled(False)
self.btn_rotate_left = QPushButton("向左旋转90度", self)
self.btn_rotate_left.clicked.connect(lambda: self.rotate_image(-90))
self.btn_rotate_left.setEnabled(False)
self.btn_rotate_right = QPushButton("向右旋转90度", self)
self.btn_rotate_right.clicked.connect(lambda: self.rotate_image(90))
self.btn_rotate_right.setEnabled(False)
self.btn_save = QPushButton("保存", self)
self.btn_save.clicked.connect(self.save_image)
self.btn_save.setEnabled(False)
layout = QVBoxLayout()
layout.addWidget(self.btn_open_folder)
layout.addWidget(self.label)
layout.addWidget(self.btn_prev)
layout.addWidget(self.btn_next)
layout.addWidget(self.btn_rotate_left)
layout.addWidget(self.btn_rotate_right)
layout.addWidget(self.btn_save)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
def open_folder(self):
folder_path = QFileDialog.getExistingDirectory(self, "选择图像文件夹")
if folder_path:
self.image_paths = [os.path.join(folder_path, f) for f in os.listdir(folder_path)
if f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.tiff'))]
self.current_image_index = 0
if self.image_paths:
self.show_image()
self.btn_prev.setEnabled(True)
self.btn_next.setEnabled(True)
self.btn_rotate_left.setEnabled(True)
self.btn_rotate_right.setEnabled(True)
self.btn_save.setEnabled(True)
else:
self.label.setText("没有符合条件的图像。")
def show_image(self):
image_path = self.image_paths[self.current_image_index]
# 使用 OpenCV 读取图像,忽略 EXIF 中的方向信息
self.cv_image = cv2.imread(image_path, cv2.IMREAD_COLOR | cv2.IMREAD_IGNORE_ORIENTATION)
self.original_size = (self.cv_image.shape[1], self.cv_image.shape[0]) # 获取原始图像分辨率
self.display_image(self.cv_image)
def display_image(self, cv_image):
"""在 QLabel 上显示 OpenCV 图像,并在右上角显示分辨率"""
height, width, channel = cv_image.shape
# 创建带有分辨率信息的图像副本
cv_image_with_text = cv_image.copy()
# 使用 OpenCV 在图像上绘制分辨率
cv2.putText(cv_image_with_text, f'{width}x{height}', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
# 转换为 QImage 并展示
bytes_per_line = 3 * width
q_image = QImage(cv_image_with_text.data, width, height, bytes_per_line, QImage.Format_BGR888)
pixmap = QPixmap.fromImage(q_image)
# 将 QPixmap 设置到 QLabel 上
self.label.setPixmap(pixmap.scaled(self.label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
def show_previous_image(self):
if self.current_image_index > 0:
self.current_image_index -= 1
self.show_image()
def show_next_image(self):
if self.current_image_index < len(self.image_paths) - 1:
self.current_image_index += 1
self.show_image()
def rotate_image(self, angle):
if self.cv_image is not None:
# 旋转图像并更新当前图像
(h, w) = self.cv_image.shape[:2]
center = (w // 2, h // 2)
matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
cos = np.abs(matrix[0, 0])
sin = np.abs(matrix[0, 1])
# 计算旋转后的图像大小
new_w = int((h * sin) + (w * cos))
new_h = int((h * cos) + (w * sin))
# 调整旋转矩阵以考虑新尺寸
matrix[0, 2] += (new_w / 2) - center[0]
matrix[1, 2] += (new_h / 2) - center[1]
# 旋转图像
self.cv_image = cv2.warpAffine(self.cv_image, matrix, (new_w, new_h))
self.display_image(self.cv_image)
def save_image(self):
if self.cv_image is not None:
save_path = self.image_paths[self.current_image_index]
# 保存图像,完全忽略 EXIF 信息
modified_image = Image.fromarray(cv2.cvtColor(self.cv_image, cv2.COLOR_BGR2RGB))
modified_image.save(save_path, format="JPEG", quality=95)
modified_size = (self.cv_image.shape[1], self.cv_image.shape[0]) # 获取修改后的图像分辨率
print(f"图像已保存:{save_path} 原图分辨率:{self.original_size[0]}x{self.original_size[1]} "
f"修改后分辨率为:{modified_size[0]}x{modified_size[1]}已保存")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = ImageRotator()
window.show()
sys.exit(app.exec_())
pip install pyqt5后直接运行本程序即可。