/** * * @author greg (at) myrobotlab.org * * This file is part of MyRobotLab (http://myrobotlab.org). * * MyRobotLab 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 2 of the License, or * (at your option) any later version (subject to the "Classpath" exception * as provided in the LICENSE.txt file that accompanied this code). * * MyRobotLab is distributed in the hope that it will be useful or fun, * 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. * * All libraries in thirdParty bundle are subject to their own license * requirements - please refer to http://myrobotlab.org/libraries for * details. * * Enjoy ! * * */ // http://stackoverflow.com/questions/11515072/how-to-identify-optimal-parameters-for-cvcanny-for-polygon-approximation package org.myrobotlab.opencv; import static org.bytedeco.javacpp.opencv_core.cvCopy; import static org.bytedeco.javacpp.opencv_core.cvPoint; import static org.bytedeco.javacpp.opencv_core.cvRect; import static org.bytedeco.javacpp.opencv_core.cvResetImageROI; import static org.bytedeco.javacpp.opencv_core.cvSetImageROI; import static org.bytedeco.javacpp.opencv_imgcodecs.CV_LOAD_IMAGE_GRAYSCALE; import static org.bytedeco.javacpp.opencv_imgcodecs.cvLoadImage; import static org.bytedeco.javacpp.opencv_imgproc.CV_BGR2GRAY; import static org.bytedeco.javacpp.opencv_imgproc.CV_GRAY2BGR; import static org.bytedeco.javacpp.opencv_imgproc.cvCvtColor; import static org.bytedeco.javacpp.opencv_imgproc.cvLine; import org.bytedeco.javacpp.opencv_core.CvScalar; import org.bytedeco.javacpp.opencv_core.IplImage; import org.bytedeco.javacv.ObjectFinder; import org.bytedeco.javacv.ObjectFinder.Settings; import org.myrobotlab.logging.LoggerFactory; import org.slf4j.Logger; public class OpenCVFilterSURF extends OpenCVFilter { private static final long serialVersionUID = 1L; public final static Logger log = LoggerFactory.getLogger(OpenCVFilterSURF.class.getCanonicalName()); public Settings settings = new Settings(); public ObjectFinder objectFinder = null; transient private IplImage object = null; public OpenCVFilterSURF() { super(); } public OpenCVFilterSURF(String name) { super(name); } @Override public void imageChanged(IplImage image) { // TODO: impl something here? } public void loadObjectImageFilename(String filename) { IplImage object = cvLoadImage(filename, CV_LOAD_IMAGE_GRAYSCALE); this.setObjectImage(object); this.objectFinder = new ObjectFinder(settings); } @Override public IplImage process(IplImage image, OpenCVData data) { // TODO: Expose configuration of the object image to find. // TODO: create proper life cycle for the objectFinder obj. if (object == null || image == null) { return image; } IplImage objectColor = IplImage.create(object.width(), object.height(), 8, 3); cvCvtColor(object, objectColor, CV_GRAY2BGR); // object is now black and white IplImage imageBW = IplImage.create(image.width(), image.height(), 8, 1); cvCvtColor(image, imageBW, CV_BGR2GRAY); // image bw is now black and white // a new image to hold the side by side comparison int correspondWidth = image.width() + object.width(); int correspondHeight = Max(image.height(), object.height()); // Create a new image to hold the object and the image side by side IplImage correspond = IplImage.create(correspondWidth, correspondHeight, 8, 1); // IplImage correspond = IplImage.create(Max(image.width(), object.width()), // object.height() + image.height(), 8, 1); // Copy the object to be found into the corresponding image cvSetImageROI(correspond, cvRect(0, 0, object.width(), object.height())); cvCopy(object, correspond); // cvSetImageROI(correspond, cvRect(0, object.height(), correspondWidth, // correspondHeight)); // Copy the image to the corresponding cvSetImageROI(correspond, cvRect(object.width(), 0, image.width(), image.height())); // cvSetImageROI(correspond, cvRect(0, object.width(), imageBW.width(), // imageBW.height())); cvCopy(imageBW, correspond); // cvResetImageROI(correspond); // set up the object finder // TOOD: potentially re-use this finder object? if (settings == null) { ObjectFinder.Settings settings = new ObjectFinder.Settings(); settings.setObjectImage(object); settings.setUseFLANN(true); settings.setRansacReprojThreshold(5); // settings.setHessianThreshold(50); } ObjectFinder finder = new ObjectFinder(settings); // grab a timestamp long start = System.currentTimeMillis(); // if we find it i guess the bounding box is here! double[] dst_corners = finder.find(image); log.info("Finding time = " + (System.currentTimeMillis() - start) + " ms"); if (dst_corners != null && dst_corners.length > 0) { log.info("DIST CORNER SIZE :" + dst_corners.length); // TODO: add a callback // TODO: add this info the the CVData int pointCount = 0; for (int i = 0; i < dst_corners.length;) { pointCount += 1; // TODO: any idea what the heck?! if (i + 3 >= dst_corners.length) { log.warn("Unexpected size of point array."); break; } // Points in the object ? int x1 = (int) Math.round(dst_corners[i]); int y1 = (int) Math.round(dst_corners[i + 1]); // points in the video ? int x2 = (int) Math.round(dst_corners[i + 2]); int y2 = (int) Math.round(dst_corners[i + 3]); // int x1 = (int) Math.round(dst_corners[2 * i]); // int y1 = (int) Math.round(dst_corners[2 * i + 1]); // int x2 = (int) Math.round(dst_corners[2 * j]); // int y2 = (int) Math.round(dst_corners[2 * j + 1]); // TODO: draw a line on the new corresponding image ? // cvLine(correspond, cvPoint(x1, y1 + object.height()), cvPoint(x2, y2 // + object.height()), CvScalar.WHITE, 1, 8, 0); cvLine(correspond, cvPoint(x1, y1), cvPoint(x2 + object.width(), y2), CvScalar.WHITE, 1, 8, 0); // increment the loop counter i += 4; } log.info("Found " + pointCount + " correlated points of interest."); } else { log.info("No Object Found in video."); } // TODO: what additional info do we get from the obj finder? // for (int i = 0; i < finder.ptpairs.size(); i += 2) { // CvPoint2D32f pt1 = // finder.objectKeypoints[finder.ptpairs.get(i)].pt(); // CvPoint2D32f pt2 = // finder.imageKeypoints[finder.ptpairs.get(i+1)].pt(); // cvLine(correspond, cvPointFrom32f(pt1), // cvPoint(Math.round(pt2.x()), Math.round(pt2.y()+object.height())), // CvScalar.WHITE, 1, 8, 0); // } // CanvasFrame objectFrame = new CanvasFrame("Object"); // CanvasFrame correspondFrame = new CanvasFrame("Object Correspond"); // correspondFrame.showImage(correspond); // for (int i = 0; i < finder.objectKeypoints.length; i++ ) { // CvSURFPoint r = finder.objectKeypoints[i]; // CvPoint center = cvPointFrom32f(r.pt()); // int radius = Math.round(r.size()*1.2f/9*2); // cvCircle(objectColor, center, radius, CvScalar.RED, 1, 8, 0); // } // objectFrame.showImage(objectColor); // objectFrame.waitKey(); // objectFrame.dispose(); // correspondFrame.dispose(); return correspond; } private int Max(int a, int b) { // TODO Auto-generated method stub if (a > b) { return a; } return b; } /** * Set the reference object to find with the surf filter. * * @param image */ public void setObjectImage(IplImage image) { this.object = image; settings.setObjectImage(image); } }