/*
* Copyright (C) 2014,2017 Jeremy Laviole, Samuel Audet, Jarek Sacha
*
* Licensed either under the Apache License, Version 2.0, or (at your option)
* under the terms of the GNU General Public License as published by
* the Free Software Foundation (subject to the "Classpath" exception),
* either version 2, or any later version (collectively, the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.gnu.org/licenses/
* http://www.gnu.org/software/classpath/license.html
*
* or as provided in the LICENSE.txt file that accompanied this code.
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bytedeco.javacv;
import java.io.File;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import org.bytedeco.javacpp.BytePointer;
import org.bytedeco.javacpp.FlyCapture2;
import org.bytedeco.javacpp.IntPointer;
import org.bytedeco.javacpp.Loader;
import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_imgproc.*;
import org.bytedeco.javacpp.FlyCapture2.Error;
import static org.bytedeco.javacpp.FlyCapture2.*;
/**
*
* @author Jeremy Laviole
* @author Jarek Sacha
*/
public class FlyCapture2FrameGrabber extends FrameGrabber {
public static String[] getDeviceDescriptions() throws FrameGrabber.Exception {
tryLoad();
BusManager busMgr = new BusManager();
int[] numCameras = new int[1];
busMgr.GetNumOfCameras(numCameras);
String[] descriptions = new String[numCameras[0]];
for (int i = 0; i < numCameras[0]; i++) {
PGRGuid guid = new PGRGuid();
Error error = busMgr.GetCameraFromIndex(i, guid);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
System.exit(-1);
}
Camera cam = new Camera();
// Connect to a camera
error = cam.Connect(guid);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
}
// Get the camera information
CameraInfo camInfo = new CameraInfo();
error = cam.GetCameraInfo(camInfo);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
}
descriptions[i] = CameraInfo(camInfo);
}
return descriptions;
}
static void PrintError(Error error) {
error.PrintErrorTrace();
}
static String CameraInfo(CameraInfo pCamInfo) {
return "\n*** CAMERA INFORMATION ***\n"
+ "Serial number - " + pCamInfo.serialNumber() + "\n"
+ "Camera model - " + pCamInfo.modelName().getString() + "\n"
+ "Camera vendor - " + pCamInfo.vendorName().getString() + "\n"
+ "Sensor - " + pCamInfo.sensorInfo().getString() + "\n"
+ "Resolution - " + pCamInfo.sensorResolution().getString() + "\n"
+ "Firmware version - " + pCamInfo.firmwareVersion().getString() + "\n"
+ "Firmware build time - " + pCamInfo.firmwareBuildTime().getString() + "\n";
}
public static FlyCaptureFrameGrabber createDefault(File deviceFile) throws FrameGrabber.Exception {
return null;
}
public static FlyCaptureFrameGrabber createDefault(String devicePath) throws FrameGrabber.Exception {
return null;
}
public static FlyCaptureFrameGrabber createDefault(int deviceNumber) throws FrameGrabber.Exception {
return new FlyCaptureFrameGrabber(deviceNumber);
}
private static FrameGrabber.Exception loadingException = null;
public static void tryLoad() throws FrameGrabber.Exception {
if (loadingException != null) {
loadingException.printStackTrace();
throw loadingException;
} else {
try {
Loader.load(org.bytedeco.javacpp.FlyCapture2.class);
} catch (Throwable t) {
throw loadingException = new FrameGrabber.Exception("Failed to load " + FlyCapture2FrameGrabber.class, t);
}
}
}
public FlyCapture2FrameGrabber(int deviceNumber) throws FrameGrabber.Exception {
int[] numCameras = new int[1];
busMgr.GetNumOfCameras(numCameras);
// Get the camera
PGRGuid guid = new PGRGuid();
Error error = busMgr.GetCameraFromIndex(deviceNumber, guid);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
System.exit(-1);
}
camera = new Camera();
// Connect to a camera
error = camera.Connect(guid);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
}
// Get the camera information
cameraInfo = new CameraInfo();
error = camera.GetCameraInfo(cameraInfo);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
}
}
public void release() throws FrameGrabber.Exception {
if (camera != null) {
stop();
camera.Disconnect();
camera = null;
}
}
@Override
protected void finalize() throws Throwable {
super.finalize();
release();
}
public static final int INITIALIZE = 0x000,
TRIGGER_INQ = 0x530,
IS_CAMERA_POWER = 0x400,
CAMERA_POWER = 0x610,
SOFTWARE_TRIGGER = 0x62C,
SOFT_ASYNC_TRIGGER = 0x102C,
IMAGE_DATA_FORMAT = 0x1048;
private BusManager busMgr = new BusManager();
private Camera camera;
private CameraInfo cameraInfo;
private Image raw_image = new Image();
private Image conv_image = new Image();
private IplImage temp_image, return_image = null;
private FrameConverter converter = new OpenCVFrameConverter.ToIplImage();
private final int[] regOut = new int[1];
private final float[] outFloat = new float[1];
private final float[] gammaOut = new float[1];
@Override
public double getGamma() {
return Float.isNaN(gammaOut[0]) || Float.isInfinite(gammaOut[0]) || gammaOut[0] == 0.0f ? 2.2 : gammaOut[0];
}
@Override
public int getImageWidth() {
return return_image == null ? super.getImageWidth() : return_image.width();
}
@Override
public int getImageHeight() {
return return_image == null ? super.getImageHeight() : return_image.height();
}
@Override
public double getFrameRate() {
if (camera == null || camera.isNull()) {
return super.getFrameRate();
} else {
IntPointer videoMode = new IntPointer(1L);
IntPointer frameRate = new IntPointer(1L);
camera.GetVideoModeAndFrameRate(videoMode, frameRate);
return frameRate.get(0);
}
}
@Override
public void setImageMode(FrameGrabber.ImageMode imageMode) {
if (imageMode != this.imageMode) {
temp_image = null;
return_image = null;
}
super.setImageMode(imageMode);
}
static final int VIDEOMODE_ANY = -1;
public void start() throws FrameGrabber.Exception {
int f = FRAMERATE_30; // TODO: Default 30 ?
if (frameRate <= 0) {
f = FRAMERATE_30;
} else if (frameRate <= 1.876) {
f = FRAMERATE_1_875;
} else if (frameRate <= 3.76) {
f = FRAMERATE_3_75;
} else if (frameRate <= 7.51) {
f = FRAMERATE_7_5;
} else if (frameRate <= 15.01) {
f = FRAMERATE_15;
} else if (frameRate <= 30.01) {
f = FRAMERATE_30;
} else if (frameRate <= 60.01) {
f = FRAMERATE_60;
} else if (frameRate <= 120.01) {
f = FRAMERATE_120;
} else if (frameRate <= 240.01) {
f = FRAMERATE_240;
}
int c = VIDEOMODE_ANY;
if (imageMode == FrameGrabber.ImageMode.COLOR || imageMode == FrameGrabber.ImageMode.RAW) {
if (imageWidth <= 0 || imageHeight <= 0) {
c = VIDEOMODE_ANY;
} else if (imageWidth <= 640 && imageHeight <= 480) {
c = VIDEOMODE_640x480RGB;
} else if (imageWidth <= 800 && imageHeight <= 600) {
c = VIDEOMODE_800x600RGB;
} else if (imageWidth <= 1024 && imageHeight <= 768) {
c = VIDEOMODE_1024x768RGB;
} else if (imageWidth <= 1280 && imageHeight <= 960) {
c = VIDEOMODE_1280x960RGB;
} else if (imageWidth <= 1600 && imageHeight <= 1200) {
c = VIDEOMODE_1600x1200RGB;
}
} else if (imageMode == FrameGrabber.ImageMode.GRAY) {
if (imageWidth <= 0 || imageHeight <= 0) {
c = VIDEOMODE_ANY;
} else if (imageWidth <= 640 && imageHeight <= 480) {
c = bpp > 8 ? VIDEOMODE_640x480Y16 : VIDEOMODE_640x480Y8;
} else if (imageWidth <= 800 && imageHeight <= 600) {
c = bpp > 8 ? VIDEOMODE_800x600Y16 : VIDEOMODE_800x600Y8;
} else if (imageWidth <= 1024 && imageHeight <= 768) {
c = bpp > 8 ? VIDEOMODE_1024x768Y16 : VIDEOMODE_1024x768Y8;
} else if (imageWidth <= 1280 && imageHeight <= 960) {
c = bpp > 8 ? VIDEOMODE_1280x960Y16 : VIDEOMODE_1280x960Y8;
} else if (imageWidth <= 1600 && imageHeight <= 1200) {
c = bpp > 8 ? VIDEOMODE_1600x1200Y16 : VIDEOMODE_1600x1200Y8;
}
}
// set or reset trigger mode
TriggerMode tm = new TriggerMode();
Error error = camera.GetTriggerMode(tm);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("GetTriggerMode() Error " + error.GetDescription());
}
tm.onOff(triggerMode);
tm.source(7);
tm.mode(14);
tm.parameter(0);
error = camera.SetTriggerMode(tm);
if (error.notEquals(PGRERROR_OK)) {
// try with trigger mode 0 instead
tm.onOff(true);
tm.source(7);
tm.mode(0);
tm.parameter(0);
error = camera.SetTriggerMode(tm);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("SetTriggerMode() Error " + error.GetDescription());
}
}
if (triggerMode) {
waitForTriggerReady();
}
// try to match the endianness to our platform
error = camera.ReadRegister(IMAGE_DATA_FORMAT, regOut);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("ReadRegister(IMAGE_DATA_FORMAT, regOut) Error " + error.GetDescription());
}
int reg;
if (ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN)) {
reg = regOut[0] | 0x1;
} else {
reg = regOut[0] & ~0x1;
}
error = camera.WriteRegister(IMAGE_DATA_FORMAT, reg);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("WriteRegister(IMAGE_DATA_FORMAT, reg) Error " + error.GetDescription());
}
// TODO: set fastest bus speed ? This may lead to system instability. Use default.
// set `gamma`
Property gammaProp = new Property(FlyCapture2.GAMMA);
if (gamma != 0.0) {
error = camera.GetProperty(gammaProp);
if (error.notEquals(PGRERROR_OK)) {
throw new FrameGrabber.Exception("GetProperty(gammaProp) Error " + error.GetDescription());
}
gammaProp.onOff(true);
gammaProp.absControl(true);
gammaProp.absValue((float)gamma);
camera.SetProperty(gammaProp);
error = camera.SetProperty(gammaProp);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("SetProperty(gammaProp) Error " + error.GetDescription());
}
}
error = camera.GetProperty(gammaProp);
if (error.notEquals(PGRERROR_OK)) {
gammaOut[0] = 2.2f;
} else {
gammaOut[0] = gammaProp.absValue();
}
// set `timeout`
error = camera.StartCapture();
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("StartCapture() Error " + error.GetDescription());
}
// Get the camera configuration
FC2Config config = new FC2Config();
error = camera.GetConfiguration(config);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("GetConfiguration() Error " + error.GetDescription());
}
// Set the grab timeout to 5 seconds
config.grabTimeout(timeout);
// Set the camera configuration
error = camera.SetConfiguration(config);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("SetConfiguration() Error " + error.GetDescription());
}
}
private void waitForTriggerReady() throws Exception {
// wait for trigger to be ready...
long time = System.currentTimeMillis();
do {
Error error = camera.ReadRegister(SOFTWARE_TRIGGER, regOut);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("GetTriggerMode() Error " + error.GetDescription());
}
if (System.currentTimeMillis() - time > timeout) {
break;
//throw new Exception("waitForTriggerReady() Error: Timeout occured.");
}
} while((regOut[0] >>> 31) != 0);
}
public void stop() throws FrameGrabber.Exception {
Error error = camera.StopCapture();
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("flycapture camera StopCapture() Error " + error);
}
temp_image = null;
return_image = null;
timestamp = 0;
frameNumber = 0;
}
/**
* @throws org.bytedeco.javacv.FrameGrabber.Exception
*/
public void trigger() throws FrameGrabber.Exception {
waitForTriggerReady();
Error error = camera.FireSoftwareTrigger();
if (error.notEquals(PGRERROR_OK)) {
throw new FrameGrabber.Exception("flycaptureSetCameraRegister() Error " + error);
}
}
private int getNumChannels(int pixelFormat) {
switch (pixelFormat) {
case PIXEL_FORMAT_BGR:
case PIXEL_FORMAT_RGB8:
case PIXEL_FORMAT_RGB16:
case PIXEL_FORMAT_S_RGB16:
return 3;
case PIXEL_FORMAT_MONO8:
case PIXEL_FORMAT_MONO16:
case PIXEL_FORMAT_RAW8:
case PIXEL_FORMAT_RAW16:
case PIXEL_FORMAT_S_MONO16:
return 1;
case PIXEL_FORMAT_BGRU:
return 4;
case PIXEL_FORMAT_411YUV8:
case PIXEL_FORMAT_422YUV8:
case PIXEL_FORMAT_444YUV8:
default:
return -1;
}
}
private int getDepth(int pixelFormat) {
switch (pixelFormat) {
case PIXEL_FORMAT_BGR:
case PIXEL_FORMAT_RGB8:
case PIXEL_FORMAT_MONO8:
case PIXEL_FORMAT_RAW8:
case PIXEL_FORMAT_BGRU:
return IPL_DEPTH_8U;
case PIXEL_FORMAT_MONO16:
case PIXEL_FORMAT_RAW16:
case PIXEL_FORMAT_RGB16:
return IPL_DEPTH_16U;
case PIXEL_FORMAT_S_MONO16:
case PIXEL_FORMAT_S_RGB16:
return IPL_DEPTH_16S;
case PIXEL_FORMAT_411YUV8:
case PIXEL_FORMAT_422YUV8:
case PIXEL_FORMAT_444YUV8:
default:
return IPL_DEPTH_8U;
}
}
private void setPixelFormat(Image image, int pixelFormat) {
image.SetDimensions(image.GetRows(),
image.GetCols(),
image.GetStride(),
pixelFormat,
image.GetBayerTileFormat());
}
private void setStride(Image image, int stride) {
image.SetDimensions(image.GetRows(),
image.GetCols(),
stride,
image.GetPixelFormat(),
image.GetBayerTileFormat());
}
public Frame grab() throws FrameGrabber.Exception {
Error error = camera.RetrieveBuffer(raw_image);
if (error.notEquals(PGRERROR_OK)) {
throw new FrameGrabber.Exception("flycaptureGrabImage2() Error " + error + " (Has start() been called?)");
}
int w = raw_image.GetCols();
int h = raw_image.GetRows();
int format = raw_image.GetPixelFormat();
int depth = getDepth(format);
int stride = raw_image.GetStride();
int size = h * stride;
int numChannels = getNumChannels(format);
error = camera.ReadRegister(IMAGE_DATA_FORMAT, regOut);
if (error.notEquals(PGRERROR_OK)) {
throw new FrameGrabber.Exception("flycaptureGetCameraRegister() Error " + error);
}
ByteOrder frameEndian = (regOut[0] & 0x1) != 0
? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;
boolean alreadySwapped = false;
boolean colorbayer = raw_image.GetBayerTileFormat() != NONE;
boolean colorrgb = format == PIXEL_FORMAT_RGB8 || format == PIXEL_FORMAT_RGB16
|| format == PIXEL_FORMAT_BGR || format == PIXEL_FORMAT_BGRU;
boolean coloryuv = format == PIXEL_FORMAT_411YUV8 || format == PIXEL_FORMAT_422YUV8
|| format == PIXEL_FORMAT_444YUV8;
BytePointer imageData = raw_image.GetData().capacity(raw_image.GetDataSize());
if ((depth == IPL_DEPTH_8U || frameEndian.equals(ByteOrder.nativeOrder()))
&& (imageMode == FrameGrabber.ImageMode.RAW || (imageMode == FrameGrabber.ImageMode.COLOR && numChannels == 3)
|| (imageMode == FrameGrabber.ImageMode.GRAY && numChannels == 1 && !colorbayer))) {
if (return_image == null) {
return_image = IplImage.createHeader(w, h, depth, numChannels);
}
return_image.widthStep(stride);
return_image.imageSize(size);
return_image.imageData(imageData);
} else {
if (return_image == null) {
return_image = IplImage.create(w, h, depth, imageMode == FrameGrabber.ImageMode.COLOR ? 3 : 1);
}
if (temp_image == null) {
if (imageMode == FrameGrabber.ImageMode.COLOR
&& (numChannels > 1 || depth > 8) && !coloryuv && !colorbayer) {
temp_image = IplImage.create(w, h, depth, numChannels);
} else if (imageMode == FrameGrabber.ImageMode.GRAY && colorbayer) {
temp_image = IplImage.create(w, h, depth, 3);
} else if (imageMode == FrameGrabber.ImageMode.GRAY && colorrgb) {
temp_image = IplImage.createHeader(w, h, depth, 3);
} else if (imageMode == FrameGrabber.ImageMode.COLOR && numChannels == 1 && !coloryuv && !colorbayer) {
temp_image = IplImage.createHeader(w, h, depth, 1);
} else {
temp_image = return_image;
}
}
setStride(conv_image, temp_image.widthStep());
conv_image.SetData(temp_image.imageData(), temp_image.width() * temp_image.height() * temp_image.depth());
if (depth == IPL_DEPTH_8U) {
setPixelFormat(conv_image, imageMode == FrameGrabber.ImageMode.RAW ? PIXEL_FORMAT_RAW8
: temp_image.nChannels() == 1 ? PIXEL_FORMAT_MONO8 : PIXEL_FORMAT_BGR);
} else {
setPixelFormat(conv_image, imageMode == FrameGrabber.ImageMode.RAW ? PIXEL_FORMAT_RAW16
: temp_image.nChannels() == 1 ? PIXEL_FORMAT_MONO16 : PIXEL_FORMAT_RGB16);
}
if (depth != IPL_DEPTH_8U && conv_image.GetPixelFormat() == format && conv_image.GetStride() == stride) {
// we just need a copy to swap bytes..
ShortBuffer in = imageData.asByteBuffer().order(frameEndian).asShortBuffer();
ShortBuffer out = temp_image.getByteBuffer().order(ByteOrder.nativeOrder()).asShortBuffer();
out.put(in);
alreadySwapped = true;
} else if ((imageMode == FrameGrabber.ImageMode.GRAY && colorrgb)
|| (imageMode == FrameGrabber.ImageMode.COLOR && numChannels == 1 && !coloryuv && !colorbayer)) {
temp_image.widthStep(stride);
temp_image.imageSize(size);
temp_image.imageData(imageData);
} else if (!colorrgb && (colorbayer || coloryuv || numChannels > 1)) {
error = raw_image.Convert(conv_image);
// error = flycaptureConvertImage(context, raw_image, conv_image);
if (error.notEquals(PGRERROR_OK)) {
PrintError(error);
throw new FrameGrabber.Exception("raw_image.Convert Error " + error);
}
}
if (!alreadySwapped && depth != IPL_DEPTH_8U
&& !frameEndian.equals(ByteOrder.nativeOrder())) {
// ack, the camera's endianness doesn't correspond to our machine ...
// swap bytes of 16-bit images
ByteBuffer bb = temp_image.getByteBuffer();
ShortBuffer in = bb.order(frameEndian).asShortBuffer();
ShortBuffer out = bb.order(ByteOrder.nativeOrder()).asShortBuffer();
out.put(in);
}
if (imageMode == FrameGrabber.ImageMode.COLOR && numChannels == 1 && !coloryuv && !colorbayer) {
cvCvtColor(temp_image, return_image, CV_GRAY2BGR);
} else if (imageMode == FrameGrabber.ImageMode.GRAY && (colorbayer || colorrgb)) {
cvCvtColor(temp_image, return_image, CV_BGR2GRAY);
}
}
int bayerFormat = cameraInfo.bayerTileFormat();
switch (bayerFormat) {
case BGGR:
sensorPattern = SENSOR_PATTERN_BGGR;
break;
case GBRG:
sensorPattern = SENSOR_PATTERN_GBRG;
break;
case GRBG:
sensorPattern = SENSOR_PATTERN_GRBG;
break;
case RGGB:
sensorPattern = SENSOR_PATTERN_RGGB;
break;
default:
sensorPattern = -1L;
}
TimeStamp timeStamp = raw_image.GetTimeStamp();
timestamp = timeStamp.seconds() * 1000000L + timeStamp.microSeconds();
return converter.convert(return_image);
}
}