정보통신기술(ICT)

맵 타임랩스 소프트웨어(12.03.24)

해머슴 2024. 12. 3. 10:11
import sys
import cv2
import numpy as np
import os
import subprocess
import platform
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QFileDialog, QLabel
from PyQt5.QtCore import Qt


def apply_shading(image, alpha=1.2, beta=30):
    shaded_image = cv2.convertScaleAbs(image, alpha=alpha, beta=beta)
    return shaded_image


def add_frame_number(image, frame_number):
    """
    이미지에 프레임 번호를 추가하는 함수.
    """
    font = cv2.FONT_HERSHEY_SIMPLEX
    text = f"Frame: {frame_number}"
    font_scale = 1
    color = (0, 255, 0)
    thickness = 2
    position = (50, 50)

    frame_with_text = cv2.putText(image.copy(), text, position, font, font_scale, color, thickness, cv2.LINE_AA)
    return frame_with_text


def create_smooth_emulsion_transition(img1, img2, transition_frames):
    """
    두 이미지 간의 부드러운 전환을 생성하는 함수.
    """
    transition_images = []
    for alpha in np.linspace(0, 1, transition_frames):
        blended = cv2.addWeighted(img1, 1 - alpha, img2, alpha, 0)
        blurred = cv2.GaussianBlur(blended, (5, 5), 0)

        # 노이즈 추가
        noise = np.random.normal(0, 10, blurred.shape).astype(np.uint8)
        emulsion_effect = cv2.add(blurred, noise)

        transition_images.append(np.clip(emulsion_effect, 0, 255).astype(np.uint8))
    return transition_images


class SatelliteMapVideoApp(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Satellite Map Video Generator")
        self.setGeometry(100, 100, 800, 600)

        layout = QVBoxLayout()
        self.label = QLabel("Select images and create a video", self)
        self.label.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.label)

        self.select_button = QPushButton("Select Images", self)
        self.select_button.clicked.connect(self.select_images)
        layout.addWidget(self.select_button)

        self.create_button = QPushButton("Create Video", self)
        self.create_button.clicked.connect(self.create_video)
        layout.addWidget(self.create_button)

        self.frame_label = QLabel("Current Frame: 0", self)
        self.frame_label.setAlignment(Qt.AlignCenter)
        layout.addWidget(self.frame_label)

        self.setLayout(layout)
        self.images = []

    def select_images(self):
        files, _ = QFileDialog.getOpenFileNames(self, "Select Image Files", "", "Images (*.png *.jpg *.jpeg *.bmp)")
        if files:
            self.images = files
            self.label.setText(f"{len(files)} images selected.")

    def create_video(self):
        if not self.images:
            self.label.setText("No images selected.")
            return

        video_path, _ = QFileDialog.getSaveFileName(self, "Save Video As", "", "Video Files (*.mp4)")
        if not video_path:
            self.label.setText("Video creation canceled.")
            return

        self.label.setText("Creating video...")
        self.generate_video(self.images, video_path, 640, 480, total_duration=10)
        self.label.setText(f"Video saved to {video_path}")
        self.play_video(video_path)

    def generate_video(self, image_files, video_path, width, height, total_duration=10):
        fps = 30
        total_frames = int(total_duration * fps)
        num_images = len(image_files)
        frames_per_image = total_frames // num_images
        transition_frames = frames_per_image // 2

        fourcc = cv2.VideoWriter_fourcc(*'mp4v')
        video = cv2.VideoWriter(video_path, fourcc, fps, (width, height))
        total_written_frames = 0

        for i in range(num_images - 1):
            img1 = cv2.imread(image_files[i])
            img2 = cv2.imread(image_files[i + 1])

            if img1 is None or img2 is None:
                print(f"Warning: Could not load image {image_files[i]} or {image_files[i + 1]}. Skipping.")
                continue

            img1 = cv2.resize(img1, (width, height))
            img2 = cv2.resize(img2, (width, height))

            shaded_img1 = apply_shading(img1)
            shaded_img2 = apply_shading(img2)

            for _ in range(frames_per_image - transition_frames):
                frame_with_text = add_frame_number(shaded_img1, total_written_frames)
                video.write(frame_with_text)
                total_written_frames += 1
                self.update_frame_label(total_written_frames)

            transition_images = create_smooth_emulsion_transition(shaded_img1, shaded_img2, transition_frames)
            for transition_frame in transition_images:
                frame_with_text = add_frame_number(transition_frame, total_written_frames)
                video.write(frame_with_text)
                total_written_frames += 1
                self.update_frame_label(total_written_frames)

        last_image = cv2.imread(image_files[-1])
        if last_image is not None:
            last_image = cv2.resize(last_image, (width, height))
            shaded_last_image = apply_shading(last_image)

            for _ in range(frames_per_image):
                frame_with_text = add_frame_number(shaded_last_image, total_written_frames)
                video.write(frame_with_text)
                total_written_frames += 1
                self.update_frame_label(total_written_frames)

        video.release()
        print(f"Video saved to {os.path.abspath(video_path)}")

    def update_frame_label(self, frame_number):
        self.frame_label.setText(f"Current Frame: {frame_number}")
        QApplication.processEvents()

    def play_video(self, video_path):
        try:
            if platform.system() == "Windows":
                os.startfile(video_path)
            elif platform.system() == "Darwin":
                subprocess.call(["open", video_path])
            else:
                subprocess.call(["xdg-open", video_path])
        except Exception as e:
            print(f"Failed to play the video: {e}")


def main():
    app = QApplication(sys.argv)
    window = SatelliteMapVideoApp()
    window.show()
    sys.exit(app.exec_())


if __name__ == "__main__":
    main()