/*
* Copyright (C) 2011 Jason von Nieda <jason@vonnieda.org>
*
* This file is part of OpenPnP.
*
* OpenPnP is free software: you can redistribute it and/or modify it under the terms of the GNU
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* OpenPnP is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with OpenPnP. If not, see
* <http://www.gnu.org/licenses/>.
*
* For more information about OpenPnP visit http://openpnp.org
*/
package org.openpnp.machine.reference.camera;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.swing.Action;
import org.opencv.core.Mat;
import org.opencv.highgui.Highgui;
import org.opencv.highgui.VideoCapture;
import org.openpnp.CameraListener;
import org.openpnp.gui.support.Wizard;
import org.openpnp.machine.reference.ReferenceCamera;
import org.openpnp.machine.reference.camera.wizards.OpenCvCameraConfigurationWizard;
import org.openpnp.spi.PropertySheetHolder;
import org.openpnp.util.OpenCvUtils;
import org.simpleframework.xml.Attribute;
/**
* A Camera implementation based on the OpenCV FrameGrabbers.
*/
public class OpenCvCamera extends ReferenceCamera implements Runnable {
static {
nu.pattern.OpenCV.loadShared();
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
}
@Attribute(name = "deviceIndex", required = true)
private int deviceIndex = 0;
@Attribute(required = false)
private int preferredWidth;
@Attribute(required = false)
private int preferredHeight;
@Attribute(required = false)
private int fps = 24;
private VideoCapture fg = new VideoCapture();
private Thread thread;
private boolean dirty = false;
public OpenCvCamera() {}
@Override
public synchronized BufferedImage internalCapture() {
if (thread == null) {
initCamera();
}
Mat mat = new Mat();
try {
if (!fg.read(mat)) {
return null;
}
BufferedImage img = OpenCvUtils.toBufferedImage(mat);
return transformImage(img);
}
catch (Exception e) {
return null;
}
finally {
mat.release();
}
}
@Override
public synchronized void startContinuousCapture(CameraListener listener, int maximumFps) {
if (thread == null) {
initCamera();
}
super.startContinuousCapture(listener, maximumFps);
}
public void run() {
while (!Thread.interrupted()) {
try {
BufferedImage image = internalCapture();
if (image != null) {
broadcastCapture(image);
}
}
catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(1000 / fps);
}
catch (InterruptedException e) {
break;
}
}
}
private void initCamera() {
if (thread != null) {
thread.interrupt();
try {
thread.join();
}
catch (Exception e) {
e.printStackTrace();
}
thread = null;
}
try {
setDirty(false);
width = null;
height = null;
fg.open(deviceIndex);
if (preferredWidth != 0) {
fg.set(Highgui.CV_CAP_PROP_FRAME_WIDTH, preferredWidth);
}
if (preferredHeight != 0) {
fg.set(Highgui.CV_CAP_PROP_FRAME_HEIGHT, preferredHeight);
}
}
catch (Exception e) {
e.printStackTrace();
return;
}
thread = new Thread(this);
thread.start();
}
@Override
public void close() throws IOException {
super.close();
if (thread != null) {
thread.interrupt();
try {
thread.join();
}
catch (Exception e) {
}
}
if (fg.isOpened()) {
fg.release();
}
}
public int getDeviceIndex() {
return deviceIndex;
}
public synchronized void setDeviceIndex(int deviceIndex) {
this.deviceIndex = deviceIndex;
initCamera();
}
public int getPreferredWidth() {
return preferredWidth;
}
public void setPreferredWidth(int preferredWidth) {
this.preferredWidth = preferredWidth;
setDirty(true);
}
public int getPreferredHeight() {
return preferredHeight;
}
public void setPreferredHeight(int preferredHeight) {
this.preferredHeight = preferredHeight;
setDirty(true);
}
public int getFps() {
return fps;
}
public void setFps(int fps) {
this.fps = fps;
}
public boolean isDirty() {
return dirty;
}
public void setDirty(boolean dirty) {
this.dirty = dirty;
}
@Override
public Wizard getConfigurationWizard() {
return new OpenCvCameraConfigurationWizard(this);
}
@Override
public String getPropertySheetHolderTitle() {
return getClass().getSimpleName() + " " + getName();
}
@Override
public PropertySheetHolder[] getChildPropertySheetHolders() {
// TODO Auto-generated method stub
return null;
}
}