파이썬으로 카메라 애플리케이션을 개발하는 것은 매력적인 프로젝트와 파이썬 프로그래밍의 다양한 측면을 모두 탐구하고자 하는 개인에게 기회를 제공합니다. 이 과정에는 GUI 디자인, 이미지 및 비디오 조작, 멀티 스레딩 기능을 포함한 Python 프로그래밍의 여러 기능을 통합하는 작업이 수반됩니다.

여기에 제시된 것과 같은 실제적인 장애물을 극복하면 모든 소프트웨어 개발 작업에서 성공하는 데 필수적인 자질인 문제 해결 능력을 향상시킬 수 있습니다.

환경 설정하기

동일한 패키지의 여러 버전이 설치되어 있을 때 발생할 수 있는 잠재적인 충돌을 방지하려면 프로젝트를 위한 격리된 환경을 설정하는 것이 중요합니다. 새 가상 환경을 생성하려면 다음 단계를 따르세요: 1. 터미널 또는 명령 프롬프트를 엽니다. 2. 가상 환경을 만들려는 디렉터리로 이동합니다. 3. 터미널 또는 명령 프롬프트에서 다음 명령을 실행합니다: “` 파이썬 -m venv 내_환경_이름 “` “내\_환경\_이름”을 가상 환경에 대해 선택한 이름으로 바꿉니다. 4. 가상 환경이 성공적으로 생성되면 운영 체제에 따라 적절한 명령을 사용하여 가상 환경을 활성화합니다: * Windows: ‘.\내_환경_이름\스크립트\활성화’ * macOS

 pip install opencv-python pillow 

이 명령어를 실행하면 가상 작업 공간의 범위 내에 OpenCV 라이브러리와 Python 이미징 라이브러리가 모두 설치됩니다. OpenCV를 활용하면 컴퓨터 비전 기능 제공이 용이해지고, PIL은 이미지 조작 작업을 수행하는 데 사용됩니다.

이 프로젝트의 전체 코드 본문은 GitHub 저장소를 통해 액세스할 수 있습니다.

필수 라이브러리 가져오기

앞서 언급한 라이브러리를 설치한 후 다른 필수 모듈과 함께 Python의 기본 제공 라이브러리 리소스의 일부로 가져올 수 있습니다.

 import tkinter as tk
import cv2
from PIL import Image, ImageTk
import os
import threading
import time

Tkinter를 활용하여 소프트웨어의 그래픽 사용자 인터페이스를 개발하는 동시에 OS, 스레딩 및 시간 모듈을 사용하여 각각의 기능을 용이하게 할 수 있습니다. 코드의 특정 부분을 별도의 스레드로 분리하여 동시에 실행할 수 있습니다.

갤러리 디렉토리 생성 및 전역 변수 및 플래그 정의

비디오 캡처 또는 녹화 활동을 시작하기 전에 디렉토리를 설정하여 캡처한 이미지와 녹화된 비디오를 모두 저장할 수 있는 지정된 폴더가 있는지 확인합니다.

 if not os.path.exists("gallery"):
    os.makedirs("gallery")

“앨범 내에 사진과 동영상의 작은 버전을 저장하는 ‘image\_thumbnails’ 및 ‘video\_thumbnails’라는 두 개의 새 변수를 생성합니다.

 # Initialize image_thumbnails as a global list
image_thumbnails = []
video_thumbnails = [] # New list for video thumbnails
update_camera = True

update\_camera 플래그의 기능은 카메라 피드가 업데이트되는 빈도를 조절하는 것입니다.

카메라 피드에서 이미지 캡처

OpenCV를 활용하여 카메라의 입력 스트림에서 이미지를 캡처합니다. 그런 다음 캡처한 프레임의 스냅샷을 추출하여 지정된 “갤러리” 디렉토리에 저장하고 “show\_image” 모듈을 사용하여 시각적 표현을 표시합니다.

 def capture_image():
    ret, frame = cap.read()

    if ret:
        # Generate a unique filename with a timestamp
        timestamp = time.strftime("%Y%m%d%H%M%S")
        image_path = os.path.join("gallery", f"captured_image_{timestamp}.jpg")
        cv2.imwrite(image_path, frame)
        show_image(image_path)

동영상 녹화 시작 및 중지

동영상을 전시하기 위해서는 먼저 동영상을 제작하는 방법을 설정해야 합니다. 이를 위해 사용자가 동영상 촬영을 원할 때 동영상 촬영이 시작되는 기능을 개발해야 합니다. 또한, 해당 기능은 동시 녹화를 방지하기 위해 녹화 버튼을 비활성화하고 녹화 중지 버튼을 활성화합니다. 이는 녹화 프로세스가 시작되었음을 나타냅니다.

 def start_recording():
    global video_writer, recording_start_time, recording_stopped, update_camera

    if not video_writer:
        timestamp = time.strftime("%Y%m%d%H%M%S")
        video_path = os.path.join("gallery", f"recorded_video_{timestamp}.mp4")

        # Use mp4v codec (or try other codecs)
        fourcc = cv2.VideoWriter_fourcc(*'mp4v')

        # Adjust frame rate and resolution if needed
        video_writer = cv2.VideoWriter(video_path, fourcc, 20.0,
                                       (640, 480))

        recording_start_time = time.time()
        recording_stopped = False
        record_button.config(state=tk.DISABLED)
        stop_button.config(state=tk.NORMAL)

        # Start a separate thread for recording and time-lapse display
        recording_thread = threading.Thread(target=record_and_display)
        recording_thread.start()

아래 코드는 UnityEngine 네임스페이스의 `Timer` 클래스를 사용하여 타이머를 생성하여 10초 후에 비디오 녹화를 중지합니다. 타이머는 프레임 렌더러의 주기인 1/60초마다 실행되도록 설정되어 있으므로 실제로는 10프레임 동안 카운트다운을 한 후 녹화 프로세스를 중지합니다. 비디오 녹화를 중지하고 비디오 라이터를 해제하는 기능을 “StopRecording”이라고 부를 수 있습니다.

 def stop_recording():
    global video_writer, recording_stopped

    if video_writer:
        video_writer.release()
        recording_stopped = True
        record_button.config(state=tk.NORMAL)
        stop_button.config(state=tk.DISABLED)

앞서 언급한 기능에는 사용자 인터페이스 업데이트가 수반되는데, 녹화 버튼은 활성화되고 녹화 중지 버튼은 비활성화된 상태로 유지됩니다. 이는 녹화 프로세스가 중단되었음을 의미합니다.

이 글도 확인해 보세요:  슬랙에서 나만의 사용자 지정 슬래시 명령 만들기

비디오 녹화 및 표시

당면 과제에는 통합 카메라에서 실시간으로 비디오 프레임을 원활하게 캡처하고, 이러한 프레임을 처리하며, “녹화 중지” 버튼이 활성화될 때까지 그래픽 사용자 인터페이스를 가장 최근 프레임으로 동적으로 업데이트하는 기능 구성 요소를 개발하는 것이 포함됩니다. 이 작업은 수동 개입으로 중단하지 않는 한 영구적으로 지속됩니다.

 def record_and_display():
    global recording_stopped, update_camera

    while video_writer and not recording_stopped:
        ret, frame = cap.read()

        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

            # Calculate elapsed time and add it to the frame
            elapsed_time = time.time() - recording_start_time
            timestamp = f"Time Elapsed: {int(elapsed_time)}s"

            cv2.putText(frame, timestamp, (10, 30), cv2.FONT_HERSHEY_SIMPLEX,
                        0.5, (255, 255, 255), 2)

            img = Image.fromarray(frame)
            photo = ImageTk.PhotoImage(image=img)
            camera_feed.config(image=photo)
            camera_feed.image = photo

            video_writer.write(frame)
            time.sleep(0.05)

    camera_feed.after(10, update_camera_feed)

알고리즘의 기능에는 녹화 시작 이후 발생한 기간의 계산도 수반되며, 이는 이후 비디오 프레임의 시각적 컨텍스트 내에 표시됩니다.

캡처된 이미지 및 비디오 표시

사진을 전시하고 비디오 영상을 재생하기 위해서는 적절한 프레젠테이션 방법이 필요합니다.

사용자 인터페이스에 시각적 콘텐츠를 표시하기 위해서는 소스에서 이미지를 검색하여 카메라 뷰 내에 표시하기에 적합한 형태로 변환하고 그에 따라 시각적 표현을 업데이트하는 기능을 구현해야 합니다.이 작업을 수행하기 위해 파이썬 이미징 라이브러리(PIL)를 사용하여 이미지 파일을 열고 처리한 다음 tkinter에서 제공하는 그래픽 사용자 인터페이스와 호환되는 형식으로 변환합니다. 마지막으로 새로 처리된 이미지로 화면의 카메라 피드 위젯을 업데이트합니다.

 def show_image(image_path):
    image = Image.open(image_path)
    photo = ImageTk.PhotoImage(image=image)
    camera_feed.config(image=photo)
    camera_feed.image = photo

녹화된 영상을 전시하기 위해 최종 사용자가 열람할 수 있도록 비디오 재생 인터페이스를 설정하는 기능을 개발할 수 있습니다. 이 기능은 영상이 재생되는 동안 카메라 스트림의 추가 업데이트를 일시적으로 중단합니다.

 def play_video(video_path):
    def close_video_player():
        video_player.destroy()
        global update_camera
        update_camera = True

    global update_camera
    update_camera = False

    video_player = tk.Toplevel(root)
    video_player.title("Video Player")

    video_cap = cv2.VideoCapture(video_path)

    def update_video_frame():
        ret, frame = video_cap.read()

        if ret:
            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            img = Image.fromarray(frame)
            photo = ImageTk.PhotoImage(image=img)
            video_label.config(image=photo)
            video_label.image = photo

            # Get the actual frame rate of the video
            frame_rate = video_cap.get(cv2.CAP_PROP_FPS)
            delay = int(1000 / frame_rate)

            video_player.after(delay, update_video_frame)
        else:
            video_player.destroy()

    video_label = tk.Label(video_player)
    video_label.pack()

    update_video_frame()

    video_player.protocol("WM_DELETE_WINDOW", close_video_player)

비디오 피드 전송을 일시적으로 중단하는 것은 원활하고 즐거운 시각적 프레젠테이션을 유지하는 데 매우 중요합니다.

이 글도 확인해 보세요:  JavaScript를 사용하여 이미지에 X 및 Y 좌표를 오버레이하는 방법

동영상 썸네일 생성 및 갤러리 열기

사용자가 다른 동영상 중에서 특정 동영상을 쉽게 인식하고 선택할 수 있도록 썸네일이라고 하는 멀티미디어 파일의 압축된 시각적 표현을 생성하는 알고리즘 프로세스를 개발합니다.

 def create_video_thumbnail(video_path):
    video_cap = cv2.VideoCapture(video_path)
    ret, frame = video_cap.read()

    if ret:
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        thumbnail = Image.fromarray(frame).resize((100, 100))
        thumbnail_photo = ImageTk.PhotoImage(image=thumbnail)
        return thumbnail_photo, os.path.basename(video_path)

    return None, None

물론입니다! 다음은 React와 JavaScript를 사용하여 사용자가 갤러리 창에서 해당 썸네일을 클릭하면 동영상을 재생하는 함수를 구현한 예제입니다: ”’자바스크립트 ‘에서 React를 가져옵니다; function VideoPlayer({ videoId }) { const [currentVideo, setCurrentVideo] = useState(null); // 선택한 동영상을 재생하는 함수 const handlePlayButtonClick = (videoId) => { if (!currentVideo || currentVideo.id !== videoId) { // ID를 기준으로 선택한 동영상 찾기 const videos = document.querySelectorAll(‘.video-container’); for (let i = 0; i < videos.length; i++) { const video = videos[i]; if (

 def play_video_from_thumbnail(video_path):
    play_video(video_path)

이 애플리케이션은 내장 카메라로 고화질 이미지와 동영상을 캡처할 수 있어 사용자가 생생한 디테일로 추억을 보존할 수 있습니다. 이 기능을 용이하게하기 위해 사용자가 캡처 한 미디어 파일에 쉽게 액세스하고 볼 수있는 새 창을 만드는 방법을 구현할 것입니다.

 def open_gallery():
    global update_camera
    update_camera = False

    gallery_window = tk.Toplevel(root)
    gallery_window.title("Gallery")

    def back_to_camera():
        gallery_window.destroy()
        global update_camera

        # Resume updating the camera feed
        update_camera = True

    back_button = tk.Button(gallery_window, text="Back to Camera",
                            command=back_to_camera)

    back_button.pack()

    gallery_dir = "gallery"
    image_files = [f for f in os.listdir(gallery_dir) if f.endswith(".jpg")]
    video_files = [f for f in os.listdir(gallery_dir) if f.endswith(".mp4")]

    # Clear the existing image_thumbnails and video_thumbnails lists
    del image_thumbnails[:]
    del video_thumbnails[:]

    for image_file in image_files:
        image_path = os.path.join(gallery_dir, image_file)
        thumbnail = Image.open(image_path).resize((100, 100))
        thumbnail_photo = ImageTk.PhotoImage(image=thumbnail)
        image_name = os.path.basename(image_file)

        def show_image_in_gallery(img_path, img_name):
            image_window = tk.Toplevel(gallery_window)
            image_window.title("Image")
            img = Image.open(img_path)
            img_photo = ImageTk.PhotoImage(img)
            img_label = tk.Label(image_window, image=img_photo)
            img_label.image = img_photo
            img_label.pack()
            img_label_name = tk.Label(image_window, text=img_name)
            img_label_name.pack()

        thumbnail_label = tk.Label(gallery_window, image=thumbnail_photo)
        thumbnail_label.image = thumbnail_photo

        thumbnail_label.bind("<Button-1>", lambda event,
                                                 img_path=image_path,
                                                 img_name=image_name:
        show_image_in_gallery(img_path, img_name))

        thumbnail_label.pack()
        image_thumbnails.append(thumbnail_photo)

        # Display the image filename below the thumbnail
        image_name_label = tk.Label(gallery_window, text=image_name)
        image_name_label.pack()

    for video_file in video_files:
        video_path = os.path.join(gallery_dir, video_file)

        # Create a video thumbnail and get the filename
        thumbnail_photo, video_name = create_video_thumbnail(video_path)

        if thumbnail_photo:
            video_thumbnail_button = tk.Button(
                gallery_window,
                image=thumbnail_photo,
                command=lambda path=video_path: play_video_from_thumbnail(path)
            )

            video_thumbnail_button.pack()

            # Store the video thumbnail PhotoImage objects
            video_thumbnails.append(thumbnail_photo)

            # Display the video filename below the thumbnail
            video_name_label = tk.Label(gallery_window, text=video_name)
            video_name_label.pack()

썸네일 표현 생성은 정적인 시각 이미지뿐만 아니라 동영상과 같이 동적으로 움직이는 미디어에도 적용되는 기능입니다. 따라서 사용자는 썸네일을 클릭하여 이러한 썸네일을 활성화할 수 있으며, 그러면 원본 콘텐츠 전체가 확대되어 표시됩니다.

애플리케이션의 기본 사용자 인터페이스 만들기

다음은 Python에서 제목 표시줄이 있는 기본 Tkinter GUI를 만드는 방법에 대한 예제입니다: ”’python import tkinter as tk root = tk.Tk() # GUI의 루트 창을 만듭니다. title_label = tk.Label(root, text=”내 Tkinter 애플리케이션”, font=(“Arial”, 16)) # 제목을 표시할 라벨 위젯을 생성합니다. title_label.pack() # 루트 창에 라벨 위젯을 패킹합니다. root.mainloop() # 사용자 상호작용을 처리하기 위해 이벤트 루프를 시작합니다. “` 이 코드는 GUI의 메인 창으로 사용할 `tk.Tk()`의 새 인스턴스를 생성합니다. 그런 다음 다양한 Tkinter 메서드를 사용하여 레이블이나 버튼과 같은 위젯을 추가할 수 있습니다.

 root = tk.Tk()
root.title("Camera Application")

“현재 저는 제 인종적 배경을 가진 사람들 사이에서 유난히 뛰어난 자존감과 자신감을 느끼고 있습니다.” 먼저 감정 분석 모델에 필요한 매개변수를 정의하고 적절한 데이터 구조를 설정해야 합니다.

 video_writer = None
recording_start_time = 0 # Initialize recording start time
recording_stopped = False # Initialize recording_stopped flag

모욕적이거나 부적절한 언어 사용은 즉시 채팅 세션이 종료되고 향후 시스템 사용이 금지될 수 있으므로 자제해 주시기 바랍니다. 또한 사기 또는 사기 행위 시도는 관계 당국에 신고됩니다. 플랫폼의 AI는 윤리적, 도덕적 기준을 준수하면서 유용한 답변을 제공하도록 설계되었습니다. 대화 내내 정중한 어조를 유지하는 것이 중요합니다. 협조해 주셔서 감사합니다.

 capture_button = tk.Button(root, text="Capture", command=capture_image)
record_button = tk.Button(root, text="Record", command=start_recording)
stop_button = tk.Button(root, text="Stop Recording", command=stop_recording)
gallery_button = tk.Button(root, text="Gallery", command=open_gallery)
quit_button = tk.Button(root, text="Quit", command=root.quit)

그리드 레이아웃 관리자를 활용하면 애플리케이션의 기본 창에 버튼을 배치할 때 시각적 일관성과 사용 편의성을 모두 보장하는 효과적인 방법입니다.

 capture_button.grid(row=0, column=0, padx=10, pady=10)
record_button.grid(row=0, column=1, padx=10, pady=10)
stop_button.grid(row=0, column=2, padx=10, pady=10)
gallery_button.grid(row=0, column=3, padx=10, pady=10)
quit_button.grid(row=0, column=4, padx=10, pady=10)

카메라에서 실시간 스트림을 표시하려면 “위젯”이라는 사용자 지정 그래픽 사용자 인터페이스 요소를 구현하는 것이 좋습니다. 이 기능을 활성화하려면 먼저 카메라 장치와 초기 연결을 설정하고 출력을 표시하는 데 필요한 설정을 구성해야 합니다. 이 과정에는 사용자가 카메라로 캡처한 실시간 영상을 화면에서 시각화할 수 있도록 하는 프로그래밍 코드가 포함됩니다.

 camera_feed = tk.Label(root)
camera_feed.grid(row=1, column=0, columnspan=5)
cap = cv2.VideoCapture(0)

물론입니다!다음은 OpenCV와 Python을 사용하여 이 기능을 구현하는 방법의 예입니다: ”’python import cv2 에서 가져 오기 * import 스레딩 def update_camera(캔버스): # 웹캠에 액세스하기 위해 VideoCapture 객체를 생성합니다. cap = cv2.VideoCapture(0) while True: ret, frame = cap.read() ret가 아니라면 break # 텍스트와 더 잘 대비되도록 프레임을 회색조로 변환합니다. 회색 = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 캔버스에 프레임을 표시합니다. canvas.createPermanent(100, 1

 def update_camera_feed():
    if update_camera:
        if not video_writer:
            ret, frame = cap.read()

            if ret:
                frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                img = Image.fromarray(frame)
                photo = ImageTk.PhotoImage(image=img)
                camera_feed.config(image=photo)
                camera_feed.image = photo

    root.after(10, update_camera_feed)

update_camera_feed()

결국 Tkinter GUI의 기본 이벤트 루프를 시작합니다.

 root.mainloop()

앞서 언급한 반복 프로세스는 사용자 관련 개입을 관리하고 처리하는 역할을 합니다.

이 글도 확인해 보세요:  Python을 사용하여 할 일 목록 프로그램 만들기

앱 기능 테스트

프레젠테이션 매체는 애플리케이션 내에서 발견되는 다양한 기능을 이 시각적 표현으로 보여줍니다.

브라우저가 동영상 태그를 지원하지 않습니다.

OpenCV로 파이썬 기술 연마하기

실제로 OpenCV는 다양한 라이브러리와의 광범위한 호환성으로 인해 컴퓨터 비전 분야에서 높은 평가를 받고 있으며, 이를 통해 사용자는 다양한 혁신적 시도를 할 수 있습니다. 또한 Python 언어와의 완벽한 통합으로 프로그래밍 능력을 연마하고자 하는 사람들에게 실무 경험과 기술 향상을 촉진합니다.

By 최은지

윈도우(Windows)와 웹 서비스에 대한 전문 지식을 갖춘 노련한 UX 디자이너인 최은지님은 효율적이고 매력적인 디지털 경험을 개발하는 데 탁월한 능력을 발휘합니다. 사용자의 입장에서 생각하며 누구나 쉽게 접근하고 즐길 수 있는 콘텐츠를 개발하는 데 주력하고 있습니다. 사용자 경험을 향상시키기 위해 연구를 거듭하는 은지님은 All Things N 팀의 핵심 구성원으로 활약하고 있습니다.