佳能相机操作 EDSDK 教程 C# 版本
介绍佳能EOS数码SDK是一个 可以用来远程控制其数码单反相机相当强大的SDK。不幸的是,想在互联网上找些很好的例子相当难,而且提供的文档也不是很齐全。因为我已经找到了很多能让其他人更容易掌握它的东西,我就想可以把我认为最重要的东西组织在一起,做成一个教程。
另外:其实我不从属于佳能公司,也不受其自助。 |
背景你必须有佳能EDSDK副本才能让这个运行起来。 (我认为)我不会被允许包含那些官方的DLL的到项目中,所以你必须自己通过申请去获取,它们在这里: 一旦你得到了那些DLL,就把它们放到项目中的 EDSDK文件夹里面,并确保再调试/发行目录中也要有相同的文件夹。 (或你认为的任何地方,同时据此调整 EDSDK.cs文件中的DLLPath变量(在右上部)。 |
使用代码我使用了三个简单的类,SDKHandler,Camera和CameraValues,还有来自 佳能SDK的EDSDK。 在SDKHandler中有几个变量: |
- /// <summary>
- /// The used camera
- /// </summary>
- public Camera MainCamera { get; private set; }
- /// <summary>
- /// States if a session with the MainCamera is opened
- /// </summary>
- public bool CameraSessionOpen { get; private set; }
- /// <summary>
- /// States if the LiveView is on or not
- /// </summary>
- public bool IsLiveViewOn { get; private set; }
- /// <summary>
- /// States if LiveView is recorded or not
- /// </summary>
- public bool IsEvfFilming { get; private set; }
- /// <summary>
- /// Directory to where photos will be saved
- /// </summary>
- public string ImageSaveDirectory { get; set; }
- /// <summary>
- /// Handles errors that happen with the SDK
- /// </summary>
- public uint Error
- {
- get { return EDSDK.EDS_ERR_OK; }
- set { if (value != EDSDK.EDS_ERR_OK) throw new Exception("SDK Error: " + value); }
- }
- /// <summary>
- /// Frame buffer for LiveView recording
- /// </summary>
- private Queue<byte[]> FrameBuffer = new Queue<byte[]>(1000);
还有一些来自SDK的以及我自己添加的一些事件:
- #region SDK Events
- public event EDSDK.EdsCameraAddedHandler SDKCameraAddedEvent;
- public event EDSDK.EdsObjectEventHandler SDKObjectEvent;
- public event EDSDK.EdsProgressCallback SDKProgressCallbackEvent;
- public event EDSDK.EdsPropertyEventHandler SDKPropertyEvent;
- public event EDSDK.EdsStateEventHandler SDKStateEvent;
- #endregion
- #region Custom Events
- public delegate void CameraAddedHandler();
- public delegate void ProgressHandler(int Progress);
- public delegate void ImageUpdate(Image img);
- public delegate void FloatUpdate(float Value);
- /// <summary>
- /// Fires if a camera is added
- /// </summary>
- public event CameraAddedHandler CameraAdded;
- /// <summary>
- /// Fires if any process reports progress
- /// </summary>
- public event ProgressHandler ProgressChanged;
- /// <summary>
- /// Fires if the LiveView image is updated
- /// </summary>
- public event ImageUpdate LiveViewUpdated;
- /// <summary>
- /// Fires if a new framerate is calculated
- /// </summary>
- public event FloatUpdate FrameRateUpdated;
- #endregion
这个类的方法将在稍后讨论。
Camera类相当简单,工作起来就像一个相机指针和有关相机的一些信息的容器:
- public class Camera
- {
- internal IntPtr Ref;
- public EDSDK.EdsDeviceInfo Info { get; private set; }
- public uint Error
- {
- get { return EDSDK.EDS_ERR_OK; }
- set { if (value != EDSDK.EDS_ERR_OK) throw new Exception("SDK Error: " + value); }
- }
- public Camera(IntPtr Reference)
- {
- this.Ref = Reference;
- EDSDK.EdsDeviceInfo dinfo;
- Error = EDSDK.EdsGetDeviceInfo(Reference, out dinfo);
- this.Info = dinfo;
- }
- }
CameraValues是一个拥有所有单元ID值以及存储从Av、Tv到ISO字符串值的静态类。
|
初始化和终止SDK初始化和终止是最容易做的事情。当您一启动程序,就创建了一个SDKHandler的新实例。 |
- /// <summary>
- /// Initialises the SDK and adds events
- /// </summary>
- public SDKHandler()
- {
- //this is the important part of initialisation
- Error = EDSDK.EdsInitializeSDK();
- //here we subscribe to the CameraAddedEvent and tell the SDK we did so
- CameraAddedEvent += new EDSDK.EdsCameraAddedHandler(SDKHandler_CameraAddedEvent);
- EDSDK.EdsSetCameraAddedHandler(CameraAddedEvent, IntPtr.Zero);
- //here we subscribe to the rest of the camera events
- SDKStateEvent += new EDSDK.EdsStateEventHandler(Camera_SDKStateEvent);
- SDKPropertyEvent += new EDSDK.EdsPropertyEventHandler(Camera_SDKPropertyEvent);
- SDKProgressCallbackEvent += new EDSDK.EdsProgressCallback(Camera_SDKProgressCallbackEvent);
- SDKObjectEvent += new EDSDK.EdsObjectEventHandler(Camera_SDKObjectEvent);
- }
而当你关闭程序时,就会调用:
- /// <summary>
- /// Closes open session and terminates the SDK
- /// </summary>
- public void Dispose()
- {
- if (CameraSessionOpen) Error = EDSDK.EdsCloseSession(MainCamera.Ref);
- Error = EDSDK.EdsTerminateSDK();
- }
获取连接的像机列表
要打开一个会话,你必须选择一个相机。如果要获得所有连接的像机的列表,那就调用这个:
- /// <summary>
- /// Get a list of all connected cameras
- /// </summary>
- /// <returns>The camera list</returns>
- public List<Camera> GetCameraList()
- {
- IntPtr camlist;
- //Get cameralist
- Error = EDSDK.EdsGetCameraList(out camlist);
- //Get each camera from camlist
- int c;
- Error = EDSDK.EdsGetChildCount(camlist, out c);
- List<Camera> OutCamList = new List<Camera>();
- for (int i = 0; i < c; i++)
- {
- IntPtr cptr;
- Error = EDSDK.EdsGetChildAtIndex(camlist, i, out cptr);
- OutCamList.Add(new Camera(cptr));
- {
- return OutCamList;
- }
打开和关闭相机会话
从以前收到的像机列表中选择一个,打开一个使用它的会话:
- /// <summary>
- /// Opens a session with given camera
- /// </summary>
- /// <param name="NewCamera">The camera which will be used</param>
- public void OpenSession(Camera NewCamera)
- {
- //make sure the previous camera session is closed
- if (CameraSessionOpen) Error = EDSDK.EdsCloseSession(MainCamera.Ref);
- if (NewCamera != null)
- {
- MainCamera = NewCamera;
- //open a session
- Error = EDSDK.EdsOpenSession(MainCamera.Ref);
- //subscribe to the camera events (this time, in-Camera)
- EDSDK.EdsSetCameraStateEventHandler(MainCamera.Ref,
- EDSDK.StateEvent_All, SDKStateEvent, IntPtr.Zero);
- EDSDK.EdsSetObjectEventHandler(MainCamera.Ref,
- EDSDK.ObjectEvent_All, SDKObjectEvent, IntPtr.Zero);
- EDSDK.EdsSetPropertyEventHandler(MainCamera.Ref,
- EDSDK.PropertyEvent_All, SDKPropertyEvent, IntPtr.Zero);
- CameraSessionOpen = true;
- }
- }
如果你完成了对相机的使用,就使用这个方法关闭会话:
- /// <summary>
- /// Closes the session with the current camera
- /// </summary>
- public void CloseSession()
- {
- if (CameraSessionOpen)
- {
- Error = EDSDK.EdsCloseSession(MainCamera.Ref);
- CameraSessionOpen = false;
- }
- }
Set 和 Get 相机设置
通过ID去设置和获取相机的设置是非常简单的,但是一些有难度的结构值(这里还没有介绍).下面这个例子你可以在这个方法中获取到Tv,Av和ISO的设置。
- /// <summary>
- /// Gets the current setting of given property ID
- /// </summary>
- /// <param name="PropID">The property ID</param>
- /// <returns>The current setting of the camera</returns>
- public uint GetSetting(uint PropID)
- {
- if (MainCamera.Ref != IntPtr.Zero)
- {
- unsafe
- {
- uint property = 0;
- EDSDK.EdsDataType dataType;
- int dataSize;
- IntPtr ptr = new IntPtr(&property);
- //get the size of this property
- Error = EDSDK.EdsGetPropertySize(MainCamera.Ref, PropID, 0, out dataType, out dataSize);
- //get the data for this property
- Error = EDSDK.EdsGetPropertyData(MainCamera.Ref, PropID, 0, dataSize, ptr);
- return property;
- }
- }
- else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
- }
Setting方法(这里的参数一般是ID,从Camera类中获取这个string值):
- /// <summary>
- /// Sets a value for the given property ID
- /// </summary>
- /// <param name="PropID">The property ID</param>
- /// <param name="Value">The value which will be set</param>
- public void SetSetting(uint PropID, uint Value)
- {
- if (MainCamera.Ref != IntPtr.Zero)
- {
- int propsize;
- EDSDK.EdsDataType proptype;
- //get the size of this property
- Error = EDSDK.EdsGetPropertySize(MainCamera.Ref, PropID, 0, out proptype, out propsize);
- //set the property
- Error = EDSDK.EdsSetPropertyData(MainCamera.Ref, PropID, 0, propsize, Value);
- }
- else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
- }
可获取的设置值清单:
特定的相机没有特定的支持设置。这就是为什么你需要去获取所有可支持的设置值清单。这些只支持"AEModeSelect", "ISO", "Av", "Tv", "MeteringMode" 和"ExposureCompensation"。传给特定的ID你可以获取到对应的返回值。在Camera类中可以找到和Av,Tv和ISO的对应值。查看PDF格式的SDK文档可以获取其他的值。
- /// <summary>
- /// Gets the list of possible values for the current camera to set.
- /// Only the PropertyIDs "AEModeSelect", "ISO", "Av", "Tv", "MeteringMode"
- /// and "ExposureCompensation" are allowed.
- /// </summary>
- /// <param name="PropID">The property ID</param>
- /// <returns>A list of available values for the given property ID</returns>
- public List<int> GetSettingsList(uint PropID)
- {
- if (MainCamera.Ref != IntPtr.Zero)
- {
- if (PropID == EDSDK.PropID_AEModeSelect || PropID == EDSDK.PropID_ISOSpeed ||
- PropID == EDSDK.PropID_Av
- || PropID == EDSDK.PropID_Tv || PropID == EDSDK.PropID_MeteringMode ||
- PropID == EDSDK.PropID_ExposureCompensation)
- {
- EDSDK.EdsPropertyDesc des;
- Error = EDSDK.EdsGetPropertyDesc(MainCamera.Ref, PropID, out des);
- return des.PropDesc.Take(des.NumElements).ToList();
- }
- else throw new ArgumentException("Method cannot be used with this Property ID");
- }
- else { throw new ArgumentNullException("Camera or camera reference is null/zero"); }
- }
在bulb mode(灯泡模式)下正常拍照
用当前设置拍照,调用TakePhoto方法。有三点需要特别注意:
1、新线程启动了所以主线程没有被挂起。
2、之所有这里用while 循环,是因为由相机有时不会立即就绪,需要稍后再试
3、如果你将pc作为外设,那么请到下一个章节学习如何获取图片。
- /// <summary>
- /// Takes a photo with the current camera settings
- /// </summary>
- public void TakePhoto()
- {
- new Thread(delegate()
- {
- int BusyCount = 0;
- uint err = EDSDK.EDS_ERR_OK;
- while (BusyCount < 20)
- {
- //try to take a photo
- err = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_TakePicture, 0);
- //if the camer is currently busy, wait and try again.
- //If successful or an error happened, break the loop
- if (err == EDSDK.EDS_ERR_DEVICE_BUSY) { BusyCount++; Thread.Sleep(50); }
- else { break; }
- }
- Error = err;
- }).Start();
- }
在bulb 模式下拍照,调用带有时间参数的takePhoto方法
- /// <summary>
- /// Takes a photo in bulb mode with the current camera settings
- /// </summary>
- /// <param name="BulbTime">The time in milliseconds for how long the shutter will be open</param>
- public void TakePhoto(uint BulbTime)
- {
- new Thread(delegate()
- {
- if (BulbTime < 1000)
- { throw new ArgumentException("Bulbtime has to be bigger than 1000ms"); }
- int BusyCount = 0;
- uint err = EDSDK.EDS_ERR_OK;
- while (BusyCount < 20)
- {
- //open the shutter
- err = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_BulbStart, 0);
- if (err == EDSDK.EDS_ERR_DEVICE_BUSY) { BusyCount++; Thread.Sleep(50); }
- else { break; }
- }
- Error = err;
- //Wait for the specified time
- Thread.Sleep((int)BulbTime);
- //close the shutter
- Error = EDSDK.EdsSendCommand(MainCamera.Ref, EDSDK.CameraCommand_BulbEnd, 0);
- }).Start();
- }
将拍摄的图片上传到电脑中
想要把拍摄的照片直接传到电脑上,代替相机存储,请调用SetSetting方法进行设置:
- SetSetting(EDSDK.PropID_SaveTo, (uint)EDSDK.EdsSaveTo.Host);
每拍摄一张照片,EDSDK.ObjectEvent_DirItemRequestTransfer 类型的SDKObjectEvent都会被触发
- /// <summary>
- /// An Objectevent fired
- /// </summary>
- /// <param name="inEvent">The ObjectEvent id</param>
- /// <param name="inRef">Pointer to the object</param>
- /// <param name="inContext"></param>
- /// <returns>An EDSDK errorcode</returns>
- private uint Camera_SDKObjectEvent(uint inEvent, IntPtr inRef, IntPtr inContext)
- {
- if(inEvent == EDSDK.ObjectEvent_DirItemRequestTransfer)
- DownloadImage(inRef, @"Images\");
- return EDSDK.EDS_ERR_OK;
- }
DownloadImage方法如下:
- /// <summary>
- /// Downloads an image to given directory
- /// </summary>
- /// <param name="Info">Pointer to the object.
- /// Get it from the SDKObjectEvent.</param>
- /// <param name="directory"></param>
- public void DownloadImage(IntPtr ObjectPointer, string directory)
- {
- EDSDK.EdsDirectoryItemInfo dirInfo;
- IntPtr streamRef;
- //get information about the image
- Error = EDSDK.EdsGetDirectoryItemInfo(ObjectPointer, out dirInfo);
- string CurrentPhoto = Path.Combine(directory, dirInfo.szFileName);
- //create a filestream for the image
- Error = EDSDK.EdsCreateFileStream(CurrentPhoto,
- EDSDK.EdsFileCreateDisposition.CreateAlways, EDSDK.EdsAccess.ReadWrite, out streamRef);
- uint blockSize = 1024 * 1024;
- uint remainingBytes = dirInfo.Size;
- //download the image data in blocks
- do
- {
- if (remainingBytes < blockSize) { blockSize = (uint)(remainingBytes / 512) * 512; }
- remainingBytes -= blockSize;
- Error = EDSDK.EdsDownload(ObjectPointer, blockSize, streamRef);
- } while (remainingBytes > 512);
- //download the last bit of the image
- Error = EDSDK.EdsDownload(ObjectPointer, remainingBytes, streamRef);
- //tell the camera that the download is done
- Error = EDSDK.EdsDownloadComplete(ObjectPointer);
- //release image and stream
- Error = EDSDK.EdsRelease(ObjectPointer);
- Error = EDSDK.EdsRelease(streamRef);
- }
打开并查看视频
视频是最难处理的事情之一,尤其是要求高性能的情况下。 首先我们这样打开视频:
- /// <summary>
- /// Starts the LiveView
- /// </summary>
- public void StartLiveView()
- {
- //make sure it's not already on
- if (!IsLiveViewOn)
- {
- //set the LiveView output to be the PC
- SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_PC);
- IsLiveViewOn = true;
- }
- }
完成之后, SDKPropertyEvent这个事件的 inPropertyID参数就被设置成了 EDSDK.PropID_Evf_OutputDevice:
- /// <summary>
- /// A property changed
- /// </summary>
- /// <param name="inEvent">The PropetyEvent ID</param>
- /// <param name="inPropertyID">The Property ID</param>
- /// <param name="inParameter">Event Parameter</param>
- /// <param name="inContext">...</param>
- /// <returns>An EDSDK errorcode</returns>
- private uint Camera_SDKPropertyEvent
- (uint inEvent, uint inPropertyID, uint inParameter, IntPtr inContext)
- {
- if (inPropertyID == EDSDK.PropID_Evf_OutputDevice)
- {
- if (IsEvfFilming == true) DownloadEvfFilm();
- else if (IsLiveViewOn == true) DownloadEvf();
- }
- return EDSDK.EDS_ERR_OK;
- }
DownloadEvf方法如下:
- /// <summary>
- /// Downloads the LiveView image
- /// </summary>
- private void DownloadEvf()
- {
- new Thread(delegate()
- {
- //To give the camera time to switch the mirror
- Thread.Sleep(1500);
- IntPtr jpgPointer;
- IntPtr stream = IntPtr.Zero;
- IntPtr EvfImageRef = IntPtr.Zero;
- UnmanagedMemoryStream ums;
- uint err;
- uint length;
- //create streams
- err = EDSDK.EdsCreateMemoryStream(0, out stream);
- err = EDSDK.EdsCreateEvfImageRef(stream, out EvfImageRef);
- Stopwatch watch = new Stopwatch(); //stopwatch for FPS calculation
- float lastfr = 24; //last actual FPS
- //Run LiveView
- while (IsLiveViewOn)
- {
- watch.Restart();
- //download current LiveView image
- err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);
- unsafe
- {
- //get pointer and create stream
- Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
- Error = EDSDK.EdsGetLength(stream, out length);
- ums = new UnmanagedMemoryStream
- ((byte*)jpgPointer.ToPointer(), length, length, FileAccess.Read);
- //fire the LiveViewUpdated event with
- //the LiveView image created from the stream
- if (LiveViewUpdated != null) LiveViewUpdated(Image.FromStream(ums));
- ums.Close();
- }
- //calculate the framerate and fire the FrameRateUpdated event
- lastfr = lastfr * 0.9f + (100f / watch.ElapsedMilliseconds);
- if (FrameRateUpdated != null) FrameRateUpdated(lastfr);
- }
- //Release and finish
- if (stream != IntPtr.Zero) { Error = EDSDK.EdsRelease(stream); }
- if (EvfImageRef != IntPtr.Zero) { Error = EDSDK.EdsRelease(EvfImageRef); }
- //stop the LiveView
- SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_TFT);
- }).Start();
- }
虽然这样下载视频图像不是最简单的,但可以说是最快的。
调用StopLiveView方法就能停止实物取景,实质上它的目的是让DownloadEvf方法跳出while循环:
- /// <summary>
- /// Stops the LiveView
- /// </summary>
- public void StopLiveView()
- {
- IsLiveViewOn = false;
- }
记录播放窗口
记录视频的工作跟播放视频的方式很像。
开始方法如下:
- /// <summary>
- /// Starts LiveView and records it
- /// </summary>
- public void StartEvfFilming()
- {
- if (!IsLiveViewOn)
- {
- SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_PC);
- IsLiveViewOn = true;
- IsEvfFilming = true;
- }
- }
捕获SDKPropertyEvent事件:
- /// <summary>
- /// A property changed
- /// </summary>
- /// <param name="inEvent">The PropetyEvent ID</param>
- /// <param name="inPropertyID">The Property ID</param>
- /// <param name="inParameter">Event Parameter</param>
- /// <param name="inContext">...</param>
- /// <returns>An EDSDK errorcode</returns>
- private uint Camera_SDKPropertyEvent
- (uint inEvent, uint inPropertyID, uint inParameter, IntPtr inContext)
- {
- if (inPropertyID == EDSDK.PropID_Evf_OutputDevice)
- {
- if (IsEvfFilming == true) DownloadEvfFilm();
- else if (IsLiveViewOn == true) DownloadEvf();
- }
- return EDSDK.EDS_ERR_OK;
- }
DownloadEvfFilmmethod和DownloadEvfmethod比较相似,但有以下不同:
- 在开始while循环之前,已经下载了一个边框,并启动了 StartEvfVideoWriter方法。
- 为了更好的性能,LiveViewUpdatedevent只在每次第四个边框中调用(让实时取景稍显缓慢,但视频很流畅)
- 实时取景图像作为byte array放入队列中,供StartEvfVideoWriter方法处理
- /// <summary>
- /// Records the LiveView image
- /// </summary>
- private void DownloadEvfFilm()
- {
- new Thread(delegate()
- {
- //To give the camera time to switch the mirror
- Thread.Sleep(1500);
- IntPtr jpgPointer;
- IntPtr stream = IntPtr.Zero;
- IntPtr EvfImageRef = IntPtr.Zero;
- UnmanagedMemoryStream ums;
- uint err;
- uint length;
- err = EDSDK.EdsCreateMemoryStream(0, out stream);
- err = EDSDK.EdsCreateEvfImageRef(stream, out EvfImageRef);
- //Download one frame to init the video size
- err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);
- unsafe
- {
- Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
- Error = EDSDK.EdsGetLength(stream, out length);
- ums = new UnmanagedMemoryStream((byte*)jpgPointer.ToPointer(),
- length, length, FileAccess.Read);
- Bitmap bmp = new Bitmap(ums);
- StartEvfVideoWriter(bmp.Width, bmp.Height);
- bmp.Dispose();
- ums.Close();
- }
- Stopwatch watch = new Stopwatch();
- byte[] barr; //bitmap byte array
- const long ft = 41; //Frametime at 24FPS
- //(actually 41.66, but there is a bit of calculation overhead)
- float lastfr = 24; //last actual FPS
- int LVUpdateBreak1 = 0;
- //Run LiveView
- while (IsEvfFilming)
- {
- watch.Restart();
- err = EDSDK.EdsDownloadEvfImage(MainCamera.Ref, EvfImageRef);
- unsafe
- {
- Error = EDSDK.EdsGetPointer(stream, out jpgPointer);
- Error = EDSDK.EdsGetLength(stream, out length);
- ums = new UnmanagedMemoryStream((byte*)jpgPointer.ToPointer(),
- length, length, FileAccess.Read);
- barr = new byte[length];
- ums.Read(barr, 0, (int)length);
- //For better performance the LiveView is only updated with every 4th frame
- if (LVUpdateBreak1 == 0 && LiveViewUpdated != null)
- { LiveViewUpdated(Image.FromStream(ums)); LVUpdateBreak1 = 4; }
- LVUpdateBreak1--;
- FrameBuffer.Enqueue(barr);
- ums.Close();
- }
- //To get a steady framerate:
- while (true) if (watch.ElapsedMilliseconds >= ft) break;
- lastfr = lastfr * 0.9f + (100f / watch.ElapsedMilliseconds);
- if (FrameRateUpdated != null) FrameRateUpdated(lastfr);
- }
- //Release and finish
- if (stream != IntPtr.Zero) { Error = EDSDK.EdsRelease(stream); }
- if (EvfImageRef != IntPtr.Zero) { Error = EDSDK.EdsRelease(EvfImageRef); }
- SetSetting(EDSDK.PropID_Evf_OutputDevice, EDSDK.EvfOutputDevice_TFT);
- }).Start();
- }
由于写硬件驱动转换图片对象很慢,并且这也不需要实时处理,所以有了下面的StartEvfVideoWriter 方法 。这个方法将边框从队列中取出来保存,直到队列为空并且电影处理已关闭。我这里没有包含实际的视频保存功能,你可以用你偏好的类库去完成。
- /// <summary>
- /// Writes video frames from the buffer to a file
- /// </summary>
- /// <param name="Width">Width of the video</param>
- /// <param name="Height">Height of the video</param>
- private void StartEvfVideoWriter(int Width, int Height)
- {
- new Thread(delegate()
- {
- byte[] byteArray;
- ImageConverter ic = new ImageConverter();
- Image img;
- while (IsEvfFilming)
- {
- while (FrameBuffer.Count > 0)
- {
- //get byte array from queue
- byteArray = FrameBuffer.Dequeue();
- //convert it to an image object
- img = (Image)ic.ConvertFrom(byteArray);
- //Save video frame here. e.g. with the VideoFileWriter from the AForge library.
- }
- //if saving is faster than the LiveView, wait a bit for new frames and start over
- if (IsEvfFilming) Thread.Sleep(10);
- }
- }).Start();
- }
下面是如何利用 AForgelibrary的一个例子 (请注意correct DLLs,它们没被包含在这个项目中)
- private void StartVideoWriter(int Width, int Height)
- {
- new Thread(delegate()
- {
- VideoFileWriter writer = new VideoFileWriter();
- writer.Open("LiveViewVideo.avi", Width, Height, 24, VideoCodec.MPEG4);
- byte[] byteArray;
- ImageConverter ic = new ImageConverter();
- Image img;
- while (IsEvfFilming)
- {
- while (FrameBuffer.Count > 0)
- {
- byteArray = FrameBuffer.Dequeue();
- img = (Image)ic.ConvertFrom(byteArray);
- writer.WriteVideoFrame(new Bitmap(img));
- }
- if (IsEvfFilming) Thread.Sleep(10);
- }
- writer.Close();
- }).Start();
- }
关闭电影功能跟关闭实时取景方法一样:
- /// <summary>
- /// Stops LiveView and filming
- /// </summary>
- public void StopEvfFilming()
- {
- IsLiveViewOn = false;
- IsEvfFilming = false;
- }
关闭/打开相机的接口
为了避免或允许用户在相机上改变设置,你可以这样关闭或者打开相机的接口:
- /// <summary>
- /// Locks or unlocks the cameras UI
- /// </summary>
- /// <param name="LockState">True for locked, false to unlock</param>
- public void UILock(bool LockState)
- {
- if (LockState == true) Error =
- EDSDK.EdsSendStatusCommand(MainCamera.Ref, EDSDK.CameraState_UILock, 0);
- else Error = EDSDK.EdsSendStatusCommand
- (MainCamera.Ref, EDSDK.CameraState_UIUnLock, 0);
- }
利用图形化界面
在图像化界面向导代码中,你可以看到如何将以上所有的代码运用到一个真实可用的软件中。你也可以设置 Av,Tv,ISO和白平衡,实时取景和拍照等模式.
插入相机,打开图形化界面就可以开始你的设置啦。
题外话
我用EOS 40D测试了以上代码:
如果你尝试了不同的方法,请告诉我,我会把它添加到这篇文章中。
如果你发现一些bug,对方法有改进或者有一些新的想法,非常希望你能告诉我。
源码下载:
佳能相机操作 EDSDK 教程 C# 版本的更多相关文章
- agentzh 的 Nginx 教程(版本 2019.07.31)
agentzh 的 Nginx 教程(版本 2019.07.31) agentzh 的 Nginx 教程(版本 2019.07.31) https://openresty.org/download/a ...
- Git安装教程最新版本(国内gitee国外github)
Git安装教程最新版本(国内gitee国外github) 欢迎关注博主公众号「Java大师」, 专注于分享Java领域干货文章, 关注回复「资源」, 获取大师使用的typora主题: http://w ...
- 安装MYSQL详细教程 版本:mysql-installer-community-5.7.16.0 免安装版本和安装版本出现错误的解决
一.版本的选择 之前安装的Mysql,现在才来总结,好像有点晚,后台换系统了,现在从新装上Mysql,感觉好多坑,我是来踩坑,大家看到坑就别跳了,这样可以省点安装时间,这个折腾了两天,安装了好多个版本 ...
- Git教程之版本回退(4)
现在,我们已经学会了修改文件,然后把修改提交到Git版本库,现在再次修改readme.txt文件如下:
- git教程--git版本库的使用
向版本控制器提交文件 我们已经成功地添加并提交了一个readme.txt文件,现在,是时候继续工作了,于是,我们继续修改readme.txt文件,改成如下内容: Git is a distribute ...
- git教程:版本退回
转载:版本回退 现在,你已经学会了修改文件,然后把修改提交到Git版本库,现在,再练习一次,修改readme.txt文件如下: Git is a distributed version control ...
- Git 基础教程 之 版本回退
不断对文件进行修改,然后不断提交修改到版本库里. 当你觉得文件修改到一定程度时,可以保存一个“快照”,这个“快照”在Git中称为“commit”. 一旦文件被改乱了.误删了,都可以从最近一个“comm ...
- [SpringCloud教程]2. 版本选型和项目搭建
Spring Cloud Alibaba 版本选型 建议先选择Spring Cloud Alibaba的大版本,方便兼容 选择 Spring Cloud Alibaba 大版本 访问链接,找到标题&q ...
- VirtualBox安装Ubuntu教程
1.VirtualBox虚拟机安装,及VirtualBox安装Ubuntu教程VirtualBox版本为VirtualBox-4.3.12-93733-Win.exe,Ubuntu版本为ubuntu- ...
随机推荐
- Windows Azure 系列-- Azure Redis Cache的配置和使用
假设还没有配置Azure Power shell 能够參照这里进行配置:http://blog.csdn.net/lan_liang/article/details/46850221 打开Azure ...
- flume A simple example
http://flume.apache.org/FlumeUserGuide.html A simple example
- GNU_MAKE--工程管理
GNU MAKE--工程管理 makefile是为工程组织编译,为“自动化编译”,一旦写成,只需要一个make命令,整个工程完全自动编译,极大提高了软件开发效率.make是一个命令工具,是一个解释ma ...
- MongoDb数据结构详解
首先,向数据库插入一条bjson数据 首先是定义文档,然后使用admin用户名密码登录,进入test数据库,向test数据库中插入此文档(“表名称和表中的记录”) 插入结果,查看mongoVUE如下图 ...
- 【spring boot】在spring boot下使用多线程
使用场景: 方法处理到某一步,需要将信息交给另一个线程去处理!! =================================================================== ...
- TextFlow with JavaFX 2
http://sahits.ch/blog/?p=2372 ———————————————————————————————————————————————————— TextFlow with Jav ...
- OC 基础语法
:Obect c 与 c 语言的区别 () 后缀名不一样,C语言是.c 结尾 ,OC 是 .h结尾. () 输出信息不同 C语言是用print() 输出,OC 是用NSLog输出. () NSLog会 ...
- haml入门
1.什么是Haml Haml是HTML abstraction markup language,遵循的原则是标记应该是美的.Haml能够加速和简化模版,长处是简洁.可读.高效. 2.erbm模板和ha ...
- Android开发:使用DialogFragment实现dialog自定义布局
使用DialogFragment实现dialog的自定义布局最大的好处是可以更好控制dialog的生命周期. TestFragment的代码: public class TestFragment ex ...
- codevs2894、2837、1669、2503、3231
6.25动态规划之背包回顾 2894 Txx考试 时间限制: 1 s 空间限制: 32000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description Txx是一个 ...