einige Fehler gefunden und den Text auf ein Label verschoben.
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}
ASPECT_RATIO = {"16/9" : 9/16,
"4/3" : 3/4,
"3/2" : 2/3,
"21/9" : 9/21,
"8/3" : 3/8,
"9/5" : 5/9,
"3/1" : 1/3,
"25/12" : 12/25,
"25/16" : 16/25,
"3/1" : 1/3,
"5/3" : 3/5,
"19/10" : 10/19,
"25/16" : 16/25,
"43/18" : 18/43,
"16/10" : 10/16}
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.inter_frame = None
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_keys = cycle(
self.INTERPOLATION_METHODS.keys())
self.interpolation_method = self.interpolation_methods_keys.next()
self.cam_width = self.zoom_width = self.width = \
int(self.cam.get(self.PROPID_WIDTH))
self.cam_height = self.zoom_height = self.height = \
int(self.cam.get(self.PROPID_HEIGHT))
aspect_ratio = self.cam_height / self.cam_width
if aspect_ratio not in self.ASPECT_RATIO.values():
self.ASPECT_RATIO["CAM"] = aspect_ratio
self.aspect_ratio_keys = cycle(self.ASPECT_RATIO.keys())
for i in xrange(len(self.ASPECT_RATIO)):
self.aspect_ratio = self.aspect_ratio_keys.next()
if self.ASPECT_RATIO[self.aspect_ratio] == aspect_ratio:
break
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def cam_size(self):
return self.cam_width, self.cam_height
@property
def size(self):
return self.width, self.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 state and np.array_equal(self.last_frame, frame):
self.release()
state = False
if not state:
raise RuntimeError("could not read image")
self.crop_frame = cv2.resize(frame, self.zoom_size,
interpolation = self.INTERPOLATION_METHODS[
self.interpolation_method])[int(self.zoom_height / 2
- self.zoom_width*self.ASPECT_RATIO[self.aspect_ratio] / 2)
: int(self.zoom_width * self.ASPECT_RATIO[self.aspect_ratio]
+ self.zoom_height / 2 - int(self.zoom_width*self.ASPECT_RATIO[
self.aspect_ratio]) / 2), 0 : self.zoom_width]
self.height, self.width = self.crop_frame.shape[0], \
self.crop_frame.shape[1]
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,
self.img_format)
cv2.imwrite(os.path.join(self.series_img_path,
self.series_dir, img_name), self.crop_frame)
else:
self.take_series = False
if self.recording:
self.video_writer.write(self.crop_frame)
return self.crop_frame
def recording_start_stop(self, name = None):
if self.recording:
self.recording = False
else:
self.recording = True
self.video_writer = cv2.VideoWriter(os.path.join(
self.video_path, name if name else
"{0:%d%b%Y_%H_%M_%S.%f}.avi".format(datetime.datetime.utcnow()
)), cv2.cv.CV_FOURCC(* VIDEO_CODEC), 24, self.size)
def take_series_picture(self):
if not self.take_series:
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)
cv2.imwrite(os.path.join(self.image_path, name), self.crop_frame)
def series_up_down(self, step):
if not self.take_series:
if self.number_of_imgs > -step:
self.number_of_imgs += step
def set_time_interval(self, step):
if not self.take_series:
if self.series_time_interval > -step:
self.series_time_interval += step
def zoom_image(self, step):
height = int(self.zoom_height + step)
width = int(height * self.cam_width / self.cam_height)
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.cam_size
def next_interpolation_method(self):
self.interpolation_method = self.interpolation_methods_keys.next()
def next_aspect_ratio(self):
self.aspect_ratio = self.aspect_ratio_keys.next()
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 1
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.cross_on = False
self.microscope = microscope
self.cross_colour_index = cycle(["white", "green", "black", "red",
"magenta", "green", "brown", "yellow", "blue", "orange", "gray"])
self.cross_colour = self.cross_colour_index.next()
self.info_text = tk.Label(self, font="Courier 12")
self.info_text.grid(column=0, row=0)
self.canvas = tk.Canvas(self, width=width, height=height)
self.canvas.grid(column=0, row=1)
self.canvas.bind("<ButtonPress-1>", self.start_slide)
self.canvas.bind("<B1-Motion>", self.slide_image)
hscrollbar = tk.Scrollbar(self)
hscrollbar.grid(column=1, row=1, sticky=tk.N+tk.S)
self.canvas.config(yscrollcommand=hscrollbar.set)
hscrollbar.config(command=self.canvas.yview)
vscrollbar = tk.Scrollbar(self, orient=tk.HORIZONTAL)
vscrollbar.grid(column=0, row=2, columnspan=5, sticky=tk.E+tk.W)
self.canvas.config(xscrollcommand=vscrollbar.set)
vscrollbar.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.microscope.take_picture, ()),
("REC", 2, self.microscope.recording_start_stop, ()),
("INTPOL", 5, self.microscope.next_interpolation_method, ()),
("[S]]]", 2, self.microscope.take_series_picture, ()),
("S+", 2, self.microscope.series_up_down, (1,)),
("S-", 2, self.microscope.series_up_down, (-1,)),
("T+", 2, self.microscope.set_time_interval, (
self.microscope.series_time_interval,)),
("T-", 2, self.microscope.set_time_interval, (
-self.microscope.series_time_interval,)),
("ON", 2, self.set_cross_on_off, ()),
("C", 2, self.change_cross_colour, ()),
("AR", 2, self.microscope.next_aspect_ratio, ()))):
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 slide_image(self, event):
self.canvas.scan_dragto(event.x, event.y, gain=-1)
def start_slide(self, event):
self.canvas.scan_mark(event.x, event.y)
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):
try:
image = self.microscope.get_image()
width, height = self.microscope.size
tk_image = Image.frombytes("RGB", (width, height),
image, "raw", "BGR")
except RuntimeError:
self.raise_cam_id_error()
return
self.canvas.delete("img", "rec")
self.tk_image = ImageTk.PhotoImage(tk_image)
self.canvas.create_image((self.width / 2,self.height / 2),
anchor=tk.CENTER, image=self.tk_image, tag="img")
if self.cross_on:
self.canvas.create_text(width / 2, height / 2,
text="+", font="Courier 30", fill=self.cross_colour,
tag="rec", anchor=tk.CENTER)
rec_text = "#" if self.microscope.recording \
and self.rec_on.next() == 0 else " "
self.info_text.config(text="REC:{0} FILTER:{1} SERIES:{2} TIME:{3} RES:{4}:{5} > {6}"
.format(
rec_text,
self.microscope.interpolation,
self.microscope.number_of_imgs,
self.microscope.series_time_interval,
width, height,
self.microscope.aspect_ratio))
series_state = tk.DISABLED if self.microscope.take_series else tk.NORMAL
for button in (1, 2, 3, 6, 7, 8, 9, 10, 11, 14):
self.buttons[button].config(state=series_state)
rec_state = tk.DISABLED if self.microscope.recording else tk.NORMAL
for button in (1, 2, 3, 6, 14):
self.buttons[button].config(state=rec_state)
width, height = self.microscope.zoom_size
self.canvas.config(scrollregion = (0, 0, width, height))
self.after_id = self.after(self.UPDATE_INTERVAL, self.run)
def change_cross_colour(self):
self.cross_colour = self.cross_colour_index.next()
def set_cross_on_off(self):
self.cross_on = not self.cross_on
self.buttons[12].config(text="OFF" if self.cross_on else "ON")
def raise_cam_id_error(self):
self.canvas.delete("img", "rec")
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 release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
try:
with Microscope(series_time_interval=1) 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()