分类: 我的作品

我与AI共同创作的历程。从文本描述到图像生成,从风格迁移到创意激发,这些作品既是技术的展示,也是新艺术形式的探索。这里集中展示使用Adobe Photoshop进行深度编辑、合成或创作的数字艺术作品。我热衷于用PS打破现实与幻想的界限。无论是宏大的场景构建还是微妙的光影调整,这里展示的是通过层层叠加与精心雕琢呈现的视觉奇迹。

  • 告别天价软件!开源数字人项目,让你轻松打造专属虚拟分身

    告别天价软件!开源数字人项目,让你轻松打造专属虚拟分身

    是否曾对炫酷的数字人技术心动,却被高昂的成本和陡峭的学习曲线劝退?无论是想成为虚拟主播,还是开发AI助手,今天这篇文章将是你的终极入门指南。我精选了5个GitHub上高星的开源项目,覆盖从人脸生成、实时驱动到智能对话的全流程,帮你零成本开启数字人创作之旅!

    为何要关注开源数字人项目?

    数字人已广泛应用于虚拟主播、数字员工、AI客服等领域,但商业解决方案往往价格不菲。开源项目则打破了这一壁垒,将顶尖技术免费开放给所有开发者与创作者。你无需从零开始,即可基于成熟框架快速定制专属虚拟形象,真正实现“数字人自由”。

    项目名核心优势适用人群技术门槛部署难度最佳场景
    Face-Transformers2D人脸生成,风格多样头像设计、新手虚拟头像制作、数字分身设计
    Live2D Cubism SDK2D实时驱动,直播适配好虚拟主播、UP主2D虚拟直播、短视频出镜
    Avatarify实时变身,会议神器打工人、社恐视频会议虚拟形象
    ChatGPT-4V Digital Human智能对话,语音交互开发者、内容党智能客服、虚拟助手
    PIFuHD3D建模,单图生成3D创作者中高中高3D虚拟偶像、游戏角色建模

    1. Face-Transformers:数字人脸“生成大师”

    介绍:小白也能上手的人脸生成工具!基于AI模型生成超逼真数字人脸,支持自定义性别、年龄、发型,还能让人脸“动起来”,做虚拟头像超方便。
    主要功能

    • 生成高清数字人脸图片,支持风格迁移(如写实、动漫、油画风)
    • 调整人脸特征:改发型、换表情、加配饰,自由度超高
    • 导出人脸模型用于视频制作或游戏角色
      应用场景:做虚拟主播头像、设计游戏NPC脸模、生成个性化数字分身
      部署方法
    1. 克隆仓库:git clone https://github.com/hukkelas/Face-Transformers.git
    2. 安装依赖:pip install -r requirements.txt
    3. 运行Web界面:python app.py,在浏览器调参数生成人脸
      亮点&小槽点:生成效果逼真,操作可视化;但需要显卡支持,低配电脑可能跑不动。
      GitHub链接:https://github.com/hukkelas/Face-Transformers

    2. Live2D Cubism SDK:2D数字人“动效引擎”

    介绍:虚拟主播圈的“顶流工具”!专门做2D数字人实时驱动,给静态头像加表情、动嘴巴、摆姿势,直播间互动感拉满。
    主要功能

    • 绑定人脸关键点,通过摄像头实时驱动数字人表情(眨眼、微笑、张嘴)
    • 支持手动调动作:点头、挥手、比心等预设动作库
    • 导出动画视频或实时推流到直播平台
      应用场景:2D虚拟主播直播、短视频数字人出镜、线上课程虚拟讲师
      部署方法
    1. 克隆仓库:git clone https://github.com/Live2D/CubismSDK.git
    2. 下载官方示例模型(需注册账号)
    3. 运行示例程序:./Samples/BasicExample,用摄像头驱动模型
      亮点&小槽点:2D动效自然,直播适配好;但高级功能需付费授权,免费版够用基础需求。
      GitHub链接:https://github.com/Live2D/CubismSDK

    3. Avatarify:实时数字人“变身神器”

    介绍:打工人狂喜的视频会议神器!通过摄像头把自己实时变成数字人,开会不想露脸?用虚拟分身代替,还能换发型妆容。
    主要功能

    • 实时人脸追踪,把摄像头画面替换成数字人形象
    • 支持自定义数字人:上传照片生成专属分身,保留你的表情特征
    • 兼容Zoom、Teams等会议软件,即插即用
      应用场景:视频会议虚拟形象、线上讲座匿名出镜、直播时切换数字人身份
      部署方法
    1. 克隆仓库:git clone https://github.com/alievk/avatarify.git
    2. 安装依赖:conda env create -f environment.yml
    3. 启动程序:python avatarify.py,选择数字人模型即可使用
      亮点&小槽点:实时性强,操作简单;但对网络和电脑性能有要求,可能偶尔卡顿。
      GitHub链接:https://github.com/alievk/avatarify.git

    4. ChatGPT-4V Digital Human:会聊天的“智能数字人”

    介绍:能说会道的数字助手框架!把ChatGPT的大脑装进数字人,支持语音对话、图像识别,问问题、讲故事、查信息样样行。
    主要功能

    • 语音交互:说话就能和数字人聊天,支持多语言
    • 视觉能力:数字人能“看”图片,描述内容或回答相关问题
    • 自定义人设:设置数字人性格、语气、专业领域(如客服、老师)
      应用场景:做智能客服数字人、开发虚拟助手、给孩子做AI玩伴
      部署方法
    1. 克隆仓库:git clone https://github.com/yangjianxin1/ChatGPT-4V-Digital-Human.git
    2. 配置OpenAI API密钥:修改config.py
    3. 运行:python app.py,通过麦克风和数字人对话
      亮点&小槽点:对话自然,功能全面;但需要OpenAI API密钥,有使用成本。
      GitHub链接:https://github.com/yangjianxin1/ChatGPT-4V-Digital-Human

    5. PIFuHD:3D数字人“建模神器”

    介绍:3D建模小白的救星!上传一张照片就能生成完整3D数字人模型,带身体、穿衣服,还能摆各种姿势,做虚拟偶像超合适。
    主要功能

    • 单张照片生成高精细3D数字人,包括面部、身体、服装细节
    • 支持调整姿势:让数字人站、坐、挥手,动作自然
    • 导出3D模型文件,用于动画制作或游戏开发
      应用场景:3D虚拟偶像制作、元宇宙数字分身、游戏角色快速建模
      部署方法
    1. 克隆仓库:git clone https://github.com/facebookresearch/pifuhd.git
    2. 安装依赖:pip install -r requirements.txt
    3. 运行:python -m apps.simple_test --input_image path/to/your/photo.jpg
      亮点&小槽点:3D建模效果惊艳,单图生成超方便;但模型训练需要大显存,普通电脑跑起来慢。
      GitHub链接:https://github.com/facebookresearch/pifuhd
  • WEBP/PNG/HEIC批量转JPG:李哥的一键式图片格式转换神器

    WEBP/PNG/HEIC批量转JPG:李哥的一键式图片格式转换神器

    兄弟们,是不是经常遇到这些头疼事?

    • 从网站扒下来的图片全是 WEBP​ 格式,编辑软件打不开?
    • PNG​ 图片虽然清晰,但体积太大,上传发布总受限制?
    • 用苹果设备拍的照片是 HEIC​ 格式,在Windows电脑上就成了“天书”?

    别慌!李哥出手,必属精品!今天给大家带来的这款 「批量图片格式转换JPG工具」,就是专门治这些“格式不服”的!它就像你图片库里的“格式统一大师”,管你什么WEBP、PNG还是HEIC,统统给咱变成最通用、最省心的 JPG​ 格式!

    真正的“傻瓜式”操作:把脚本和图片放一个文件夹,双击运行,剩下的交给程序。自动安装环境、自动转换、自动整理文件,你只管喝杯茶等着收JPG就行!特别加入了 HEIC 格式支持,再也不用为苹果照片在电脑上打不开而发愁了。转换后的JPG、原始文件、转换失败的图片,会自动分门别类存到 convert/source/failed/三个文件夹里,井井有条,绝不乱套。万一有同名文件?不存在的!程序会自动给你加上序号,保证一个文件都不会被覆盖。

    下载脚本 -> 双击运行 -> 收获一文件夹整齐的JPG图片!

    李哥已经把代码和详细的使用说明都准备好了,就等你来取。赶紧下载试试,从此告别图片格式转换的烦恼!做人呢,最重要的就是开心!用李哥的工具,让你的图片处理也开心起来!

    核心解读:

    作用:自动检查并安装必要的Python库(Pillow和pillow-heif)启用HEIC文件格式支持(苹果设备照片格式)

    创建虚拟环境并安装python库

    # 退出当前环境
    deactivate
    
    # 删除损坏的虚拟环境
    cd ~/Documents/env
    rm -rf myenv
    
    # 重新创建虚拟环境
    python3 -m venv myenv
    
    # 激活新环境
    source myenv/bin/activate
    
    # 检查pip是否正常
    pip --version
    
    # 安装Pillow
    pip install Pillow
    
    # 检查安装是否成功
    python3 -c "from PIL import Image; print('Pillow安装成功!')"

    创建三个目录:

    • convert/– 存放转换后的JPG文件
    • source/– 存放原始图片文件
    • failed/– 存放转换失败的文件

    智能移动文件到指定目录,自动处理重名文件(添加序号)输出格式JPG (.jpg) – 通用的有损压缩图片格式

    文件整理逻辑

    转换前目录结构:
    当前目录/
    ├── image1.webp
    ├── image2.png
    ├── image3.heic
    └── convert_images.py
    
    转换后目录结构:
    当前目录/
    ├── convert/           # 转换后的JPG文件
    │   ├── image1.jpg
    │   ├── image2.jpg
    │   └── image3.jpg
    ├── source/            # 原始文件(已移动)
    │   ├── image1.webp
    │   ├── image2.png
    │   └── image3.heic
    ├── failed/            # 转换失败的文件
    └── convert_images.py

    实现代码:

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    import os
    import glob
    import shutil
    import sys
    import subprocess
    
    def check_and_install_dependencies():
        """检查并安装必要的依赖"""
        dependencies = ['Pillow', 'pillow-heif']
        missing_deps = []
        
        # 检查Pillow
        try:
            from PIL import Image
            print("✓ Pillow 已安装")
        except ImportError:
            missing_deps.append('Pillow')
        
        # 检查pillow-heif
        try:
            import pillow_heif
            print("✓ pillow-heif 已安装")
        except ImportError:
            missing_deps.append('pillow-heif')
        
        # 安装缺失的依赖
        if missing_deps:
            print(f"❌ 缺少依赖: {', '.join(missing_deps)}")
            print("正在安装依赖...")
            
            for dep in missing_deps:
                try:
                    if dep == 'Pillow':
                        subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'Pillow'])
                    elif dep == 'pillow-heif':
                        subprocess.check_call([sys.executable, '-m', 'pip', 'install', 'pillow-heif'])
                    print(f"✓ {dep} 安装成功")
                except subprocess.CalledProcessError:
                    print(f"❌ {dep} 安装失败,尝试使用镜像源...")
                    try:
                        subprocess.check_call([sys.executable, '-m', 'pip', 'install', dep, 
                                             '-i', 'https://pypi.tuna.tsinghua.edu.cn/simple/'])
                        print(f"✓ {dep} 安装成功(使用镜像源)")
                    except:
                        print(f"❌ {dep} 安装失败,请手动安装: pip install {dep}")
                        return False
            # 重新检查
            try:
                from PIL import Image
                import pillow_heif
                print("✓ 所有依赖安装成功")
                return True
            except ImportError as e:
                print(f"❌ 依赖安装后仍然失败: {e}")
                return False
        return True
    
    def setup_heic_support():
        """设置HEIC支持"""
        try:
            import pillow_heif
            pillow_heif.register_heif_opener()
            print("✓ HEIC格式支持已启用")
            return True
        except Exception as e:
            print(f"❌ HEIC支持初始化失败: {e}")
            return False
    
    def create_directories():
        """创建必要的目录"""
        directories = ['convert', 'source', 'failed']
        for directory in directories:
            if not os.path.exists(directory):
                os.makedirs(directory)
                print(f"✓ 创建目录: {directory}/")
    
    def move_file_to_directory(original_file, directory):
        """移动文件到指定目录"""
        try:
            filename = os.path.basename(original_file)
            destination = os.path.join(directory, filename)
            
            # 如果目标文件已存在,添加序号
            counter = 1
            base_name, ext = os.path.splitext(filename)
            while os.path.exists(destination):
                new_filename = f"{base_name}_{counter}{ext}"
                destination = os.path.join(directory, new_filename)
                counter += 1
            
            shutil.move(original_file, destination)
            return True
        except Exception as e:
            print(f"⚠ 移动文件失败 {original_file}: {e}")
            return False
    
    def convert_image_file(input_file, temp_jpg_file, is_heic=False):
        """转换图片文件"""
        try:
            from PIL import Image
            
            if is_heic:
                # HEIC文件特殊处理
                try:
                    import pillow_heif
                    heif_file = pillow_heif.open_heif(input_file)
                    image = Image.frombytes(
                        heif_file.mode, 
                        heif_file.size, 
                        heif_file.data,
                        "raw",
                        heif_file.mode,
                        heif_file.stride,
                    )
                except:
                    # 如果直接读取失败,尝试通过PIL打开
                    pillow_heif.register_heif_opener()
                    image = Image.open(input_file)
            else:
                # 其他格式文件
                image = Image.open(input_file)
            
            # 处理图片模式
            if image.mode in ('RGBA', 'LA', 'P'):
                background = Image.new('RGB', image.size, (255, 255, 255))
                if image.mode == 'P':
                    image = image.convert('RGBA')
                if image.mode == 'RGBA':
                    background.paste(image, mask=image.split()[-1])
                else:
                    background.paste(image)
                image = background
            elif image.mode != 'RGB':
                image = image.convert('RGB')
            
            # 保存为JPG
            image.save(temp_jpg_file, "JPEG", quality=85, optimize=True)
            return True, "成功"
            
        except Exception as e:
            return False, str(e)
    
    def batch_convert_images():
        """批量转换图片"""
        print("=== 图片格式批量转换工具 ===")
        
        # 检查并安装依赖
        if not check_and_install_dependencies():
            print("❌ 依赖安装失败,无法继续")
            return
        
        # 设置HEIC支持
        heic_supported = setup_heic_support()
        
        # 创建目录
        create_directories()
        
        # 收集文件
        files_to_convert = []
        for pattern in ['*.webp', '*.WEBP', '*.png', '*.PNG', '*.heic', '*.HEIC']:
            files_to_convert.extend(glob.glob(pattern))
        
        files_to_convert = sorted(list(set(files_to_convert)))
        files_to_convert = [f for f in files_to_convert if not any(f.startswith(d) for d in ['convert/', 'source/', 'failed/'])]
        
        if not files_to_convert:
            print("❌ 未找到可转换的图片文件")
            return
        
        # 分类统计
        webp_files = [f for f in files_to_convert if f.lower().endswith('.webp')]
        png_files = [f for f in files_to_convert if f.lower().endswith('.png')]
        heic_files = [f for f in files_to_convert if f.lower().endswith('.heic')]
        
        print(f"找到 {len(files_to_convert)} 个文件:")
        print(f"  WEBP: {len(webp_files)} 个, PNG: {len(png_files)} 个, HEIC: {len(heic_files)} 个")
        
        if heic_files and not heic_supported:
            print("⚠ HEIC文件将无法转换")
        
        # 转换统计
        results = {'success': 0, 'failed': 0, 'skipped': 0}
        
        for i, input_file in enumerate(files_to_convert, 1):
            filename_without_ext = os.path.splitext(os.path.basename(input_file))[0]
            temp_jpg_file = filename_without_ext + ".jpg"
            final_jpg_path = os.path.join('convert', temp_jpg_file)
            
            # 跳过已存在
            if os.path.exists(final_jpg_path):
                print(f"{i}/{len(files_to_convert)} ⚡ 跳过已存在: {final_jpg_path}")
                results['skipped'] += 1
                continue
            
            file_size = os.path.getsize(input_file) / 1024
            file_ext = os.path.splitext(input_file)[1].upper()
            is_heic = input_file.lower().endswith('.heic')
            
            print(f"{i}/{len(files_to_convert)} 🔄 转换: {os.path.basename(input_file)} ({file_size:.1f} KB)", end="")
            
            try:
                if is_heic and not heic_supported:
                    success, message = False, "HEIC支持未启用"
                else:
                    success, message = convert_image_file(input_file, temp_jpg_file, is_heic)
                
                if success:
                    # 移动成功文件
                    if os.path.exists(temp_jpg_file):
                        move_file_to_directory(temp_jpg_file, 'convert')
                    move_file_to_directory(input_file, 'source')
                    results['success'] += 1
                    print(" -> ✅ 完成")
                else:
                    # 移动失败文件
                    move_file_to_directory(input_file, 'failed')
                    results['failed'] += 1
                    print(f" -> ❌ 失败: {message}")
                    
            except Exception as e:
                move_file_to_directory(input_file, 'failed')
                results['failed'] += 1
                print(f" -> 💥 异常: {str(e)}")
        
        # 输出结果
        print(f"\n=== 转换完成 ===")
        print(f"✅ 成功: {results['success']}, ❌ 失败: {results['failed']}, ⚡ 跳过: {results['skipped']}")
    
    if __name__ == "__main__":
        batch_convert_images()
        input("\n按Enter键退出...")

  • 数字囤积症救星!LeePoet教你用AI智能整理海量图片

    数字囤积症救星!LeePoet教你用AI智能整理海量图片

    图片太多了怎么办?LeePoet一站式智能整理方案

    💡 LeePoet技术理念:复杂的科技,应该以最简单的方式服务每个普通人。

    你是否也曾在数千张照片中翻找一张重要合影?是否因为图片太多而放弃整理?本文是数字时代每个人的“图片救星”。无论你是拥有上万张照片的摄影爱好者,还是被工作图片淹没的职场人,LeePoet将用AI技术为你提供从简单到专业的全系列解决方案。

    从人物识别到内容分类,Python自动化搞定图片管理,每个人手机里几千张照片的普遍现象,手动整理的痛苦:耗时、低效、容易遗漏,LeePoet的解决方案理念:技术让生活更简单。”隐私保护+内容管理,一键分类敏感图片”,多层级风险评估。

    包含开箱即用的Python脚本、详细配置教程和常见问题解决方案。LeePoet用实际案例证明,技术不应该高高在上,而要真正服务于生活。

    UBUNTU创建虚拟环境操作

    1.创建虚拟环境
    # 进入你的项目文件夹
    cd /path/to/your/project
    
    # 创建虚拟环境(会在当前文件夹创建 venv 目录)
    python3 -m venv myenv
    
    2.激活虚拟环境
    source myenv/bin/activate
    
    3.安装依赖
    python -m pip install opencv-python
    

    如果要使用增强版本,还需要安装:

    python -m pip install torch ultralytics
    
    4.基本完成。

    初级检测:

    创建一个名为 extract_people_images.py的文件完整代码:

    import os
    import shutil
    import cv2
    from pathlib import Path
    
    def detect_people_in_image(image_path, face_cascade=None):
        """
        检测图片中是否包含人物
        """
        if face_cascade is None:
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        
        try:
            img = cv2.imread(image_path)
            if img is None:
                return False
            
            gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
            
            faces = face_cascade.detectMultiScale(
                gray,
                scaleFactor=1.1,
                minNeighbors=5,
                minSize=(30, 30)
            )
            
            return len(faces) > 0
            
        except Exception as e:
            print(f"处理图片 {image_path} 时出错: {e}")
            return False
    
    def extract_images_with_people(source_dir, target_dir):
        """
        从源文件夹提取带人物的图片到目标文件夹
        """
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 加载人脸检测器
        face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        
        print("开始扫描图片...")
        
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            
            # 检查文件格式
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                total_images += 1
                print(f"处理第 {total_images} 张图片: {filename}")
                
                # 检测是否包含人物
                if detect_people_in_image(file_path, face_cascade):
                    images_with_people += 1
                    
                    # 构建目标路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 复制文件
                    shutil.copy2(file_path, target_path)
                    print(f"✓ 检测到人物: {filename}")
                else:
                    print(f"✗ 未检测到人物: {filename}")
        
        print("\n" + "="*50)
        print("处理完成!")
        print(f"总共处理图片: {total_images}张")
        print(f"检测到包含人物的图片: {images_with_people}张")
        print(f"图片已保存到: {target_dir}")
    
    def main():
        # 设置路径
        current_dir = os.getcwd()
        target_dir = os.path.join(current_dir, "images_with_people")
        
        print(f"当前文件夹: {current_dir}")
        print(f"目标文件夹: {target_dir}")
        print("-" * 50)
        
        # 执行提取
        extract_images_with_people(current_dir, target_dir)
    
    if __name__ == "__main__":
        main()
    
    5. 运行脚本
    python extract_people_images.py
    
    6. 退出虚拟环境

    完成后,可以退出虚拟环境:

    其它说明:安装所需库(上面装完了可以不看这)
    # 升级pip(可选)
    python -m pip install --upgrade pip
    
    # 安装OpenCV(基础版本)
    python -m pip install opencv-python
    
    # 或者安装增强版本所需的库
    python -m pip install opencv-python torch ultralytics
    
    创建 requirements.txt 文件(可选)

    你可以创建一个依赖文件,方便以后重新安装:

    # 生成requirements.txt
    python -m pip freeze requirements.txt
    

    requirements.txt 内容示例:

    opencv-python==4.8.1.78
    numpy==1.24.3
    

    以后重新安装依赖:

    python -m pip install -r requirements.txt
    
    完整的项目结构建议
    your_project/
    ├── venv/                    # 虚拟环境(不要提交到版本控制)
    ├── extract_people_images.py # 主程序
    ├── requirements.txt         # 依赖列表
    └── images_with_people/      # 输出文件夹(程序自动创建)
    

    库装不上的其它操作

    python -m pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple –verbose

    中级检测:

    正常激活虚拟环境

    cd myenv  #即虚拟环境目录
    source myenv/bin/activate   # 进入虚拟环境(如果还没激活)
    pip install opencv-python    # 确保已安装所需库
    

    安装依赖的完整步骤

    # 1. 激活虚拟环境
    source myenv/bin/activate
    
    # 2. 安装依赖(如果网络慢可以使用清华镜像)
    python -m pip install torch torchvision ultralytics opencv-python
    
    # 或者使用国内镜像加速安装
    python -m pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python
    
    # 直接使用python命令运行,不需要执行权限
    python extract_people_images.py
    
    # 给脚本执行权限:
    chmod +x extract_people_images.py
    

    ##

    一、增强检测人物图片:

    使用YOLOv8模型进行更准确的人物检测,增强版人物图片检测

    模型说明

    • yolov8n.pt:最小最快,适合快速检测
    • yolov8s.pt:平衡速度和精度
    • yolov8m.pt:中等精度
    • yolov8l.pt:高精度
    • yolov8x.pt:最高精度,最慢

    特性

    1. 更准确的人物检测:YOLO可以检测各种姿势、大小的人物
    2. 可调置信度:根据需求调整检测敏感度
    3. 检测预览:可选保存带检测框的图片
    4. 详细统计:显示检测数量、置信度、处理时间等
    5. 错误处理:完善的异常处理,不会因为单张图片失败而停止
    6. 进度显示:实时显示处理进度

    这个增强版本比基础版本准确得多,特别是对于侧面、远处、遮挡的人物检测效果更好!

    完整的Python代码

    #!/usr/bin/env python3
    """
    增强版人物图片检测程序
    使用YOLOv8模型进行更准确的人物检测
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            print("\n如果安装缓慢,可以使用清华镜像:")
            print("pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python")
            return None, None
    
    def extract_images_with_people_enhanced(source_dir, target_dir, confidence_threshold=0.3, 
                                          model_size='yolov8n.pt', device='cpu', 
                                          save_detection_preview=False):
        """
        使用YOLO模型检测并提取包含人物的图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值(0.0-1.0),值越小检测越敏感
        model_size: 模型大小 ('yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt')
        device: 运行设备 ('cpu' 或 'cuda')
        save_detection_preview: 是否保存带检测框的预览图
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp', '.JPG', '.JPEG', '.PNG']
        
        print("=" * 60)
        print("增强版人物图片检测程序")
        print("=" * 60)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print(f"设备: {device}")
        print(f"保存检测预览: {save_detection_preview}")
        print("-" * 60)
        
        try:
            # 加载YOLO模型(会自动下载如果不存在)
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            print("请检查网络连接或手动下载模型")
            return
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 处理: {filename}")
            total_images += 1
            
            try:
                # 记录开始时间
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检查是否检测到人物(YOLO中person类的ID是0)
                has_people = False
                people_count = 0
                max_confidence = 0.0
                
                for result in results:
                    if result.boxes is not None and len(result.boxes) > 0:
                        for box in result.boxes:
                            class_id = int(box.cls)
                            confidence = float(box.conf)
                            
                            # class_id 0 对应 'person'
                            if class_id == 0:
                                has_people = True
                                people_count += 1
                                max_confidence = max(max_confidence, confidence)
                
                if has_people:
                    images_with_people += 1
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    base_target_path = target_path
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 复制原图到目标文件夹
                    shutil.copy2(file_path, target_path)
                    
                    # 如果启用预览,保存带检测框的图片
                    if save_detection_preview and has_people:
                        try:
                            # 绘制检测结果
                            plotted_image = results[0].plot()
                            preview_filename = f"preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    print(f"  ✓ 检测到 {people_count} 个人物 (最高置信度: {max_confidence:.3f})")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已复制到: {os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'people_count': people_count,
                        'max_confidence': max_confidence,
                        'detection_time': detection_time
                    })
                    
                else:
                    print(f"  ✗ 未检测到人物 (检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 60)
        print("处理完成!")
        print("=" * 60)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到包含人物的图片: {images_with_people}张")
            print(f"检测率: {(images_with_people/total_images*100):.1f}%")
            
            if detection_times:
                avg_detection_time = sum(detection_times) / len(detection_times)
                print(f"平均检测时间: {avg_detection_time:.2f}秒/张")
                print(f"总检测时间: {sum(detection_times):.2f}秒")
            
            if images_with_people > 0:
                print(f"\n包含人物的图片已保存到: {target_dir}")
                if save_detection_preview:
                    print(f"检测预览图已保存到: {preview_dir}")
                
                # 显示检测到最多人物的前几张图片
                if processed_files:
                    processed_files.sort(key=lambda x: x['people_count'], reverse=True)
                    print(f"\n检测结果最好的图片:")
                    for i, file_info in enumerate(processed_files[:3]):
                        print(f"  {i+1}. {file_info['filename']} - {file_info['people_count']}人 "
                              f"(置信度: {file_info['max_confidence']:.3f})")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='增强版人物图片检测程序')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='images_with_people',
                           help='目标文件夹路径 (默认: images_with_people)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        
        args = parser.parse_args()
        
        # 检查源文件夹是否存在
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        # 运行检测程序
        extract_images_with_people_enhanced(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview
        )
    
    # 简化版本函数(不需要命令行参数)
    def simple_extract():
        """简化版本,使用默认参数"""
        source_dir = os.getcwd()  # 当前文件夹
        target_dir = os.path.join(source_dir, "images_with_people")
        
        print("使用简化模式运行...")
        extract_images_with_people_enhanced(source_dir, target_dir)
    
    if __name__ == "__main__":
        # 如果没有命令行参数,使用简化版本
        import sys
        if len(sys.argv) == 1:
            simple_extract()
        else:
            main()
    

    步骤1:保存文件

    在nano编辑器中:

    • Ctrl+X退出
    • Y确认保存
    • Enter确认文件名

    步骤2:运行程序

    python extract_people_images_enhanced_copy.py
    

    方法2:使用命令行参数

    # 基本使用
    python extract_people_images_enhanced_copy.py --source /path/to/images --target ./output
    
    # 调整检测敏感度(值越小越敏感)
    python extract_people_images_enhanced_copy.py --confidence 0.2
    
    # 使用更大的模型(更准确但更慢)
    python extract_people_images_enhanced_copy.py --model yolov8s.pt
    
    # 保存检测预览图
    python extract_people_images_enhanced_copy.py --preview
    
    # 使用GPU加速(如果有NVIDIA显卡)
    python extract_people_images_enhanced_copy.py --device cuda
    
    # 查看所有选项
    python extract_people_images_enhanced_copy.py --help
    

    如果还是有问题,使用这个简单版本:

    # 先删除所有有问题的文件
    rm -f *.py
    
    # 创建简单版本
    cat > simple_detection.py << 'EOF'
    import os
    import shutil
    import cv2
    from pathlib import Path
    
    def detect_people():
        print("开始检测人物图片...")
        
        # 检查OpenCV
        try:
            face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
        except:
            print("请先安装OpenCV: pip install opencv-python")
            return
        
        # 创建目标文件夹
        target_dir = "images_with_people"
        Path(target_dir).mkdir(exist_ok=True)
        
        # 支持的图片格式
        formats = ['.jpg', '.jpeg', '.png']
        count = 0
        
        for filename in os.listdir('.'):
            if any(filename.lower().endswith(fmt) for fmt in formats):
                print(f"处理: {filename}")
                img = cv2.imread(filename)
                if img is not None:
                    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
                    faces = face_cascade.detectMultiScale(gray, 1.1, 5)
                    if len(faces) > 0:
                        shutil.copy2(filename, os.path.join(target_dir, filename))
                        print(f"✓ 检测到人物")
                        count += 1
                    else:
                        print(f"✗ 未检测到人物")
        
        print(f"\n完成! 找到 {count} 张包含人物的图片")
    
    if __name__ == "__main__":
        detect_people()
    EOF
    
    # 运行简单版本
    python simple_detection.py
    

    请按照步骤1-4操作,应该能解决问题!

    二、增强检测人物图片(自定义文件夹):

    这个版本实现了把检测到的图片直接移动到新的文件夹而不是复制,也可以通过后面的加参数定义移动或者复制。

    主要修改 shutil.copy2()shutil.move()

    #!/usr/bin/env python3
    """
    增强版人物图片检测程序(移动版本)
    使用YOLOv8模型进行更准确的人物检测,并将图片移动到新文件夹
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            print("\n如果安装缓慢,可以使用清华镜像:")
            print("pip install -i https://pypi.tuna.tsinghua.edu.cn/simple torch torchvision ultralytics opencv-python")
            return None, None
    
    def extract_images_with_people_enhanced(source_dir, target_dir, confidence_threshold=0.3, 
                                          model_size='yolov8n.pt', device='cpu', 
                                          save_detection_preview=False, move_instead_of_copy=True):
        """
        使用YOLO模型检测并移动包含人物的图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值(0.0-1.0),值越小检测越敏感
        model_size: 模型大小 ('yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt')
        device: 运行设备 ('cpu' 或 'cuda')
        save_detection_preview: 是否保存带检测框的预览图
        move_instead_of_copy: 是否移动而不是复制图片
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp', '.JPG', '.JPEG', '.PNG']
        
        print("=" * 60)
        print("增强版人物图片检测程序(移动版本)")
        print("=" * 60)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"操作模式: {'移动' if move_instead_of_copy else '复制'}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print(f"设备: {device}")
        print(f"保存检测预览: {save_detection_preview}")
        print("-" * 60)
        
        # 警告信息
        if move_instead_of_copy:
            print("⚠️  警告: 此操作将移动图片文件,原文件夹中的图片将被删除!")
            response = input("是否继续?(y/N): ")
            if response.lower() != 'y':
                print("操作已取消")
                return
        
        try:
            # 加载YOLO模型(会自动下载如果不存在)
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            print("请检查网络连接或手动下载模型")
            return
        
        # 统计信息
        total_images = 0
        images_with_people = 0
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 处理: {filename}")
            total_images += 1
            
            try:
                # 记录开始时间
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检查是否检测到人物(YOLO中person类的ID是0)
                has_people = False
                people_count = 0
                max_confidence = 0.0
                
                for result in results:
                    if result.boxes is not None and len(result.boxes) > 0:
                        for box in result.boxes:
                            class_id = int(box.cls)
                            confidence = float(box.conf)
                            
                            # class_id 0 对应 'person'
                            if class_id == 0:
                                has_people = True
                                people_count += 1
                                max_confidence = max(max_confidence, confidence)
                
                if has_people:
                    images_with_people += 1
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_dir, filename)
                    
                    # 处理重名文件
                    counter = 1
                    base_target_path = target_path
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_dir, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 移动或复制文件到目标文件夹
                    if move_instead_of_copy:
                        shutil.move(file_path, target_path)
                        operation_text = "移动"
                    else:
                        shutil.copy2(file_path, target_path)
                        operation_text = "复制"
                    
                    # 如果启用预览,保存带检测框的图片
                    if save_detection_preview and has_people:
                        try:
                            # 重新读取图片用于预览(如果是移动操作,需要重新加载)
                            if move_instead_of_copy:
                                preview_source_path = target_path
                            else:
                                preview_source_path = file_path
                                
                            preview_results = model(preview_source_path, conf=confidence_threshold, device=device, verbose=False)
                            plotted_image = preview_results[0].plot()
                            preview_filename = f"preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    print(f"  ✓ 检测到 {people_count} 个人物 (最高置信度: {max_confidence:.3f})")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已{operation_text}到: {os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'people_count': people_count,
                        'max_confidence': max_confidence,
                        'detection_time': detection_time,
                        'operation': operation_text
                    })
                    
                else:
                    print(f"  ✗ 未检测到人物 (检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 60)
        print("处理完成!")
        print("=" * 60)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到包含人物的图片: {images_with_people}张")
            print(f"检测率: {(images_with_people/total_images*100):.1f}%")
            
            if detection_times:
                avg_detection_time = sum(detection_times) / len(detection_times)
                print(f"平均检测时间: {avg_detection_time:.2f}秒/张")
                print(f"总检测时间: {sum(detection_times):.2f}秒")
            
            if images_with_people > 0:
                operation_mode = "移动" if move_instead_of_copy else "复制"
                print(f"\n包含人物的图片已{operation_mode}到: {target_dir}")
                if save_detection_preview:
                    print(f"检测预览图已保存到: {preview_dir}")
                
                # 显示检测到最多人物的前几张图片
                if processed_files:
                    processed_files.sort(key=lambda x: x['people_count'], reverse=True)
                    print(f"\n检测结果最好的图片:")
                    for i, file_info in enumerate(processed_files[:3]):
                        print(f"  {i+1}. {file_info['filename']} - {file_info['people_count']}人 "
                              f"(置信度: {file_info['max_confidence']:.3f})")
                    
                # 安全提示
                if move_instead_of_copy:
                    remaining_files = len([f for f in os.listdir(source_dir) 
                                         if any(f.lower().endswith(fmt) for fmt in supported_formats)])
                    print(f"\n⚠️  原文件夹剩余图片: {remaining_files}张")
                    print("⚠️  检测到的图片已被移动到目标文件夹,原文件已删除")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='增强版人物图片检测程序(移动版本)')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='images_with_people',
                           help='目标文件夹路径 (默认: images_with_people)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        parser.add_argument('--copy', action='store_true',
                           help='使用复制模式而不是移动模式')
        
        args = parser.parse_args()
        
        # 检查源文件夹是否存在
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        # 运行检测程序
        extract_images_with_people_enhanced(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview,
            move_instead_of_copy=not args.copy  # 如果指定--copy则使用复制模式
        )
    
    # 简化版本函数(不需要命令行参数)
    def simple_extract():
        """简化版本,使用默认参数(移动模式)"""
        source_dir = os.getcwd()  # 当前文件夹
        target_dir = os.path.join(source_dir, "images_with_people")
        
        print("使用简化模式运行(移动模式)...")
        print("此操作将把检测到人物的图片移动到新文件夹!")
        
        response = input("是否继续?(y/N): ")
        if response.lower() != 'y':
            print("操作已取消")
            return
        
        extract_images_with_people_enhanced(source_dir, target_dir, move_instead_of_copy=True)
    
    if __name__ == "__main__":
        # 如果没有命令行参数,使用简化版本
        import sys
        if len(sys.argv) == 1:
            simple_extract()
        else:
            main()
    

    主要修改内容:

    1. shutil.copy2()改为 shutil.move()
    2. 添加了移动模式的安全确认,避免误操作
    3. 增加了 move_instead_of_copy参数,可以控制是移动还是复制
    4. 添加了 --copy命令行参数,如果需要复制模式可以加上这个参数
    5. 改进了预览图生成逻辑,适应移动操作
    6. 增加了操作完成后的统计信息,显示剩余文件数量

    使用方法:

    移动模式(默认):

    # 简单使用(移动图片)
    python extract_people_images_enhanced_move.py
    
    # 带参数使用
    python extract_people_images_enhanced_move.py --source ./图片文件夹 --target ./人物图片
    

    复制模式(如果需要保留原文件):

    # 使用复制模式
    python extract_people_images_enhanced_move.py --copy
    
    # 带预览的复制模式
    python extract_people_images_enhanced_move.py --copy --preview
    

    其他参数:

    # 调整检测敏感度
    python extract_people_images_enhanced_move.py --confidence 0.2
    
    # 使用更大的模型
    python extract_people_images_enhanced_move.py --model yolov8s.pt
    
    # 保存检测预览图
    python extract_people_images_enhanced_move.py --preview
    

    安全特性:

    1. 运行前确认:移动模式会要求用户确认
    2. 进度显示:实时显示处理进度
    3. 结果统计:完成后显示移动/复制的文件数量
    4. 剩余文件提示:显示原文件夹剩余图片数量

    这样修改后,检测到人物的图片会被直接移动到目标文件夹,原文件会被删除,节省磁盘空间。如果你需要保留原文件,使用 --copy参数即可。

    高级检测:

    方案1:基于YOLO的人体部位检测

    专门检测女性人体暴露或色情内容。这里有几个不同级别的实现方案:

    #!/usr/bin/env python3
    """
    女性人体暴露/色情图片检测程序
    使用YOLO模型检测暴露的身体部位
    """
    
    import os
    import shutil
    import argparse
    from pathlib import Path
    import time
    
    def setup_environment():
        """检查并导入所需的库"""
        try:
            from ultralytics import YOLO
            import cv2
            return YOLO, cv2
        except ImportError as e:
            print("错误: 缺少必要的库")
            print("请安装以下依赖:")
            print("pip install torch torchvision ultralytics opencv-python")
            return None, None
    
    class NudityDetector:
        """暴露内容检测器"""
        
        def __init__(self, confidence_threshold=0.3):
            self.confidence_threshold = confidence_threshold
            # 定义敏感部位类别(基于COCO数据集)
            self.sensitive_parts = {
                'person': 0,      # 人物
                'face': 1,        # 脸部(某些数据集有)
            }
            
            # 定义暴露风险等级的关键词(用于文件名和路径分析)
            self.risky_keywords = [
                'nude', 'naked', 'bikini', 'swimsuit', 'lingerie', 'sexy', 'hot',
                '暴露', '性感', '内衣', '比基尼', '泳装', '裸体', '色情'
            ]
        
        def detect_exposure_level(self, results, filename=""):
            """
            检测图片的暴露等级
            返回: (暴露等级, 置信度, 检测到的部位)
            """
            exposure_level = 0  # 0: 安全, 1: 轻度, 2: 中度, 3: 高度暴露
            max_confidence = 0
            detected_parts = []
            
            for result in results:
                if result.boxes is not None and len(result.boxes) > 0:
                    for box in result.boxes:
                        class_id = int(box.cls)
                        confidence = float(box.conf)
                        
                        # 检测人物
                        if class_id == 0:  # person
                            detected_parts.append('person')
                            max_confidence = max(max_confidence, confidence)
                            
                            # 如果有高置信度的人物检测,基础暴露等级为1
                            if confidence > 0.5:
                                exposure_level = max(exposure_level, 1)
            
            # 基于文件名分析
            filename_risk = self.analyze_filename_risk(filename.lower())
            exposure_level = max(exposure_level, filename_risk)
            
            return exposure_level, max_confidence, detected_parts
        
        def analyze_filename_risk(self, filename):
            """分析文件名的风险等级"""
            risk_level = 0
            for keyword in self.risky_keywords:
                if keyword in filename:
                    if keyword in ['nude', 'naked', '裸体', '色情']:
                        risk_level = max(risk_level, 3)
                    elif keyword in ['bikini', 'swimsuit', 'lingerie', '比基尼', '泳装', '内衣']:
                        risk_level = max(risk_level, 2)
                    else:
                        risk_level = max(risk_level, 1)
            return risk_level
        
        def analyze_skin_ratio(self, image_path):
            """简单的肤色比例分析(基础版本)"""
            try:
                import cv2
                import numpy as np
                
                # 读取图片
                img = cv2.imread(image_path)
                if img is None:
                    return 0
                    
                # 转换到HSV颜色空间进行肤色检测
                hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
                
                # 定义肤色范围(需要根据实际情况调整)
                lower_skin = np.array([0, 20, 70], dtype=np.uint8)
                upper_skin = np.array([20, 255, 255], dtype=np.uint8)
                
                # 创建肤色掩码
                mask = cv2.inRange(hsv, lower_skin, upper_skin)
                
                # 计算肤色像素比例
                skin_ratio = np.sum(mask > 0) / (img.shape[0] * img.shape[1])
                
                return skin_ratio
                
            except Exception as e:
                print(f"肤色分析错误: {e}")
                return 0
    
    def extract_sensitive_images(source_dir, target_dir, confidence_threshold=0.3, 
                               model_size='yolov8n.pt', device='cpu', 
                               save_detection_preview=False, move_instead_of_copy=True,
                               min_exposure_level=1):
        """
        检测并提取敏感图片
        
        参数:
        source_dir: 源文件夹路径
        target_dir: 目标文件夹路径
        confidence_threshold: 置信度阈值
        model_size: 模型大小
        device: 运行设备
        save_detection_preview: 是否保存检测预览
        move_instead_of_copy: 是否移动文件
        min_exposure_level: 最小暴露等级 (1-3)
        """
        
        # 检查库是否可用
        YOLO, cv2 = setup_environment()
        if YOLO is None:
            return
        
        # 创建目标文件夹
        Path(target_dir).mkdir(parents=True, exist_ok=True)
        
        # 按暴露等级创建子文件夹
        level_folders = {
            1: os.path.join(target_dir, "level1_mild"),
            2: os.path.join(target_dir, "level2_moderate"),
            3: os.path.join(target_dir, "level3_high")
        }
        
        for folder in level_folders.values():
            Path(folder).mkdir(parents=True, exist_ok=True)
        
        # 如果启用预览,创建预览文件夹
        preview_dir = None
        if save_detection_preview:
            preview_dir = os.path.join(target_dir, "detection_previews")
            Path(preview_dir).mkdir(parents=True, exist_ok=True)
        
        # 支持的图片格式
        supported_formats = ['.jpg', '.jpeg', '.png', '.bmp', '.tiff', '.webp']
        
        print("=" * 70)
        print("女性人体暴露/色情图片检测程序")
        print("=" * 70)
        print(f"源文件夹: {source_dir}")
        print(f"目标文件夹: {target_dir}")
        print(f"操作模式: {'移动' if move_instead_of_copy else '复制'}")
        print(f"最小暴露等级: {min_exposure_level}")
        print(f"模型: {model_size}")
        print(f"置信度阈值: {confidence_threshold}")
        print("-" * 70)
        
        # 警告信息
        if move_instead_of_copy:
            print("⚠️  警告: 此操作将移动图片文件!")
            response = input("是否继续?(y/N): ")
            if response.lower() != 'y':
                print("操作已取消")
                return
        
        # 初始化检测器
        detector = NudityDetector(confidence_threshold)
        
        try:
            # 加载YOLO模型
            print("正在加载YOLO模型...")
            start_time = time.time()
            model = YOLO(model_size)
            load_time = time.time() - start_time
            print(f"✓ 模型加载完成,耗时: {load_time:.2f}秒")
            
        except Exception as e:
            print(f"✗ 模型加载失败: {e}")
            return
        
        # 统计信息
        total_images = 0
        detected_images = 0
        level_stats = {1: 0, 2: 0, 3: 0}
        processed_files = []
        detection_times = []
        
        print("\n开始扫描图片...")
        
        # 获取所有图片文件
        image_files = []
        for filename in os.listdir(source_dir):
            file_path = os.path.join(source_dir, filename)
            if os.path.isfile(file_path) and any(filename.lower().endswith(fmt) for fmt in supported_formats):
                image_files.append(filename)
        
        total_files = len(image_files)
        print(f"找到 {total_files} 张待处理图片")
        
        # 处理每张图片
        for i, filename in enumerate(image_files, 1):
            file_path = os.path.join(source_dir, filename)
            
            print(f"\n[{i}/{total_files}] 分析: {filename}")
            total_images += 1
            
            try:
                start_time = time.time()
                
                # 使用YOLO进行检测
                results = model(file_path, conf=confidence_threshold, device=device, verbose=False)
                detection_time = time.time() - start_time
                detection_times.append(detection_time)
                
                # 检测暴露等级
                exposure_level, max_confidence, detected_parts = detector.detect_exposure_level(results, filename)
                
                # 简单的肤色比例分析
                skin_ratio = detector.analyze_skin_ratio(file_path)
                if skin_ratio > 0.3:  # 如果肤色比例较高,提高暴露等级
                    exposure_level = max(exposure_level, 2)
                
                if exposure_level >= min_exposure_level:
                    detected_images += 1
                    level_stats[exposure_level] = level_stats.get(exposure_level, 0) + 1
                    
                    # 确定目标文件夹
                    target_level_folder = level_folders.get(exposure_level, target_dir)
                    
                    # 构建目标文件路径
                    target_path = os.path.join(target_level_folder, filename)
                    
                    # 处理重名文件
                    counter = 1
                    while os.path.exists(target_path):
                        name, ext = os.path.splitext(filename)
                        target_path = os.path.join(target_level_folder, f"{name}_{counter}{ext}")
                        counter += 1
                    
                    # 移动或复制文件
                    if move_instead_of_copy:
                        shutil.move(file_path, target_path)
                        operation_text = "移动"
                    else:
                        shutil.copy2(file_path, target_path)
                        operation_text = "复制"
                    
                    # 保存检测预览
                    if save_detection_preview:
                        try:
                            preview_results = model(target_path if move_instead_of_copy else file_path, 
                                                  conf=confidence_threshold, device=device, verbose=False)
                            plotted_image = preview_results[0].plot()
                            preview_filename = f"L{exposure_level}_preview_{os.path.splitext(filename)[0]}.jpg"
                            preview_path = os.path.join(preview_dir, preview_filename)
                            cv2.imwrite(preview_path, plotted_image)
                        except Exception as e:
                            print(f"  警告: 无法保存检测预览图: {e}")
                    
                    # 暴露等级描述
                    level_descriptions = {
                        1: "轻度暴露",
                        2: "中度暴露", 
                        3: "高度暴露"
                    }
                    
                    print(f"  ✓ 检测结果: {level_descriptions.get(exposure_level, '未知')} (等级{exposure_level})")
                    print(f"  ✓ 肤色比例: {skin_ratio:.3f}")
                    print(f"  ✓ 检测部位: {', '.join(detected_parts) if detected_parts else '无'}")
                    print(f"  ✓ 检测时间: {detection_time:.2f}秒")
                    print(f"  ✓ 已{operation_text}到: level{exposure_level}/{os.path.basename(target_path)}")
                    
                    processed_files.append({
                        'filename': filename,
                        'exposure_level': exposure_level,
                        'skin_ratio': skin_ratio,
                        'detected_parts': detected_parts,
                        'detection_time': detection_time,
                        'operation': operation_text
                    })
                    
                else:
                    print(f"  ✗ 安全图片 (暴露等级: {exposure_level}, 检测时间: {detection_time:.2f}秒)")
                    
            except Exception as e:
                print(f"  ✗ 处理图片时出错: {e}")
                continue
        
        # 输出统计信息
        print("\n" + "=" * 70)
        print("检测完成!")
        print("=" * 70)
        
        if total_images > 0:
            print(f"总共处理图片: {total_images}张")
            print(f"检测到敏感图片: {detected_images}张")
            print(f"检测率: {(detected_images/total_images*100):.1f}%")
            
            print(f"\n暴露等级分布:")
            for level, count in level_stats.items():
                if count > 0:
                    level_desc = {1: "轻度暴露", 2: "中度暴露", 3: "高度暴露"}.get(level, "未知")
                    print(f"  等级{level} ({level_desc}): {count}张")
            
            if detected_images > 0:
                operation_mode = "移动" if move_instead_of_copy else "复制"
                print(f"\n敏感图片已{operation_mode}到对应等级的文件夹")
                
                # 显示检测结果
                if processed_files:
                    processed_files.sort(key=lambda x: x['exposure_level'], reverse=True)
                    print(f"\n风险最高的图片:")
                    for i, file_info in enumerate(processed_files[:5]):
                        print(f"  {i+1}. {file_info['filename']} - 等级{file_info['exposure_level']} "
                              f"(肤色比例: {file_info['skin_ratio']:.3f})")
        else:
            print("未找到任何可处理的图片文件")
    
    def main():
        """主函数"""
        parser = argparse.ArgumentParser(description='女性人体暴露/色情图片检测程序')
        parser.add_argument('--source', '-s', default='.', 
                           help='源文件夹路径 (默认: 当前文件夹)')
        parser.add_argument('--target', '-t', default='sensitive_images',
                           help='目标文件夹路径 (默认: sensitive_images)')
        parser.add_argument('--confidence', '-c', type=float, default=0.3,
                           help='检测置信度阈值 (0.0-1.0, 默认: 0.3)')
        parser.add_argument('--model', '-m', default='yolov8n.pt',
                           choices=['yolov8n.pt', 'yolov8s.pt', 'yolov8m.pt', 'yolov8l.pt', 'yolov8x.pt'],
                           help='YOLO模型大小 (默认: yolov8n.pt)')
        parser.add_argument('--device', '-d', default='cpu',
                           choices=['cpu', 'cuda'],
                           help='运行设备 (默认: cpu)')
        parser.add_argument('--preview', '-p', action='store_true',
                           help='保存带检测框的预览图')
        parser.add_argument('--copy', action='store_true',
                           help='使用复制模式而不是移动模式')
        parser.add_argument('--level', type=int, default=1, choices=[1, 2, 3],
                           help='最小暴露等级 (1:轻度, 2:中度, 3:高度, 默认: 1)')
        
        args = parser.parse_args()
        
        if not os.path.exists(args.source):
            print(f"错误: 源文件夹 '{args.source}' 不存在")
            return
        
        extract_sensitive_images(
            source_dir=args.source,
            target_dir=args.target,
            confidence_threshold=args.confidence,
            model_size=args.model,
            device=args.device,
            save_detection_preview=args.preview,
            move_instead_of_copy=not args.copy,
            min_exposure_level=args.level
        )
    
    if __name__ == "__main__":
        import sys
        if len(sys.argv) == 1:
            # 简化模式运行
            source_dir = os.getcwd()
            target_dir = os.path.join(source_dir, "sensitive_images")
            
            print("女性人体暴露图片检测程序")
            print("此操作将检测并分类暴露程度的图片!")
            
            response = input("是否继续?(y/N): ")
            if response.lower() == 'y':
                extract_sensitive_images(source_dir, target_dir, move_instead_of_copy=True)
            else:
                print("操作已取消")
        else:
            main()
    

    方案2:使用专门的NSFW检测模型

    如果需要更准确的结果,可以使用专门的NSFW检测模型:

    # 需要额外安装的库
    # pip install tensorflow keras
    
    def setup_nsfw_detector():
        """设置专门的NSFW检测器"""
        try:
            # 这里可以使用预训练的NSFW检测模型
            # 例如: https://github.com/rockyzhengwu/nsfw
            print("正在加载NSFW检测模型...")
            # 实际实现需要下载预训练模型
            return None
        except ImportError:
            print("请安装TensorFlow: pip install tensorflow")
            return None
    

    使用方法:

    # 基本使用(移动模式,检测所有暴露等级)
    python sensitive_detector.py
    
    # 只检测高度暴露的图片
    python sensitive_detector.py --level 3
    
    # 复制模式(保留原文件)
    python sensitive_detector.py --copy
    
    # 指定源文件夹和目标文件夹
    python sensitive_detector.py --source ./图片库 --target ./敏感图片
    
    # 保存检测预览
    python sensitive_detector.py --preview
    
    # 使用更准确的模型
    python sensitive_detector.py --model yolov8s.pt
    

    暴露等级说明:

    • 等级1(轻度): 检测到人物,可能有轻微暴露
    • 等级2(中度): 检测到较多肤色区域或敏感关键词
    • 等级3(高度): 高度暴露内容,包含大量肤色区域或明确敏感内容

    注意事项:

    1. 准确率限制: 这种检测方法有一定误判率
    2. 隐私保护: 请确保合法使用,尊重他人隐私
    3. 法律合规: 在不同地区使用此类工具可能受到法律限制
    4. 人工审核: 建议最终结果由人工审核确认

    这个程序会按暴露程度将图片分类到不同的文件夹,方便你进一步处理。

    正确的运行方法:

    方法1:直接运行Python脚本

    # 进入脚本所在目录
    cd /home/leepoet/Documents/env/myenv/甜心
    
    # 直接运行Python脚本
    python 女性人体暴露.py
    

    方法2:给脚本添加执行权限后直接运行

    # 进入脚本所在目录
    cd /home/leepoet/Documents/env/myenv/甜心
    
    # 给脚本添加执行权限
    chmod +x 女性人体暴露.py
    
    # 直接运行脚本
    ./女性人体暴露.py
    

    设置自定义检测路径

    你可以通过命令行参数灵活指定源文件夹和目标文件夹:

    # 检测指定文件夹,结果保存到自定义目录
    python your_script.py --source /path/to/your/images --target /path/to/output

    # 完整参数示例
    python your_script.py --source /home/user/photos --target /home/user/sorted_photos --confidence 0.5 --model yolov8s.pt --preview --copy

    4. 关键参数说明

    • --source: 指定需要检测的图片文件夹路径
    • --target: 指定结果输出文件夹路径
    • --confidence: 调整检测灵敏度(0.1-1.0)
    • --model: 选择不同的YOLO模型(影响精度和速度)
    • --preview: 保存带检测框的预览图
    • --copy: 使用复制模式(默认是移动文件)
  • MyWorks产品篇:AIGC与PS深度结合 20240630

    MyWorks产品篇:AIGC与PS深度结合 20240630

    在AIGC的浪潮中,我选择成为一名“调律师”而非简单的“使用者”。我的作品试图探索人类与AI协同创作的全新工作流。不追求以假乱真的图片生成,而是将AI作为激发灵感的缪斯和提升效率的伙伴。系列AIGC插画与概念图,它们不仅是图像,更是人机对话的记录,是理性提示与感性审美共同作用下的数字诗篇。

    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
    MyWorks产品篇:AIGC与PS深度结合 20240630
  • 批量转换txt文档编码与格式:解决直接修改后缀之后导入Obsidian出现的乱码问题

    批量转换txt文档编码与格式:解决直接修改后缀之后导入Obsidian出现的乱码问题

    之前收集了几万部TXT小说,因为想把它们都导入到markdown的obsbian里,做一个集所有学习资料与备份文档的仓库方便以后导读,于是一开始只是在当前需要改txt文档的目录用cmd命令

    ren *.txt *.md

    执行了一下。它的作用是​​将当前目录下所有扩展名为 .txt的文件,批量重命名为扩展名为 .md的文件​​。

    但是把批理修改后缀后的txt文档【修改后即*.md,(*代表当前目录下所有的文件命令)】

    例如,执行命令后,当前目录下(包括当前目录下所有的子文件夹):

    • 笔记.txt→ 笔记.md
    • 报告.txt→ 报告.md

    然后放到obsidian的仓库目录下,结果显示大部份文件全是乱码。

    于是找了下原因,Obsidian 默认使用 ​​UTF-8​​ 编码来读取文件。Windows 系统默认创建的 .txt文本文件,编码通常是 ​​ANSI​​(在中文系统中通常对应 ​​GBK​​ 或 ​​GB2312​​)。简单的重命名(ren *.txt *.md)只改变了文件扩展名,并没有改变文件内部的编码格式。当编码不匹配时,乱码就会出现

    然后再全部放到obsbian仓库目录下,是可以调用的,但是显示的全是乱码。我想了想肯定是因为字符编码不匹配,于是去查了一下如果obsidian是可以识别UTF-8字符编码的,出现了乱码的文档是因为在转后缀之前就不是UTF-8字符编码,所以才会出现这种情况。

    解决方法:

    新建一个txt文档,把以下代码复制进去,保存文件格式为py。(前提是电脑先要装python)

    相当于做一个Python 脚本批量处理​​,,它能​​递归遍历指定目录及其所有子文件夹​​,批量将 .txt文件转换为 .md文件,并同时将文件编码从 ANSI (GBK) 转换为 UTF-8。

    批量转换txt文档编码与格式:解决直接修改后缀之后导入Obsidian出现的乱码问题

    然后再把这个文件放到需要批量修改txt文件的目录中,并在当前目录打开cmd,把这个py文件丢进去执行,或者直接命令提示符cd到该目录,执行即可。

    批量转换txt文档编码与格式:解决直接修改后缀之后导入Obsidian出现的乱码问题
    import os
    import codecs
    
    def rename_txt_to_md_and_convert_encoding(directory):
        # 遍历目录中的所有文件和子文件夹
        for root, _, files in os.walk(directory):
            for file_name in files:
                # 检查文件是否以.txt结尾
                if file_name.endswith('.txt'):
                    # 构建旧文件路径和新文件路径
                    old_file_path = os.path.join(root, file_name)
                    new_file_path = os.path.join(root, file_name.replace('.txt', '.md'))
                    
                    # 检查目标文件是否已经存在
                    if not os.path.exists(new_file_path):
                        # 重命名文件
                        os.rename(old_file_path, new_file_path)
                        print(f'将文件 {old_file_path} 重命名为 {new_file_path}')
                        
                        # 尝试将ANSI编码的文件转换为UTF-8编码
                        try:
                            with codecs.open(new_file_path, 'r', 'ansi') as ansi_file:
                                utf8_content = ansi_file.read()
                            with codecs.open(new_file_path, 'w', 'utf-8') as utf8_file:
                                utf8_file.write(utf8_content)
                            print(f'已将文件 {new_file_path} 从ANSI转换为UTF-8')
                        except Exception as e:
                            print(f'无法处理文件 {new_file_path}: {e}')
                    else:
                        print(f'目标文件 {new_file_path} 已经存在,跳过重命名')
    
    # 指定要修改的根文件夹路径
    root_folder_path = r'G:\PoetNode\poetnote\Novel\change' # 请修改为你的实际文件夹路径
    # 调用函数来递归修改文件扩展名和文件编码
    rename_txt_to_md_and_convert_encoding(root_folder_path)
    print('批量修改文件扩展名和文件编码完成')

  • windows怎么找查当前目录下所有TXT文件里的内容

    windows怎么找查当前目录下所有TXT文件里的内容

    在一些整理文档场景中,我们不知道文档内会有什么内容,又不知道如何通过内容来归类,可以用以下方法进行操作,即可得到我们想要的内容。

    运用批处理,新建一个txt文档,再把后缀改成bat,右链编辑此bat文件,把以下代码复制,粘贴进去。

    然后保存为u-tf8编码。点击运行。

    #需要注意的是:这个批处理会把当前所在目录下所有的TXT文件都会查收,所以建议是最好是先新建一个文件夹再把这个文件以及所有的TXT文档都COPY在一起,

    windows怎么找查当前目录下所有TXT文件里的内容

    然后通过在当前窗口处输入CMD调出,命令提示符。再把BAT文件拖进提示符内执行。

    windows怎么找查当前目录下所有TXT文件里的内容

    比如,我输入叶凡,它即会执行查找当前目录下所有TXT文档内含有“叶凡”两个字的文件,及出现的次数统计。

    windows怎么找查当前目录下所有TXT文件里的内容

    并保存一份统计文档

    windows怎么找查当前目录下所有TXT文件里的内容

    代码如下:

    @echo off
    chcp 65001 > nul
    setlocal enabledelayedexpansion

    echo =====================================
    echo *脚本名称: txt_content_search.bat*
    echo *功能: 搜索当前目录及子目录TXT文件中*
    echo *包含指定内容的匹配次数*
    echo *作者: Leepoet*
    echo *日期: 2025-09-05*
    echo =====================================

    REM 设置UTF-8编码支持中文

    :: 初始化结果文件
    set “resultFile=search_results_%date:~0,4%%date:~5,2%%date:~8,2%.txt”
    if exist “%resultFile%” del “%resultFile%”

    :: 用户输入
    :input
    echo 请输入要查找的文本内容:
    set /p “searchText=”
    if “!searchText!”==”” (
    echo 错误:内容不能为空!
    goto :input
    )

    :: 搜索处理
    echo [查找内容]: !searchText! > “%resultFile%”
    echo ============================ >> “%resultFile%”
    echo 文件路径 匹配次数 >> “%resultFile%”
    echo ————————— >> “%resultFile%”

    set /a totalCount=0
    for /r %%f in (*.txt) do (
    findstr /i /c:”!searchText!” “%%f” >nul && (
    set /a count=0
    for /f %%a in (‘findstr /i /c:”!searchText!” “%%f” ^| find /c /v “”‘) do set /a count=%%a
    set /a totalCount+=count
    echo %%~ff !count! >> “%resultFile%”
    )
    )

    :: 结果汇总
    echo ============================ >> “%resultFile%”
    echo 总匹配文件数: %totalCount% >> “%resultFile%”
    if %totalCount% gtr 0 (
    echo 搜索完成!结果已保存到 %resultFile%
    start “” “%resultFile%”
    ) else (
    echo 未找到包含指定内容的TXT文件
    del “%resultFile%”
    )
    endlocal