使用edsdk 2.8拍照并直接将图像保存到PC

Posted

技术标签:

【中文标题】使用edsdk 2.8拍照并直接将图像保存到PC【英文标题】:take picture and directly save image to pc using edsdk 2.8 【发布时间】:2010-09-21 16:46:56 【问题描述】:

我是 EDSDK 2.8 的新手

目前,我的程序可以拍照。但是,当拍摄照片时,该照片会临时存储在佳能相机的缓冲区中。我想知道如何将它的目录保存到PC?

有人有什么想法吗?或者 c# 或 vb.net 中的示例代码?

【问题讨论】:

【参考方案1】:

我也是这样做的,因为我的相机中没有存储卡,并且想在发送拍照命令后将图像传输到主机。这是我在佳能 EOS50D 中未安装存储卡时调用 ObjectEventHandler 回调的方法。

EdsUInt32 setsaveto = kEdsSaveTo_Both;
err = EdsSetPropertyData(camera, kEdsPropID_SaveTo, 0, sizeof(setsaveto), &setsaveto);

瞧,回调被调用,然后我可以继续执行 Wayne 在之前的帖子中发布的 getCapturedItem() 函数。

【讨论】:

【参考方案2】:

这是我所做的:

首先,您必须在创建对象(即图片)时注册回调事件。我在我创建的 registerEvents 方法中做到了这一点:

//  Register OBJECT events
edsObjectEventHandler = new EDSDK.EdsObjectEventHandler(objectEventHandler);
error = EDSDK.EdsSetObjectEventHandler(this.CameraDevice, 
                EDSDK.ObjectEvent_All, edsObjectEventHandler, IntPtr.Zero);
if (EDSDK.EDS_ERR_OK != error)

    throw new CameraEventRegistrationException("Unable to
        register object events with the camera!", error);

objectEventHandler 是创建图片时将调用的方法。

该方法需要符合 API 规定的接口。这是该方法的示例实现:

/// <summary>
/// Registered callback function for recieving object events
/// </summary>
/// <param name="inEvent">Indicate the event type supplemented.</param>
/// <param name="inRef">Returns a reference to objects created by the event.</param>
/// <param name="inContext">Passes inContext without modification</param>
/// <returns>Status 0 (OK)</returns>
private uint objectEventHandler(uint inEvent, IntPtr inRef, IntPtr inContext)

    switch (inEvent)
    
        case EDSDK.ObjectEvent_DirItemCreated:
             this.invokeNewItemCreatedEvent(new NewItemCreatedEventArgs(getCapturedItem(inRef)));
             Console.WriteLine("Directory Item Created");
             break;
        case EDSDK.ObjectEvent_DirItemRequestTransfer:
             Console.WriteLine("Directory Item Requested Transfer");
             break;
         default:
             Console.WriteLine(String.Format("ObjectEventHandler: event 0, ref 1", inEvent.ToString("X"), inRef.ToString()));
             break;
    

    return 0x0;

在此示例中,我转身并生成我自己的事件,该事件具有对流对象的引用。这是由以下代码处理的:

        /// <summary>
        /// Gets a photo or video clip from the camera
        /// </summary>
        /// <param name="directoryItem">Reference to the item that the camera captured.</param>
        /// <returns></returns>
        private CapturedItem getCapturedItem(IntPtr directoryItem)
        
            uint err = EDSDK.EDS_ERR_OK;
            IntPtr stream = IntPtr.Zero;

            EDSDK.EdsDirectoryItemInfo dirItemInfo;

            err = EDSDK.EdsGetDirectoryItemInfo(directoryItem, out dirItemInfo);

            if (err != EDSDK.EDS_ERR_OK)
            
                throw new CameraException("Unable to get captured item info!", err);
            

            //  Fill the stream with the resulting image
            if (err == EDSDK.EDS_ERR_OK)
            
                err = EDSDK.EdsCreateMemoryStream((uint)dirItemInfo.Size, out stream);
            

            //  Copy the stream to a byte[] and 
            if (err == EDSDK.EDS_ERR_OK)
            
                err = EDSDK.EdsDownload(directoryItem, (uint)dirItemInfo.Size, stream);
            

            //  Create the returned item
            CapturedItem item = new CapturedItem();

            if (err == EDSDK.EDS_ERR_OK)
            
                IntPtr imageRef = IntPtr.Zero;

                err = EDSDK.EdsCreateImageRef(stream, out imageRef);

                if (err == EDSDK.EDS_ERR_OK)
                
                    EDSDK.EdsImageInfo info;
                    err = EDSDK.EdsGetImageInfo(imageRef, EDSDK.EdsImageSource.FullView, out info);

                    if (err == EDSDK.EDS_ERR_OK)
                    
                        item.Dimensions = new com.waynehartman.util.graphics.Dimension((int)info.Width, (int)info.Height);

                        EDSDK.EdsRelease(imageRef);
                    
                
            

            if (err == EDSDK.EDS_ERR_OK)
            
                byte[] buffer = new byte[(int)dirItemInfo.Size];

                GCHandle gcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned);

                IntPtr address = gcHandle.AddrOfPinnedObject();

                IntPtr streamPtr = IntPtr.Zero;

                err = EDSDK.EdsGetPointer(stream, out streamPtr);

                if (err != EDSDK.EDS_ERR_OK)
                
                    throw new CameraDownloadException("Unable to get resultant image.", err);
                

                try
                
                    Marshal.Copy(streamPtr, buffer, 0, (int)dirItemInfo.Size);

                    item.Image = buffer;
                    item.Name = dirItemInfo.szFileName;
                    item.Size = (long)dirItemInfo.Size;
                    item.IsFolder = Convert.ToBoolean(dirItemInfo.isFolder);

                    return item;
                
                catch (AccessViolationException ave)
                
                    throw new CameraDownloadException("Error copying unmanaged stream to managed byte[].", ave);
                
                finally
                
                    gcHandle.Free();
                    EDSDK.EdsRelease(stream);
                    EDSDK.EdsRelease(streamPtr);
                
            
            else
            
                throw new CameraDownloadException("Unable to get resultant image.", err);
            
        

【讨论】:

谢谢,有时我收到一个错误:在类型为“testcamera1!EDSDKLib.EDSDK+EdsObjectEventHandler::Invoke”的垃圾收集委托上进行了回调。这可能会导致应用程序崩溃、损坏和数据丢失。将委托传递给非托管代码时,托管应用程序必须使它们保持活动状态,直到保证它们永远不会被调用。 @ulduz114 我也一直这样。我所做的是为EdsObjectEventHandler 创建一个复杂的实例变量。正在发生的事情是委托被收集并且您丢失了参考。你需要坚持参考,直到你真正完成。我所做的是创建了一个 Camera 对象的抽象。它是一个单例对象,抽象了 Canon SDK 的状态和行为。在那里,我为私有 EdsObjectEventHandler 委托创建了一个实例变量。 谢谢,如果我的相机没有存储卡,我们如何将图像传输到电脑? @ulduz114。 SDK(据我所知)仅以相机文件系统(即SD卡)上创建的对象的形式公开拍照事件。没有一种我熟悉的从缓冲区捕获的方法。从某种意义上说,这是有道理的,因为在只有少量板载内存的环境中,保持易失性内存畅通非常重要,这样它才能继续拍照。一旦缓冲区被刷新到非易失性内存中,您就可以与这些字节进行交互了。限制,我知道,但它就是这样。 @ulduz114:您的问题已在***.com/questions/3796658/…得到答复

以上是关于使用edsdk 2.8拍照并直接将图像保存到PC的主要内容,如果未能解决你的问题,请参考以下文章

佳能 EDSDK Liveview 的示例 C 代码?

将 arkit 快照直接保存到照片库 swift 4

将图像从 url 直接上传到数据库 blob 字段

Android:如何用相机拍照并将位图转换为字节数组并保存到sqlite db?

如何在 OpenCV 中显示流图像?

使用适用于 Android 7.1.1 的 FileProvider 使用相机拍照后,我无法将文件保存到图库