360度読み込みをPythonで
天球画像を色々いじる
import tkinter as tkfrom tkinter
import filedialogfrom PIL
import Image, ImageTk, ImageChops, ImageOps
import time
class PanoramaViewer:
def init(self, root):
self.root = root
self.root.title("Panorama Viewer")
self.horizontal_angle = 0
self.vertical_angle = 0
self.view_distance = 0
self.play_speed = 1
self.last_update_time = time.time()
self.image_path = ""
self.original_image = None
self.processed_image = None
self.tk_image = None
self.canvas_width = 800
self.canvas = tk.Canvas(root, width=self.canvas_width)
self.canvas.pack()
self.horizontal_scrollbar = tk.Scale(root, from_=0, to=360, orient=tk.HORIZONTAL, label="Horizontal Angle", command=self.update_view_angle)
self.horizontal_scrollbar.pack(fill=tk.X)
self.vertical_scrollbar = tk.Scale(root, from_=-90, to=90, orient=tk.HORIZONTAL, label="Vertical Angle", command=self.update_vertical_angle)
self.vertical_scrollbar.pack(fill=tk.X)
self.distance_scrollbar = tk.Scale(root, from_=-100, to=100, orient=tk.HORIZONTAL, label="View Distance", command=self.update_distance)
self.distance_scrollbar.pack(fill=tk.X)
open_button = tk.Button(root, text="Open", command=self.open_image)
open_button.pack(side=tk.LEFT)
save_button = tk.Button(root, text="Save As", command=self.save_image_as)
save_button.pack(side=tk.LEFT)
play_button = tk.Button(root, text="Play", command=self.play)
play_button.pack(side=tk.LEFT)
pause_button = tk.Button(root, text="Pause", command=self.pause)
pause_button.pack(side=tk.LEFT)
fast_forward_button = tk.Button(root, text="Fast Forward", command=self.fast_forward)
fast_forward_button.pack(side=tk.LEFT)
rewind_button = tk.Button(root, text="Rewind", command=self.rewind)
rewind_button.pack(side=tk.LEFT)
self.image_type = tk.StringVar()
self.image_type.set("360")
panorama_button = tk.Radiobutton(root, text="360-Degree Image", variable=self.image_type, value="360", command=self.select_image_type)
panorama_button.pack(side=tk.LEFT)
plane_button = tk.Radiobutton(root, text="Flat Image", variable=self.image_type, value="flat", command=self.select_image_type)
plane_button.pack(side=tk.LEFT)
self.display_mode = tk.StringVar()
self.display_mode.set("original")
original_button = tk.Radiobutton(root, text="Original", variable=self.display_mode, value="original", command=self.select_display_mode)
original_button.pack(side=tk.LEFT)
grayscale_button = tk.Radiobutton(root, text="Grayscale", variable=self.display_mode, value="grayscale", command=self.select_display_mode)
grayscale_button.pack(side=tk.LEFT)
color_extraction_button = tk.Radiobutton(root, text="Color Extraction", variable=self.display_mode, value="color_extraction", command=self.select_display_mode)
color_extraction_button.pack(side=tk.LEFT)
self.lower_red_slider = tk.Scale(root, from_=0, to=255, orient=tk.HORIZONTAL, label="Lower Red", command=self.update_color_extraction)
self.lower_red_slider.pack(side=tk.LEFT)
self.upper_red_slider = tk.Scale(root, from_=0, to=255, orient=tk.HORIZONTAL, label="Upper Red", command=self.update_color_extraction)
self.upper_red_slider.pack(side=tk.LEFT)
self.lower_green_slider = tk.Scale(root, from_=0, to=255, orient=tk.HORIZONTAL, label="Lower Green", command=self.update_color_extraction)
self.lower_green_slider.pack(side=tk.LEFT)
self.upper_green_slider = tk.Scale(root, from_=0, to=255, orient=tk.HORIZONTAL, label="Upper Green", command=self.update_color_extraction)
self.upper_green_slider.pack(side=tk.LEFT)
self.lower_blue_slider = tk.Scale(root, from_=0, to=255, orient=tk.HORIZONTAL, label="Lower Blue", command=self.update_color_extraction)
self.lower_blue_slider.pack(side=tk.LEFT)
self.upper_blue_slider = tk.Scale(root, from_=0, to=255, orient=tk.HORIZONTAL, label="Upper Blue", command=self.update_color_extraction)
self.upper_blue_slider.pack(side=tk.LEFT)
self.playing = False
def open_image(self):
file_path = filedialog.askopenfilename(title="Open Image", filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif")])
if file_path:
self.image_path = file_path
self.original_image = Image.open(file_path)
self.processed_image = self.original_image.copy()
self.tk_image = ImageTk.PhotoImage(self.original_image)
self.display_image()
def save_image_as(self):
if self.original_image:
file_path = filedialog.asksaveasfilename(title="Save Image As", defaultextension=".png", filetypes=[("PNG files", "*.png"), ("JPEG files", "*.jpg;*.jpeg")])
if file_path:
self.processed_image.save(file_path)
def display_image(self):
if self.image_type.get() == "360":
rotated_image = self.original_image.rotate(self.horizontal_angle)
shifted_image = rotated_image.rotate(self.vertical_angle, resample=Image.BICUBIC, center=(rotated_image.width // 2, rotated_image.height // 2))
translated_image = ImageChops.offset(shifted_image, self.view_distance, 0)
else:
translated_image = self.original_image
self.processed_image = self.apply_display_mode(translated_image)
self.tk_image = ImageTk.PhotoImage(self.processed_image)
self.canvas.config(width=self.canvas_width, height=self.calculate_canvas_height())
self.canvas.create_image(0, 0, anchor=tk.NW, image=self.tk_image)
def apply_display_mode(self, image):
mode = self.display_mode.get()
if mode == "grayscale":
return ImageOps.grayscale(image)
elif mode == "color_extraction":
return self.extract_color(image)
else:
return image
def extract_color(self, image):
lower_red = self.lower_red_slider.get()
upper_red = self.upper_red_slider.get()
lower_green = self.lower_green_slider.get()
upper_green = self.upper_green_slider.get()
lower_blue = self.lower_blue_slider.get()
upper_blue = self.upper_blue_slider.get()
color_mask = Image.new("RGB", image.size, color=(255, 255, 255))
color_mask.paste(image, mask=image)
data = color_mask.getdata()
new_data = []
for item in data:
red, green, blue = item
if lower_red <= red <= upper_red and lower_green <= green <= upper_green and lower_blue <= blue <= upper_blue:
new_data.append(item)
else:
grayscale_value = int(0.299 * red + 0.587 * green + 0.114 * blue)
new_data.append((grayscale_value, grayscale_value, grayscale_value))
color_mask.putdata(new_data)
return ImageChops.multiply(image, color_mask)
def calculate_canvas_height(self):
if self.image_type.get() == "360":
aspect_ratio = self.original_image.width / self.original_image.height
return int(self.canvas_width / aspect_ratio)
else:
return self.original_image.height
def update_view_angle(self, angle):
self.horizontal_angle = float(angle)
self.display_image()
def update_vertical_angle(self, angle):
self.vertical_angle = float(angle)
self.display_image()
def update_distance(self, distance):
self.view_distance = int(distance)
self.display_image()
def play(self):
self.playing = True
self.play_continuous()
def play_continuous(self):
if self.playing:
current_time = time.time()
elapsed_time = current_time - self.last_update_time
update_interval = 1 / 30 # 30フレーム/秒(適宜調整)
if elapsed_time >= update_interval:
# 指定された再生速度で角度を更新
self.horizontal_angle += 1 * self.play_speed # 仮の角度更新(適宜調整)
self.display_image()
self.last_update_time = current_time
self.root.after(10, self.play_continuous)
def pause(self):
self.playing = False
def fast_forward(self):
self.play_speed *= 2 # 2倍速
def rewind(self):
self.play_speed /= 2 # 2分の1倍速
if __name__ == "__main__":
root = tk.Tk()
viewer = PanoramaViewer(root)
root.mainloop()
この記事が気に入ったらサポートをしてみませんか?