/* * Copyright (C) 2009-2012 Samuel Audet * * 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.Loader; import static org.bytedeco.javacpp.opencv_core.*; import static org.bytedeco.javacpp.opencv_imgproc.*; import static org.bytedeco.javacpp.PGRFlyCapture.*; /** * * @author Samuel Audet */ public class FlyCaptureFrameGrabber extends FrameGrabber { public static String[] getDeviceDescriptions() throws Exception { tryLoad(); int[] count = new int[1]; int error = flycaptureBusCameraCount(count); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureBusCameraCount() Error " + error); } int c = count[0]; String[] descriptions = new String[c]; if (c > 0) { FlyCaptureInfoEx info = new FlyCaptureInfoEx(c); error = flycaptureBusEnumerateCamerasEx(info, count); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureBusEnumerateCamerasEx() Error " + error); } for (int i = 0; i < descriptions.length; i++) { info.position(i); descriptions[i] = info.pszVendorName() + " " + info.pszModelName() + " " + info.SerialNumber(); } } return descriptions; } public static FlyCaptureFrameGrabber createDefault(File deviceFile) throws Exception { throw new Exception(FlyCaptureFrameGrabber.class + " does not support device files."); } public static FlyCaptureFrameGrabber createDefault(String devicePath) throws Exception { throw new Exception(FlyCaptureFrameGrabber.class + " does not support device paths."); } public static FlyCaptureFrameGrabber createDefault(int deviceNumber) throws Exception { return new FlyCaptureFrameGrabber(deviceNumber); } private static Exception loadingException = null; public static void tryLoad() throws Exception { if (loadingException != null) { throw loadingException; } else { try { Loader.load(org.bytedeco.javacpp.PGRFlyCapture.class); } catch (Throwable t) { throw loadingException = new Exception("Failed to load " + FlyCaptureFrameGrabber.class, t); } } } public FlyCaptureFrameGrabber(int deviceNumber) throws Exception { int error = flycaptureCreateContext(context); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureCreateContext() Error " + error); } error = flycaptureInitializePlus(context, deviceNumber, numBuffers, (BytePointer)null); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureInitialize() Error " + error); } } public void release() throws Exception { if (context != null) { stop(); int error = flycaptureDestroyContext(context); context = null; if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureDestroyContext() Error " + error); } } } @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 FlyCaptureContext context = new FlyCaptureContext(null); private FlyCaptureImage raw_image = new FlyCaptureImage(); private FlyCaptureImage conv_image = new FlyCaptureImage(); 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 (context == null || context.isNull()) { return super.getFrameRate(); } else { flycaptureGetCameraAbsProperty(context, FLYCAPTURE_FRAME_RATE, outFloat); return outFloat[0]; } } @Override public void setImageMode(ImageMode imageMode) { if (imageMode != this.imageMode) { temp_image = null; return_image = null; } super.setImageMode(imageMode); } public void start() throws Exception { int f = FLYCAPTURE_FRAMERATE_ANY; if (frameRate <= 0) { f = FLYCAPTURE_FRAMERATE_ANY; } else if (frameRate <= 1.876) { f = FLYCAPTURE_FRAMERATE_1_875; } else if (frameRate <= 3.76) { f = FLYCAPTURE_FRAMERATE_3_75; } else if (frameRate <= 7.51) { f = FLYCAPTURE_FRAMERATE_7_5; } else if (frameRate <= 15.01) { f = FLYCAPTURE_FRAMERATE_15; } else if (frameRate <= 30.01) { f = FLYCAPTURE_FRAMERATE_30; } else if (frameRate <= 60.01) { f = FLYCAPTURE_FRAMERATE_60; } else if (frameRate <= 120.01) { f = FLYCAPTURE_FRAMERATE_120; } else if (frameRate <= 240.01) { f = FLYCAPTURE_FRAMERATE_240; } int c = FLYCAPTURE_VIDEOMODE_ANY; if (imageMode == ImageMode.COLOR || imageMode == ImageMode.RAW) { if (imageWidth <= 0 || imageHeight <= 0) { c = FLYCAPTURE_VIDEOMODE_ANY; } else if (imageWidth <= 640 && imageHeight <= 480) { c = FLYCAPTURE_VIDEOMODE_640x480RGB; } else if (imageWidth <= 800 && imageHeight <= 600) { c = FLYCAPTURE_VIDEOMODE_800x600RGB; } else if (imageWidth <= 1024 && imageHeight <= 768) { c = FLYCAPTURE_VIDEOMODE_1024x768RGB; } else if (imageWidth <= 1280 && imageHeight <= 960) { c = FLYCAPTURE_VIDEOMODE_1280x960RGB; } else if (imageWidth <= 1600 && imageHeight <= 1200) { c = FLYCAPTURE_VIDEOMODE_1600x1200RGB; } } else if (imageMode == ImageMode.GRAY) { if (imageWidth <= 0 || imageHeight <= 0) { c = FLYCAPTURE_VIDEOMODE_ANY; } else if (imageWidth <= 640 && imageHeight <= 480) { c = bpp > 8 ? FLYCAPTURE_VIDEOMODE_640x480Y16 : FLYCAPTURE_VIDEOMODE_640x480Y8; } else if (imageWidth <= 800 && imageHeight <= 600) { c = bpp > 8 ? FLYCAPTURE_VIDEOMODE_800x600Y16 : FLYCAPTURE_VIDEOMODE_800x600Y8; } else if (imageWidth <= 1024 && imageHeight <= 768) { c = bpp > 8 ? FLYCAPTURE_VIDEOMODE_1024x768Y16 : FLYCAPTURE_VIDEOMODE_1024x768Y8; } else if (imageWidth <= 1280 && imageHeight <= 960) { c = bpp > 8 ? FLYCAPTURE_VIDEOMODE_1280x960Y16 : FLYCAPTURE_VIDEOMODE_1280x960Y8; } else if (imageWidth <= 1600 && imageHeight <= 1200) { c = bpp > 8 ? FLYCAPTURE_VIDEOMODE_1600x1200Y16 : FLYCAPTURE_VIDEOMODE_1600x1200Y8; } } // set or reset trigger mode int[] iPolarity = new int[1]; int[] iSource = new int[1]; int[] iRawValue = new int[1]; int[] iMode = new int[1]; int error = flycaptureGetTrigger(context, (boolean[])null, iPolarity, iSource, iRawValue, iMode, null); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureGetTrigger() Error " + error); } error = flycaptureSetTrigger(context, triggerMode, iPolarity[0], 7, 14, 0); if (error != FLYCAPTURE_OK) { // try with trigger mode 0 instead error = flycaptureSetTrigger(context, true, iPolarity[0], 7, 0, 0); } if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureSetTrigger() Error " + error); } if (triggerMode) { waitForTriggerReady(); } // try to match the endianness to our platform error = flycaptureGetCameraRegister(context, IMAGE_DATA_FORMAT, regOut); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureGetCameraRegister() Error " + error); } int reg; if (ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN)) { reg = regOut[0] | 0x1; } else { reg = regOut[0] & ~0x1; } error = flycaptureSetCameraRegister(context, IMAGE_DATA_FORMAT, reg); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureSetCameraRegister() Error " + error); } error = flycaptureSetBusSpeed(context, FLYCAPTURE_S_FASTEST, FLYCAPTURE_S_FASTEST); if (error != FLYCAPTURE_OK) { error = flycaptureSetBusSpeed(context, FLYCAPTURE_ANY, FLYCAPTURE_ANY); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureSetBusSpeed() Error " + error); } } if (gamma != 0.0) { error = flycaptureSetCameraAbsProperty(context, FLYCAPTURE_GAMMA, (float)gamma); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureSetCameraAbsProperty() Error " + error + ": Could not set gamma."); } } error = flycaptureGetCameraAbsProperty(context, FLYCAPTURE_GAMMA, gammaOut); if (error != FLYCAPTURE_OK) { gammaOut[0] = 2.2f; } error = flycaptureStart(context, c, f); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureStart() Error " + error); } error = flycaptureSetGrabTimeoutEx(context, timeout); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureSetGrabTimeoutEx() Error " + error); } } private void waitForTriggerReady() throws Exception { // wait for trigger to be ready... long time = System.currentTimeMillis(); do { int error = flycaptureGetCameraRegister(context, SOFTWARE_TRIGGER, regOut); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureGetCameraRegister() Error " + error); } if (System.currentTimeMillis() - time > timeout) { break; //throw new Exception("waitForTriggerReady() Error: Timeout occured."); } } while((regOut[0] >>> 31) != 0); } public void stop() throws Exception { int error = flycaptureStop(context); if (error != FLYCAPTURE_OK && error != FLYCAPTURE_FAILED) { throw new Exception("flycaptureStop() Error " + error); } temp_image = null; return_image = null; timestamp = 0; frameNumber = 0; } public void trigger() throws Exception { waitForTriggerReady(); int error = flycaptureSetCameraRegister(context, SOFT_ASYNC_TRIGGER, 0x80000000); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureSetCameraRegister() Error " + error); } } private int getNumChannels(int pixelFormat) { switch (pixelFormat) { case FLYCAPTURE_BGR: case FLYCAPTURE_RGB8: case FLYCAPTURE_RGB16: case FLYCAPTURE_S_RGB16: return 3; case FLYCAPTURE_MONO8: case FLYCAPTURE_MONO16: case FLYCAPTURE_RAW8: case FLYCAPTURE_RAW16: case FLYCAPTURE_S_MONO16: return 1; case FLYCAPTURE_BGRU: return 4; case FLYCAPTURE_411YUV8: case FLYCAPTURE_422YUV8: case FLYCAPTURE_444YUV8: default: return -1; } } private int getDepth(int pixelFormat) { switch (pixelFormat) { case FLYCAPTURE_BGR: case FLYCAPTURE_RGB8: case FLYCAPTURE_MONO8: case FLYCAPTURE_RAW8: case FLYCAPTURE_BGRU: return IPL_DEPTH_8U; case FLYCAPTURE_MONO16: case FLYCAPTURE_RAW16: case FLYCAPTURE_RGB16: return IPL_DEPTH_16U; case FLYCAPTURE_S_MONO16: case FLYCAPTURE_S_RGB16: return IPL_DEPTH_16S; case FLYCAPTURE_411YUV8: case FLYCAPTURE_422YUV8: case FLYCAPTURE_444YUV8: default: return IPL_DEPTH_8U; } } public Frame grab() throws Exception { int error = flycaptureGrabImage2(context, raw_image); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureGrabImage2() Error " + error + " (Has start() been called?)"); } int w = raw_image.iCols(); int h = raw_image.iRows(); int format = raw_image.pixelFormat(); int depth = getDepth(format); int stride = raw_image.iRowInc(); int size = h*stride; int numChannels = getNumChannels(format); error = flycaptureGetCameraRegister(context, IMAGE_DATA_FORMAT, regOut); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureGetCameraRegister() Error " + error); } ByteOrder frameEndian = (regOut[0] & 0x1) != 0 ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; boolean alreadySwapped = false; boolean colorbayer = raw_image.bStippled(); boolean colorrgb = format == FLYCAPTURE_RGB8 || format == FLYCAPTURE_RGB16 || format == FLYCAPTURE_BGR || format == FLYCAPTURE_BGRU; boolean coloryuv = format == FLYCAPTURE_411YUV8 || format == FLYCAPTURE_422YUV8 || format == FLYCAPTURE_444YUV8; BytePointer imageData = raw_image.pData(); if ((depth == IPL_DEPTH_8U || frameEndian.equals(ByteOrder.nativeOrder())) && (imageMode == ImageMode.RAW || (imageMode == ImageMode.COLOR && numChannels == 3) || (imageMode == 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 == ImageMode.COLOR ? 3 : 1); } if (temp_image == null) { if (imageMode == ImageMode.COLOR && (numChannels > 1 || depth > 8) && !coloryuv && !colorbayer) { temp_image = IplImage.create(w, h, depth, numChannels); } else if (imageMode == ImageMode.GRAY && colorbayer) { temp_image = IplImage.create(w, h, depth, 3); } else if (imageMode == ImageMode.GRAY && colorrgb) { temp_image = IplImage.createHeader(w, h, depth, 3); } else if (imageMode == ImageMode.COLOR && numChannels == 1 && !coloryuv && !colorbayer) { temp_image = IplImage.createHeader(w, h, depth, 1); } else { temp_image = return_image; } } conv_image.iRowInc(temp_image.widthStep()); conv_image.pData(temp_image.imageData()); if (depth == IPL_DEPTH_8U) { conv_image.pixelFormat(imageMode == ImageMode.RAW ? FLYCAPTURE_RAW8 : temp_image.nChannels() == 1 ? FLYCAPTURE_MONO8 : FLYCAPTURE_BGR); } else { conv_image.pixelFormat(imageMode == ImageMode.RAW ? FLYCAPTURE_RAW16 : temp_image.nChannels() == 1 ? FLYCAPTURE_MONO16 : FLYCAPTURE_RGB16); } if (depth != IPL_DEPTH_8U && conv_image.pixelFormat() == format && conv_image.iRowInc() == stride) { // we just need a copy to swap bytes.. ShortBuffer in = raw_image.getByteBuffer().order(frameEndian).asShortBuffer(); ShortBuffer out = temp_image.getByteBuffer().order(ByteOrder.nativeOrder()).asShortBuffer(); out.put(in); alreadySwapped = true; } else if ((imageMode == ImageMode.GRAY && colorrgb) || (imageMode == 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 = flycaptureConvertImage(context, raw_image, conv_image); if (error != FLYCAPTURE_OK) { throw new Exception("flycaptureConvertImage() 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 == ImageMode.COLOR && numChannels == 1 && !coloryuv && !colorbayer) { cvCvtColor(temp_image, return_image, CV_GRAY2BGR); } else if (imageMode == ImageMode.GRAY && (colorbayer || colorrgb)) { cvCvtColor(temp_image, return_image, CV_BGR2GRAY); } } error = flycaptureGetColorTileFormat(context, regOut); if (error != FLYCAPTURE_OK) { sensorPattern = -1L; } else switch (regOut[0]) { case FLYCAPTURE_STIPPLEDFORMAT_BGGR: sensorPattern = SENSOR_PATTERN_BGGR; break; case FLYCAPTURE_STIPPLEDFORMAT_GBRG: sensorPattern = SENSOR_PATTERN_GBRG; break; case FLYCAPTURE_STIPPLEDFORMAT_GRBG: sensorPattern = SENSOR_PATTERN_GRBG; break; case FLYCAPTURE_STIPPLEDFORMAT_RGGB: sensorPattern = SENSOR_PATTERN_RGGB; break; default: sensorPattern = -1L; } FlyCaptureTimestamp timeStamp = raw_image.timeStamp(); timestamp = timeStamp.ulSeconds() * 1000000L + timeStamp.ulMicroSeconds(); return converter.convert(return_image); } }