chore: 更新最新代码

This commit is contained in:
琉璃月光
2025-08-13 14:49:06 +08:00
parent 4716e5f2e2
commit da205bf47c
1123 changed files with 990 additions and 3 deletions

90
image/del_photo/change.py Normal file
View File

@ -0,0 +1,90 @@
import os
from PIL import Image
import numpy as np
def is_large_gray(image, gray_lower_threshold=70, gray_upper_threshold=230, gray_ratio_threshold=0.7):
"""
判断图片是否大面积为灰色(基于像素的颜色值)
参数:
- image: 图片对象PIL Image
- gray_lower_threshold: 灰色下限(低于此值不算“灰色”)
- gray_upper_threshold: 灰色上限(高于此值不算“灰色”)
- gray_ratio_threshold: 灰色像素占比阈值(>70% 算大面积灰色)
返回True 表示是大面积灰色,应删除
"""
# 将图片转换为 numpy 数组
img_array = np.array(image)
# 获取图片的尺寸
height, width, _ = img_array.shape
total_pixels = height * width
# 判断是否为灰色像素R、G、B 值都在 gray_lower_threshold 和 gray_upper_threshold 之间)
gray_pixels = np.sum(
(img_array[:, :, 0] >= gray_lower_threshold) &
(img_array[:, :, 0] <= gray_upper_threshold) &
(img_array[:, :, 1] >= gray_lower_threshold) &
(img_array[:, :, 1] <= gray_upper_threshold) &
(img_array[:, :, 2] >= gray_lower_threshold) &
(img_array[:, :, 2] <= gray_upper_threshold)
)
gray_ratio = gray_pixels / total_pixels
return gray_ratio > gray_ratio_threshold
def process_images_in_folder(input_folder, output_folder):
"""
遍历文件夹,旋转图片并根据条件保存到输出文件夹
"""
# 创建输出文件夹(如果不存在)
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 支持的图片格式
supported_formats = ('.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.tif', '.webp')
for filename in os.listdir(input_folder):
file_path = os.path.join(input_folder, filename)
if not os.path.isfile(file_path):
continue
if not filename.lower().endswith(supported_formats):
continue
print(f"处理: {filename}")
try:
with Image.open(file_path) as img:
# 判断是否为大面积灰色
if is_large_gray(img):
print(f" 🔴 不保存大面积灰色图片: {filename}")
continue # 不保存该图片
# 否则:打开并旋转 180 度
rotated_img = img.rotate(180, expand=False)
# 构建新的保存路径
save_path = os.path.join(output_folder, filename)
# 保持原格式保存(覆盖原图)
rotated_img.save(save_path, format=img.format)
print(f" ✅ 已旋转并保存至: {save_path}")
except Exception as e:
print(f" ❌ 处理失败 {filename}: {e}")
# ================ 使用示例 ================
if __name__ == "__main__":
folder = "/media/hx/disk/folder_5"
output_folder = "/media/hx/disk/folder_5"
if not os.path.exists(folder):
print("❌ 输入文件夹不存在!")
else:
process_images_in_folder(folder, output_folder)
print("✅ 所有图片处理完成!")

View File

@ -0,0 +1,118 @@
import os
from pathlib import Path
from PIL import Image
import numpy as np
def is_grayscale_image(image_path, saturation_threshold=0.05, gray_intensity_threshold=200):
"""
判断图像是否为“灰色图片”(低饱和度或接近灰度)
:param image_path: 图像路径
:param saturation_threshold: 饱和度阈值0~1越低越可能是灰色
:param gray_intensity_threshold: 亮度阈值,过滤纯白/纯黑
:return: True 表示是灰色图,应删除
"""
try:
img = Image.open(image_path)
# 转为 RGB处理灰度图自动转为 3 通道)
if img.mode != 'RGB':
img = img.convert('RGB')
# 转为 numpy 数组
rgb = np.array(img).astype(np.float32) # (H, W, 3)
H, W, _ = rgb.shape
if H * W == 0:
return True # 空图
# 转为 HSV手动计算避免 PIL 的 hsv 转换问题)
r, g, b = rgb[..., 0], rgb[..., 1], rgb[..., 2]
max_c = np.maximum(np.maximum(r, g), b)
min_c = np.minimum(np.minimum(r, g), b)
delta = max_c - min_c
# 饱和度 S = delta / max_c
with np.errstate(divide='ignore', invalid='ignore'):
s = np.where(max_c == 0, 0, delta / max_c)
# 只取非纯黑区域的饱和度(避免纯黑区域干扰)
valid_s = s[(max_c > 10) & (max_c < gray_intensity_threshold)] # 忽略极暗和极亮
if len(valid_s) == 0:
return True # 全黑或全白
# 计算平均饱和度
avg_saturation = valid_s.mean()
# 如果平均饱和度很低,认为是灰色图
return avg_saturation < saturation_threshold
except Exception as e:
print(f"⚠️ 无法读取图像 {image_path}: {e}")
return True # 出错的图也删除(可选)
def delete_gray_images(folder_path, extensions=None, dry_run=False):
"""
删除文件夹中的灰色图片
:param folder_path: 图片文件夹路径
:param extensions: 支持的图片格式
:param dry_run: 如果为 True只打印不删除
"""
if extensions is None:
extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff']
folder = Path(folder_path)
if not folder.exists():
print(f"❌ 文件夹不存在: {folder_path}")
return
image_files = []
for ext in extensions:
image_files.extend(folder.glob(f'*{ext}'))
image_files.extend(folder.glob(f'*{ext.upper()}'))
if not image_files:
print(f"🔍 文件夹中没有找到图片: {folder_path}")
return
print(f"🔍 扫描到 {len(image_files)} 张图片...")
deleted_count = 0
for img_path in image_files:
if is_grayscale_image(img_path):
print(f"🗑️ 灰色图: {img_path.name}")
if not dry_run:
try:
img_path.unlink() # 删除文件
print(f"✅ 已删除: {img_path.name}")
deleted_count += 1
except Exception as e:
print(f"❌ 删除失败 {img_path.name}: {e}")
else:
print(f"✅ 彩色图: {img_path.name} (保留)")
print("\n" + "=" * 50)
if dry_run:
print(f"🧪 模拟完成,共发现 {deleted_count} 张灰色图将被删除")
else:
print(f"✅ 删除完成!共删除 {deleted_count} 张灰色图片")
print(f"📁 保留图片数: {len(image_files) - deleted_count}")
print("=" * 50)
# ================== 用户配置 ==================
FOLDER_PATH = "/media/hx/disk/folder_5" # 修改为你的图片文件夹
DRY_RUN = False # 先设为 True 测试,确认无误后再改为 False
# ================== 执行 ==================
if __name__ == "__main__":
print(f"🚀 开始检测并删除灰色图片...")
delete_gray_images(
folder_path=FOLDER_PATH,
dry_run=DRY_RUN
)

View File

@ -0,0 +1,103 @@
import os
import cv2
from skimage.metrics import structural_similarity as ssim
def calculate_ssim(image_path1, image_path2):
"""
计算两张图片的 SSIM 相似度
"""
# 读取图像
img1 = cv2.imread(image_path1)
img2 = cv2.imread(image_path2)
if img1 is None:
print(f"❌ 无法读取图片1: {image_path1}")
return None
if img2 is None:
print(f"❌ 无法读取图片2: {image_path2}")
return None
# 转为灰度图
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# 确保尺寸一致
if gray1.shape != gray2.shape:
print("⚠️ 图像尺寸不一致,正在调整...")
h, w = min(gray1.shape[0], gray2.shape[0]), min(gray1.shape[1], gray2.shape[1])
gray1 = cv2.resize(gray1, (w, h))
gray2 = cv2.resize(gray2, (w, h))
# 计算 SSIM
try:
similarity = ssim(gray1, gray2)
return similarity
except Exception as e:
print(f"❌ SSIM 计算失败: {e}")
return None
def delete_similar_consecutive_images(folder_path, threshold=0.95, extensions=None):
"""
删除相似度高于阈值的连续图片
:param folder_path: 图片所在的文件夹路径
:param threshold: SSIM 阈值,默认为 0.95
:param extensions: 支持的图片格式列表,默认为 ['.jpg', '.jpeg', '.png']
"""
if extensions is None:
extensions = ['.jpg', '.jpeg', '.png']
folder = os.path.abspath(folder_path)
if not os.path.exists(folder):
print(f"❌ 文件夹不存在: {folder_path}")
return
# 获取所有图片文件路径
image_files = []
for ext in extensions:
image_files.extend([os.path.join(folder, f) for f in os.listdir(folder) if f.lower().endswith(ext)])
if not image_files:
print(f"🔍 文件夹中没有找到图片: {folder_path}")
return
# 按文件名排序以确保顺序正确
image_files.sort()
print(f"🔍 扫描到 {len(image_files)} 张图片...")
deleted_count = 0
# 遍历每一对连续的图片
for i in range(len(image_files) - 1):
img_path1 = image_files[i]
img_path2 = image_files[i + 1]
similarity = calculate_ssim(img_path1, img_path2)
if similarity is not None and similarity > threshold:
print(f"🗑️ 删除相似图片: {img_path2} (SSIM: {similarity:.4f})")
try:
os.remove(img_path2)
deleted_count += 1
except Exception as e:
print(f"❌ 删除失败 {img_path2}: {e}")
else:
print(f"✅ 保留图片: {img_path2}")
print("\n" + "=" * 50)
print(f"✅ 删除完成!共删除 {deleted_count} 张相似图片")
print(f"📁 保留图片数: {len(image_files) - deleted_count}")
print("=" * 50)
# ================== 用户配置 ==================
FOLDER_PATH = "/media/hx/disk/folder_5" # 修改为你的图片文件夹路径
THRESHOLD = 0.90 # SSIM 阈值
# ================== 执行 ==================
if __name__ == "__main__":
print(f"🚀 开始检测并删除相似图片...")
delete_similar_consecutive_images(
folder_path=FOLDER_PATH,
threshold=THRESHOLD
)

63
image/del_photo/ssim.py Normal file
View File

@ -0,0 +1,63 @@
import cv2
from skimage.metrics import structural_similarity as ssim
import os
def calculate_ssim(image_path1, image_path2):
"""
计算两张图片的 SSIM 相似度
"""
# 读取图像
img1 = cv2.imread(image_path1)
img2 = cv2.imread(image_path2)
if img1 is None:
print(f"❌ 无法读取图片1: {image_path1}")
return None
if img2 is None:
print(f"❌ 无法读取图片2: {image_path2}")
return None
# 转为灰度图
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# 确保尺寸一致
if gray1.shape != gray2.shape:
print("⚠️ 图像尺寸不一致,正在调整...")
h, w = min(gray1.shape[0], gray2.shape[0]), min(gray1.shape[1], gray2.shape[1])
gray1 = cv2.resize(gray1, (w, h))
gray2 = cv2.resize(gray2, (w, h))
# 计算 SSIM
try:
similarity = ssim(gray1, gray2)
return similarity
except Exception as e:
print(f"❌ SSIM 计算失败: {e}")
return None
# ==================== 使用示例 ====================
if __name__ == "__main__":
# 替换成你本地的两张图片路径
path1 = "/home/hx/桌面/image/image/frame_20250805_120334_585.jpg"
path2 = "/home/hx/桌面/image/image/frame_20250805_120334_570.jpg"
# 检查文件是否存在
if not os.path.exists(path1):
print(f"文件不存在: {path1}")
print("请修改 path1 为实际存在的图片路径")
elif not os.path.exists(path2):
print(f"文件不存在: {path2}")
print("请修改 path2 为实际存在的图片路径")
else:
print("正在计算 SSIM...")
sim = calculate_ssim(path1, path2)
if sim is not None:
print(f"✅ SSIM 相似度: {sim:.4f}")
if sim > 0.9:
print("🔴 太相似(>0.9),应跳过重复帧")
elif sim > 0.7:
print("🟡 较相似,内容变化不大")
else:
print("🟢 差异明显,建议保存")