/**
* FiducialTest code provided by Cri S. Demonstrates round fiducial finding using contours.
*/
package org.openpnp.experiments;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.KeyStroke;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.RotatedRect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.Highgui;
import org.opencv.imgproc.Imgproc;
public class FiducialTest {
static {
nu.pattern.OpenCV.loadShared();
System.loadLibrary(org.opencv.core.Core.NATIVE_LIBRARY_NAME);
}
public static void showResult(String name, Mat img) {
// Imgproc.resize(img, img, new Size(640, 480));
MatOfByte matOfByte = new MatOfByte();
Highgui.imencode(".jpg", img, matOfByte);
byte[] byteArray = matOfByte.toArray();
BufferedImage bufImage = null;
try {
InputStream in = new ByteArrayInputStream(byteArray);
bufImage = ImageIO.read(in);
final JFrame frame = new JFrame(name);
frame.getContentPane().add(new JLabel(new ImageIcon(bufImage)));
frame.pack();
frame.setVisible(true);
// frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW)
.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "EXIT");
frame.getRootPane().getActionMap().put("EXIT", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
// frame.dispose();
System.exit(0);
}
});
}
catch (Exception e) {
e.printStackTrace();
}
}
public static void showResult(Mat img) {
showResult("", img);
}
static private Mat dst;
// triangle, square and diamont code removed
static public Point fiducial(Mat gray, int min, int max) throws Exception {
final List<MatOfPoint> contours = new ArrayList<>();
// final List<Rect> box = new ArrayList<>();
final List<RotatedRect> box = new ArrayList<>();
final List<Double> dist = new ArrayList<>();
final Mat dummy = new Mat();
// final Mat gray= OpenCvUtils.toMat(image,Highgui.IMREAD_GRAYSCALE);
// prepare image
if (gray.empty())
return null;
final Point ret = new Point(gray.width() / 2, gray.height() / 2);
final Mat bw = new Mat();
Imgproc.GaussianBlur(gray, gray, new Size(7, 7), 0);
Imgproc.Canny(gray, bw, 0, 50, 5, false);
Imgproc.threshold(bw, bw, 100, 255, 0);
showResult("Canny", bw);
// scan blobs
Imgproc.findContours(bw, contours, dummy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
// get dimension, in java bit different
final MatOfPoint2f temp = new MatOfPoint2f();
for (int i = 0; i < contours.size(); i++) {
temp.fromList(contours.get(i).toList());
box.add(Imgproc.minAreaRect(temp));
}
// filter blob
for (int i = contours.size(); i-- > 0;) {
double a, l, t, f, x, y;
temp.fromList(contours.get(i).toList());
f = box.get(i).size.width / box.get(i).size.height;
l = Imgproc.arcLength(temp, true);
a = Imgproc.contourArea(contours.get(i));
t = (a / (Math.PI * Math.pow(box.get(i).size.width / 2, 2)));
if (f <= 0.8 || f >= 1.2 || t >= 1.2 || t <= 0.8 || box.get(i).size.width < min
|| box.get(i).size.width > max || a < 100.) {
contours.remove(i);
continue;
}
final MatOfPoint2f approx = new MatOfPoint2f();
final MatOfPoint matrix = new MatOfPoint();
Imgproc.approxPolyDP(temp, approx, l * 0.02, true);
approx.convertTo(matrix, CvType.CV_32S); // in java different
// matrix.fromList(temp.toList()); // gives lot of trouble
if (approx.toList().size() <= 6) // java thing
{
contours.remove(i);
continue;
}
if (!Imgproc.isContourConvex(matrix)) {
contours.remove(i);
continue;
}
x = (box.get(i).center.x - ret.x);
y = (box.get(i).center.y - ret.y);
dist.add(0, x * x + y * y); // in java different
}
// return blob
if (contours.size() != 0) {
int i = 0; // holds nearest blob
Rect r;
// search nearest blob
for (int j = 1; j < contours.size(); j++)
if (dist.get(j) < dist.get(i))
i = j;
r = Imgproc.boundingRect(contours.get(i)); // java thing
// >>>>>>>>>>> this is for debug output, not for function
Imgproc.drawContours(dst, contours, i, new Scalar(0, 0, 255), 2); // java
// thing
Core.circle(dst, ret, 4, new Scalar(0, 255, 255), -1);
Core.circle(dst, new Point(r.x + r.width / 2, r.y + r.height / 2), 4,
new Scalar(0, 0, 255), -1);
showResult("found", dst);
// <<<<<<<<<<< end of debug
// do java problem, it don't have supixel resulution, as cv version
ret.x = r.x + r.width / 2 - ret.x;
ret.y = r.y + r.height / 2 - ret.y;
ret.y *= -1; // adj coord system
return ret;
}
// no blob found
return null;
}
public static void main(String[] args) throws Exception {
int min = 0, max = 999999;
args = new String[] {"",
"/Users/jason/.openpnp/org.openpnp.machine.reference.vision.OpenCvVisionProvider/camera_41173395697117969.png",
"/Users/jason/Desktop/result.png"};
if (args.length > 2)
;
else {
System.out.println("Usage: <prg> <image> <result> [ <min-pixel> <max-pixel> ]");
return;
}
if (args.length > 4) {
min = Integer.valueOf(args[3]);
max = Integer.valueOf(args[4]);
}
// System.out.println("Usage: <prg> " + args[1]+" "+args[2]);
Mat src = Highgui.imread(args[1], 0);
dst = Highgui.imread(args[1], 1);
// showResult(dst);
Imgproc.cvtColor(src, dst, Imgproc.COLOR_GRAY2BGR);
Point p = fiducial(src, min, max);
try {
System.out.println("Point: " + p.x + " " + p.y);
Highgui.imwrite(args[2], dst);
// showResult("dst",dst);
}
catch (Exception ex) {
;
}
return;
}
}