Загрузка...

Уникализатор фото/видео

Тема в разделе Python создана пользователем 0О0 27 май 2025. 151 просмотр

Загрузка...
  1. 0О0
    0О0 Автор темы 27 май 2025 lolz.live/threads/11111/ - Работайте с лучшими. 629 1 май 2022
    Привет! Хочу поделиться своим скриптом для уникализации фото и видео. Софт применяет различные эффекты (шум, цветокоррекция, контраст и др.) и проверяет уникальность через перцептивные хэши (dhash, phash, ahash).

    Функции
    - Уникализация фото (.jpg, .png, .jpeg) и видео (.mp4, .avi, .mov, .mkv).
    - Эффекты: шум, размытие, поворот, цветокоррекция, контраст, насыщенность и др.
    - Проверка уникальности с заданным порогом.
    - Параллельная обработка файлов для скорости.

    Python
    import os
    import random
    import typer
    from tqdm import tqdm
    from typing import Dict, List
    from pathlib import Path
    from PIL import Image, ImageFilter, ImageOps, ImageEnhance
    import numpy as np
    from moviepy.editor import VideoFileClip
    import csv
    from datetime import datetime
    import cv2
    import imagehash
    from colorama import init, Fore, Style
    from concurrent.futures import ThreadPoolExecutor

    # Инициализация colorama
    init()

    app = typer.Typer()

    PHOTO_EXT = [".jpg", ".jpeg", ".png"]
    VIDEO_EXT = [".mp4", ".avi", ".mov", ".mkv"]

    HASH_ALGORITHMS = {
    "dhash": imagehash.dhash,
    "phash": imagehash.phash,
    "ahash": imagehash.average_hash
    }

    def is_photo(file: str) -> bool:
    return Path(file).suffix.lower() in PHOTO_EXT

    def is_video(file: str) -> bool:
    return Path(file).suffix.lower() in VIDEO_EXT

    def perceptual_diff(img1: Image.Image, img2: Image.Image, algo="dhash") -> int:
    hash_func = HASH_ALGORITHMS.get(algo, imagehash.dhash)
    return abs(hash_func(img1) - hash_func(img2))

    def extract_frame(video_path: str, timestamp: float = 0.5) -> Image.Image:
    clip = VideoFileClip(video_path)
    t = min(timestamp, clip.duration - 0.1)
    frame = clip.get_frame(t)
    clip.reader.close()
    if clip.audio:
    clip.audio.reader.close_proc()
    return Image.fromarray(frame)

    def add_noise(img_np):
    noise = np.random.randint(0, 15, img_np.shape, dtype='uint8') # Уменьшен до 15
    return cv2.add(img_np, noise)

    def color_correction(img):
    r, g, b = img.split()
    channel = random.choice(['r', 'g', 'b'])
    if channel == 'r':
    r = r.point(lambda x: x * 1.1)
    elif channel == 'g':
    g = g.point(lambda x: x * 1.1)
    else:
    b = b.point(lambda x: x * 1.1)
    return Image.merge("RGB", (r, g, b))

    def adjust_gamma(img, gamma=1.0):
    invGamma = 1.0 / gamma
    table = np.array([((i / 255.0) ** invGamma) * 255 for i in range(256)]).astype("uint8")
    img_np = np.array(img)
    img_np = cv2.LUT(img_np, table)
    return Image.fromarray(img_np)

    def adjust_contrast(img, contrast_factor):
    enhancer = ImageEnhance.Contrast(img)
    return enhancer.enhance(contrast_factor / 100.0)

    def adjust_saturation(img, saturation_factor):
    enhancer = ImageEnhance.Color(img)
    return enhancer.enhance(saturation_factor / 100.0)

    def adjust_darkness(img, darkness_factor):
    img_np = np.array(img)
    img_np = np.clip(img_np * (darkness_factor / 100.0), 0, 255).astype("uint8")
    return Image.fromarray(img_np)

    def adjust_warmth(img, warmth_factor):
    img_np = np.array(img)
    warmth_adjust = warmth_factor / 100.0
    img_np[..., 0] = np.clip(img_np[..., 0] * (1 + warmth_adjust * 0.5), 0, 255)
    img_np[..., 2] = np.clip(img_np[..., 2] * (1 - warmth_adjust * 0.3), 0, 255)
    return Image.fromarray(img_np)

    def adjust_peak_brightness(img, peak_factor):
    enhancer = ImageEnhance.Brightness(img)
    return enhancer.enhance(peak_factor / 100.0)

    def adjust_brightness(img, brightness_factor):
    enhancer = ImageEnhance.Brightness(img)
    return enhancer.enhance(brightness_factor / 100.0)

    def adjust_sharpness(img, sharpness_factor):
    enhancer = ImageEnhance.Sharpness(img)
    return enhancer.enhance(sharpness_factor / 100.0)

    def add_background(img, video_mode=False):
    if video_mode:
    h, w, _ = np.array(img).shape
    else:
    w, h = img.size
    bg_color1 = tuple(random.randint(0, 255) for _ in range(3))
    bg_color2 = tuple(random.randint(0, 255) for _ in range(3))
    bg = np.zeros((h, w, 3), dtype=np.uint8)
    for i in range(h):
    r = int(bg_color1[0] + (bg_color2[0] - bg_color1[0]) * i / h)
    g = int(bg_color1[1] + (bg_color2[1] - bg_color1[1]) * i / h)
    b = int(bg_color1[2] + (bg_color2[2] - bg_color1[2]) * i / h)
    bg[i, :] = [r, g, b]
    if video_mode:
    return bg
    else:
    bg_img = Image.fromarray(bg).convert("RGBA")
    img = img.convert("RGBA")
    img = Image.blend(bg_img, img, alpha=0.7)
    return img.convert("RGB")

    def add_invisible_lines(img, video_mode=False):
    img_np = np.array(img)
    h, w = img_np.shape[:2]
    for _ in range(random.randint(5, 10)): # Уменьшен до 10
    x1, y1 = random.randint(0, w), random.randint(0, h)
    x2, y2 = random.randint(0, w), random.randint(0, h)
    color = tuple(random.randint(0, 50) for _ in range(3))
    cv2.line(img_np, (x1, y1), (x2, y2), color, 1)
    return img_np if video_mode else Image.fromarray(img_np)

    def candy_effect(img, video_mode=False):
    enhancer = ImageEnhance.Color(img)
    img = enhancer.enhance(random.uniform(1.2, 2.0)) # Уменьшен диапазон
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(random.uniform(1.1, 1.5)) # Уменьшен диапазон
    return np.array(img) if video_mode else img

    def apply_image_unique(path_in: str, path_out: str, methods: Dict[str, bool], min_diff: int = 10, hash_algo: str = "dhash") -> List[str]:
    original_img = Image.open(path_in).convert("RGB")
    available = [m for m, v in methods.items() if v]
    applied = []

    for _ in range(3): # Уменьшено до 3 попыток
    img = original_img.copy()
    applied.clear()

    for method in random.sample(available, k=min(2, len(available))): # Уменьшено до 2 методов
    if method == "noise":
    img = Image.fromarray(add_noise(np.array(img)))
    elif method == "blur":
    img = img.filter(ImageFilter.BLUR)
    elif method == "rotate":
    img = img.rotate(random.choice([90, 180, 270]))
    elif method == "flip":
    img = ImageOps.mirror(img)
    elif method == "sharpen":
    img = img.filter(ImageFilter.SHARPEN)
    elif method == "resize":
    img = img.resize((img.width - 10, img.height - 10))
    elif method == "color_correction":
    img = color_correction(img)
    elif method == "gamma":
    img = adjust_gamma(img, random.uniform(0.9, 1.1)) # Уменьшен диапазон
    elif method == "brightness":
    img = adjust_brightness(img, random.uniform(80, 120)) # Уменьшен диапазон
    elif method == "background":
    img = add_background(img)
    elif method == "invisible_lines":
    img = add_invisible_lines(img)
    elif method == "candy_effect":
    img = candy_effect(img)
    elif method == "contrast":
    img = adjust_contrast(img, random.uniform(80, 120)) # Уменьшен диапазон
    elif method == "saturation":
    img = adjust_saturation(img, random.uniform(50, 100)) # Уменьшен диапазон
    elif method == "darkness":
    img = adjust_darkness(img, random.uniform(50, 70)) # Уменьшен диапазон
    elif method == "warmth":
    img = adjust_warmth(img, random.uniform(45, 65)) # Уменьшен диапазон
    elif method == "peak_brightness":
    img = adjust_peak_brightness(img, random.uniform(70, 130)) # Уменьшен диапазон
    elif method == "sharpness":
    img = adjust_sharpness(img, random.uniform(80, 120)) # Уменьшен диапазон
    applied.append(method)

    diff = perceptual_diff(original_img, img, hash_algo)
    if diff >= min_diff:
    img.save(path_out, format="JPEG", quality=90)
    applied.append(f"{hash_algo}_diff={diff}")
    return applied

    img.save(path_out, format="JPEG", quality=90)
    applied.append(f"{hash_algo}_diff=FAIL")
    return applied

    def apply_video_unique(path_in: str, path_out: str, methods: Dict[str, bool], min_diff: int = 10, hash_algo: str = "dhash") -> List[str]:
    original_frame = extract_frame(path_in, 0.5) # Один кадр вместо трёх
    available = [m for m, v in methods.items() if v]
    applied = []
    temp_output = path_out.replace(".mp4", "_temp.mp4")

    for _ in range(2): # Уменьшено до 2 попыток
    clip = VideoFileClip(path_in)
    applied.clear()

    for method in random.sample(available, k=min(2, len(available))): # Уменьшено до 2 методов
    if method == "fps":
    clip = clip.set_fps(max(1, clip.fps - random.uniform(0.1, 0.5))) # Меньшее изменение
    elif method == "resize":
    clip = clip.resize(height=int(clip.h * 0.99)) # Меньшее изменение
    elif method == "brightness":
    clip = clip.fl_image(lambda frame: np.clip(frame * 0.98, 0, 255).astype("uint8")) # Меньшее изменение
    elif method == "crop":
    clip = clip.subclip(0.3, clip.duration) # Меньшее обрезание
    elif method == "color_correction":
    clip = clip.fl_image(lambda f: np.array(color_correction(Image.fromarray(f))))
    elif method == "gamma":
    g = random.uniform(0.9, 1.1) # Уменьшен диапазон
    clip = clip.fl_image(lambda f: np.array(adjust_gamma(Image.fromarray(f), gamma=g)))
    elif method == "background":
    clip = clip.fl_image(lambda f: add_background(Image.fromarray(f), video_mode=True))
    elif method == "invisible_lines":
    clip = clip.fl_image(lambda f: add_invisible_lines(Image.fromarray(f), video_mode=True))
    elif method == "candy_effect":
    clip = clip.fl_image(lambda f: candy_effect(Image.fromarray(f), video_mode=True))
    elif method == "contrast":
    v = random.uniform(80, 120) # Уменьшен диапазон
    clip = clip.fl_image(lambda f: np.array(adjust_contrast(Image.fromarray(f), v)))
    elif method == "saturation":
    v = random.uniform(50, 100) # Уменьшен диапазон
    clip = clip.fl_image(lambda f: np.array(adjust_saturation(Image.fromarray(f), v)))
    elif method == "darkness":
    v = random.uniform(50, 70) # Уменьшен диапазон
    clip = clip.fl_image(lambda f: np.array(adjust_darkness(Image.fromarray(f), v)))
    elif method == "warmth":
    v = random.uniform(45, 65) # Уменьшен диапазон
    clip = clip.fl_image(lambda f: np.array(adjust_warmth(Image.fromarray(f), v)))
    elif method == "peak_brightness":
    v = random.uniform(70, 130) # Уменьшен диапазон
    clip = clip.fl_image(lambda f: np.array(adjust_peak_brightness(Image.fromarray(f), v)))
    elif method == "sharpness":
    v = random.uniform(80, 120) # Уменьшен диапазон
    clip = clip.fl_image(lambda f: np.array(adjust_sharpness(Image.fromarray(f), v)))
    applied.append(method)

    clip.write_videofile(temp_output, codec='libx264', audio_codec='aac', verbose=False, logger=None)
    clip.reader.close()
    if clip.audio:
    clip.audio.reader.close_proc()

    new_frame = extract_frame(temp_output, 0.5)
    diff = perceptual_diff(original_frame, new_frame, hash_algo)
    if diff >= min_diff:
    os.replace(temp_output, path_out)
    applied.append(f"{hash_algo}_diff={round(diff, 1)}")
    os.remove(temp_output) if os.path.exists(temp_output) else None
    return applied
    else:
    os.remove(temp_output) if os.path.exists(temp_output) else None

    clip.write_videofile(path_out, codec='libx264', audio_codec='aac', verbose=False, logger=None)
    applied.append(f"{hash_algo}_diff=FAIL")
    return applied

    def process_file(file: str, input_folder: Path, output_folder: Path, photo_settings: Dict[str, bool], video_settings: Dict[str, bool], min_diff: int, hash_algo: str) -> List[str]:
    input_path = input_folder / file
    try:
    if is_photo(file):
    out_file = output_folder / f"{Path(file).stem}_uniq.jpg"
    applied = apply_image_unique(str(input_path), str(out_file), photo_settings, min_diff, hash_algo)
    return ["Фото", file, out_file.name, ", ".join(applied), "OK"]
    elif is_video(file):
    out_file = output_folder / f"{Path(file).stem}_uniq.mp4"
    applied = apply_video_unique(str(input_path), str(out_file), video_settings, min_diff, hash_algo)
    return ["Видео", file, out_file.name, ", ".join(applied), "OK"]
    except Exception as e:
    return ["?", file, "-", "-", f"Ошибка: {e}"]

    @app.command()
    def run():
    typer.echo(f"{Fore.GREEN}==== УНИКАЛИЗАТОР ФОТО И ВИДЕО ===={Style.RESET_ALL}")
    input_folder = Path(typer.prompt("Введите путь к ВХОДНОЙ папке"))
    output_folder = Path(typer.prompt("Введите путь к ВЫХОДНОЙ папке"))
    output_folder.mkdir(parents=True, exist_ok=True)

    # Тип обрабатываемого медиа
    typer.echo("\nЧто обрабатывать?")
    typer.echo("1 — Только фото")
    typer.echo("2 — Только видео")
    typer.echo("3 — Всё сразу")
    media_choice = typer.prompt("Ваш выбор (1/2/3): ")
    media_mode = {"1": "photo", "2": "video", "3": "all"}.get(media_choice, "all")

    # Выбор алгоритма хэша
    typer.echo("\nВыберите алгоритм хэша (для проверки уникальности):")
    typer.echo("1 — dhash (рекомендуется)")
    typer.echo("2 — phash (точнее, но медленнее)")
    typer.echo("3 — ahash (простой)")
    hash_choice = typer.prompt("Ваш выбор (1/2/3): ", default="1")
    hash_algo = {"1": "dhash", "2": "phash", "3": "ahash"}.get(hash_choice, "dhash")

    min_diff = int(typer.prompt("Минимальная уникальность по хэшу (рекомендуется 10–15): ", default="12"))

    # Настройки фильтров (активируем все по умолчанию)
    all_methods = {
    "noise": True, "blur": True, "rotate": True, "flip": True, "sharpen": True, "resize": True,
    "color_correction": True, "gamma": True, "brightness": True, "background": True,
    "invisible_lines": True, "candy_effect": True, "contrast": True, "saturation": True,
    "darkness": True, "warmth": True, "peak_brightness": True, "sharpness": True,
    "fps": True, "crop": True
    }

    photo_settings = {k: v for k, v in all_methods.items() if k not in ["fps", "crop"]}
    video_settings = {k: v for k, v in all_methods.items()}

    files = os.listdir(input_folder)
    media_files = [f for f in files if (
    (is_photo(f) and media_mode in ["photo", "all"]) or
    (is_video(f) and media_mode in ["video", "all"])
    )]

    report = []
    with ThreadPoolExecutor(max_workers=min(4, os.cpu_count() or 1)) as executor: # Параллельная обработка
    results = list(tqdm(executor.map(
    lambda f: process_file(f, input_folder, output_folder, photo_settings, video_settings, min_diff, hash_algo),
    media_files
    ), total=len(media_files), desc="Обработка", ncols=80))

    report.extend(results)

    # Сохранение отчета
    save_report = typer.confirm("Сохранить отчёт в CSV-файл?")
    if save_report:
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    report_file = output_folder / f"uniquify_report_{timestamp}.csv"
    with open(report_file, "w", newline='', encoding="utf-8") as f:
    writer = csv.writer(f)
    writer.writerow(["Тип", "Оригинал", "Результат", "Методы", "Статус"])
    writer.writerows(report)
    typer.echo(f"\n{Fore.GREEN}Готово! Отчёт сохранён: {report_file}{Style.RESET_ALL}")
    else:
    typer.echo(f"\n{Fore.GREEN}Готово! Отчёт не сохранён.{Style.RESET_ALL}")

    typer.echo(f"{Fore.CYAN}by lolz.live/soft 0O0{Style.RESET_ALL}")

    if __name__ == "__main__":
    app()
    pip install Pillow moviepy opencv-python imagehash typer tqdm colorama numpy
     
  2. r8w9
    r8w9 27 май 2025 агент a911 108 22 мар 2019
    А где примеры работы? Прост код выкинул и всё
     
  3. cococolavanila
    не сохраняет готовый видос в Выходную папку, отчет сохраняет
     
Top