Cách xây dựng ứng dụng máy ảnh bằng Python
Cho dù bạn muốn làm việc trong một dự án Python hấp dẫn hay khám phá các khía cạnh khác nhau của lập trình Python, thì việc xây dựng một ứng dụng máy ảnh đều phục vụ mục đích này. Nó liên quan đến việc kết hợp các khía cạnh khác nhau của lập trình Python, chẳng hạn như phát triển giao diện đồ họa người dùng (GUI), xử lý hình ảnh và video cũng như đa luồng.
Ngoài ra, việc giải quyết các vấn đề trong thế giới thực như vấn đề này còn giúp nâng cao khả năng tư duy phản biện và giải quyết vấn đề của một người. Những khả năng như vậy có ý nghĩa to lớn trong một loạt các dự án phát triển phần mềm.
Thiết lập môi trường của bạn
Để bắt đầu, hãy thiết lập một môi trường ảo mới giúp tách biệt dự án của bạn khỏi những khác biệt tiềm ẩn phát sinh do các phiên bản gói xung đột. Sau đó, thực hiện lệnh sau trong terminal của bạn:
pip install opencv-python pillow
Lệnh hiện tại sẽ tạo điều kiện thuận lợi cho việc cài đặt cả thư viện OpenCV, thư viện cung cấp một bộ công cụ toàn diện để thực hiện các tác vụ thị giác máy tính khác nhau, cũng như Thư viện hình ảnh Python (PIL), một mô-đun thiết yếu cho phép người dùng thực hiện các hoạt động xử lý hình ảnh mở rộng. Do đó, bạn có thể sử dụng OpenCV cho mảng chức năng thị giác máy tính mạnh mẽ của nó trong khi sử dụng PIL để xử lý hình ảnh phức tạp trong môi trường ảo của bạn.
Mã nguồn hoàn chỉnh cho dự án này có thể được truy cập thông qua kho GitHub, kho lưu trữ này đóng vai trò là không gian lưu trữ kỹ thuật số để các nhà phát triển chia sẻ và cộng tác trong công việc của họ.
Nhập các thư viện cần thiết
Sau khi cài đặt các thư viện này, chúng có thể được nhập cùng với các mô-đun bổ sung lấy từ thư viện nền tảng của Python, phù hợp với các yêu cầu cụ thể của một ứng dụng hoặc tác vụ nhất định.
import tkinter as tk
import cv2
from PIL import Image, ImageTk
import os
import threading
import time
Bằng cách sử dụng thư viện Tkinter, tôi sẽ phát triển giao diện người dùng đồ họa (GUI) hấp dẫn trực quan giúp nâng cao trải nghiệm người dùng tổng thể cho ứng dụng của tôi. Ngoài ra, việc tận dụng các mô-đun hệ điều hành, phân luồng và thời gian sẽ cung cấp các chức năng thiết yếu để cải thiện hiệu suất hệ thống. Thông qua việc triển khai đồng thời bằng cách tách các phần nhất định của mã thành các luồng riêng biệt, tôi mong muốn tối ưu hóa hiệu quả thực thi và hợp lý hóa các hoạt động.
Tạo thư mục thư viện và xác định các biến và cờ toàn cục
Quá trình này bao gồm việc thiết lập một thư mục được chỉ định để lưu trữ cả ảnh thu được và đoạn video đã ghi, từ đó đảm bảo rằng có sẵn không gian lưu trữ cần thiết trước khi chụp hoặc ghi bất kỳ nội dung hình ảnh nào.
if not os.path.exists("gallery"):
os.makedirs("gallery")
Để tạo các biến lưu trữ hình thu nhỏ của ảnh và video trong album ảnh, trước tiên chúng ta cần thiết lập hai cấu trúc dữ liệu mới gọi là “image\_thumbnails” và “video\_thumbnails”.
# Initialize image_thumbnails as a global list
image_thumbnails = []
video_thumbnails = [] # New list for video thumbnails
update_camera = True
Cờ “cập nhật\_máy ảnh” dùng để điều chỉnh tần suất cập nhật cho nguồn cấp dữ liệu máy ảnh.
Chụp ảnh từ nguồn cấp dữ liệu máy ảnh
pythondef process_frame(máy ảnh):# Chụp khung từ khung cấp dữ liệu của máy ảnh=cv2.imread(‘input_video.mp4’)# Lưu khung vào thư mục’gallery’với tên tệp duy nhất dựa trên số chỉ mục của nói=0while True:filename=f"{i}.jpg"if not os.path.exists(“gallery”):os.makedirs(“gallery”)retval=cv2.imwrite(filename, frame)i +=1# Hiển thị khung đã lưu bằng show\_image
cv2.imshow(cv2.namedWindow(“Thư viện”, cv2.WINDOW
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)
Bắt đầu và dừng quay video
Để hiển thị một video, bắt buộc phải thiết lập một phương pháp tạo ra nó. Do đó, chúng tôi sẽ phát triển một chức năng kích hoạt bắt đầu quay video theo hướng dẫn của người dùng để quay video. Ngoài ra, chức năng này sẽ tắt nút “Ghi” (để ngăn chặn việc ghi đồng thời), đồng thời kích hoạt nút “Dừng ghi”. Hành động này biểu thị rằng quá trình ghi đã được bắt đầu.
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()
Sau đó, phát triển chức năng chấm dứt quá trình quay video và giải phóng bộ mã hóa video.
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)
Chức năng nói trên thực hiện một thao tác bổ sung là cập nhật giao diện người dùng, bao gồm việc kích hoạt nút “Ghi” trong khi tắt nút “Dừng ghi”. Những hành động như vậy biểu thị rằng quá trình ghi đã chấm dứt.
Ghi và hiển thị video
Vui lòng phát triển một chức năng sẽ thu thập liền mạch các khung hình từ nguồn video, thực hiện các tác vụ xử lý cần thiết và hiển thị chúng trong giao diện người dùng đồ họa cho đến khi lệnh “Dừng ghi” được kích hoạt. Việc thực hiện quá trình này sẽ bị ngừng khi thực hiện hành động nói trên.
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)
Chức năng của chức năng này cũng bao gồm việc tính toán và hiển thị thời lượng tính bằng phút và giây đã diễn ra kể từ khi bắt đầu ghi trong mỗi khung hình video riêng lẻ.
Hiển thị hình ảnh và video đã chụp
Để thể hiện nội dung hình ảnh đã được thu thập thành công thông qua quá trình ghi hình và quay video, cần có một phương pháp trình bày thích hợp.
Để hiển thị nội dung trực quan trên giao diện người dùng, cần phát triển chức năng truy xuất tệp hình ảnh từ vị trí lưu trữ của nó, chuyển đổi nó thành định dạng tương thích với giao diện người dùng đồ họa của thư viện Python Tkinter và cập nhật chế độ xem được hiển thị với dữ liệu hình ảnh mới thu được. Quá trình này đòi hỏi phải sử dụng Thư viện hình ảnh Python (PIL) để truy cập và xử lý hình ảnh được lưu trữ, sau đó sử dụng các phương pháp thích hợp của khung GUI Tkinter để kết hợp hình ảnh đã chuyển đổi trong khu vực được chỉ định của màn hình xem trước máy ảnh.
def show_image(image_path):
image = Image.open(image_path)
photo = ImageTk.PhotoImage(image=image)
camera_feed.config(image=photo)
camera_feed.image = photo
Để hiển thị các video đã ghi, người ta phải triển khai chức năng kích hoạt giao diện phát lại video cho phép người xem quan sát các cảnh quay đã quay. Ngoài ra, quá trình này sẽ tạm dừng mọi cập nhật tiếp theo của luồng camera trong quá trình phát lại video.
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)
việc tạm dừng phổ biến các bản cập nhật luồng video góp phần mang lại nhận thức trực quan liền mạch.
Tạo hình thu nhỏ video và mở thư viện
Kết hợp tuyên bố sau một cách hùng hồn: Việc triển khai tính năng tạo hình thu nhỏ được coi là cần thiết vì nó cho phép người dùng nhanh chóng phân biệt và chọn nội dung video mong muốn của họ thông qua cách trình bày ngắn gọn, trực quan về nội dung đó.
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
Tạo một hàm JavaScript mới có tên là “playVideo”, hàm này sẽ được kích hoạt khi nhấp vào hình thu nhỏ của video trong cửa sổ thư viện. Chức năng này sẽ bắt đầu phát lại video đã chọn và hiển thị nó trong vùng chứa trình phát video.
def play_video_from_thumbnail(video_path):
play_video(video_path)
Chắc chắn, đây là ví dụ về cách bạn có thể triển khai chức năng này trong Python bằng thư viện OpenCV:pythonimport cv2import numpy as npfrom tkinter import Tk, Frame, Button, Label, Text, Scrollbar, VERTICAL)def save_captured_frames(window):# Xác định tham số chụp (có thể thay đổi để điều chỉnh độ phân giải, tốc độ khung hình, v.v.)cap=cv2.VideoCapture(0)fourcc=cv2.VideoWriter_fourcc(*“mp4v”)fps=int(cap.get(cv2.CAP_PROP_FPS))width=int( cap.get(cv2.CAP_PROP_FRAME_WIDTH))
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()
Việc tạo các biểu diễn hình thu nhỏ được mở rộng để chứa cả hình ảnh tĩnh cũng như hình ảnh chuyển động, từ đó cho phép người dùng truy cập nội dung gốc tương ứng của họ bằng cách nhấp vào các bản tóm tắt trực quan này và sau đó xem qua mô tả quy mô đầy đủ hoặc sàng lọc quá trình sản xuất phim.
Tạo giao diện người dùng chính cho ứng dụng của bạn
Bắt đầu quá trình bằng cách xây dựng giao diện tkinter chính, sau đó đặt cho nó một tên gọi khác biệt.
root = tk.Tk()
root.title("Camera Application")
Sau đó khởi tạo các biến cần thiết.
video_writer = None
recording_start_time = 0 # Initialize recording start time
recording_stopped = False # Initialize recording_stopped flag
Sau đó tạo các nút cho các hành động khác nhau.
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)
Sử dụng Trình quản lý bố cục dạng lưới là một chiến lược hiệu quả để sắp xếp các nút trong cửa sổ chính của ứng dụng, mang đến bản trình bày có tổ chức và hấp dẫn về mặt trực quan đồng thời đảm bảo khả năng truy cập và tương tác dễ dàng với từng nút riêng lẻ.
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)
Kết hợp chức năng hiển thị nguồn cấp dữ liệu camera trong giao diện người dùng đồ họa tương tác bằng cách thiết lập các kết nối cần thiết với các thành phần phần cứng của thiết bị, định cấu hình cài đặt phù hợp để hiển thị tối ưu và khởi tạo mô-đun hoặc thư viện tương ứng để hiển thị luồng video từ camera trên vùng được chỉ định của màn hình khi khởi động ứng dụng hoặc khi được người dùng nhắc nhập.
camera_feed = tk.Label(root)
camera_feed.grid(row=1, column=0, columnspan=5)
cap = cv2.VideoCapture(0)
Chắc chắn! Dưới đây là ví dụ về cách bạn có thể triển khai chức năng này bằng OpenCV và Python:pythonimport cv2from tkinter import *import threadingimport timedef update_máy ảnh_feed():# Khởi tạo thiết bị quay videocap=cv2.VideoCapture(0)while True:# Đọc khung hình từ video Streamret, frame=cap.read()if not ret:break# Hiển thị khung trên GUIlabel.config(image=frame)# Đợi nhấn phím để thoát looproot.update()event=root.wait_event()if sự kiện==‘q’:
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()
Cuối cùng, bắt đầu vòng lặp maintkinterevent.
root.mainloop()
Vòng lặp hiện tại đóng vai trò then chốt trong việc quản lý sự tương tác của người dùng và tạo điều kiện thuận lợi cho sự tương tác của họ với hệ thống.
Kiểm tra các tính năng của ứng dụng
Nội dung trình bày giới thiệu một loạt các chức năng mà ứng dụng thể hiện, nêu bật khả năng và tính linh hoạt trong hoạt động của nó.
Trình duyệt của bạn không hỗ trợ thẻ video.
Rèn luyện kỹ năng Python của bạn với OpenCV
OpenCV được công nhận rộng rãi như một công cụ ưu việt cho các ứng dụng thị giác máy tính, nhờ khả năng tương thích của nó với nhiều thư viện tạo điều kiện thuận lợi cho việc phát triển các dự án đổi mới khác nhau. Hơn nữa, người dùng có tùy chọn tận dụng khả năng của nó thông qua Python, đây là nền tảng tuyệt vời để mài giũa khả năng lập trình của một người.