Canon-Kamera

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
dani94k
User
Beiträge: 5
Registriert: Freitag 20. Dezember 2013, 14:25

Hallo liebe Community,

ich soll hier ein wenig Entwicklung als Werksstudent machen. Aber da ich im Punkt Programmieren im Moment vermutlich nur über ein wenig Halbwissen verfüge und der Großteil des Projekts eigentlich Hardware ist, versuche ich über diese Community vielleicht ein wenig Hilfe für mich zu bekommen. Im Wesentlichen, möchte ich eine Canon-Kamera über Python in eine spezielle BMW-Entwicklungsumgebung einbinden um damit Fotos zu erzeugen. Ich hab nach reichlichem googlen eine Lösung gefunden, nur verstehe ich sie jetzt nicht wirklich. Zwei Fragen hätte ich an dieser Stelle. 1. An welcher Stelle, könnte ich den Namen der gemachten und abzuspeichernden Fotos ändern und wie?
2.Woher kommt diese Fehlermeldung: "Exception TypeError: "hex() argument can't be converted to hex" in <bound method Camera.__del__ of <PyEDSDK.Camera instance at 0x02C9B5A8>> ignored" und wie kann man sie beheben?

Code:

Code: Alles auswählen

from ctypes import *
import pythoncom
import datetime

edsdk = windll.edsdk


def AddTime(fname):
    now = datetime.datetime.now()
    nname = fname[:-4]+'_'+now.isoformat()[:-7].replace(':','-')+fname[-4:]
    return nname


class EDSDKError(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

def EDErrorMsg(code):
    return "EDSDK error code"+hex(code)
    
def Call(code):
    if code!=0:
        raise EDSDKError,EDErrorMsg(code)
        
def Release(ref):
    edsdk.EdsRelease(ref)
    
def GetChildCount(ref):
    i = c_int()
    Call(edsdk.EdsGetChildCount(ref,byref(i)))
    return i.value

def GetChild(ref,number):
    c = c_void_p()
    Call(edsdk.EdsGetChildAtIndex(ref,number,byref(c)))
    return c
    

kEdsObjectEvent_DirItemRequestTransfer  =    0x00000208
kEdsObjectEvent_DirItemCreated       =       0x00000204


ObjectHandlerType = WINFUNCTYPE   (c_int,c_int,c_void_p,c_void_p)
def ObjectHandler_py(event,object,context):
    if event==kEdsObjectEvent_DirItemRequestTransfer:
        DownloadImage(object)
    return 0
ObjectHandler = ObjectHandlerType(ObjectHandler_py)


kEdsStateEvent_WillSoonShutDown       =      0x00000303

StateHandlerType = WINFUNCTYPE   (c_int,c_int,c_int,c_void_p)
def StateHandler_py(event,state,context):
    if event==kEdsStateEvent_WillSoonShutDown:
        print "cam about to shut off"
        Call(edsdk.EdsSendCommand(context,1,0))
    return 0
StateHandler = StateHandlerType(StateHandler_py)


PropertyHandlerType = WINFUNCTYPE   (c_int,c_int,c_int,c_int,c_void_p)
def PropertyHandler_py(event,property,param,context):
    return 0
PropertyHandler = PropertyHandlerType(PropertyHandler_py)


class DirectoryItemInfo(Structure):
    _fields_ = [("size", c_int),
                ("isFolder", c_int),
                ("groupID",c_int),
                ("option",c_int),
                ("szFileName",c_char*256),
                ("format",c_int)]

WaitingForImage = False
ImageFilename = None

def DownloadImage(image):
    dirinfo = DirectoryItemInfo()
    Call(edsdk.EdsGetDirectoryItemInfo(image,byref(dirinfo)))
    stream = c_void_p()
    global ImageFilename
    if ImageFilename is None:
        print "Image was taken manually"
        ImageFilename = AddTime("Manuell.jpg")
    print "Saving as",ImageFilename
    Call(edsdk.EdsCreateFileStream(ImageFilename,1,2,byref(stream)))
    
    Call(edsdk.EdsDownload(image,dirinfo.size,stream))
    Call(edsdk.EdsDownloadComplete(image))
    Release(stream)
    
    global WaitingForImage
    WaitingForImage = False


kEdsSaveTo_Camera       =   1
kEdsSaveTo_Host         =   2
kEdsSaveTo_Both         =   kEdsSaveTo_Camera | kEdsSaveTo_Host
kEdsPropID_SaveTo  = 0x0000000b



class EdsCapacity(Structure):
    _fields_ = [("numberOfFreeClusters", c_int),
                ("bytesPerSector", c_int),
                ("reset",c_int)]


class Camera:
    def __init__(self,camnum=0):
        self.cam = None
        l = CameraList()
        self.cam = l.GetCam(camnum)
        Call(edsdk.EdsSetObjectEventHandler(self.cam,0x200,ObjectHandler,None))
        Call(edsdk.EdsSetPropertyEventHandler(self.cam,0x100,PropertyHandler,None))
        Call(edsdk.EdsSetCameraStateEventHandler(self.cam,0x300,StateHandler,self.cam))
        Call(edsdk.EdsOpenSession(self.cam))
        
        self.SetProperty(kEdsPropID_SaveTo,kEdsSaveTo_Host)
        
        # set large capacity
        cap = EdsCapacity(10000000,512,1)
        Call(edsdk.EdsSetCapacity(self.cam,cap))
    def __del__(self):
        if self.cam is not None:
            Call(edsdk.EdsCloseSession(self.cam))
            Call(Release(self.cam))
    def SetProperty(self,property,param):
        d = c_int(param)
        Call(edsdk.EdsSetPropertyData(self.cam,property,0,4,byref(d)))
    def AutoFocus(self):
        kEdsCameraCommand_ShutterButton_OFF                    = 0x00000000,
#    kEdsCameraCommand_ShutterButton_Halfway                = 0x00000001,
#    kEdsCameraCommand_ShutterButton_Completely            = 0x00000003,
#    kEdsCameraCommand_ShutterButton_Halfway_NonAF        = 0x00010001,
#    kEdsCameraCommand_ShutterButton_Completely_NonAF    = 0x00010003,
        # note that this can fail when AF fails (error code 0x8D01)
        self.SendCommand(4,1)
    def Shoot(self,fname=None):
        # set saving flag
        global WaitingForImage
        WaitingForImage = True

        # set filename
        global ImageFilename
        if fname is None:
            ImageFilename = AddTime("Kombi.jpg")
        else:
            ImageFilename = fname

        # note that this can fail when AF fails (error code 0x8D01)
        self.SendCommand(0)
        # capture succeeded so go on to download image
        while WaitingForImage:
            pythoncom.PumpWaitingMessages()
        return ImageFilename
    
    def Shutter(self):
        self.SendCommand(4)
    def KeepOn(self):
        # important command - keeps the camera connected when not used
        self.SendCommand(1)
    def SendCommand(self,command,param=0):
        #define kEdsCameraCommand_TakePicture                     0x00000000
        #define kEdsCameraCommand_ExtendShutDownTimer             0x00000001
        #define kEdsCameraCommand_BulbStart                          0x00000002 
        #define kEdsCameraCommand_BulbEnd                          0x00000003 
        #define kEdsCameraCommand_DoEvfAf                         0x00000102
        #define kEdsCameraCommand_DriveLensEvf                    0x00000103
        #define kEdsCameraCommand_DoClickWBEvf                    0x00000104        
        #define kEdsCameraCommand_PressShutterButton              0x00000004
        Call(edsdk.EdsSendCommand(self.cam,command,param))

class CameraList:
    def __init__(self):
        self.list = c_void_p(None)
        Call(edsdk.EdsGetCameraList(byref(self.list)))
        print "found",GetChildCount(self.list),"cameras"
    def Count(self):
        return GetChildCount(self.list)
    def GetCam(self,number=0):
        print "get cam"
        if self.Count()<(number+1):
            raise ValueError,"Camera not found, make sure it's on and connected"
        return GetChild(self.list,number)
    def __del__(self):
        Release(self.list)
    
edsdk.EdsInitializeSDK()

if __name__=="__main__":
    pythoncom.CoInitialize()
    c = Camera()
    from time import sleep

    c.Shoot()
    
    sleep(1)
    
    
   


    c.KeepOn()
 

   
    del c
    edsdk.EdsTerminateSDK()


    sleep(2)
Vielen Dank im Vorraus für eure Hilfe auch so kurz vor Weihnachten ;)
Zuletzt geändert von Anonymous am Freitag 20. Dezember 2013, 15:46, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

dani94k hat geschrieben:ich soll hier ein wenig Entwicklung als Werksstudent machen. Aber da ich im Punkt Programmieren im Moment vermutlich nur über ein wenig Halbwissen verfüge und der Großteil des Projekts eigentlich Hardware ist, versuche ich über diese Community vielleicht ein wenig Hilfe für mich zu bekommen. Im Wesentlichen, möchte ich eine Canon-Kamera über Python in eine spezielle BMW-Entwicklungsumgebung einbinden um damit Fotos zu erzeugen. Ich hab nach reichlichem googlen eine Lösung gefunden, nur verstehe ich sie jetzt nicht wirklich.
Puh, ohne Programmieren zu können wird eine Anbindung an eine C-Library extrem schwer für dich.
dani94k hat geschrieben:Zwei Fragen hätte ich an dieser Stelle. 1. An welcher Stelle, könnte ich den Namen der gemachten und abzuspeichernden Fotos ändern und wie?
Das hättest du doch einfach im Quellcode nachschauen können. ``Camera.Shoot`` setzt den Dateinamen, da musst du halt deinen gewünschten Dateinamen übergeben… wenns daran schon hapert solltest du besser mal ein Python-Tutorial lesen.
dani94k hat geschrieben:2.Woher kommt diese Fehlermeldung: "Exception TypeError: "hex() argument can't be converted to hex" in <bound method Camera.__del__ of <PyEDSDK.Camera instance at 0x02C9B5A8>> ignored" und wie kann man sie beheben?
Aus ``Camera.__del__``, wie in der Fehlermeldung steht. Das wird wohl an ``EDErrorMsg`` scheitern, weil es versucht etwas in Hex umzuwandeln was nicht als Hex darstellbar ist. Müsstest halt mal schauen was da genau übergeben wird.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
dani94k
User
Beiträge: 5
Registriert: Freitag 20. Dezember 2013, 14:25

Leonidas hat geschrieben:
dani94k hat geschrieben:ich soll hier ein wenig Entwicklung als Werksstudent machen. Aber da ich im Punkt Programmieren im Moment vermutlich nur über ein wenig Halbwissen verfüge und der Großteil des Projekts eigentlich Hardware ist, versuche ich über diese Community vielleicht ein wenig Hilfe für mich zu bekommen. Im Wesentlichen, möchte ich eine Canon-Kamera über Python in eine spezielle BMW-Entwicklungsumgebung einbinden um damit Fotos zu erzeugen. Ich hab nach reichlichem googlen eine Lösung gefunden, nur verstehe ich sie jetzt nicht wirklich.
Puh, ohne Programmieren zu können wird eine Anbindung an eine C-Library extrem schwer für dich.
Musste ich leider schon merken, ich versuch mich da irgendwie durchzubeißen, geht ja nicht anders und der Weihnachtsurlaub muss genutzt werden...
Leonidas hat geschrieben:
dani94k hat geschrieben:Zwei Fragen hätte ich an dieser Stelle. 1. An welcher Stelle, könnte ich den Namen der gemachten und abzuspeichernden Fotos ändern und wie?
Das hättest du doch einfach im Quellcode nachschauen können. ``Camera.Shoot`` setzt den Dateinamen, da musst du halt deinen gewünschten Dateinamen übergeben… wenns daran schon hapert solltest du besser mal ein Python-Tutorial lesen.
Die Frage erscheint mir jetzt reichlich dämlich, habs wohl heute schon zu lang angeschaut entschuldige diese Frage bitte.
Leonidas hat geschrieben:
dani94k hat geschrieben:2.Woher kommt diese Fehlermeldung: "Exception TypeError: "hex() argument can't be converted to hex" in <bound method Camera.__del__ of <PyEDSDK.Camera instance at 0x02C9B5A8>> ignored" und wie kann man sie beheben?
Aus ``Camera.__del__``, wie in der Fehlermeldung steht. Das wird wohl an ``EDErrorMsg`` scheitern, weil es versucht etwas in Hex umzuwandeln was nicht als Hex darstellbar ist. Müsstest halt mal schauen was da genau übergeben wird.
Ja hier wird die code-Variable übergeben, ich versteh nur noch nicht ganz den Ursprung der Variable bzw. wo diese genau erzeugt wird und wie ich dann verhindern kann, das es mir jedesmal den Fehler schmeißt, weil wenn nacher das Programm laufen soll, darf es keine Fehlermeldungen ausspucken, wenn es dann in bereits vorhandenen Code zur Testautomatisierung eingebunden werden soll... Zusätzlich vielleicht nur soviel das Programm läuft im Moment bereits zum weitesten Teil, d.h. es macht Fotos und speichert diese.

Danke dir schonmal für deine Hilfe!
dani94k
User
Beiträge: 5
Registriert: Freitag 20. Dezember 2013, 14:25

Wenn man dann einige Zeit wartet und wieder startet, passiert nämlich folgendes:

Das Programm schmeißt folgende Zeilen aus:

found 1 cameras
get cam
Traceback (most recent call last):
File "C:\TAF\eclipse_workspace\Kombishot\src\versuch2.py", line 12, in <module>
e=Camera()
File "C:\TAF\eclipse_workspace\Kombishot\src\PyEDSDK.py", line 121, in __init__
Call(edsdk.EdsOpenSession(self.cam))
File "C:\TAF\eclipse_workspace\Kombishot\src\PyEDSDK.py", line 25, in Call
raise EDSDKError,EDErrorMsg(code)
PyEDSDK.EDSDKError: 'EDSDK error code0xc0'
Exception PyEDSDK.EDSDKError: EDSDKError() in <bound method Camera.__del__ of <PyEDSDK.Camera instance at 0x02CAB5D0>> ignored




Jetzt muss ich die Umgebung neustarten um wieder ein Foto machen zu können. Das ist so äußerst unpraktisch ;)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

dani94k hat geschrieben:Ja hier wird die code-Variable übergeben, ich versteh nur noch nicht ganz den Ursprung der Variable bzw. wo diese genau erzeugt wird und wie ich dann verhindern kann, das es mir jedesmal den Fehler schmeißt, weil wenn nacher das Programm laufen soll, darf es keine Fehlermeldungen ausspucken, wenn es dann in bereits vorhandenen Code zur Testautomatisierung eingebunden werden soll...
Dazu muss man doch einfach nur nachverfolgen was der Code macht: In ``Camera.__del__`` wird ``Call(edsdk.EdsCloseSession(self.cam))`` ausgeführt. Dieses ``edsdk.EdsCloseSession(self.cam)`` gibt offenbar nen Fehlercode zurück, weil in ``Call`` geprüft wird ob der Code 0 ist (was er nicht ist) und dann wird dieser Wert an ``EDErrorMsg(code)`` übergeben, die versucht daraus nen Hex-Wert zu machen. Das scheitert, weil dieser Code etwas ist, was der Autor des Codes nicht erwartet hat. Daher solltest du nachschauen was in diesem Fall an ``code`` gebunden ist.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

Wobei jetzt beim Traceback ja 0xc0 problemlos als Hexadezimaldarstellung umgewandelt werden konnte, aber auch 0xc0 ist nicht 0. Also muss man für *diesen* Fall in der Dokumentation der C-API mal nachschauen was der Rückgabewert 0xc0 bedeutet.

Grundsätzlich würde ich auch sagen das man zum Anbinden einer C-Bibliothek sowohl Python als auch C *gut* können muss, weil das zum Beispiel auch Kenntnisse der Speicherverwaltung von der Python-Implementierung erfordert und Verständnis was die Bemerkung/Warnung in der Python-Dokumentation zur `__del__()`-Methode konkret bedeutet. Das ist nämlich alles andere als robust so wie es da geschrieben ist. Spätestens beim Programmende kann es wieder Probleme mit Ausnahmen geben oder das so eine `__del__()` auch *überhaupt nicht* ausgeführt werden muss. Genau das könnte zum Beispiel zu einem Problem führen wenn die Bibliothek einen Aufruf der Funktion zum Beenden einer Session zwingend erwartet bevor man eine neue eröffnen kann. So etwas sollte man nicht in der `__del__()` abhandeln, höchstens als Rückfall zur Sicherheit, sondern mit einem Kontextmanager. Dann wären wir wieder bei Python-Kenntnissen: objektorientierte Programmierung und ``with``/Kontextmanager.
dani94k
User
Beiträge: 5
Registriert: Freitag 20. Dezember 2013, 14:25

Also laut API gibt es ca. 100 verschiedene Fehler die die Methode auswerfen kann ( sehen alle ca. wie folgender aus : "EDS_ERR_xxxxxx(beliebiger Text unterschiedlich für verschiedene Fehler"). Leider finde ich in der API auch keinen Eintrag für 0xc0...
Wenn ich einfach den ganzen Block "__del__...." rauswerfe terminiert mein ganzes Programm einwandfrei.


Okey du gibst mir damit mehr als deutlich zu verstehen, dass mir das ganze womöglich über den Kopf gewachsen ist. Gibt es denn eine Möglichkeit in den nächsten Wochen hier fit zu werden? Und wenn ja, kannst du mir spezielle Tutorials empfehlen um schnell in ein solche Richtung fit zu werden?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

dani94k hat geschrieben:Also laut API gibt es ca. 100 verschiedene Fehler die die Methode auswerfen kann ( sehen alle ca. wie folgender aus : "EDS_ERR_xxxxxx(beliebiger Text unterschiedlich für verschiedene Fehler"). Leider finde ich in der API auch keinen Eintrag für 0xc0...
Du kannst eventuell in die Headerdatei schauen, welcher Fehlercode dem wert 0xc0 zugeordnet ist.
dani94k hat geschrieben:Wenn ich einfach den ganzen Block "__del__...." rauswerfe terminiert mein ganzes Programm einwandfrei.
Weil nicht korrekt aufgeräumt wird. Du hast ja selbst angemerkt dass du das ganze neu starten musst. Eigentlich willst du korrekt aufräumen, dann solltest du auch nicht neu starten müssen weil die Bibliothek korrekt benutzt wird und in den richtigen Zustand überführt wird.
dani94k hat geschrieben:Okey du gibst mir damit mehr als deutlich zu verstehen, dass mir das ganze womöglich über den Kopf gewachsen ist. Gibt es denn eine Möglichkeit in den nächsten Wochen hier fit zu werden? Und wenn ja, kannst du mir spezielle Tutorials empfehlen um schnell in ein solche Richtung fit zu werden?
Python lernen, zumindest bis Objektorientierung, C lernen, besonders dessen Datentypen und wie sie im Speicher angeordnet werden, das ctypes-Tutorial lesen. Ich denke dass ist mehr als ein paar Wochen Arbeit wenn man keine Vorkenntnisse hat. Bevor ich meine erste C-Anbindung gemacht habe hatte ich etliche Jahre Python hinter mir und richtig brauchbar ist es erst geworden als ich verstanden habe wie C "tickt".

Ohne dich entmutigen zu wollen, aber das ist gar nicht so trivial, leider.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
dani94k
User
Beiträge: 5
Registriert: Freitag 20. Dezember 2013, 14:25

Okey, dann hilft das ganze hier vermutlich nicht viel, weil ich dich nur weiter in meine Fragen verstricken werde, die womöglich wenig Sinn haben für einen erfahrenen Programmierer.

Keine Vorkenntnisse ist vermutlich nicht zu 100% der Fall aber ich hab bis jetzt das ganze immer nur angeschnitten, mal ein wenig Java, dann mal eine Prüfung im C-Programmieren bestanden und jetzt darf man sich am besten auch noch in Python auskennen (und das als E-technicker :/ ) Vielleicht such ich mir für die Anbindung doch profesionelle Hilfe. Kannst du ungefähr abschätzen, mit welchem Zeitaufwand so etwas verbunden wäre?

Mit welchen Büchern/Tutorials lernt man das denn am schnellsten und packendsten? :D


Danke dir auf jedenfall schonmal, dass du dich so schnell um mich gekümmert hast, immerhin kann ich das Ganze jetzt ein wenig besser einschätzen.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

dani94k hat geschrieben:Vielleicht such ich mir für die Anbindung doch profesionelle Hilfe.
Ich denke das ist nicht ganz unvernünftig, wenn du sowas einigermaßen bald nutzen willst.
dani94k hat geschrieben:Kannst du ungefähr abschätzen, mit welchem Zeitaufwand so etwas verbunden wäre?
Puh, schwer zu sagen. Hängt wohl auf von der Lib ab, die du da ansprechen willst und wie umfangreich oder einfach diese zu nutzen ist. Wie viel Arbeit in debuggen reingesteckt werden muss.
dani94k hat geschrieben:Mit welchen Büchern/Tutorials lernt man das denn am schnellsten und packendsten? :D
Für Python würde ich das Python-Tutorial vorschlagen bzw. "Learn Python the Hard Way" und für C fällt mir vor allem das K&R-Buch ein.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten