File size: 4,666 Bytes
0140812
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c0c39ac
0140812
 
c0c39ac
 
 
 
 
 
0140812
c0c39ac
 
 
 
 
 
 
 
 
0140812
 
c0c39ac
 
 
 
 
0140812
 
c0c39ac
 
 
 
 
 
0140812
 
 
 
 
 
c0c39ac
 
0140812
c0c39ac
0140812
 
 
c0c39ac
 
0140812
c0c39ac
0140812
c0c39ac
 
0140812
c0c39ac
 
0140812
 
c0c39ac
 
 
 
 
 
0140812
 
 
 
 
 
 
 
 
 
c0c39ac
0140812
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122

import moviepy.editor as mp
import cv2
import numpy as np
from PIL import Image
import os
import json
from datetime import datetime
from transformers import BlipProcessor, BlipForConditionalGeneration
import torch

# BLIP setup
blip_processor = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
blip_model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base")

class VideoSceneAnalyzer:
    def __init__(self, video_path, scene_duration=8):
        self.video_path = video_path
        self.scene_duration = scene_duration
        self.clip = None
        self.video_info = {}
        self.scenes = []

    def load_video(self):
        try:
            self.clip = mp.VideoFileClip(self.video_path)
            self.video_info = {
                'duration': self.clip.duration,
                'fps': self.clip.fps,
                'size': self.clip.size,
                'aspect_ratio': self.clip.size[0] / self.clip.size[1],
                'total_frames': int(self.clip.duration * self.clip.fps)
            }
            return True
        except Exception as e:
            print(f"Erro ao carregar vídeo: {e}")
            return False

    def describe_image_and_generate_prompt(self, frame, idx):
        tmp_path = f"temp_{idx:02d}.jpg"
        Image.fromarray(np.uint8(frame)).save(tmp_path)
        img = Image.open(tmp_path).convert("RGB")

        inputs = blip_processor(images=img, return_tensors="pt")
        out = blip_model.generate(**inputs)
        cap = blip_processor.decode(out[0], skip_special_tokens=True).strip().capitalize()

        descricao = (
            f"Cena {idx}: {cap}. "
            "Registrada ao entardecer com luz dourada suave, profundidade de campo rasa desfocando o fundo. "
            "O ambiente apresenta uma paisagem urbana vibrante com vegetação e construções ao longe, "
            "enquanto o sujeito exibe expressão serena e postura confiante. "
            "Atmosfera de leve nostalgia e contemplação."
        )

        prompt = (
            f"A cinematic, warm golden-hour shot of {cap}. "
            "Captured with a 35mm lens at f/1.8 for shallow depth of field, "
            "soft backlighting, and gentle handheld motion. "
            "Background features a vibrant urban setting with trees and distant buildings, "
            "evoking a sense of nostalgia and calm. "
            "--ar 16:9 --v 6 --style photorealistic --quality 2"
        )

        negative = (
            "--no (CGI artifacts, plastic textures, overexposed skies, cartoonish colors, static poses, low detail)"
        )

        return descricao, prompt, negative

    def extract_keyframes(self, threshold=30.0):
        output_dir = f"keyframes_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
        os.makedirs(output_dir, exist_ok=True)

        cap = cv2.VideoCapture(self.video_path)
        prev = None
        count = 0
        success, frame = cap.read()
        self.scenes = []

        while success:
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            diff = np.inf if prev is None else np.mean(cv2.absdiff(gray, prev))
            if prev is None or diff > threshold:
                timestamp = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000.0
                img_path = os.path.join(output_dir, f"keyframe_{count+1:02d}.jpg")
                Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)).save(img_path)
                desc, prmpt, neg = self.describe_image_and_generate_prompt(
                    cv2.cvtColor(frame, cv2.COLOR_BGR2RGB), count+1
                )
                self.scenes.append({
                    'scene_number': count+1,
                    'time': timestamp,
                    'image_path': img_path,
                    'descricao_detalhada': desc,
                    'prompt_ia': prmpt,
                    'negative_prompt': neg
                })
                count += 1
            prev = gray
            success, frame = cap.read()

        cap.release()
        return True

    def save_results(self, output_file=None):
        if not output_file:
            output_file = f"video_analysis_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
        results = {
            'video_info': self.video_info,
            'analysis_type': 'keyframe_extraction',
            'scenes': self.scenes,
            'generated_at': datetime.now().isoformat()
        }
        with open(output_file, 'w', encoding='utf-8') as f:
            json.dump(results, f, indent=2, ensure_ascii=False)
        return output_file

    def cleanup(self):
        if self.clip:
            self.clip.close()