using System;
using System.Runtime.InteropServices;
using System.Text;
namespace AutoFocusTool.Camera
{
///
/// Microview MVC2000 相机封装。精简自原工程 aivfo_ccd\Util\Camera.cs +
/// ivf_tl_CameraHelper\Camera.cs,只保留自动对焦测试程序需要的能力:
/// 连接 / 采集模式 / 抓单帧 / 调曝光增益 / 取像素 / 转 WPF 位图 / 序列号。
///
/// 重要:所有原生调用用同一把锁串行化(SDK 非线程安全)。
/// 多舱室共用同一 SDK,跨相机操作也走这把全局锁。
///
public class Camera : IDisposable
{
private static readonly object Locker = new object();
private readonly int _width;
private readonly int _height;
private int _index;
private int _exposure;
private CapInfoStruct _capInfo;
private IntPtr _hImager; // MV_Usb2Init 返回的设备句柄
private IntPtr _pDest; // RGB 输出缓冲(width*height*3)
public int Index => _index;
public int Width => _width;
public int Height => _height;
public int Exposure => _exposure;
public string SerialNumber { get; private set; } = "";
public bool IsInit { get; private set; }
public bool IsStart { get; private set; }
/// 相机枚举索引 0..9(MV_Usb2Init 用)
/// 分辨率宽,默认 1600
/// 分辨率高,默认 1200
/// 曝光时间,单位 100us
public Camera(int index, int width = 1600, int height = 1200, int exposure = 400)
{
_index = index;
_width = width;
_height = height;
_exposure = exposure;
_pDest = Marshal.AllocCoTaskMem(_width * _height * 3);
}
/// 初始化相机。执行后需立即 SetOpMode 才能抓图。返回 0 成功。
public int Init(byte redGain = 25, byte greenGain = 14, byte blueGain = 25)
{
_capInfo.Buffer = Marshal.AllocCoTaskMem(_width * _height * 3);
_capInfo.Width = _width;
_capInfo.Height = _height;
_capInfo.HorizontalOffset = 0;
_capInfo.VerticalOffset = 0;
_capInfo.Exposure = _exposure;
_capInfo.Gain = new byte[] { redGain, greenGain, blueGain };
_capInfo.Control = 0x04;
_capInfo.Reserved = new byte[8];
int result;
lock (Locker)
{
result = MVCAPI.MV_Usb2Init("MVC2000", out _index, ref _capInfo, out _hImager);
}
IsInit = result == 0;
return result;
}
/// 设置采集模式:0=拍照(单帧,对焦用),1=实时图像。返回 0 成功。
public int SetOpMode(byte mode = 0, bool strobe = false)
{
if (!IsInit) return -1;
int result;
lock (Locker)
{
result = MVCAPI.MV_Usb2SetOpMode(_hImager, mode, strobe);
}
IsStart = result == 0;
return result;
}
/// 读相机序列号到 SerialNumber。返回 0 成功。
public int ReadSerial()
{
try
{
lock (Locker)
{
var sb = new StringBuilder(125);
int r = MVCAPI.MV_Usb2GetSerial(_hImager, sb);
SerialNumber = sb.ToString();
return r;
}
}
catch { return -2; }
}
/// 抓取一帧 RGB 到内部缓冲。返回 0 成功,之后用 GetSourceBuffer / GetBitmapSource 取。
public int GrabRgb()
{
if (!IsStart) return -1;
lock (Locker)
{
return MVCAPI.MV_Usb2GetRgbData(_hImager, ref _capInfo, _pDest);
}
}
/// 设置曝光时间(单位 100us)。返回 0 成功。
public int SetExposure(int exposure100us)
{
_exposure = exposure100us;
_capInfo.Exposure = exposure100us;
lock (Locker)
{
return MVCAPI.MV_Usb2SetPartOfCapInfo(_hImager, ref _capInfo);
}
}
/// 设置 RGB 三通道增益(0-255)。返回 0 成功。
public int SetGain(byte red, byte green, byte blue)
{
if (_capInfo.Gain == null) _capInfo.Gain = new byte[3];
_capInfo.Gain[0] = red;
_capInfo.Gain[1] = green;
_capInfo.Gain[2] = blue;
lock (Locker)
{
return MVCAPI.MV_Usb2SetPartOfCapInfo(_hImager, ref _capInfo);
}
}
/// 取当前帧像素(24bpp BGR,width*height*3 字节,未翻转)。
public byte[] GetSourceBuffer()
{
byte[] buf = new byte[_width * _height * 3];
Marshal.Copy(_pDest, buf, 0, buf.Length);
return buf;
}
/// 卸载相机。
public int UnInit()
{
int result = 0;
lock (Locker)
{
if (_hImager != IntPtr.Zero)
result = MVCAPI.MV_Usb2Uninit(ref _hImager);
}
IsInit = false;
IsStart = false;
return result;
}
public void Dispose()
{
try { UnInit(); } catch { }
if (_pDest != IntPtr.Zero) { Marshal.FreeCoTaskMem(_pDest); _pDest = IntPtr.Zero; }
if (_capInfo.Buffer != IntPtr.Zero) { Marshal.FreeCoTaskMem(_capInfo.Buffer); _capInfo.Buffer = IntPtr.Zero; }
}
}
}