Hi all,
I’m newbie in module development using Ignition SDK. I tried the examples and I focused on the Vision Component Example. I am trying to develop a new component to connect to an IP camera using OpenCV.
Right now my code generates a .modl file, but maybe I’m doing things wrong when I repaint my component because I’m getting the exception:
Exception in thread “AWT-EventQueue-0” java.lang.NullPointerException
- at imas.client.OCRComponent.paintComponent(OCRComponent.java:116)*
- at java.desktop/javax.swing.JComponent.paint(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paintChildren(Unknown Source)*
- at com.inductiveautomation.vision.api.client.components.model.AbstractVisionPanel.paintChildren(AbstractVisionPanel.java:290)*
- at java.desktop/javax.swing.JComponent.paint(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paintChildren(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paint(Unknown Source)*
- at java.desktop/javax.swing.JLayeredPane.paint(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paintChildren(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paint(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paintChildren(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paint(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paintChildren(Unknown Source)*
- at com.inductiveautomation.ignition.designer.designable.DesignPanel$DesignableContainerLayer.paintChildren(DesignPanel.java:1169)*
- at java.desktop/javax.swing.JComponent.paint(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paintChildren(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paint(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paintToOffscreen(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBufferedImpl(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager$PaintManager.paintDoubleBuffered(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager$PaintManager.paint(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager.paint(Unknown Source)*
- at java.desktop/javax.swing.JComponent._paintImmediately(Unknown Source)*
- at java.desktop/javax.swing.JComponent.paintImmediately(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager$4.run(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager$4.run(Unknown Source)*
- at java.base/java.security.AccessController.doPrivileged(Native Method)*
- at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager.paintDirtyRegions(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager.prePaintDirtyRegions(Unknown Source)*
- at java.desktop/javax.swing.RepaintManager$ProcessingRunnable.run(Unknown Source)*
- at java.desktop/java.awt.event.InvocationEvent.dispatch(Unknown Source)*
- at java.desktop/java.awt.EventQueue.dispatchEventImpl(Unknown Source)*
- at java.desktop/java.awt.EventQueue$4.run(Unknown Source)*
- at java.desktop/java.awt.EventQueue$4.run(Unknown Source)*
- at java.base/java.security.AccessController.doPrivileged(Native Method)*
- at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(Unknown Source)*
- at java.desktop/java.awt.EventQueue.dispatchEvent(Unknown Source)*
- at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)*
- at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)*
- at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)*
- at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)*
- at java.desktop/java.awt.EventDispatchThread.pumpEvents(Unknown Source)*
- at java.desktop/java.awt.EventDispatchThread.run(Unknown Source)*
This is my component class:
package imas.client;
import imas.client.VideoCamera;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import javax.swing.JFrame;
import javax.swing.Timer;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.Font;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.videoio.VideoCapture;
import com.inductiveautomation.ignition.client.model.LocaleListener;
import com.inductiveautomation.vision.api.client.components.model.AbstractVisionComponent;
public class OCRComponent extends AbstractVisionComponent implements LocaleListener {
/**
* PROPERTIES
*/
private String cameraURL = "";
private int state = STATE_OFF;
/// ENUM PROPERTIES
public static final int STATE_OFF = 0;
public static final int STATE_ON = 1;
private static VideoCamera cam;
// a timer for acquiring the video stream
private Timer _timer;
// a flag to change the button behavior
private boolean cameraActive = false;
/**
* The listener for the swing timer
*/
private ActionListener animationListener = new ActionListener() {
public void actionPerformed(ActionEvent e) {
if(cam.isOpened())
{
repaint();
}
else
{
if(cameraURL != "")
{
cam.startCamera(cameraURL);
repaint();
}
}
}
};
public OCRComponent() {
setOpaque(false);
setPreferredSize(new Dimension(640, 480));
setFont(new Font("Dialog", Font.PLAIN, 24));
try
{
cam = new VideoCamera();
}catch(Exception e)
{
System.out.println(e.getMessage());
}
System.out.println("OCR component inicializado");
}
public static void main(String[] args) {
JFrame frame = new JFrame("ocrTest");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new OCRComponent());
frame.setSize(800,800);
frame.setBounds(100, 100, 300, 300);
frame.setVisible(true);
}
@Override
protected void onStartup() {
// Seems like a no-op, but actually will trigger logic to re-start the timer if necessary
System.out.println("onStartup(URL): " + cameraURL);
}
@Override
protected void onShutdown() {
if (_timer != null && _timer.isRunning()) {
_timer.stop();
System.out.println("onShutdown, timer detenido");
}
}
@Override
protected void paintComponent(Graphics _g) {
Graphics2D g = (Graphics2D) _g;
// Preserve the original transform to roll back to at the end
AffineTransform originalTx = g.getTransform();
g.drawImage(cam.lastFrame,10,10,cam.lastFrame.getWidth(),cam.lastFrame.getHeight(), null);
// Reverse any transforms we made
g.setTransform(originalTx);
}
public String getCameraURL() {
System.out.println("getCameraURL(): " + cameraURL);
return cameraURL;
}
public void setCameraURL(String _url) {
String oldValue = this.cameraURL;
this.cameraURL = _url;
this.cam.startCamera(this.cameraURL);
repaint();
}
public int getState() {
return state;
}
public void setState(int _state) {
this.state = _state;
repaint();
}
}
And my VideoCamera class to connect:
package imas.client;
import javax.swing.JPanel;
import org.opencv.core.Core;
import org.opencv.videoio.VideoCapture;
import org.opencv.core.Mat;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class VideoCamera extends JPanel
{
/// Video stream
VideoCapture camera;
/// Camera URL
private String url;
// a timer for acquiring the video stream
private ScheduledExecutorService timer;
BufferedImage lastFrame;
public VideoCamera()
{
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
camera = new VideoCapture();
}
public void startCamera(String _url)
{
this.url = _url;
this.camera.open(this.url);
// is the video stream available?
if (isOpened())
{
// grab a frame every 33 ms (30 frames/sec)
Runnable frameGrabber = new Runnable() {
@Override
public void run()
{
// effectively grab and process a single frame
Mat frame = new Mat();
camera.read(frame);
lastFrame = Mat2BufferedImage(frame);
}
};
this.timer = Executors.newSingleThreadScheduledExecutor();
this.timer.scheduleAtFixedRate(frameGrabber, 0, 33, TimeUnit.MILLISECONDS);
}
else
{
// log the error
System.err.println("Impossible to open the camera connection...");
}
}
public boolean isOpened()
{
return camera.isOpened();
}
public void resetURL(String _newURL)
{
url = _newURL;
if(isOpened())
{
camera.release();
}
if(_newURL == "0")
{
camera.open(0);
}
else
{
camera.open(url);
}
}
public BufferedImage Mat2BufferedImage(Mat m)
{
int type = BufferedImage.TYPE_BYTE_GRAY;
if (m.channels() > 1)
{
type = BufferedImage.TYPE_3BYTE_BGR;
}
int bufferSize = m.channels() * m.cols() * m.rows();
byte[] b = new byte[bufferSize];
m.get(0, 0, b); // get all the pixels
BufferedImage img = new BufferedImage(m.cols(), m.rows(), type);
final byte[] targetPixels = ((DataBufferByte) img.getRaster().getDataBuffer()).getData();
System.arraycopy(b, 0, targetPixels, 0, b.length);
return img;
}
}