Code: Alles auswählen
#! /usr/bin/env python
# -*- coding: utf-8
from __future__ import division
import tkinter as tk
import os
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
from itertools import cycle
import numpy as np
WIDTH = 640
HEIGHT = 480
VIDEO_CODEC = "XVID"
DEFAULT_CAM_ID = 0
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
INTERPOLATION_METHODS= {"NEAREST" : cv2.INTER_NEAREST,
"LINEAR" : cv2.INTER_LINEAR,
"AREA" : cv2.INTER_AREA,
"CUBIC" : cv2.INTER_CUBIC,
"LANCZOS4" : cv2.INTER_LANCZOS4}
def __init__(self, cam_id=DEFAULT_CAM_ID, number_of_imgs=10,
series_time_interval=1, image_path=".", video_path=".",
series_img_path=".", img_format=".tiff"):
self.cam = cv2.VideoCapture(cam_id)
if not self.cam.isOpened():
raise RuntimeError("can not open camera {0!r}".format(
cam_id))
self.img_format = img_format
self.last_frame = None
self.take_series = False
self.recording = False
self.number_of_imgs = number_of_imgs
self.series_counter = None
self.series_time_counter = None
self.series_time_interval = series_time_interval
self.image_path = image_path
self.video_path = video_path
self.series_img_path = series_img_path
self.series_dir = None
self.interpolation_methods = self.INTERPOLATION_METHODS
self.interpolation_methods_keys = cycle(
self.interpolation_methods.keys())
self.interpolation_method = self.interpolation_methods_keys.next()
self.cam_width = self.zoom_width = int(self.cam.get(self.PROPID_WIDTH))
self.cam_height = self.zoom_height = int(self.cam.get(self.PROPID_HEIGHT))
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return self.cam_width, self.cam_height
@property
def zoom_size(self):
return self.zoom_width, self.zoom_height
@property
def interpolation(self):
return self.interpolation_method
def get_image(self):
state, frame = self.cam.read()
if np.array_equal(self.last_frame, frame):
self.release()
state = False
self.last_frame = frame
if state:
inter_frame = cv2.resize(frame, self.zoom_size,
interpolation = self.interpolation_methods[
self.interpolation_method])
image = Image.frombytes("RGB", self.zoom_size, inter_frame,
"raw", "BGR")
if self.take_series:
self.series_time_counter += 1
if self.series_time_counter == self.series_time_interval:
self.series_counter += 1
self.series_time_counter = 0
if self.series_counter != self.number_of_imgs:
img_name = "{0}{1}".format(self.series_counter +1,
self.img_format)
self.get_image().save(os.path.join(
self.series_img_path, self.series_dir, img_name))
else:
self.take_series = False
if self.recording:
self.video_writer.write(inter_frame)
return image
else:
return state
def recording_start_stop(self, name = None):
if not name:
name = "{0:%d%b%Y_%H_%M_%S.%f}.avi".format(
datetime.datetime.utcnow())
if self.recording:
self.recording = False
else:
self.recording = True
self.video_writer = cv2.VideoWriter(os.path.join(
self.video_path, name), cv2.cv.CV_FOURCC(* VIDEO_CODEC),
24, self.zoom_size)
def take_series_picture(self):
if self.take_series == False:
self.series_dir = "{0:%d%b%Y_%H_%M_%S.%f}".format(
datetime.datetime.utcnow())
os.makedirs(self.series_dir)
self.series_time_counter = 0
self.series_counter = 0
self.take_series = True
def take_picture(self, name = None):
if not name:
name = "{0:%d%b%Y_%H_%M_%S.%f}{1}".format(
datetime.datetime.utcnow(), self.img_format)
self.get_image().save(os.path.join(self.image_path, name))
def series_up_down(self, step):
if self.take_series == False:
if self.number_of_imgs > step *-1 or step > 0:
self.number_of_imgs += step
def set_time_interval(self, step):
if self.take_series == False:
if self.series_time_interval > step *-1 or step > 0:
self.series_time_interval += step
def zoom_image(self, step):
width = int(self.zoom_width + step * self.zoom_width / self.zoom_height)
height = int(self.zoom_height + step)
if width > 0 and height > 0:
self.zoom_width = width
self.zoom_height = height
def reset_zoom(self):
self.zoom_width, self.zoom_height = self.size
def next_interpolation_method(self):
self.interpolation_method = self.interpolation_methods_keys.next()
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 10
REC_ON = 5
def __init__(self, parent, microscope, width, height, zoom_step=10):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.tk_image = None
self.rec_on = cycle(x for x in xrange(self.REC_ON))
self.recording = False
self.text_on = False
self.microscope = microscope
self.text_colour_index = cycle(["white", "green", "black", "red",
"magenta", "green", "brown", "yellow", "blue", "orange", "gray"])
self.text_colour = self.text_colour_index.next()
self.canvas = tk.Canvas(self, width=width, height=height)
self.canvas.grid(column=0, row=0)
vscrollbar = tk.Scrollbar(self)
vscrollbar.grid(column=1, row=0, sticky=tk.N+tk.S)
self.canvas.config(yscrollcommand=vscrollbar.set)
vscrollbar.config(command=self.canvas.yview)
hscrollbar = tk.Scrollbar(self, orient=tk.HORIZONTAL)
hscrollbar.grid(column=0, row=1, columnspan=5, sticky=tk.E+tk.W)
self.canvas.config(xscrollcommand=hscrollbar.set)
hscrollbar.config(command=self.canvas.xview)
button_frame = tk.Frame(self)
button_frame.grid(column=0, row=3, columnspan=2)
self.buttons = list()
for column, (text, width, command, var)in enumerate(
(("||", 2, self.capture_start_stop, ()),
("Z+", 2, self.microscope.zoom_image, (zoom_step,)),
("Z-", 2, self.microscope.zoom_image, (-zoom_step,)),
("Z+/-", 2, self.microscope.reset_zoom, ()),
("[1]", 2, self.take_picture, ()),
("REC", 2, self.recording_film, ()),
("INTPOL", 5, self.next_interpolation_method, ()),
("[S]]]", 2, self.take_series_pictures, ()),
("S+", 2, self.series_up_down, (5,)),
("S-", 2, self.series_up_down, (-5,)),
("T+", 2, self.time_interval_up_down, (5,)),
("T-", 2, self.time_interval_up_down, (-5,)),
("ON", 2, self.text_on_off, ()),
("C", 2, self.change_text_colour, ()))):
button = tk.Button(button_frame, text=text, width=width,
relief="raised", font="Arial 10 bold",
command=partial(command, *var))
button.grid(column=column, row=0)
self.buttons.append(button)
def capture_start_stop(self):
if self.after_id is None:
self.buttons[0].config(text = "||")
self.run()
else:
self.buttons[0].config(text = ">")
self.after_cancel(self.after_id)
self.after_id = None
def run(self):
tk_image = self.microscope.get_image()
if tk_image:
self.canvas.delete("img", "rec", "txt")
self.tk_image = ImageTk.PhotoImage(tk_image)
self.canvas.create_image((0,0), anchor=tk.NW,
image=self.tk_image, tag="img")
if self.recording:
if self.rec_on.next() == 0:
self.canvas.create_oval(10, 10, 25, 25, fill="red",
tag="rec")
if self.text_on:
self.canvas.create_text(self.width / 2, self.height / 2,
text="+", font="Arial 30", fill=self.text_colour,
tag="txt")
self.canvas.create_text(30, 10, font="Arial 11 bold",
text = "FILTER: {0} SERIES: {1} TIME: {2} RES: {3}".format(
self.microscope.interpolation,
self.microscope.number_of_imgs,
self.microscope.series_time_interval,
self.microscope.zoom_size), anchor="nw",
fill = self.text_colour, tag = "txt")
for button in (1, 2, 3, 7, 8, 9, 10, 11):
if self.microscope.take_series:
self.buttons[button].config(state = tk.DISABLED)
else:
self.buttons[button].config(state = tk.NORMAL)
width, height = self.microscope.zoom_size
self.canvas.config(scrollregion = (0, 0, width, height))
self.after_id = self.after(self.UPDATE_INTERVAL, self.run)
else:
self.raise_cam_id_error()
def change_text_colour(self):
self.text_on_off(True)
self.text_colour = self.text_colour_index.next()
def text_on_off(self, state = False):
if state or not self.text_on:
self.text_on = True
else:
self.text_on = state
self.buttons[12].config(text="ON" if self.text_on else "OFF")
def raise_cam_id_error(self):
self.canvas.delete("img", "rec", "txt")
self.canvas.create_text((self.width / 2, self.height / 2),
text='NO CAM', font='Arial 40')
for button in self.buttons:
button.config(state="disabled")
def series_up_down(self, step):
self.text_on_off(True)
self.microscope.series_up_down(step)
def time_interval_up_down(self, step):
self.text_on_off(True)
self.microscope.set_time_interval(step)
def next_interpolation_method(self):
self.text_on_off(True)
self.microscope.next_interpolation_method()
def recording_film(self):
if self.recording:
self.microscope.recording_start_stop()
self.recording = False
else:
self.microscope.recording_start_stop()
self.recording = True
def take_series_pictures(self):
self.microscope.take_series_picture()
def take_picture(self):
self.microscope.take_picture()
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
try:
with Microscope(series_time_interval=5) as microscope:
def take_picture(e):
microscope_ui.take_picture()
microscope_ui = MicroscopeUI(
root, microscope, WIDTH, HEIGHT)
microscope_ui.pack(expand=tk.YES)
microscope_ui.run()
root.protocol("WM_DELETE_WINDOW", microscope_ui.release)
#root.bind("<Key" + chr(10) + ">", take_picture)
root.mainloop()
except RuntimeError:
tk.Label(root, text = 'can not open camera {0!r}'.format(
DEFAULT_CAM_ID), font = "Arial 20", height = 10).pack()
root.mainloop()
if __name__ == '__main__':
main()