求助,求大佬帮我看一下这个图片转视频的Python代码,图片转视频时,颜色改变

查看 48|回复 6
作者:樂青影   
求助,求大佬帮我看一下这个图片转视频的代码,
图片添加动画后转成视频的操作时,可以实现,但是到处的时候图片颜色发生了改变,好像转成了对比色,应该时进行色彩空间BGR和RGB部分转化时出现了问题。,请大佬帮我看一看,谢谢!!
import cv2
import numpy as np
from moviepy.editor import ImageSequenceClip
from PIL import Image, ImageDraw, ImageFont
def create_animation(image, frames, duration, fps):
    """创建旋转动画效果."""
    for t in np.linspace(0, 1, int(fps * duration)):
        angle = t * 360  # 从0到360度旋转
        M = cv2.getRotationMatrix2D(
            (image.shape[1] // 2, image.shape[0] // 2), angle, 1)
        rotated = cv2.warpAffine(image, M, (image.shape[1], image.shape[0]))
        frames.append(rotated)
def load_image(image_path):
    """加载图片并返回其路径和调整后的图片."""
    image = cv2.imread(image_path)
    return image_path.split("/")[-1].split(".")[0], image
def resize_image(image, target_width, target_height):
    """根据目标宽高比调整图片大小,并保持原始比例."""
    height, width, _ = image.shape
    aspect_ratio = width / height
    if aspect_ratio > (target_width / target_height):
        new_width = target_width
        new_height = int(target_width / aspect_ratio)
    else:
        new_height = target_height
        new_width = int(target_height * aspect_ratio)
    resized_image = cv2.resize(image, (new_width, new_height))
    # 创建背景并将图片居中放置
    background = np.zeros((target_height, target_width, 3), dtype=np.uint8)
    y_offset = (target_height - new_height) // 2
    x_offset = (target_width - new_width) // 2
    background[y_offset:y_offset + new_height,
               x_offset:x_offset + new_width] = resized_image
    return background, new_width, new_height
def generate_video(frames, output_path, target_width, target_height, fps):
    """生成视频并输出."""
    clip = ImageSequenceClip(frames, fps=fps)
    clip = clip.resize(newsize=(target_width, target_height))
    clip.write_videofile(output_path, codec="libx264", fps=fps)
def add_text_with_pil(frame, text, position, font_path, font_size, color):
    """使用 PIL 在帧上添加中文文本."""
    pil_image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    draw = ImageDraw.Draw(pil_image)
    font = ImageFont.truetype(font_path, font_size)
    draw.text(position, text, font=font, fill=color)
    return cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
def main(image_path):
    # 加载原始图片
    file_name, image = load_image(image_path)
    # 设定目标视频的分辨率
    target_width = 1080
    target_height = 2060
    # 调整图片大小并居中
    image_resized, new_width, new_height = resize_image(
        image, target_width, target_height)
    # 创建视频帧列表
    frames = []
    # 设置文本参数
    font_path = "SourceHanSerifCN-Heavy.otf"  # 确保这个路径是正确的
    font_size_file = 50  # 文件名字体大小
    font_size_text = 50  # 测试test字体大小
    color_file = (45, 204, 159)  # 文件名颜色
    color_text = (45, 204, 159)  # 测试test颜色
    # 计算文件名文本位置
    text_size_file = cv2.getTextSize(
        file_name, cv2.FONT_HERSHEY_SIMPLEX, 3, 5)[0]
    text_x_file = (target_width - text_size_file[0]) // 2
    text_y_file = target_height // 3  # 上方1/3位置
    # 计算“测试test”文本位置(左下角)
    text = "测试test"
    text_x_text = 10  # 左边距
    text_y_text = target_height - 60  # 底边距,留出一些空间
    # 添加原图的前半秒并写上文件名
    for _ in range(int(0.5 * 30)):  # 30 FPS
        frame = image_resized.copy()
        frame = add_text_with_pil(
            frame, file_name, (text_x_file, text_y_file), font_path, font_size_file, color_file)
        frames.append(frame)
    # 添加动画效果
    create_animation(image_resized, frames, duration=2, fps=30)  # 2秒的旋转动画
    # 添加原图的最后两秒
    for _ in range(int(2 * 30)):
        frames.append(image_resized)
    # 在每一帧中添加“测试test”文本
    for frame in frames:
        frame = add_text_with_pil(
            frame, text, (text_x_text, text_y_text), font_path, font_size_text, color_text)
    # 构建输出视频路径
    output_path = f"{file_name}.mp4"
    # 输出视频
    generate_video(frames, output_path, target_width, target_height, fps=30)
    print("视频已生成:", output_path)
if __name__ == "__main__":
    image_path = "test001.jpg"  # 替换为你的图片路径
    main(image_path)

图片, 视频

zxcvbnm10230   


zxcvbnm10230 发表于 2024-10-30 16:51
可以看出是处理色彩通道的时候出了问题。
AI写了段代码,试了的确能用
[mw_shl_code=python,true]from da ...

你的初始代码在load_image 时载入转为RGB就行了,其他代码的色彩通道转换就不需要了
Lelee   

可以问问AI
zxcd324   

必须看看有什么
樂青影
OP
  


Lelee 发表于 2024-10-30 15:42
可以问问AI

ai回答的有些问题,一直在说压缩方式和空间色彩方面的内容,按照他的修改之后并不能解决问题
zxcvbnm10230   

可以看出是处理色彩通道的时候出了问题。
AI写了段代码,试了的确能用
[Python] 纯文本查看 复制代码from dataclasses import dataclass
from typing import List, Tuple, Optional
from pathlib import Path
import logging
from abc import ABC, abstractmethod
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
# 1. 使用数据类来管理配置
@dataclass
class VideoConfig:
    target_width: int = 1080
    target_height: int = 2060
    fps: int = 30
    static_text_duration: float = 0.5  # 秒
    rotation_duration: float = 2.0      # 秒
    final_static_duration: float = 2.0  # 秒
    font_size: int = 40
    text_color: Tuple[int, int, int] = (0, 0, 0)
# 2. 创建异常类
class VideoProcessingError(Exception):
    """视频处理相关的自定义异常"""
    pass
# 3. 创建抽象基类定义接口
class FrameEffect(ABC):
    @abstractmethod
    def apply(self, image: Image.Image) -> Image.Image:
        pass
class TextEffect(FrameEffect):
    def __init__(self, text: str, position: Tuple[int, int], font_path: Path, config: VideoConfig):
        self.text = text
        self.position = position
        self.font = ImageFont.truetype(str(font_path), config.font_size)
        self.color = config.text_color
    def apply(self, image: Image.Image) -> Image.Image:
        image = image.copy()
        draw = ImageDraw.Draw(image)
        draw.text(self.position, self.text, font=self.font, fill=self.color)
        return image
class RotationEffect(FrameEffect):
    def __init__(self, angle: float):
        self.angle = angle
    def apply(self, image: Image.Image) -> Image.Image:
        numpy_image = np.array(image)
        height, width = numpy_image.shape[:2]
        center = (width // 2, height // 2)
        M = cv2.getRotationMatrix2D(center, self.angle, 1.0)
        rotated = cv2.warpAffine(numpy_image, M, (width, height), borderValue=(255, 255, 255))
        return Image.fromarray(rotated)
# 4. 创建视频生成器类
class VideoGenerator:
    def __init__(self, config: VideoConfig):
        self.config = config
        self.logger = logging.getLogger(__name__)
        self.frames: List[Image.Image] = []
    def load_image(self, image_path: Path) -> Tuple[str, Image.Image]:
        """加载并验证图片"""
        try:
            image = Image.open(image_path)
            if image.mode != 'RGB':
                image = image.convert('RGB')
            return image_path.name, image
        except Exception as e:
            raise VideoProcessingError(f"Failed to load image: {e}")
    def resize_image(self, image: Image.Image) -> Image.Image:
        """调整图片大小并保持比例"""
        aspect_ratio = image.size[0] / image.size[1]
        target_ratio = self.config.target_width / self.config.target_height
        if aspect_ratio > target_ratio:
            new_width = self.config.target_width
            new_height = int(new_width / aspect_ratio)
        else:
            new_height = self.config.target_height
            new_width = int(new_height * aspect_ratio)
        resized_image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
        background = Image.new('RGB',
                             (self.config.target_width, self.config.target_height),
                             'white')
        
        paste_x = (self.config.target_width - new_width) // 2
        paste_y = (self.config.target_height - new_height) // 2
        background.paste(resized_image, (paste_x, paste_y))
        
        return background
    def generate_frames(self,
                       image: Image.Image,
                       filename: str,
                       font_path: Path) -> None:
        """生成所有帧"""
        # 静态文本帧
        frames_count = int(self.config.static_text_duration * self.config.fps)
        static_frame = image.copy()
        filename_effect = TextEffect(filename, (50, 50), font_path, self.config)
        static_frame = filename_effect.apply(static_frame)
        self.frames.extend([static_frame.copy() for _ in range(frames_count)])
        # 旋转动画帧
        frames_count = int(self.config.rotation_duration * self.config.fps)
        for i in range(frames_count):
            angle = (i / frames_count) * 360
            rotation_effect = RotationEffect(angle)
            rotated_frame = rotation_effect.apply(image)
            self.frames.append(rotated_frame)
        # 最终静态帧
        frames_count = int(self.config.final_static_duration * self.config.fps)
        self.frames.extend([image.copy() for _ in range(frames_count)])
        # 为所有帧添加固定文本
        text_effect = TextEffect("测试test", (50, 100), font_path, self.config)
        self.frames = [text_effect.apply(frame) for frame in self.frames]
    def save_video(self, output_path: Path) -> None:
        """保存视频"""
        try:
            height, width = np.array(self.frames[0]).shape[:2]
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(str(output_path),
                                fourcc,
                                self.config.fps,
                                (width, height))
            for frame in self.frames:
                cv_frame = cv2.cvtColor(np.array(frame), cv2.COLOR_RGB2BGR)
                out.write(cv_frame)
            out.release()
        except Exception as e:
            raise VideoProcessingError(f"Failed to save video: {e}")
def process_video(image_path: str,
                 font_path: str,
                 output_path: str = "output.mp4",
                 config: Optional[VideoConfig] = None) -> None:
    """主处理函数"""
    # 设置日志
    logging.basicConfig(level=logging.INFO)
    logger = logging.getLogger(__name__)
    try:
        # 转换路径
        image_path = Path(image_path)
        font_path = Path(font_path)
        output_path = Path(output_path)
        # 验证路径
        if not image_path.exists():
            raise VideoProcessingError(f"Image file not found: {image_path}")
        if not font_path.exists():
            raise VideoProcessingError(f"Font file not found: {font_path}")
        # 使用默认配置或自定义配置
        config = config or VideoConfig()
        # 创建视频生成器
        generator = VideoGenerator(config)
        
        # 处理流程
        logger.info("Loading image...")
        filename, image = generator.load_image(image_path)
        
        logger.info("Resizing image...")
        resized_image = generator.resize_image(image)
        
        logger.info("Generating frames...")
        generator.generate_frames(resized_image, filename, font_path)
        
        logger.info("Saving video...")
        generator.save_video(output_path)
        
        logger.info("Video generation completed successfully!")
    except VideoProcessingError as e:
        logger.error(f"Video processing error: {e}")
        raise
    except Exception as e:
        logger.error(f"Unexpected error: {e}")
        raise VideoProcessingError(f"Unexpected error during video processing: {e}")
if __name__ == "__main__":
    # 示例用法
    config = VideoConfig(
        target_width=1080,
        target_height=2060,
        fps=30,
        static_text_duration=0.5,
        rotation_duration=2.0,
        final_static_duration=2.0,
        font_size=40,
        text_color=(0, 0, 0)
    )
   
    try:
        process_video(
            image_path="resources/images/001.jpg",
            font_path="font.ttf",
            output_path="output.mp4",
            config=config
        )
    except VideoProcessingError as e:
        print(f"Error: {e}")
樂青影
OP
  


zxcvbnm10230 发表于 2024-10-30 16:56
你的初始代码在load_image 时载入转为RGB就行了,其他代码的色彩通道转换就不需要了

嗯嗯,好滴,谢谢大佬,去调整一下我的代码去,谢谢哦!!
您需要登录后才可以回帖 登录 | 立即注册

返回顶部