/** * * @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 ! * * */ package org.myrobotlab.opencv; import static org.bytedeco.javacpp.helper.opencv_imgproc.cvFindContours; import static org.bytedeco.javacpp.opencv_core.cvClearMemStorage; import static org.bytedeco.javacpp.opencv_core.cvCreateImage; import static org.bytedeco.javacpp.opencv_core.cvCreateMemStorage; //import static org.bytedeco.javacpp.opencv_core.cvDrawRect; import static org.bytedeco.javacpp.opencv_core.cvGetSize; import static org.bytedeco.javacpp.opencv_core.cvPoint; import static org.bytedeco.javacpp.opencv_imgproc.CV_BGR2GRAY; import static org.bytedeco.javacpp.opencv_imgproc.CV_CHAIN_APPROX_SIMPLE; import static org.bytedeco.javacpp.opencv_imgproc.CV_FONT_HERSHEY_PLAIN; import static org.bytedeco.javacpp.opencv_imgproc.CV_POLY_APPROX_DP; import static org.bytedeco.javacpp.opencv_imgproc.cvApproxPoly; import static org.bytedeco.javacpp.opencv_imgproc.cvBoundingRect; import static org.bytedeco.javacpp.opencv_imgproc.cvContourPerimeter; import static org.bytedeco.javacpp.opencv_imgproc.cvCvtColor; import static org.bytedeco.javacpp.opencv_imgproc.cvDrawRect; import static org.bytedeco.javacpp.opencv_imgproc.cvFont; import static org.bytedeco.javacpp.opencv_imgproc.cvPutText; import java.util.ArrayList; import org.bytedeco.javacpp.Loader; import org.bytedeco.javacpp.opencv_core.CvContour; //import org.bytedeco.javacpp.opencv_core.CvFont; import org.bytedeco.javacpp.opencv_core.CvMemStorage; import org.bytedeco.javacpp.opencv_core.CvPoint; import org.bytedeco.javacpp.opencv_core.CvRect; import org.bytedeco.javacpp.opencv_core.CvScalar; import org.bytedeco.javacpp.opencv_core.CvSeq; import org.bytedeco.javacpp.opencv_core.IplImage; import org.bytedeco.javacpp.opencv_imgproc.CvFont; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.data.Rectangle; import org.slf4j.Logger; //import static org.bytedeco.javacpp.opencv_core.cvFont; //import static org.bytedeco.javacpp.opencv_core.cvPutText; public class OpenCVFilterFindContours extends OpenCVFilter { private static final long serialVersionUID = 1L; public final static Logger log = LoggerFactory.getLogger(OpenCVFilterFindContours.class.getCanonicalName()); transient CvFont font = cvFont(CV_FONT_HERSHEY_PLAIN); // FIXME - ok - use awt - use mrl pojo's if expected to serialize to Android // TODO - publish MRL objects - TODO make SerializableImage bundle with // Object map for data publishing // Stabalize with attributes of Object Map defined in OpenCV // boolean useMinArea = true; public boolean publishBoundingBox = true; public boolean publishPolygon = false; boolean useMaxArea = false; int minArea = 150; int maxArea = -1; int thresholdValue = 0; boolean addPolygon = false; boolean isMinArea; boolean isMaxArea; transient IplImage grey = null; // transient IplImage display = null; transient IplImage dst = null; transient CvSeq contourPointer = new CvSeq(); transient CvPoint drawPoint0 = cvPoint(0, 0); transient CvPoint drawPoint1 = cvPoint(0, 0); transient CvMemStorage cvStorage = null; public OpenCVFilterFindContours() { super(); } public OpenCVFilterFindContours(String name) { super(name); } /* * @Override public BufferedImage display(IplImage image, OpenCVData data) { * * BufferedImage frameBuffer = image.getBufferedImage(); Graphics2D g = * frameBuffer.createGraphics(); g.setColor(Color.green); if (data != null) { * ArrayList<Rectangle> boxes = data.getBoundingBoxArray(); if (boxes != null) * { for (Rectangle box : boxes) { if (useFloatValues){ * g.drawRect((int)(box.x*width), (int)(box.y*height), (int)(box.width*width), * (int)(box.height*height)); } else { g.drawRect((int)box.x, (int)box.y, * (int)box.width, (int)box.height); } } g.drawString(String.format("cnt %d", * boxes.size()), 10, 10); } else { g.drawString("null", 10, 10); } } return * frameBuffer; } */ @Override public IplImage display(IplImage image, OpenCVData data) { ArrayList<Rectangle> boxes = data.getBoundingBoxArray(); if (boxes != null) { for (Rectangle box : boxes) { // cvDrawRect(image, cvPoint(x0, y0), cvPoint(x1, y1), // CvScalar.RED, 1, 1, 0); if (useFloatValues) { int x = (int) (box.x * width); int y = (int) (box.y * height); int w = x + (int) (box.width * width); int h = y + (int) (box.height * height); cvDrawRect(image, cvPoint(x, y), cvPoint(w, h), CvScalar.WHITE, 1, 1, 0); } else { int x = (int) box.x; int y = (int) box.y; int w = x + (int) box.width; int h = y + (int) box.height; cvDrawRect(image, cvPoint(x, y), cvPoint(w, h), CvScalar.WHITE, 1, 1, 0); } } cvPutText(image, String.format("cnt %d", boxes.size()), cvPoint(10, 10), font, CvScalar.WHITE); } else { cvPutText(image, "null", cvPoint(10, 10), font, CvScalar.WHITE); } // cvPutText(image, "killroy was here", cvPoint(10,10), font, // CvScalar.WHITE); return image; } @Override public void imageChanged(IplImage image) { if (cvStorage == null) { cvStorage = cvCreateMemStorage(0); } grey = cvCreateImage(cvGetSize(image), 8, 1); // display = cvCreateImage(cvGetSize(frame), 8, 3); } @Override public IplImage process(IplImage image, OpenCVData data) { // FIXME 3 channel search ??? if (image.nChannels() == 3) { cvCvtColor(image, grey, CV_BGR2GRAY); } else { grey = image.clone(); } cvFindContours(grey, cvStorage, contourPointer, Loader.sizeof(CvContour.class), 0, CV_CHAIN_APPROX_SIMPLE); CvSeq contour = contourPointer; ArrayList<Rectangle> list = new ArrayList<Rectangle>(); while (contour != null && !contour.isNull()) { if (contour.elem_size() > 0) { // TODO - limit here for // "TOOOO MANY !!!!" CvRect rect = cvBoundingRect(contour, 0); minArea = 600; // find all the avg color of each polygon // cxcore.cvZero(polyMask); // cvDrawContours(polyMask, points, CvScalar.WHITE, // CvScalar.BLACK, -1, cxcore.CV_FILLED, CV_AA); // publish polygons // CvScalar avg = cxcore.cvAvg(image, polyMask); - good idea - // but not implemented // log.error("{}", rect); // size filter if (useMinArea) { isMinArea = (rect.width() * rect.height() > minArea) ? true : false; // log.error("{} {}", isMinArea, rect.width() * // rect.height()); } else { useMinArea = true; } if (useMaxArea) { isMaxArea = (rect.width() * rect.height() < maxArea) ? true : false; } else { isMaxArea = true; } if (isMinArea && isMaxArea) { Rectangle box = new Rectangle(); if (useFloatValues) { box.x = (float) rect.x() / width; box.y = (float) rect.y() / height; box.width = (float) rect.width() / width; box.height = (float) rect.height() / height; } else { box.x = rect.x(); box.y = rect.y(); box.width = rect.width(); box.height = rect.height(); } list.add(box); if (publishPolygon) { // CvSeq points = cvApproxPoly(contour, // Loader.sizeof(CvContour.class), cvStorage, CV_POLY_APPROX_DP, // cvContourPerimeter(contour) * 0.02, 1); cvApproxPoly(contour, Loader.sizeof(CvContour.class), cvStorage, CV_POLY_APPROX_DP, cvContourPerimeter(contour) * 0.02, 1); } // Polygon polygon = new Polygon(); // iterate through points - points.total() build awt Polygon // polygons.add(polygon); // polygons.add(new Polygon(rect, null, // (cvCheckContourConvexity(points) == 1) ? true : false, // cvPoint(rect.x() + rect.width() / 2, rect.y() + // rect.height() / 2), points.total())); /* * WRONG FIXME - post processing should be done in Java on the * buffered image !!!!S cvPutText(display, " " + points.total() + " " * + (rect.x() + rect.width() / 2) + "," + (rect.y() + rect.height() / * 2) + " " + rect.width() + "x" + rect.height() + "=" + (rect.width() * * rect.height()) + " " + " " + cvCheckContourConvexity(points), * cvPoint(rect.x() + rect.width() / 2, rect.y()), font, * CvScalar.WHITE); */ } // cvPutText(display, " " + points.total() + " " + (rect.x() * // rect.height()) + "c" + (int)avg.getRed() + "," + // (int)avg.getGreen() + "," + (int)avg.getBlue(), // cvPoint(rect.x() + rect.width()/2,rect.y()), font, // CV_RGB(255, 0, 0)); // cvPutText(display, " " + points.total() + " " + rect.x() + // "," + // rect.y() + " "+ (rect.x() * rect.height()/1000) + " " + // OpenCVFilterAverageColor.getColorName2(avg) + " " + // cv.cvCheckContourConvexity(points), cvPoint(rect.x() + // rect.width()/2,rect.y()), font, CvScalar.WHITE); /* * drawPoint0.x(rect.x()); drawPoint0.y(rect.y()); * * drawPoint1.x(rect.x() + rect.width()); drawPoint1.y(rect.y() + * rect.height()); * * cvDrawRect(display, drawPoint0, drawPoint1, CvScalar.RED, 1, 8, 0); */ } contour = contour.h_next(); } // FIXME - sources could use this too data.put(list); // if (publishOpenCVData) invoke("publishOpenCVData", data); // cvPutText(display, " " + cnt, cvPoint(10, 14), font, CvScalar.RED); // log.error("x"); cvClearMemStorage(cvStorage); // display(image, data); return image; } }