org.bytedeco.javacv.PS3EyeFrameGrabber Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javacv Show documentation
Show all versions of javacv Show documentation
Java interface to OpenCV and more
/*
* Copyright (C) 2011-2012 Jiri Masa, 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 cl.eye.CLCamera;
import java.io.File;
import java.lang.reflect.Field;
import sun.misc.Unsafe;
import static org.bytedeco.javacpp.opencv_core.*;
import static org.bytedeco.javacpp.opencv_imgproc.*;
/** Minimal Sony PS3 Eye camera grabber implementation.
*
* It allows grabbing of frames at higher speed than OpenCVFrameGrabber or VideoInputFrameGrabber.
* Underlying implementation of last two grabbers is limited to 30 FPS. PS3 allows grabbing
* at maximum speed of 75 FPS in VGA and 187 FPS in QVGA modes.
*
* This code was developed and tested with CLEyeMulticam.dll, version 1.2.0.1008. The dll library
* is part of Code Laboratories CL-Eye Platform SDK and is distributed as part of CLEyeMulticam
* Redistributable Dynamic Link Library. For license, download and installation see http://www.codelaboratories.com.
*
* The grab() method returns an internal instance of IplImage image with fresh camera frame. This returned image
* have to be considered "read only" and the caller needs to create it's own copy or clone that image.
* Calling of release() method for this image shall be avoided.
* Based on used resolution the image is in format either 640x480 or 320x240, IPL_DEPTH_8U, 4 channel (color) or 1 channel (gray).
* timestamp is set to actual value of System.nanoTime()/1000 obtained after return from the CL driver.
*
* Typical use case scenario:
* create new instance of PS3MiniGrabber
* set camera parameters
* start() grabber
* wait at least 2 frames
* grab() in loop
* stop() grabber
* release() internal resources
*
* Note:
* This code depends on the cl.eye.CLCamera class from Code Laboratories CL-Eye
* Platform SDK. It is suggested to download SDK and edit the sample file
* ....\cl\eye\CLCamera.java. A few references to processing.core.PApplet class
* shall be removed and the file recompiled. The tailored file is not included
* here namely because of unclear licence.
*
* @author jmasa, [email protected]
*
*/
public class PS3EyeFrameGrabber extends FrameGrabber {
public static String[] getDeviceDescriptions() throws Exception {
tryLoad();
String[] descriptions = new String[CLCamera.cameraCount()];
for (int i = 0; i < descriptions.length; i++) {
descriptions[i] = CLCamera.cameraUUID(i);
}
return descriptions;
}
public static PS3EyeFrameGrabber createDefault(File deviceFile) throws Exception { throw new Exception(PS3EyeFrameGrabber.class + " does not support device files."); }
public static PS3EyeFrameGrabber createDefault(String devicePath) throws Exception { throw new Exception(PS3EyeFrameGrabber.class + " does not support device paths."); }
public static PS3EyeFrameGrabber createDefault(int deviceNumber) throws Exception { return new PS3EyeFrameGrabber(deviceNumber); }
private static Exception loadingException = null;
public static void tryLoad() throws Exception {
if (loadingException != null) {
throw loadingException;
} else {
try {
CLCamera.IsLibraryLoaded();
} catch (Throwable t) {
throw loadingException = new Exception("Failed to load " + PS3EyeFrameGrabber.class, t);
}
}
}
CLCamera camera;
int cameraIndex = 0;
int[] ps3_frame = null; // buffer for PS3 camera frame data
byte[] ipl_frame = null; // buffer for RGB-3ch, not allocated unless grab_RGB3() is called
IplImage image_4ch = null;
IplImage image_1ch = null;
FrameConverter converter = new OpenCVFrameConverter.ToIplImage();
String stat; // status of PS3 camera handling - mostly for debugging
String uuid; // assigned camera unique key
// variables for trigger() implementation
//
protected enum Triggered {NO_TRIGGER, HAS_FRAME, NO_FRAME};
protected Triggered triggered = Triggered.NO_TRIGGER;
/** Default grabber, camera idx = 0, color mode, VGA resolution, 60 FPS frame rate.
*
*/
public PS3EyeFrameGrabber() throws Exception {
this(0);
}
/** Color mode, VGA resolution, 60 FPS frame rate.
* @param system wide camera index
*/
public PS3EyeFrameGrabber(int cameraIndex) throws Exception {
this(cameraIndex, 640, 480, 60);
}
public PS3EyeFrameGrabber(int cameraIndex, int imageWidth, int imageHeight, int framerate) throws Exception {
this(cameraIndex, 640, 480, 60, null);
}
/** Creates grabber, the caller can control basic image and grabbing parameters.
*
* @param cameraIndex - zero based index of used camera (OS system wide)
* @param imageWidth - width of image
* @param imageHeight - height of image
* @param framerate - frame rate - see CLCamera for allowed frame rates based on resolution
* @param applet - PApplet object required by CLCamera
* @throws Exception - if parameters don't follow CLCamera definition or camera is not created
*/
public PS3EyeFrameGrabber(int cameraIndex, int imageWidth, int imageHeight, int framerate, Object applet) throws Exception {
camera = null;
if (! CLCamera.IsLibraryLoaded()) {
throw new Exception("CLEye multicam dll not loaded");
}
try {
try {
// maybe some new version of CLCamera works without a PApplet...
camera = CLCamera.class.newInstance();
} catch (Throwable t) {
if (applet == null) {
// do some really hacky stuff to create an instance
// without calling the constructor
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe)unsafeField.get(null);
camera = (CLCamera)unsafe.allocateInstance(CLCamera.class);
} else {
camera = (CLCamera)CLCamera.class.getConstructors()[0].newInstance(applet);
}
}
} catch (Throwable t) {
throw new Exception("Failed to construct " + PS3EyeFrameGrabber.class, t);
}
this.cameraIndex = cameraIndex;
stat = "created";
uuid = CLCamera.cameraUUID(cameraIndex);
if (((imageWidth == 640) && (imageHeight == 480)) ||
((imageWidth == 320) && (imageHeight == 240))) {
setImageWidth(imageWidth);
setImageHeight(imageHeight);
}
else throw new Exception("Only 640x480 or 320x240 images supported");
setImageMode(ImageMode.COLOR);
setFrameRate((double) framerate);
setTimeout(1 + 1000/framerate);
setBitsPerPixel(8);
setTriggerMode(false);
setNumBuffers(4);
}
/**
* @return system wide number of installed/detected Sony PS3 Eye cameras
*/
public static int getCameraCount() {
return CLCamera.cameraCount();
}
/** Ask the driver for all installed PS3 cameras. Resulting array is sorted in order of camera index.
* Its size is defined by CLCamera.cameraCount().
*
* @return array of camera unique uuids or null if there is no PS3 camera
*/
public static String[] listPS3Cameras() {
int no = getCameraCount();
String[] uuids;
if (no > 0) {
uuids = new String[no];
for (--no; no >=0; no--) { uuids[no] = CLCamera.cameraUUID(no); }
return uuids;
}
return null;
}
/** Make IplImage form raw int[] frame data
* Note: NO array size checks!!
*
* @param frame int[] image frame data
* @return internal IplImage set to frame
*/
public IplImage makeImage(int[] frame) {
image_4ch.getIntBuffer().put(ps3_frame);
return image_4ch;
}
/** Grab one frame and return it as int[] (in the internal camera format RGBA).
* Note: use makeImage() to create RGBA, 4-ch image
* @return frame as int[] without any processing or null if frame is not available
*/
public int[] grab_raw() {
if (camera.getCameraFrame(ps3_frame, timeout)) {
return ps3_frame;
}
else return null;
}
public void trigger() throws Exception {
for (int i = 0; i < numBuffers+1; i++) {
grab_raw();
}
if ((ps3_frame = grab_raw()) != null) {
triggered = Triggered.HAS_FRAME;
timestamp = System.nanoTime()/1000;
}
else
triggered = Triggered.NO_FRAME;
}
/** Grab and convert one frame, default timeout is (1 + 1000/framerate) [milliseconds].
* Every successful call returns an internal (preallocated) 640x480 or 320x240, IPL_DEPTH_8U, 4-channel image.
* The caller shall consider it "read only" and make a copy/clone of it before further processing.
*
* The call might block for timeout [milliseconds].
* @return the image or null if there is no new image
*/
public IplImage grab_RGB4() {
if (camera.getCameraFrame(ps3_frame, timeout)) {
timestamp = System.nanoTime()/1000;
image_4ch.getIntBuffer().put(ps3_frame);
return image_4ch;
}
else return null;
}
/** Grab one frame;
* the caller have to make a copy of returned image before processing.
*
* It will throw null pointer exception if not started before grabbing.
* @return "read-only" RGB, 4-channel or GRAY/1-channel image, it throws exception if no image is available
*/
@Override
public Frame grab() throws Exception {
IplImage img = null;
switch (triggered) {
case NO_TRIGGER:
img = grab_RGB4();
break;
case HAS_FRAME:
triggered = Triggered.NO_TRIGGER;
img = makeImage(ps3_frame);
break;
case NO_FRAME:
triggered = Triggered.NO_TRIGGER;
return null;
default: // just schizophrenia - for future enhancement
throw new Exception("Int. error - unknown triggering state");
}
if ((img != null) && (imageMode == ImageMode.GRAY)) {
cvCvtColor(img, image_1ch, CV_RGB2GRAY);
img = image_1ch;
}
return converter.convert(img);
}
/** Start camera first (before grabbing).
*
* @return success/failure (true/false)
*/
public void start() throws Exception {
boolean b;
if (ps3_frame == null) {
ps3_frame = new int[ imageWidth * imageHeight ];
image_4ch = IplImage.create(imageWidth, imageHeight, IPL_DEPTH_8U, 4);
image_1ch = IplImage.create(imageWidth, imageHeight, IPL_DEPTH_8U, 1);
}
b = camera.createCamera(
cameraIndex,
(imageMode == ImageMode.GRAY) ? CLCamera.CLEYE_MONO_PROCESSED : CLCamera.CLEYE_COLOR_PROCESSED,
(imageWidth == 320 && imageHeight == 240) ? CLCamera.CLEYE_QVGA : CLCamera.CLEYE_VGA,
(int)frameRate);
if (!b) throw new Exception("Low level createCamera() failed");
b = camera.startCamera();
if (!b) throw new Exception("Camera start() failed");
stat = "started";
}
/** Stop camera. It can be re-started if needed.
*
* @return success/failure (true/false)
*/
public void stop() throws Exception {
boolean b = camera.stopCamera();
if (b) stat = "stopped";
else throw new Exception("Camera stop() failed");
}
/** Release resources:
* - CL driver internal resources binded with camera HW
* - internal IplImage
* After calling this function, this mini-grabber object instance can not be used anymore.
*/
public void release() {
if (camera != null) {
camera.dispose();
camera = null;
}
if (image_4ch != null) {
image_4ch.release();
image_4ch = null;
}
if (image_1ch != null) {
image_1ch.release();
image_1ch = null;
}
if (ipl_frame != null) ipl_frame = null;
if (ps3_frame != null) ps3_frame = null;
stat = "released";
}
/** Release internal resources, the same as calling release()
*/
public void dispose() {
release();
}
@Override protected void finalize() throws Throwable {
super.finalize();
release();
}
/** Return internal CLCamera object, mainly to set camera parameters,
* changing camera parameters must be done on stopped camera and before start() is called.
* See CL SDK - setCameraParameter(int param, int val) function.
*
* @return internal CLCamera instance
*/
public CLCamera getCamera() { return camera; }
public String getUUID() { return uuid; }
/**
* @return status and camera parameters of the grabber
*/
@Override public String toString() {
return "UUID="+uuid + "; status=" + stat + "; timeout=" + timeout
+ "; "
+ ((camera != null) ? camera.toString() : "")
;
}
/** Just for testing - loads the CL CLEyeMulticam.dll file, invokes driver
* and lists available cameras.
*
* @param argv - argv is not used
*/
public static void main(String[] argv) {
String[] uuids = listPS3Cameras();
for (int i = 0; i < uuids.length; i++)
System.out.println(i+": "+uuids[i]);
}
}