Mikroskop mit Tkinter-GUi
Hallo,
habe bei einem großen Auktionshaus ein USB-Mikroskop gekauft und es war nur eine Software für Windows dabei. Da sie aber so schön günstig war (20 €), wurde sie erworben und ich habe gehofft etwas mit OpenCV basteln zu können. Ist soweit recht brauchbar geworden und für meine Bedürfnisse ausreichend. Was muß so ein Ding noch können - Filter oder so ?
CAM STOP/STOP --> "||"
ZOOM + --> "+"
ZOOM - --> "-"
ZOOM NORMAL --> "+/-"
AUFNAHME FOTO --> "#"
Gruß Frank
[codebox=python file=Unbenannt.txt]#! /usr/bin/env python
# -*- coding: utf-8
import Tkinter as tk
import cv2
from time import gmtime, strftime
from PIL import Image, ImageTk
from functools import partial
WIDTH = 640
HEIGHT = 480
PATH = "microscop/"
FORMAT = "tiff"
ZOOM_STEP = 10
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id):
self.cam = cv2.VideoCapture(cam_id)
if self.cam.isOpened():
self.width = self.cam.get(self.PROPID_WIDTH)
self.height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.width / self.height
def get_image(self):
if self.cam.isOpened():
return Image.frombytes("RGB", (int(self.cam.get(
self.PROPID_WIDTH)), int(self.cam.get(self.PROPID_HEIGHT))),
self.cam.read()[1],"raw", "BGR").resize((self.width,
self.height))
else:
return None
def take_picture(self, path):
image = self.get_image().resize((self.width, self.height))
image.save(path)
def zoom_image(self, step):
width = int(self.width + step * self.aspect_ratio)
height = int(self.height + step)
if width > self.cam.get(self.PROPID_WIDTH)\
and height > self.cam.get(self.PROPID_HEIGHT)\
or height > self.cam.get(self.PROPID_HEIGHT) \
and width > self.cam.get(self.PROPID_WIDTH) :
self.width = width
self.height = height
def reset_zoom(self):
self.width = self.cam.get(self.PROPID_WIDTH)
self.height = self.cam.get(self.PROPID_HEIGHT)
def get_size(self):
return self.width, self.height
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 10
def __init__(self, parent, width, height, path, format, zoom_step):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.path = path
self.format = format
self.tk_image = None
self.microscope = Microscope(-1)
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)
self.buttons = list()
button_frame = tk.Frame(self)
button_frame.grid(column=0, row=3, columnspan=2)
for column, (text, command, var) in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.microscope.reset_zoom, None),
("#", self.take_picture, None))):
button = tk.Button(button_frame, text=text, width=4,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW, image=self.tk_image,
tag="img")
width, height = self.microscope.get_size()
self.canvas.config(scrollregion = (0, 0, width, height))
self.after_id = self.after(self.UPDATE_INTERVAL, self.run)
else:
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 take_picture(self, event = None):
self.microscope.take_picture("{0}{1}.{2}".format(self.path, strftime(
"%d%b%Y_%H_%M_%S", gmtime()), self.format))
def release(self):
self.microscope.release()
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
microscope_ui = MicroscopeUI(root, WIDTH, HEIGHT, PATH, FORMAT, ZOOM_STEP)
microscope_ui.pack(expand=tk.YES)
microscope_ui.run()
root.protocol("WM_DELETE_WINDOW", microscope_ui.release)
root.mainloop()
if __name__ == '__main__':
main()[/code]
Gruß Frank
habe bei einem großen Auktionshaus ein USB-Mikroskop gekauft und es war nur eine Software für Windows dabei. Da sie aber so schön günstig war (20 €), wurde sie erworben und ich habe gehofft etwas mit OpenCV basteln zu können. Ist soweit recht brauchbar geworden und für meine Bedürfnisse ausreichend. Was muß so ein Ding noch können - Filter oder so ?
CAM STOP/STOP --> "||"
ZOOM + --> "+"
ZOOM - --> "-"
ZOOM NORMAL --> "+/-"
AUFNAHME FOTO --> "#"
Gruß Frank
[codebox=python file=Unbenannt.txt]#! /usr/bin/env python
# -*- coding: utf-8
import Tkinter as tk
import cv2
from time import gmtime, strftime
from PIL import Image, ImageTk
from functools import partial
WIDTH = 640
HEIGHT = 480
PATH = "microscop/"
FORMAT = "tiff"
ZOOM_STEP = 10
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id):
self.cam = cv2.VideoCapture(cam_id)
if self.cam.isOpened():
self.width = self.cam.get(self.PROPID_WIDTH)
self.height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.width / self.height
def get_image(self):
if self.cam.isOpened():
return Image.frombytes("RGB", (int(self.cam.get(
self.PROPID_WIDTH)), int(self.cam.get(self.PROPID_HEIGHT))),
self.cam.read()[1],"raw", "BGR").resize((self.width,
self.height))
else:
return None
def take_picture(self, path):
image = self.get_image().resize((self.width, self.height))
image.save(path)
def zoom_image(self, step):
width = int(self.width + step * self.aspect_ratio)
height = int(self.height + step)
if width > self.cam.get(self.PROPID_WIDTH)\
and height > self.cam.get(self.PROPID_HEIGHT)\
or height > self.cam.get(self.PROPID_HEIGHT) \
and width > self.cam.get(self.PROPID_WIDTH) :
self.width = width
self.height = height
def reset_zoom(self):
self.width = self.cam.get(self.PROPID_WIDTH)
self.height = self.cam.get(self.PROPID_HEIGHT)
def get_size(self):
return self.width, self.height
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 10
def __init__(self, parent, width, height, path, format, zoom_step):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.path = path
self.format = format
self.tk_image = None
self.microscope = Microscope(-1)
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)
self.buttons = list()
button_frame = tk.Frame(self)
button_frame.grid(column=0, row=3, columnspan=2)
for column, (text, command, var) in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.microscope.reset_zoom, None),
("#", self.take_picture, None))):
button = tk.Button(button_frame, text=text, width=4,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW, image=self.tk_image,
tag="img")
width, height = self.microscope.get_size()
self.canvas.config(scrollregion = (0, 0, width, height))
self.after_id = self.after(self.UPDATE_INTERVAL, self.run)
else:
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 take_picture(self, event = None):
self.microscope.take_picture("{0}{1}.{2}".format(self.path, strftime(
"%d%b%Y_%H_%M_%S", gmtime()), self.format))
def release(self):
self.microscope.release()
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
microscope_ui = MicroscopeUI(root, WIDTH, HEIGHT, PATH, FORMAT, ZOOM_STEP)
microscope_ui.pack(expand=tk.YES)
microscope_ui.run()
root.protocol("WM_DELETE_WINDOW", microscope_ui.release)
root.mainloop()
if __name__ == '__main__':
main()[/code]
Gruß Frank
@kaytec: `Microscope` ist nicht robust. Wenn die Kamera nicht ”offen” ist, dann werden nicht alle Attribute definiert und damit gibt es in einigen Methoden `AttributeError`\s. Die `__init__()` sollte ein benutzbares Objekt hinterlassen. Also am besten eine Ausnahme auslösen wenn die Kamera nicht offen ist, denn dann ist das Objekt sowieso unbrauchbar.
Wenn es eine externe Ressource gibt, die man explizit wieder freigeben muss, dann bietet es sich an aus dem Objekt das diese Ressource kapselt einen „context manager“ zu machen, damit man ``with`` verwenden kann um sicherzustellen, dass die Ressource auch tatsächlich wieder freigegeben wird.
Ich gehe mal davon aus das sich die Höhe und Breite vom Kamerabild nicht ändert. Trotzdem wird das sehr oft im Code abgefragt. Sollte man es doch immer live abfragen müssen, würde ich da Properties draus machen, damit das nicht immer wieder im Quelltext stehen muss.
Beim `Image.frombytes()` hilft die Formatierung nicht unbedingt dabei zu sehen wo die Argumente anfangen und aufhören. Die Methode prüft nicht ob tatsächlich ein Bild gelesen wurde.
Die ``if``-Bedingung in der Zoom-Methode ist komisch. Sehe ich das falsch oder fragst Du da zweimal das gleiche ab, nur in umgekehrter Reihenfolge.
Ungetestet:
Wenn es eine externe Ressource gibt, die man explizit wieder freigeben muss, dann bietet es sich an aus dem Objekt das diese Ressource kapselt einen „context manager“ zu machen, damit man ``with`` verwenden kann um sicherzustellen, dass die Ressource auch tatsächlich wieder freigegeben wird.
Ich gehe mal davon aus das sich die Höhe und Breite vom Kamerabild nicht ändert. Trotzdem wird das sehr oft im Code abgefragt. Sollte man es doch immer live abfragen müssen, würde ich da Properties draus machen, damit das nicht immer wieder im Quelltext stehen muss.
Beim `Image.frombytes()` hilft die Formatierung nicht unbedingt dabei zu sehen wo die Argumente anfangen und aufhören. Die Methode prüft nicht ob tatsächlich ein Bild gelesen wurde.
Die ``if``-Bedingung in der Zoom-Methode ist komisch. Sehe ich das falsch oder fragst Du da zweimal das gleiche ab, nur in umgekehrter Reihenfolge.
Ungetestet:
Code: Alles auswählen
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id):
self.cam = cv2.VideoCapture(cam_id)
if not self.cam.isOpened():
raise RuntimeError('can not open camera {0!r}'.format(cam_id))
self.cam_width = int(self.cam.get(self.PROPID_WIDTH))
self.cam_height = int(self.cam.get(self.PROPID_HEIGHT))
self.width = self.height = None
self.reset_zoom()
self.aspect_ratio = self.width / self.height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (self.width, self.height)
def get_image(self):
is_ok, image_data = self.cam.read()
if is_ok:
return Image.frombytes(
'RGB',
(self.cam_width, self.cam_height),
image_data,
'raw',
'BGR'
).resize(self.size)
else:
return None
def take_picture(self, path):
self.get_image().resize(self.size).save(path)
def zoom_image(self, step):
width = int(self.width + step * self.aspect_ratio)
height = int(self.height + step)
if width > self.cam_width and height > self.cam_height:
self.width = width
self.height = height
def reset_zoom(self):
self.width = self.cam_width
self.height = self.cam_height
def release(self):
self.cam.release()
Hallo BlackJack,
Bei mir hat es nie einen `AttributeError` geworfen - kann es auch gerade nicht mit Kamera testen, denn in meinem gebrauchten Leasingrückläufer haben schlaue Leute Kamera/Mikro/Bluetooth nicht eingebaut. Das mit dem benutzbaren Objekt ist jetzt für mich ziemlich egal aber bei gezeigtem Code sollte es klargestellt werden.
Den zweiten Absatz verstehe ich mal gar nicht.
Es gibt ja immer drei Bildgrössen (tatsächliches Kamerabild / das veränderte (Zoom) / Die Bildgrösse in der GUI --> wird dir klar sein) und daher frage ich sie bestimmt immer wieder ab - das Script ist schon älter und es hat einer die Doku vergessen. Das mit "@property" sieht echt immer gut aus, doch habe ich die Verwendung nie so verstanden. Die Methoden mit dem Unterstrich sind auch irgendwie schön, doch auch hier .... - was macht es ?
Ob ein Bild wirklich gelesen wird gibt die Abfrage nicht her --> war hier auch schon das Problem viewtopic.php?f=6&t=37926&p=291671#p291671
Die Abfrage in der "zoom_image" Methode beruhte aus dem Problem, dass bei dem Unterschreiten der tatsächlichen Bildgrösse immer ein step zu viel war und daher habe ich es so hingebastelt. Es wird bestimmt nach deiner Veränderung auch gehen.
Gruß und Dank Frank
Bei mir hat es nie einen `AttributeError` geworfen - kann es auch gerade nicht mit Kamera testen, denn in meinem gebrauchten Leasingrückläufer haben schlaue Leute Kamera/Mikro/Bluetooth nicht eingebaut. Das mit dem benutzbaren Objekt ist jetzt für mich ziemlich egal aber bei gezeigtem Code sollte es klargestellt werden.
Den zweiten Absatz verstehe ich mal gar nicht.
Es gibt ja immer drei Bildgrössen (tatsächliches Kamerabild / das veränderte (Zoom) / Die Bildgrösse in der GUI --> wird dir klar sein) und daher frage ich sie bestimmt immer wieder ab - das Script ist schon älter und es hat einer die Doku vergessen. Das mit "@property" sieht echt immer gut aus, doch habe ich die Verwendung nie so verstanden. Die Methoden mit dem Unterstrich sind auch irgendwie schön, doch auch hier .... - was macht es ?
Ob ein Bild wirklich gelesen wird gibt die Abfrage nicht her --> war hier auch schon das Problem viewtopic.php?f=6&t=37926&p=291671#p291671
Die Abfrage in der "zoom_image" Methode beruhte aus dem Problem, dass bei dem Unterschreiten der tatsächlichen Bildgrösse immer ein step zu viel war und daher habe ich es so hingebastelt. Es wird bestimmt nach deiner Veränderung auch gehen.
Gruß und Dank Frank
@kaytec: Wenn die Kamera nicht geöffnet ist, dann werden die Attribute `witdh`, `height`, und `aspect_ratio` nicht erstellt. `take_picture()`, `zoom_image()` und `get_size()` greifen darauf aber zu, das heisst die werden dann einen `AttributeError` auslösen.
Die Kamera ist eine externe Ressource die man wieder freigeben muss wenn man damit fertig ist. Python weiss nicht das man `realease()` aufrufen muss wenn das `Microscope`-Objekt nicht mehr benötigt wird. Um eine saubere Verwendung von solchen externen Ressourcen sicherzustellen hat Python die ``with``-Anweisung und das „context manager“-Protokoll das Datentypen verwenden um mit ``with`` zu interagieren. Das sind die `__enter__()`- und `__exit__()`-Methoden die beim betreten und verlassen eines ``with``-Blocks aufgerufen werden.
Solange sich das tatsächliche Kamerabild in der grösse nicht ändert, braucht man es nicht jedes mal abfragen. Und falls das doch der Fall sein sollte, dann würde man den Code dafür nicht in jede Methode schreiben, sondern Getter, beziehungsweise in Python dann eher Properties.
Wenn das Flag sich nicht an die Dokumentation hält sollte man es trotzdem nicht ignorieren. Es kann ja trotzdem noch Fälle geben wo tatsächlich `False` zurückgegeben wird. Und vielleicht fixt ja mal irgendwann jemand den Fehler in OpenCV bzw. der Python-Anbindung.
Bei der Zoom-Bedingung habe ich ja nichts an der Bedingung verändert, also ich habe nicht eine vorhandene Bedingung irgendwie anders formuliert, sondern nur den sehr offensichtlich redundanten Teil weg gelassen. Und dann jetzt aber nachgefragt ob das denn überhaupt so sein sollte, oder ob Du da nicht vielleicht einen Fehler gemacht hast. Also das irgendwo width vielleicht height heissen sollte, eben so das da nicht zweimal das gleiche geprüft wird.
Die Kamera ist eine externe Ressource die man wieder freigeben muss wenn man damit fertig ist. Python weiss nicht das man `realease()` aufrufen muss wenn das `Microscope`-Objekt nicht mehr benötigt wird. Um eine saubere Verwendung von solchen externen Ressourcen sicherzustellen hat Python die ``with``-Anweisung und das „context manager“-Protokoll das Datentypen verwenden um mit ``with`` zu interagieren. Das sind die `__enter__()`- und `__exit__()`-Methoden die beim betreten und verlassen eines ``with``-Blocks aufgerufen werden.
Code: Alles auswählen
# ...
with Microscope(-1) as microscope:
microscope_ui = MicroscopeUI(
root, microscope, WIDTH, HEIGHT, PATH, FORMAT, ZOOM_STEP
)
# ...
root.mainloop()
Wenn das Flag sich nicht an die Dokumentation hält sollte man es trotzdem nicht ignorieren. Es kann ja trotzdem noch Fälle geben wo tatsächlich `False` zurückgegeben wird. Und vielleicht fixt ja mal irgendwann jemand den Fehler in OpenCV bzw. der Python-Anbindung.
Bei der Zoom-Bedingung habe ich ja nichts an der Bedingung verändert, also ich habe nicht eine vorhandene Bedingung irgendwie anders formuliert, sondern nur den sehr offensichtlich redundanten Teil weg gelassen. Und dann jetzt aber nachgefragt ob das denn überhaupt so sein sollte, oder ob Du da nicht vielleicht einen Fehler gemacht hast. Also das irgendwo width vielleicht height heissen sollte, eben so das da nicht zweimal das gleiche geprüft wird.
Hallo,
nach langer Zeit mal wieder gebastelt und versucht die Verbesserungen einzubauen. Das Aufnehmen von Videos ist neu, doch wenn es in in Echtzeit sein soll, dann müsste die zeitliche Steuerung mit einem Nebenthread (sagt man glaub ich so ?) gelöst werden. Ich mache mit meine Tochter Aufnahmen von Uhrwerke, kleinen Lebewesen etc. Für solche Spielereien langt es und macht recht viel Spaß. Für die Steuerung der Aufnahme verwende ich den Farbstatus des Buttons und ist bestimmt eine richtige Bastelei !?
[codebox=python file=Unbenannt.txt]
#! /usr/bin/env python
# -*- coding: utf-8
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import time
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
WIDTH = 640
HEIGHT = 480
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = -1):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError('can not open camera {0!r}'.format(
cam_id))
self.cam_width = self.width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.width / self.height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (self.width, self.height)
def get_image(self):
state, frame = self.cam.read()
if state:
image = Image.frombytes("RGB", (int(self.cam_width),
int(self.cam_height)) ,frame, "raw", "BGR"
).resize(self.size)
if self.recording:
self.video_writer.write(frame)
return image
else:
return None
def recording_start_stop(self, state, path = ""):
self.recording = state
if self.recording:
self.video_writer = cv2.VideoWriter(path, cv2.cv.CV_FOURCC(
*"XVID"), 24, (int(self.cam_width),
int(self.cam_height)))
def take_picture(self, path):
image = self.get_image().resize((self.width, self.height))
image.save(path)
def zoom_image(self, step):
width = int(self.width + step * self.aspect_ratio)
height = int(self.height + step)
if width > 0 and height > 0:
self.width = width
self.height = height
def reset_zoom(self):
self.width, self.height = self.cam_width, self.cam_height
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 10
def __init__(self, parent, microscope, width, height,
zoom_step = 10, picture_path = "", video_path = ""):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.picture_path = picture_path
self.video_path = video_path
self.tk_image = None
self.buttons = list()
self.microscope = microscope
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)
for column, (text, command, var)in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.reset_zoom, None),
("[ ]", self.take_picture, None),
("REC", self.recording_film, None))):
button = tk.Button(button_frame, text=text, width=4,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
self.buttons[-1].config(bg = "lightgreen")
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW,
image=self.tk_image, tag="img")
width, height = self.microscope.size
self.canvas.config(scrollregion = (0, 0, width, height))
self.after_id = self.after(self.UPDATE_INTERVAL, self.run)
else:
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 reset_zoom(self):
self.microscope.reset_zoom()
def recording_film(self):
if self.buttons[-1].config("bg")[-1] == "lightgreen":
self.buttons[-1].config(bg = "red")
self.microscope.recording_start_stop(True,
"{0}{1:%d%b%Y_%H_%M_%S.%f}.avi".format(self.video_path,
datetime.datetime.utcnow()))
else:
self.buttons[-1].config(bg = "lightgreen")
self.microscope.recording_start_stop(False)
def take_picture(self):
self.microscope.take_picture("{0}{1:%d%b%Y_%H_%M_%S.%f}.tiff"
.format(self.picture_path, datetime.datetime.utcnow()))
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
with Microscope() as microscope:
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.mainloop()
if __name__ == '__main__':
main()
[/code]
Gruß Frank
nach langer Zeit mal wieder gebastelt und versucht die Verbesserungen einzubauen. Das Aufnehmen von Videos ist neu, doch wenn es in in Echtzeit sein soll, dann müsste die zeitliche Steuerung mit einem Nebenthread (sagt man glaub ich so ?) gelöst werden. Ich mache mit meine Tochter Aufnahmen von Uhrwerke, kleinen Lebewesen etc. Für solche Spielereien langt es und macht recht viel Spaß. Für die Steuerung der Aufnahme verwende ich den Farbstatus des Buttons und ist bestimmt eine richtige Bastelei !?
[codebox=python file=Unbenannt.txt]
#! /usr/bin/env python
# -*- coding: utf-8
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import time
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
WIDTH = 640
HEIGHT = 480
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = -1):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError('can not open camera {0!r}'.format(
cam_id))
self.cam_width = self.width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.width / self.height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (self.width, self.height)
def get_image(self):
state, frame = self.cam.read()
if state:
image = Image.frombytes("RGB", (int(self.cam_width),
int(self.cam_height)) ,frame, "raw", "BGR"
).resize(self.size)
if self.recording:
self.video_writer.write(frame)
return image
else:
return None
def recording_start_stop(self, state, path = ""):
self.recording = state
if self.recording:
self.video_writer = cv2.VideoWriter(path, cv2.cv.CV_FOURCC(
*"XVID"), 24, (int(self.cam_width),
int(self.cam_height)))
def take_picture(self, path):
image = self.get_image().resize((self.width, self.height))
image.save(path)
def zoom_image(self, step):
width = int(self.width + step * self.aspect_ratio)
height = int(self.height + step)
if width > 0 and height > 0:
self.width = width
self.height = height
def reset_zoom(self):
self.width, self.height = self.cam_width, self.cam_height
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 10
def __init__(self, parent, microscope, width, height,
zoom_step = 10, picture_path = "", video_path = ""):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.picture_path = picture_path
self.video_path = video_path
self.tk_image = None
self.buttons = list()
self.microscope = microscope
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)
for column, (text, command, var)in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.reset_zoom, None),
("[ ]", self.take_picture, None),
("REC", self.recording_film, None))):
button = tk.Button(button_frame, text=text, width=4,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
self.buttons[-1].config(bg = "lightgreen")
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW,
image=self.tk_image, tag="img")
width, height = self.microscope.size
self.canvas.config(scrollregion = (0, 0, width, height))
self.after_id = self.after(self.UPDATE_INTERVAL, self.run)
else:
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 reset_zoom(self):
self.microscope.reset_zoom()
def recording_film(self):
if self.buttons[-1].config("bg")[-1] == "lightgreen":
self.buttons[-1].config(bg = "red")
self.microscope.recording_start_stop(True,
"{0}{1:%d%b%Y_%H_%M_%S.%f}.avi".format(self.video_path,
datetime.datetime.utcnow()))
else:
self.buttons[-1].config(bg = "lightgreen")
self.microscope.recording_start_stop(False)
def take_picture(self):
self.microscope.take_picture("{0}{1:%d%b%Y_%H_%M_%S.%f}.tiff"
.format(self.picture_path, datetime.datetime.utcnow()))
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
with Microscope() as microscope:
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.mainloop()
if __name__ == '__main__':
main()
[/code]
Gruß Frank
Hallo,
wollte die Ausnahme in der Haupt-Gui verarbeiten, doch nehme ich den "mainloop" aus der "with" Anweisung, dann löst er auch bei einer Nichtauslösung des "except" Blockes, die "__exit__" Funktion aus und somit brauche ich einen zweiten "mainloop". Werden ja nur nach Bedarf gestartet, doch sollte es keine zwei geben !?
Gruß Frank
wollte die Ausnahme in der Haupt-Gui verarbeiten, doch nehme ich den "mainloop" aus der "with" Anweisung, dann löst er auch bei einer Nichtauslösung des "except" Blockes, die "__exit__" Funktion aus und somit brauche ich einen zweiten "mainloop". Werden ja nur nach Bedarf gestartet, doch sollte es keine zwei geben !?
Gruß Frank
Code: Alles auswählen
def main():
root = tk.Tk()
root.title('MICROSCOPE')
try:
with Microscope(DEFAULT_CAM_ID) as microscope:
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.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()
Hallo,
das Zoom hat nicht funktioniert und ich habe es umgebastelt und die Größe des Zooms auch zum "property" gemacht.
Gruß Frank
das Zoom hat nicht funktioniert und ich habe es umgebastelt und die Größe des Zooms auch zum "property" gemacht.
Code: Alles auswählen
#! /usr/bin/env python
# -*- coding: utf-8
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import time
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
WIDTH = 640
HEIGHT = 480
VIDEO_CODEC = "XVID"
DEFAULT_CAM_ID = 1
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = id):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError("can not open camera {0!r}".format(
cam_id))
self.cam_width = self.zoom_width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.zoom_height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.zoom_width / self.zoom_height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (int(self.cam_width), int(self.cam_height))
@property
def zoom_size(self):
return (int(self.zoom_width), int(self.zoom_height))
def get_image(self):
state, frame = self.cam.read()
if state:
image = Image.frombytes("RGB", self.size ,frame,
"raw", "BGR").resize(self.zoom_size)
if self.recording:
self.video_writer.write(frame)
return image
else:
return state
def recording_start_stop(self, state, path = ""):
self.recording = state
if self.recording:
self.video_writer = cv2.VideoWriter(path, cv2.cv.CV_FOURCC(
* VIDEO_CODEC), 24, (self.size))
def take_picture(self, path):
self.get_image().save(path)
def zoom_image(self, step):
width = int(self.zoom_width + step * self.aspect_ratio)
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 release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 100
def __init__(self, parent, microscope, width, height,
zoom_step = 10, picture_path = "", video_path = ""):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.picture_path = picture_path
self.video_path = video_path
self.tk_image = None
self.buttons = list()
self.microscope = microscope
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)
for column, (text, command, var)in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.reset_zoom, None),
("[ ]", self.take_picture, None),
("REC", self.recording_film, None))):
button = tk.Button(button_frame, text=text, width=4,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
self.buttons[-1].config(bg = "lightgreen")
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW,
image=self.tk_image, tag="img")
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 raise_cam_id_error(self):
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 reset_zoom(self):
self.microscope.reset_zoom()
def recording_film(self):
if self.buttons[-1].config("bg")[-1] == "lightgreen":
self.buttons[-1].config(bg = "red")
self.microscope.recording_start_stop(True,
"{0}{1:%d%b%Y_%H_%M_%S.%f}.avi".format(self.video_path,
datetime.datetime.utcnow()))
else:
self.buttons[-1].config(bg = "lightgreen")
self.microscope.recording_start_stop(False)
def take_picture(self):
self.microscope.take_picture("{0}{1:%d%b%Y_%H_%M_%S.%f}.tiff"
.format(self.picture_path, datetime.datetime.utcnow()))
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
try:
with Microscope(DEFAULT_CAM_ID) as microscope:
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.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()
Hallo,
Die Interpolationsmethode kann jetzt gewählt werden und die Bilder/Filme werden gezoomt gespeichert.
[codebox=python file=Unbenannt.txt]
#!/usr/bin/env python
# -*- coding: utf-8
from __future__ import division
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import time
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
from itertools import cycle
WIDTH = 640
HEIGHT = 480
VIDEO_CODEC = "XVID"
DEFAULT_CAM_ID = 1
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = id):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError("can not open camera {0!r}".format(
cam_id))
self.interpolation_methods = {"NEAREST" : cv2.INTER_NEAREST,
"LINEAR" : cv2.INTER_LINEAR,
"AREA" : cv2.INTER_AREA,
"CUBIC" : cv2.INTER_CUBIC,
"LANCZOS4" : cv2.INTER_LANCZOS4}
self.interpolation_methods_keys = cycle(self.interpolation_methods.keys())
self.interpolation_method = self.interpolation_methods_keys.next()
self.cam_width = self.zoom_width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.zoom_height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.zoom_width / self.zoom_height
self.aspect_ratio = self.zoom_width / self.zoom_height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (int(self.cam_width), int(self.cam_height))
@property
def zoom_size(self):
return (int(self.zoom_width), int(self.zoom_height))
@property
def interpolation(self):
return self.interpolation_method
def get_image(self):
state, frame = self.cam.read()
inter_frame = cv2.resize(frame, self.zoom_size,
interpolation = self.interpolation_methods[
self.interpolation_method])
if state:
image = Image.frombytes("RGB", self.zoom_size, inter_frame,
"raw", "BGR")
if self.recording:
self.video_writer.write(inter_frame)
return image
else:
return state
def recording_start_stop(self, state, path = ""):
self.recording = state
if self.recording:
self.video_writer = cv2.VideoWriter(path, cv2.cv.CV_FOURCC(
* VIDEO_CODEC), 24, self.zoom_size)
def take_picture(self, path):
self.get_image().save(path)
def zoom_image(self, step):
width = int(self.zoom_width + step * self.aspect_ratio)
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 set_interpolation_method(self):
self.interpolation_method = self.interpolation_methods_keys.next()
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 50
def __init__(self, parent, microscope, width, height,
zoom_step = 10, picture_path = "", video_path = ""):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.picture_path = picture_path
self.video_path = video_path
self.tk_image = None
self.buttons = list()
self.microscope = microscope
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)
for column, (text, command, var)in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.reset_zoom, None),
("[ ]", self.take_picture, None),
("REC", self.recording_film, None),
(self.microscope.interpolation, self.set_interpolation_method
, None))):
button = tk.Button(button_frame, text=text, width=7,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
self.buttons[5].config(bg = "lightgreen")
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW,
image=self.tk_image, tag="img")
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 raise_cam_id_error(self):
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 reset_zoom(self):
self.microscope.reset_zoom()
def set_interpolation_method(self):
self.microscope.set_interpolation_method()
self.buttons[-1].config(text = self.microscope.interpolation)
def recording_film(self):
if self.buttons[5].config("bg")[-1] == "lightgreen":
self.buttons[5].config(bg = "red")
self.microscope.recording_start_stop(True,
"{0}{1:%d%b%Y_%H_%M_%S.%f}.avi".format(self.video_path,
datetime.datetime.utcnow()))
else:
self.buttons[5].config(bg = "lightgreen")
self.microscope.recording_start_stop(False)
def take_picture(self):
self.microscope.take_picture("{0}{1:%d%b%Y_%H_%M_%S.%f}.tiff"
.format(self.picture_path, datetime.datetime.utcnow()))
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
try:
with Microscope(DEFAULT_CAM_ID) as microscope:
microscope_ui = MicroscopeUI(
root, microscope, WIDTH, HEIGHT)
microscope_ui.import time
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
from itertools import cycle
WIDTH = 640
HEIGHT = 480
VIDEO_CODEC = "XVID"
DEFAULT_CAM_ID = 1
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = id):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError("can not open camera {0!r}".format(
cam_id))
self.interpolation_methods = {"NEAREST" : cv2.INTER_NEAREST,
"LINEAR" : cv2.INTER_LINEAR,
"AREA" : cv2.INTER_AREA,
"CUBIC" : cv2.INTER_CUBIC,
"LANCZOS4" : cv2.INTER_LANCZOS4}
self.interpolation_methods_keys = cycle(self.interpolation_methods.keys())
self.interpolation_method = self.interpolation_methods_keys.next()
self.cam_width = self.zoom_width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.zoom_height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.zoom_width / self.zoom_height
self.aspect_ratio = self.zoom_width / self.zoom_height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (int(self.cam_width), int(self.cam_height))
@property
def zoom_size(self):
return (int(self.zoom_width), int(self.zoom_height))
@property
def interpolation(self):
return self.interpolation_method
def get_image(self):
state, frame = self.cam.read()
inter_frame = cv2.resize(frame, self.zoom_size,
interpolation = self.interpolation_methods[
self.interpolation_method])
if state:
image = Image.frombytes("RGB", self.zoom_size, inter_frame,
"raw", "BGR")
if self.recording:
self.video_writer.write(inter_frame)
return image
else:
return state
def recording_start_stop(self, state, path = ""):
self.recording = state
if self.recording:
self.video_writer = cv2.VideoWriter(path, cv2.cv.CV_FOURCC(
* VIDEO_CODEC), 24, self.zoom_size)
def take_picture(self, path):
self.get_image().save(path)
def zoom_image(self, step):
width = int(self.zoom_width + step * self.aspect_ratio)
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 set_interpolation_method(self):
self.interpolation_method = self.interpolation_methods_keys.next()
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 50
def __init__(self, parent, microscope, width, height,
zoom_step = 10, picture_path = "", video_path = ""):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.picture_path = picture_path
self.video_path = video_path
self.tk_image = None
self.buttons = list()
self.microscope = microscope
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)
for column, (text, command, var)in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.reset_zoom, None),
("[ ]", self.take_picture, None),
("REC", self.recording_film, None),
(self.microscope.interpolation, self.set_interpolation_method
, None))):
button = tk.Button(button_frame, text=text, width=7,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
self.buttons[5].config(bg = "lightgreen")
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW,
image=self.tk_image, tag="img")
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 raise_cam_id_error(self):
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 reset_zoom(self):
self.microscope.reset_zoom()
def set_interpolation_method(self):
self.microscope.set_interpolation_method()
self.buttons[-1].config(text = self.microscope.interpolation)
def recording_film(self):
if self.buttons[5].config("bg")[-1] == "lightgreen":
self.buttons[5].config(bg = "red")
self.microscope.recording_start_stop(True,
"{0}{1:%d%b%Y_%H_%M_%S.%f}.avi".format(self.video_path,
datetime.datetime.utcnow()))
else:
self.buttons[5].config(bg = "lightgreen")
self.microscope.recording_start_stop(False)
def take_picture(self):
self.microscope.take_picture("{0}{1:%d%b%Y_%H_%M_%S.%f}.tiff"
.format(self.picture_path, datetime.datetime.utcnow()))
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
try:
with Microscope(DEFAULT_CAM_ID) as microscope:
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.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()
pack(expand=tk.YES)
microscope_ui.run()
root.protocol("WM_DELETE_WINDOW", microscope_ui.release)
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()[/code]
Gruß Frank
Die Interpolationsmethode kann jetzt gewählt werden und die Bilder/Filme werden gezoomt gespeichert.
[codebox=python file=Unbenannt.txt]
#!/usr/bin/env python
# -*- coding: utf-8
from __future__ import division
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import time
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
from itertools import cycle
WIDTH = 640
HEIGHT = 480
VIDEO_CODEC = "XVID"
DEFAULT_CAM_ID = 1
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = id):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError("can not open camera {0!r}".format(
cam_id))
self.interpolation_methods = {"NEAREST" : cv2.INTER_NEAREST,
"LINEAR" : cv2.INTER_LINEAR,
"AREA" : cv2.INTER_AREA,
"CUBIC" : cv2.INTER_CUBIC,
"LANCZOS4" : cv2.INTER_LANCZOS4}
self.interpolation_methods_keys = cycle(self.interpolation_methods.keys())
self.interpolation_method = self.interpolation_methods_keys.next()
self.cam_width = self.zoom_width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.zoom_height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.zoom_width / self.zoom_height
self.aspect_ratio = self.zoom_width / self.zoom_height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (int(self.cam_width), int(self.cam_height))
@property
def zoom_size(self):
return (int(self.zoom_width), int(self.zoom_height))
@property
def interpolation(self):
return self.interpolation_method
def get_image(self):
state, frame = self.cam.read()
inter_frame = cv2.resize(frame, self.zoom_size,
interpolation = self.interpolation_methods[
self.interpolation_method])
if state:
image = Image.frombytes("RGB", self.zoom_size, inter_frame,
"raw", "BGR")
if self.recording:
self.video_writer.write(inter_frame)
return image
else:
return state
def recording_start_stop(self, state, path = ""):
self.recording = state
if self.recording:
self.video_writer = cv2.VideoWriter(path, cv2.cv.CV_FOURCC(
* VIDEO_CODEC), 24, self.zoom_size)
def take_picture(self, path):
self.get_image().save(path)
def zoom_image(self, step):
width = int(self.zoom_width + step * self.aspect_ratio)
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 set_interpolation_method(self):
self.interpolation_method = self.interpolation_methods_keys.next()
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 50
def __init__(self, parent, microscope, width, height,
zoom_step = 10, picture_path = "", video_path = ""):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.picture_path = picture_path
self.video_path = video_path
self.tk_image = None
self.buttons = list()
self.microscope = microscope
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)
for column, (text, command, var)in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.reset_zoom, None),
("[ ]", self.take_picture, None),
("REC", self.recording_film, None),
(self.microscope.interpolation, self.set_interpolation_method
, None))):
button = tk.Button(button_frame, text=text, width=7,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
self.buttons[5].config(bg = "lightgreen")
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW,
image=self.tk_image, tag="img")
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 raise_cam_id_error(self):
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 reset_zoom(self):
self.microscope.reset_zoom()
def set_interpolation_method(self):
self.microscope.set_interpolation_method()
self.buttons[-1].config(text = self.microscope.interpolation)
def recording_film(self):
if self.buttons[5].config("bg")[-1] == "lightgreen":
self.buttons[5].config(bg = "red")
self.microscope.recording_start_stop(True,
"{0}{1:%d%b%Y_%H_%M_%S.%f}.avi".format(self.video_path,
datetime.datetime.utcnow()))
else:
self.buttons[5].config(bg = "lightgreen")
self.microscope.recording_start_stop(False)
def take_picture(self):
self.microscope.take_picture("{0}{1:%d%b%Y_%H_%M_%S.%f}.tiff"
.format(self.picture_path, datetime.datetime.utcnow()))
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
try:
with Microscope(DEFAULT_CAM_ID) as microscope:
microscope_ui = MicroscopeUI(
root, microscope, WIDTH, HEIGHT)
microscope_ui.import time
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
from itertools import cycle
WIDTH = 640
HEIGHT = 480
VIDEO_CODEC = "XVID"
DEFAULT_CAM_ID = 1
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = id):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError("can not open camera {0!r}".format(
cam_id))
self.interpolation_methods = {"NEAREST" : cv2.INTER_NEAREST,
"LINEAR" : cv2.INTER_LINEAR,
"AREA" : cv2.INTER_AREA,
"CUBIC" : cv2.INTER_CUBIC,
"LANCZOS4" : cv2.INTER_LANCZOS4}
self.interpolation_methods_keys = cycle(self.interpolation_methods.keys())
self.interpolation_method = self.interpolation_methods_keys.next()
self.cam_width = self.zoom_width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.zoom_height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.zoom_width / self.zoom_height
self.aspect_ratio = self.zoom_width / self.zoom_height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (int(self.cam_width), int(self.cam_height))
@property
def zoom_size(self):
return (int(self.zoom_width), int(self.zoom_height))
@property
def interpolation(self):
return self.interpolation_method
def get_image(self):
state, frame = self.cam.read()
inter_frame = cv2.resize(frame, self.zoom_size,
interpolation = self.interpolation_methods[
self.interpolation_method])
if state:
image = Image.frombytes("RGB", self.zoom_size, inter_frame,
"raw", "BGR")
if self.recording:
self.video_writer.write(inter_frame)
return image
else:
return state
def recording_start_stop(self, state, path = ""):
self.recording = state
if self.recording:
self.video_writer = cv2.VideoWriter(path, cv2.cv.CV_FOURCC(
* VIDEO_CODEC), 24, self.zoom_size)
def take_picture(self, path):
self.get_image().save(path)
def zoom_image(self, step):
width = int(self.zoom_width + step * self.aspect_ratio)
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 set_interpolation_method(self):
self.interpolation_method = self.interpolation_methods_keys.next()
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 50
def __init__(self, parent, microscope, width, height,
zoom_step = 10, picture_path = "", video_path = ""):
tk.Frame.__init__(self, parent)
self.parent = parent
self.width = width
self.height = height
self.picture_path = picture_path
self.video_path = video_path
self.tk_image = None
self.buttons = list()
self.microscope = microscope
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)
for column, (text, command, var)in enumerate(
(("||", self.start_stop, None),
("+", self.microscope.zoom_image, zoom_step),
("-", self.microscope.zoom_image, -zoom_step),
("+/-", self.reset_zoom, None),
("[ ]", self.take_picture, None),
("REC", self.recording_film, None),
(self.microscope.interpolation, self.set_interpolation_method
, None))):
button = tk.Button(button_frame, text=text, width=7,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
self.buttons[5].config(bg = "lightgreen")
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img")
self.tk_image = ImageTk.PhotoImage(self.tk_image)
self.canvas.create_image((0,0), anchor=tk.NW,
image=self.tk_image, tag="img")
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 raise_cam_id_error(self):
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 reset_zoom(self):
self.microscope.reset_zoom()
def set_interpolation_method(self):
self.microscope.set_interpolation_method()
self.buttons[-1].config(text = self.microscope.interpolation)
def recording_film(self):
if self.buttons[5].config("bg")[-1] == "lightgreen":
self.buttons[5].config(bg = "red")
self.microscope.recording_start_stop(True,
"{0}{1:%d%b%Y_%H_%M_%S.%f}.avi".format(self.video_path,
datetime.datetime.utcnow()))
else:
self.buttons[5].config(bg = "lightgreen")
self.microscope.recording_start_stop(False)
def take_picture(self):
self.microscope.take_picture("{0}{1:%d%b%Y_%H_%M_%S.%f}.tiff"
.format(self.picture_path, datetime.datetime.utcnow()))
def release(self):
self.parent.destroy()
def main():
root = tk.Tk()
root.title('MICROSCOPE')
try:
with Microscope(DEFAULT_CAM_ID) as microscope:
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.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()
pack(expand=tk.YES)
microscope_ui.run()
root.protocol("WM_DELETE_WINDOW", microscope_ui.release)
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()[/code]
Gruß Frank
Hallo,
hier sind einige Aufnahme mit der Software und die Beobachtungen des Mondes werde ich noch weiterführen. Das Teleskop hat 12,49€ gekostet und das Mikroskop gibt es für 11€ bei eBay.
https://m.youtube.com/channel/UCFFMvm-lul72XVpl0kNMhlA
Gruß Frank
hier sind einige Aufnahme mit der Software und die Beobachtungen des Mondes werde ich noch weiterführen. Das Teleskop hat 12,49€ gekostet und das Mikroskop gibt es für 11€ bei eBay.
https://m.youtube.com/channel/UCFFMvm-lul72XVpl0kNMhlA
Gruß Frank
Hallo,
für die Aufnahmen von Himmelskörpern ist die Serienbildaufnahme von Vorteil, da Luftunruhen die Bilder unscharf machen. Mit mehreren Bilder ist die Chance von guten Aufnahmen erhöht. Diese Funktion und die Möglichkeit den Zeitabstand zwischen den Bilder zu verändern ist jetzt auch vorhanden. Bei Serienbildaufnahmen wird immer ein neuer Ordner mit Zeitangabe angelegt. Die Buttons erklären sich selbst und Veränderungen werden auf dem Bildschirm angezeigt. Diese können mit dem ON/OFF-Button an/abgeschaltet werden.
Gruß Frank
für die Aufnahmen von Himmelskörpern ist die Serienbildaufnahme von Vorteil, da Luftunruhen die Bilder unscharf machen. Mit mehreren Bilder ist die Chance von guten Aufnahmen erhöht. Diese Funktion und die Möglichkeit den Zeitabstand zwischen den Bilder zu verändern ist jetzt auch vorhanden. Bei Serienbildaufnahmen wird immer ein neuer Ordner mit Zeitangabe angelegt. Die Buttons erklären sich selbst und Veränderungen werden auf dem Bildschirm angezeigt. Diese können mit dem ON/OFF-Button an/abgeschaltet werden.
Code: Alles auswählen
#! /usr/bin/env python
# -*- coding: utf-8
from __future__ import division
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import os
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
from itertools import cycle
WIDTH = 640
HEIGHT = 480
VIDEO_CODEC = "XVID"
DEFAULT_CAM_ID = 0
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = id, number_of_imgs = 10,
series_time_interval = 1, image_path = "", video_path = "",
series_img_path = ""):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError("can not open camera {0!r}".format(
cam_id))
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 = {"NEAREST" : cv2.INTER_NEAREST,
"LINEAR" : cv2.INTER_LINEAR,
"AREA" : cv2.INTER_AREA,
"CUBIC" : cv2.INTER_CUBIC,
"LANCZOS4" : cv2.INTER_LANCZOS4}
self.interpolation_methods_keys = cycle(self.interpolation_methods.keys())
self.interpolation_method = self.interpolation_methods_keys.next()
self.cam_width = self.zoom_width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.zoom_height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.zoom_width / self.zoom_height
self.aspect_ratio = self.zoom_width / self.zoom_height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (int(self.cam_width), int(self.cam_height))
@property
def zoom_size(self):
return (int(self.zoom_width), int(self.zoom_height))
@property
def interpolation(self):
return self.interpolation_method
def get_image(self):
state, frame = self.cam.read()
inter_frame = cv2.resize(frame, self.zoom_size,
interpolation = self.interpolation_methods[
self.interpolation_method])
if state:
image = Image.frombytes("RGB", self.zoom_size, inter_frame,
"raw", "BGR")
if self.series_counter:
if self.series_time_counter.next() == \
self.series_time_interval:
self.series_time_counter = (x for x in xrange(
self.series_time_interval +1))
counter = self.series_counter.next()
if counter != self.number_of_imgs:
self.take_picture("{0}{1}/{2}.tiff".format(
self.series_dir, self.series_img_path,
counter + 1))
else:
self.series_counter = None
if self.recording:
self.video_writer.write(inter_frame)
return image
else:
return state
def recording_start_stop(self, name = None):
if name:
name = name
else:
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("{0}{1}".format(
self.video_path, name), cv2.cv.CV_FOURCC(* VIDEO_CODEC),
24, self.zoom_size)
def take_series_picture(self):
if self.series_counter == None:
self.series_dir = "{0:%d%b%Y_%H_%M_%S.%f}".format(
datetime.datetime.utcnow())
os.makedirs(self.series_dir)
self.series_time_counter = (x for x in xrange(
self.series_time_interval + 1))
self.series_counter = (x for x in xrange(self.number_of_imgs +1))
def take_picture(self, name = None):
if name:
name = name
else:
name = "{0:%d%b%Y_%H_%M_%S.%f}.tiff".format(
datetime.datetime.utcnow())
self.get_image().save("{0}{1}".format(self.image_path, name))
def series_up_down(self, step):
if self.series_counter == None:
if self.number_of_imgs > 1 or step > 0:
self.number_of_imgs += step
def set_time_interval(self, step):
if self.series_counter == None:
if self.series_time_interval > 1 or step > 0:
self.series_time_interval += step
def zoom_image(self, step):
width = int(self.zoom_width + step * self.aspect_ratio)
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 set_interpolation_method(self):
self.interpolation_method = self.interpolation_methods_keys.next()
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 20
REC_ON = 3
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 = (x for x in xrange(self.REC_ON))
self.buttons = list()
self.recording = False
self.text_on = False
self.microscope = microscope
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)
for column, (text, width, command, var)in enumerate(
(("||", 2, self.start_stop, None),
("Z+", 2, self.microscope.zoom_image, zoom_step),
("Z-", 2, self.microscope.zoom_image, -zoom_step),
("Z+/-", 2, self.microscope.reset_zoom, None),
("[1]", 2, self.take_picture, None),
("REC", 2, self.recording_film, None),
("INTPOL", 5, self.set_interpolation_method, None),
("[S]]]", 2, self.take_series_pictures, None),
("S+", 2, self.series_up_down, 1),
("S-", 2, self.series_up_down, -1),
("T+", 2, self.time_interval_up_down, 1),
("T-", 2, self.time_interval_up_down, -1),
("ON", 2, self.text_on_off, None))):
button = tk.Button(button_frame, text=text, width=width,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img", "rec", "txt")
self.tk_image = ImageTk.PhotoImage(self.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() == self.REC_ON -1:
self.rec_on = (x for x in xrange(self.REC_ON))
self.canvas.create_oval(10, 10, 25, 25, fill="red",
tag="rec")
if self.text_on:
self.buttons[12].config(text = "OFF")
self.canvas.create_text(self.width / 2, self.height / 2,
text="+", font="Arial 30", tag = "txt")
self.canvas.create_text(30, 10,
text = "FILTER: {0} SERIES: {1} TIME: {2}".format(
self.microscope.interpolation,
self.microscope.number_of_imgs,
self.microscope.series_time_interval), anchor = "nw",
tag = "txt")
else:
self.buttons[12].config(text = "ON")
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 text_on_off(self):
if self.text_on:
self.text_on = False
else:
self.text_on = True
def raise_cam_id_error(self):
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):
if self.text_on == False:
self.text_on_off()
self.microscope.series_up_down(step)
def time_interval_up_down(self, step):
if self.text_on == False:
self.text_on_off()
self.microscope.set_time_interval(step)
def set_interpolation_method(self):
if self.text_on == False:
self.text_on_off()
self.microscope.set_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(DEFAULT_CAM_ID) 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()
Hallo,
die Textfarbe war nur in schwarz und bei Beobachtungen am Nachthimmel eher unbrauchbar. Mit der Taste "C" lässt sich die Farbe ändern.
Gruß Frank
die Textfarbe war nur in schwarz und bei Beobachtungen am Nachthimmel eher unbrauchbar. Mit der Taste "C" lässt sich die Farbe ändern.
Code: Alles auswählen
#! /usr/bin/env python
# -*- coding: utf-8
from __future__ import division
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import os
import datetime
import cv2
from PIL import Image, ImageTk
from functools import partial
from itertools import cycle
WIDTH = 640
HEIGHT = 480
VIDEO_CODEC = "XVID"
DEFAULT_CAM_ID = 0
class Microscope(object):
PROPID_WIDTH = 3
PROPID_HEIGHT = 4
def __init__(self, cam_id = id, number_of_imgs = 10,
series_time_interval = 1, image_path = "", video_path = "",
series_img_path = ""):
self.cam = cv2.VideoCapture(cam_id)
self.recording = False
if not self.cam.isOpened():
raise RuntimeError("can not open camera {0!r}".format(
cam_id))
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 = {"NEAREST" : cv2.INTER_NEAREST,
"LINEAR" : cv2.INTER_LINEAR,
"AREA" : cv2.INTER_AREA,
"CUBIC" : cv2.INTER_CUBIC,
"LANCZOS4" : cv2.INTER_LANCZOS4}
self.interpolation_methods_keys = cycle(self.interpolation_methods.keys())
self.interpolation_method = self.interpolation_methods_keys.next()
self.cam_width = self.zoom_width = self.cam.get(self.PROPID_WIDTH)
self.cam_height = self.zoom_height = self.cam.get(self.PROPID_HEIGHT)
self.aspect_ratio = self.zoom_width / self.zoom_height
self.aspect_ratio = self.zoom_width / self.zoom_height
def __enter__(self):
return self
def __exit__(self, *args):
self.release()
@property
def size(self):
return (int(self.cam_width), int(self.cam_height))
@property
def zoom_size(self):
return (int(self.zoom_width), int(self.zoom_height))
@property
def interpolation(self):
return self.interpolation_method
def get_image(self):
state, frame = self.cam.read()
inter_frame = cv2.resize(frame, self.zoom_size,
interpolation = self.interpolation_methods[
self.interpolation_method])
if state:
image = Image.frombytes("RGB", self.zoom_size, inter_frame,
"raw", "BGR")
if self.series_counter:
if self.series_time_counter.next() == \
self.series_time_interval:
self.series_time_counter = (x for x in xrange(
self.series_time_interval +1))
counter = self.series_counter.next()
if counter != self.number_of_imgs:
self.take_picture("{0}{1}/{2}.tiff".format(
self.series_dir, self.series_img_path,
counter + 1))
else:
self.series_counter = None
if self.recording:
self.video_writer.write(inter_frame)
return image
else:
return state
def recording_start_stop(self, name = None):
if name:
name = name
else:
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("{0}{1}".format(
self.video_path, name), cv2.cv.CV_FOURCC(* VIDEO_CODEC),
24, self.zoom_size)
def take_series_picture(self):
if self.series_counter == None:
self.series_dir = "{0:%d%b%Y_%H_%M_%S.%f}".format(
datetime.datetime.utcnow())
os.makedirs(self.series_dir)
self.series_time_counter = (x for x in xrange(
self.series_time_interval + 1))
self.series_counter = (x for x in xrange(self.number_of_imgs +1))
def take_picture(self, name = None):
if name:
name = name
else:
name = "{0:%d%b%Y_%H_%M_%S.%f}.tiff".format(
datetime.datetime.utcnow())
self.get_image().save("{0}{1}".format(self.image_path, name))
def series_up_down(self, step):
if self.series_counter == None:
if self.number_of_imgs > 1 or step > 0:
self.number_of_imgs += step
def set_time_interval(self, step):
if self.series_counter == None:
if self.series_time_interval > 1 or step > 0:
self.series_time_interval += step
def zoom_image(self, step):
width = int(self.zoom_width + step * self.aspect_ratio)
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 set_interpolation_method(self):
self.interpolation_method = self.interpolation_methods_keys.next()
def release(self):
self.cam.release()
class MicroscopeUI(tk.Frame):
UPDATE_INTERVAL = 20
REC_ON = 3
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 = (x for x in xrange(self.REC_ON))
self.buttons = list()
self.recording = False
self.text_on = False
self.microscope = microscope
self.text_colour = ["white", "green", "black", "red", "magenta",
"green", "brown", "yellow", "blue", "orange", "gray"]
self.text_colour_index = cycle(self.text_colour)
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)
for column, (text, width, command, var)in enumerate(
(("||", 2, self.start_stop, None),
("Z+", 2, self.microscope.zoom_image, zoom_step),
("Z-", 2, self.microscope.zoom_image, -zoom_step),
("Z+/-", 2, self.microscope.reset_zoom, None),
("[1]", 2, self.take_picture, None),
("REC", 2, self.recording_film, None),
("INTPOL", 5, self.set_interpolation_method, None),
("[S]]]", 2, self.take_series_pictures, None),
("S+", 2, self.series_up_down, 1),
("S-", 2, self.series_up_down, -1),
("T+", 2, self.time_interval_up_down, 1),
("T-", 2, self.time_interval_up_down, -1),
("ON", 2, self.text_on_off, None),
("C", 2, self.change_text_colour, None))):
button = tk.Button(button_frame, text=text, width=width,
relief="raised", font="Arial 10 bold")
button.grid(column=column, row=0)
self.buttons.append(button)
if var:
button.config(command=partial(command, var))
else:
button.config(command=command)
def 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):
self.tk_image = self.microscope.get_image()
if self.tk_image:
self.canvas.delete("img", "rec", "txt")
self.tk_image = ImageTk.PhotoImage(self.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() == self.REC_ON -1:
self.rec_on = (x for x in xrange(self.REC_ON))
self.canvas.create_oval(10, 10, 25, 25, fill="red",
tag="rec")
if self.text_on:
self.buttons[12].config(text = "OFF")
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}".format(
self.microscope.interpolation,
self.microscope.number_of_imgs,
self.microscope.series_time_interval), anchor="nw",
fill = self.text_colour, tag = "txt")
else:
self.buttons[12].config(text = "ON")
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):
if self.text_on == False:
self.text_on_off()
self.text_colour = self.text_colour_index.next()
def text_on_off(self):
if self.text_on:
self.text_on = False
else:
self.text_on = True
def raise_cam_id_error(self):
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):
if self.text_on == False:
self.text_on_off()
self.microscope.series_up_down(step)
def time_interval_up_down(self, step):
if self.text_on == False:
self.text_on_off()
self.microscope.set_time_interval(step)
def set_interpolation_method(self):
if self.text_on == False:
self.text_on_off()
self.microscope.set_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(DEFAULT_CAM_ID) 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()
@kaytec: hier ein paar Anmerkungen zum Code
Zeile 6: Du benutzt hier eine Fallunterscheidung zwischen Python2 und 3, später aber xrange, was nur in Python2 existiert.
Zeile 27: um die Gleichheitszeichen von Defaultargumenten macht man keine Leerzeichen. Der Defaultwert von `cam_id` `id` ist quatsch, wahrscheinlich wolltest Du DEFAULT_CAM_ID verwenden. Die Defaultwerte der Pfade sollten "." sein, also aktuelles Verzeichnis.
Zeile 43: interpolation_methods sollte besser eine Klassenkonstante sein.
Zeile 52/53: doppelte Zeile
Zeile 64/68: die Werte sind schon Integer, eine Umwandlung also überflüssig
Zeile 77: wenn ein Fehler auftritt, ist frame ungültig, das muß also in den if-Block.
Zeile 81/101: Wenn ein Fehler auftritt, sollte eine Exception geworfen werden und nicht ein ungültiger Wert zurückgeliefert werden. Später erwartest Du, dass get_image ein Bild liefert, was dann zu Folgefehlern führt.
Zeile 85: statt mit Iteratoren zu spielen, solltest Du einfach einen Zähler von series_time_interval bis 0 zählen lassen.
Zeile 90: ebenso hier, entweder Du nimmst einen Iterator und fängst StopIteration ab, um zu wissen, wann Du fertig bist, oder Du zählst mit einem einfachen Zähler.
Zeile 91: Pfade setzt man mit os.path.join zusammen, nicht mit format.
Zeile 103: start und stop tun zwei völlig verschiedene Dinge, mach zwei Methoden draus.
Zeile 104f: der if-Block tut nichts und kann weg. Besser `if not name:`
Zeile 107: Datumsdateinamen am besten im Format YYYYMMDD, dann kann man sie lexikalisch sortieren.
Zeile 118: Funktionen, die einfach nichts machen, wenn etwas nicht stimmt, sind komisch. Besser Fehlermeldung
Zeile 137: dieses komische If-Konstrukt verhindert nicht, dass number_of_imgs negativ werden kann. Mach es explizit, z.b. mit max(number_of_imgs + step, 1)
Zeile 146: bei mehrfachem Zoomen wird width irgendwann durch Rundungsfehler ungenau, besser jedesmal aus aspect_ratio und height berechnen.
Zeile 155: set_interpolation_method sollte besser next_interpolation_method heißen.
Zeile 173: Variablen sollten erst dann initialisiert werden, wenn sie gebraucht werden und nicht 20 Zeilen davor.
Zeile 177: text_colour wird zwei Zeilen später überschrieben, sollte also hier kein Attribut sein
Zeile 121: var sollte eine Liste der Argumente sein, denn None/False/0/etc. kann ja durchaus ein gültiger Parameterwert sein. Dann entfällt auch die Fallunterscheidung
Zeile 219,222,239,249: magische Werte vermeiden, buttons könnte ein Wörterbuch sein.
Zeile 227: tk_image wird drei Zeilen später überschrieben, sollte hier also kein Attribut sein.
Zeile 228: Fehlerbehandlung wurde ja schon bei get_image angesprochen
Zeile 239/249: sollte in text_on_off gemacht werden
Zeile 258f: diese zwei Zeilen kommen so oft vor, dass sie in eine eigene Methode wandern sollten.
Zeile 6: Du benutzt hier eine Fallunterscheidung zwischen Python2 und 3, später aber xrange, was nur in Python2 existiert.
Zeile 27: um die Gleichheitszeichen von Defaultargumenten macht man keine Leerzeichen. Der Defaultwert von `cam_id` `id` ist quatsch, wahrscheinlich wolltest Du DEFAULT_CAM_ID verwenden. Die Defaultwerte der Pfade sollten "." sein, also aktuelles Verzeichnis.
Zeile 43: interpolation_methods sollte besser eine Klassenkonstante sein.
Zeile 52/53: doppelte Zeile
Zeile 64/68: die Werte sind schon Integer, eine Umwandlung also überflüssig
Zeile 77: wenn ein Fehler auftritt, ist frame ungültig, das muß also in den if-Block.
Zeile 81/101: Wenn ein Fehler auftritt, sollte eine Exception geworfen werden und nicht ein ungültiger Wert zurückgeliefert werden. Später erwartest Du, dass get_image ein Bild liefert, was dann zu Folgefehlern führt.
Zeile 85: statt mit Iteratoren zu spielen, solltest Du einfach einen Zähler von series_time_interval bis 0 zählen lassen.
Zeile 90: ebenso hier, entweder Du nimmst einen Iterator und fängst StopIteration ab, um zu wissen, wann Du fertig bist, oder Du zählst mit einem einfachen Zähler.
Zeile 91: Pfade setzt man mit os.path.join zusammen, nicht mit format.
Zeile 103: start und stop tun zwei völlig verschiedene Dinge, mach zwei Methoden draus.
Zeile 104f: der if-Block tut nichts und kann weg. Besser `if not name:`
Zeile 107: Datumsdateinamen am besten im Format YYYYMMDD, dann kann man sie lexikalisch sortieren.
Zeile 118: Funktionen, die einfach nichts machen, wenn etwas nicht stimmt, sind komisch. Besser Fehlermeldung
Zeile 137: dieses komische If-Konstrukt verhindert nicht, dass number_of_imgs negativ werden kann. Mach es explizit, z.b. mit max(number_of_imgs + step, 1)
Zeile 146: bei mehrfachem Zoomen wird width irgendwann durch Rundungsfehler ungenau, besser jedesmal aus aspect_ratio und height berechnen.
Zeile 155: set_interpolation_method sollte besser next_interpolation_method heißen.
Zeile 173: Variablen sollten erst dann initialisiert werden, wenn sie gebraucht werden und nicht 20 Zeilen davor.
Zeile 177: text_colour wird zwei Zeilen später überschrieben, sollte also hier kein Attribut sein
Zeile 121: var sollte eine Liste der Argumente sein, denn None/False/0/etc. kann ja durchaus ein gültiger Parameterwert sein. Dann entfällt auch die Fallunterscheidung
Zeile 219,222,239,249: magische Werte vermeiden, buttons könnte ein Wörterbuch sein.
Zeile 227: tk_image wird drei Zeilen später überschrieben, sollte hier also kein Attribut sein.
Zeile 228: Fehlerbehandlung wurde ja schon bei get_image angesprochen
Zeile 239/249: sollte in text_on_off gemacht werden
Zeile 258f: diese zwei Zeilen kommen so oft vor, dass sie in eine eigene Methode wandern sollten.