My approach to this was creating an abstract class CameraPointGreyCamera and two classes that inherit from it: Camera12PointGreyUSBFireWire and Camera3PointGreyGigE.
CameraPointGreyCamera has two abstract methods, void SetConfigurations() and dynamic NewCamera() (and a lot of other methods that implement what I want to do with the cameras).
Since the children need to use methods from their respective classes to set configurations, CameraPointGreyCamera has a protected dynamic camera variable.
The Camera constructorThis is likepart of the followingbase class code:
public abstract class PointGreyCamera : ICamera
{
// Dynamic because depending on the class that inherits it'll be a different type
protected Cameradynamic camera;
protected bool isCapturing;
protected ManagedBusManager busMgr;
private Bitmap cameraImage;
protected CameraMode cameraMode;
protected Resolution currentResolution;
protected float frameRate;
protected LmaFlipMode flipMode;
protected LmaRotationAngle rotationAngle;
private ImageDataArrivedHandler _imageDataHandler;
/// <summary>
/// Will be called every frame with the byte[] imageData
/// </summary>
public ImageDataArrivedHandler ImageDataHandler
{
get { return _imageDataHandler; }
set
{
_imageDataHandler = value;
// Only one handler must be active, so if this is being activated, disable the other
if (value != null)
_imageHandler = null;
}
}
private ImageArrivedHandler _imageHandler;
/// <summary>
/// Will be called every frame with the Bitmap
/// </summary>
public ImageArrivedHandler ImageHandler
{
get { return _imageHandler; }
set
{
_imageHandler = value;
// Only one handler must be active, so if this is being activated, disable the other
if (value != null)
_imageDataHandler = null;
}
}
/// <summary>
/// Initializes variables and camera via index.
/// </summary>
/// <param name="index">Camera to be initialized</param>
protected PointGreyCamera(uint index)
{
isCapturing = false;
camera = NewCamera();
busMgr = new ManagedBusManager();
InitializeCamera(index);
}
/// <summary>
/// Initializes variables and camera via serial number.
/// </summary>
/// <param name="serialNumber">Camera serial</param>
protected PointGreyCamera(string serialNumber)
{
isCapturing = false;
camera = NewCamera();
busMgr = new ManagedBusManager();
InitializeCamera(serialNumber);
}
/// <summary>
/// Set camera configurations and, if continuous mode is selected, starts capturing.
/// </summary>
/// <param name="mode">Continuous/Trigger</param>
/// <param name="resolution">Width x Height</param>
/// <param name="rotation">Rotation angle</param>
/// <param name="flip">Flip enabled/disabled</param>
public abstract void SetConfigurations(CameraMode mode, Resolution resolution, LmaRotationAngle rotation, LmaFlipMode flip);
/// <summary>
/// Initialize camera dynamically
/// </summary>
protected abstract dynamic NewCamera();
/// <summary>
/// When there is a new frame, the API will call this handler.
/// If there is an active external handler, call it. If not, update the last image.
/// </summary>
/// <param name="image">New frame</param>
private void ManagedImageHandler(ManagedImage image)
{
// If there is no handler, just store the last image so it can be acessed via getters
cameraImage = Processing.RotateImage(image.bitmap, rotationAngle);
if (ImageDataHandler != null)
ImageDataHandler?.Invoke(Conversion.ToByteArray(cameraImage));
else if (ImageHandler != null)
ImageHandler?.Invoke(cameraImage);
}
public byte[] GetImageData()
{
if (ImageDataHandler != null || ImageHandler != null)
throw new HandlerActiveException("There is an active handler for receiving images. " +
"Therefore, GetImageData() and GetImage() are disabled.");
return cameraImage == null ? null : Conversion.ToByteArray(cameraImage);
}
public Bitmap GetImage()
{
if (ImageDataHandler != null || ImageHandler != null)
throw new HandlerActiveException("There is an active handler for receiving images. " +
"Therefore, GetImageData() and GetImage() are disabled.");
return cameraImage;
}
public Resolution GetResolution()
{
return currentResolution;
}
public CameraInformation GetCameraInformation()
{
CameraInfo info = camera.GetCameraInfo();
return new CameraInformation()
{
Model = info.modelName,
Serial = info.serialNumber.ToString(),
Type = LmaConversion.ToCameraType(info.interfaceType),
Resolutions = GetAvailableResolutions(info)
};
}
public void StartCapture() { ... }
public void SetFPS() { ... }
// ....
where NewCamera() will just return a new instanceAnd one of the API class relative to the camera in question, e.gclasses that inherit from it.
public class PointGreyGige : PointGreyCamera
{
public PointGreyGige(uint index) : base(index) { }
public PointGreyGige(string serialNumber) : base(serialNumber) { }
protected override dynamic NewCamera()
{
return new ManagedGigECamera();
}
public override void SetConfigurations(CameraMode mode, Resolution resolution, LmaRotationAngle rotation, LmaFlipMode flip)
{
// Camera12The implementationmethods called here that don't appear are implemented in the base class
StopCapture();
SetImagingMode(resolution);
SetImagingSettings();
currentResolution = resolution;
SetFPS();
rotationAngle = rotation;
FlipImage(flip);
ConfigureModeAndStartCapturing(mode);
DisableAutomaticGainAndShutter();
}
private void SetImagingSettings()
{
return GigEImageSettingsInfo settingsInfo = camera.GetGigEImageSettingsInfo();
var camerasSettings = new ManagedCameraGigEImageSettings()
{
offsetX = 0,
offsetY = 0,
width = settingsInfo.maxWidth,
height = settingsInfo.maxHeight,
pixelFormat = PixelFormat.PixelFormatMono8
};
camera.SetGigEImageSettings(camerasSettings);
}
private void SetImagingMode(Resolution resolution)
{
Mode format7Mode = Mode.Mode0;
var maxResolution = new Resolution(camera.GetCameraInfo().sensorResolution);
var secondResolution = new Resolution(maxResolution.Width / 2, maxResolution.Height / 2);
if (resolution.Equals(maxResolution))
format7Mode = Mode.Mode0;
else if (resolution.Equals(secondResolution))
format7Mode = Mode.Mode2;
else
throw new ArgumentException("Resolution is not supported.", nameof(resolution));
camera.SetGigEImagingMode(format7Mode);
}
}
The duplication I'm trying to avoid is of those public methods in `PointGreyCamera`, since they are the same for any kind of camera. But to have a base class, it seems I need this dynamic field. I have a couple questions about this:
and the children's constructor will just call the base constructor.
I have a couple questions about this:EDIT:
The duplication that I'm trying to avoid is of what I called
a lot of other methods that implement what I want to do with the
cameras
I understand it is very general and abstract but the problem is not within those methods.
What I meant is that I want to avoid having these methods duplicated in two different classes, namely Camera12 and Camera3. My solution to this is having a base class with these methods, but then it has to have dynamic fields, as explained above.
Maybe I misunderstood this stack? I want my approach to be reviewed, not some specific chunk of code.