/** * * * 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 ! * * */ // TODO - have no published OpenCV items - move all to java.awt objects - no native code necessary in viewer 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.cvCopy; import static org.bytedeco.javacpp.opencv_core.cvCreateImage; import static org.bytedeco.javacpp.opencv_core.cvCreateMemStorage; import static org.bytedeco.javacpp.opencv_core.cvInRangeS; 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.cvScalar; import static org.bytedeco.javacpp.opencv_core.cvSetImageROI; import static org.bytedeco.javacpp.opencv_core.cvSize; import static org.bytedeco.javacpp.opencv_core.cvZero; 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.cvCheckContourConvexity; 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.cvPutText; import static org.bytedeco.javacpp.opencv_imgproc.cvPyrDown; import java.awt.Rectangle; import java.util.ArrayList; import org.bytedeco.javacpp.Loader; import org.bytedeco.javacpp.opencv_core.CvContour; 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.image.KinectImageNode; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.service.OpenCV; import org.slf4j.Logger; public class OpenCVFilterKinectDepthMask extends OpenCVFilter { private static final long serialVersionUID = 1L; public final static Logger log = LoggerFactory.getLogger(OpenCVFilterKinectDepthMask.class.getCanonicalName()); transient IplImage kinectDepth = null; transient IplImage ktemp = null; transient IplImage ktemp2 = null; transient IplImage black = null; transient IplImage itemp = null; transient IplImage itemp2 = null; transient IplImage gray = null; transient IplImage mask = null; // Make memory - do not optimize - will only lead to bugs // the correct optimization would be NOT TO PUBLISH // public ArrayList<KinectImageNode> nodes = new // ArrayList<KinectImageNode>(); public ArrayList<KinectImageNode> nodes = null; String imageKey = "kinectDepth"; int mWidth = 0; int mHeight = 0; int mX = 0; int mY = 0; int scale = 2; // countours CvSeq contourPointer = new CvSeq(); int minArea = 30; int maxArea = 0; boolean isMinArea = true; boolean isMaxArea = true; public boolean drawBoundingBoxes = false; public boolean publishNodes = false; transient CvFont font = new CvFont(CV_FONT_HERSHEY_PLAIN); // cvDrawRect has to have 2 points - no cvDrawRect can't draw a cvRect ??? // http://code.google.com/p/opencvx/ - apparently - I'm not the only one who // thinks this is silly // http://opencvx.googlecode.com/svn/trunk/cvdrawrectangle.h transient CvMemStorage cvStorage = null; transient CvPoint p0 = cvPoint(0, 0); transient CvPoint p1 = cvPoint(0, 0); public OpenCVFilterKinectDepthMask() { super(); } public OpenCVFilterKinectDepthMask(String name) { super(name); } @Override public void imageChanged(IplImage image) { // TODO Auto-generated method stub } @Override public IplImage process(IplImage image, OpenCVData data) throws InterruptedException { /* * * 0 - is about 23 " 30000 - is about 6' There is a blackzone in between - * (sign issue?) * * CvScalar min = cvScalar( 30000, 0.0, 0.0, 0.0); CvScalar max = * cvScalar(100000, 0.0, 0.0, 0.0); */ if (cvStorage == null) { cvStorage = cvCreateMemStorage(0); } // TODO - clean up - remove input parameters? only use storage? if (imageKey != null) { // TODO: validate what this is doing? kinectDepth = vp.sources.get(String.format("%s.%s", vp.boundServiceName, OpenCV.SOURCE_KINECT_DEPTH)); } else { kinectDepth = image; } // cv Pyramid Down if (mask == null) // || image.width() != mask.width() { mask = cvCreateImage(cvSize(kinectDepth.width() / scale, kinectDepth.height() / scale), 8, 1); ktemp = cvCreateImage(cvSize(kinectDepth.width() / scale, kinectDepth.height() / scale), 16, 1); ktemp2 = cvCreateImage(cvSize(kinectDepth.width() / scale, kinectDepth.height() / scale), 8, 1); black = cvCreateImage(cvSize(kinectDepth.width() / scale, kinectDepth.height() / scale), 8, 1); itemp = cvCreateImage(cvSize(kinectDepth.width() / scale, kinectDepth.height() / scale), 8, 3); itemp2 = cvCreateImage(cvSize(kinectDepth.width() / scale, kinectDepth.height() / scale), 8, 3); gray = cvCreateImage(cvSize(kinectDepth.width() / scale, kinectDepth.height() / scale), 8, 1); } cvZero(black); cvZero(mask); cvZero(itemp2); cvPyrDown(image, itemp, 7); cvPyrDown(kinectDepth, ktemp, 7); // cvReshape(arg0, arg1, arg2, arg3); // cvConvertScale(ktemp, ktemp2, 0.009, 0); CvScalar min = cvScalar(0, 0.0, 0.0, 0.0); // CvScalar max = cvScalar(30000, 0.0, 0.0, 0.0); CvScalar max = cvScalar(10000, 0.0, 0.0, 0.0); cvInRangeS(ktemp, min, max, mask); int offsetX = 0; int offsetY = 0; mWidth = 607 / scale - offsetX; mHeight = 460 / scale - offsetY; mX = 25 / scale + offsetX; mY = 20 / scale + offsetY; // shifting mask 32 down and to the left 25 x 25 y cvSetImageROI(mask, cvRect(mX, 0, mWidth, mHeight)); // 615-8 = to // remove right // hand band cvSetImageROI(black, cvRect(0, mY, mWidth, mHeight)); cvCopy(mask, black); cvResetImageROI(mask); cvResetImageROI(black); cvCopy(itemp, itemp2, black); invoke("publishDisplay", "input", OpenCV.IplImageToBufferedImage(itemp)); invoke("publishDisplay", "kinectDepth", OpenCV.IplImageToBufferedImage(ktemp)); invoke("publishDisplay", "kinectMask", OpenCV.IplImageToBufferedImage(mask)); // TODO - publish KinectImageNode ArrayList // find contours ---- begin ------------------------------------ CvSeq contour = contourPointer; // int cnt = 0; // cvFindContours(mask, cvStorage, contourPointer, // Loader.sizeof(CvContour.class), 0 ,CV_CHAIN_APPROX_SIMPLE); NOT // CORRECTED if (itemp2.nChannels() == 3) { cvCvtColor(itemp2, gray, CV_BGR2GRAY); } else { gray = itemp2.clone(); } cvFindContours(gray, cvStorage, contourPointer, Loader.sizeof(CvContour.class), 0, CV_CHAIN_APPROX_SIMPLE); // new cvFindContours(gray, storage, contourPointer, // Loader.sizeof(CvContour.class), CV_RETR_LIST, // CV_CHAIN_APPROX_SIMPLE); // old cvFindContours(gray, storage, contourPointer, sizeofCvContour, 0 // ,CV_CHAIN_APPROX_SIMPLE); // log.error("getStructure"); if (publishNodes) { minArea = 1500; nodes = new ArrayList<KinectImageNode>(); while (contour != null && !contour.isNull()) { if (contour.elem_size() > 0) { // TODO - limit here for // "TOOOO MANY !!!!" CvRect rect = cvBoundingRect(contour, 0); // size filter if (minArea > 0 && (rect.width() * rect.height()) < minArea) { isMinArea = false; } if (maxArea > 0) { isMaxArea = false; } if (isMinArea && isMaxArea) { CvSeq points = cvApproxPoly(contour, Loader.sizeof(CvContour.class), cvStorage, CV_POLY_APPROX_DP, cvContourPerimeter(contour) * 0.02, 1); // FIXME - do the work of changing all data types so // that the only // published material is java.awt object no OpenCV // objects KinectImageNode node = new KinectImageNode(); // node.cameraFrame = image.getBufferedImage(); node.cvCameraFrame = itemp.clone(); // pyramid down // version node.cvBoundingBox = new CvRect(rect); node.boundingBox = new Rectangle(rect.x(), rect.y(), rect.width(), rect.height()); // convert camera frame // FIXME node.cameraFrame = OpenCV.publishFrame("", // node.cvCameraFrame.getBufferedImage()); // cropped cvSetImageROI(node.cvCameraFrame, node.cvBoundingBox); node.cvCropped = cvCreateImage(cvSize(node.cvBoundingBox.width(), node.cvBoundingBox.height()), 8, 3); cvCopy(node.cvCameraFrame, node.cvCropped); cvResetImageROI(node.cvCameraFrame); // FIXME node.cropped = OpenCV.publishFrame("", // node.cvCropped.getBufferedImage()); log.error("{}", rect); log.error("{}", node.cvBoundingBox); log.error("{}", node.boundingBox); nodes.add(node); if (drawBoundingBoxes) { cvPutText(itemp2, " " + 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); p0.x(rect.x()); p0.y(rect.y()); p1.x(rect.x() + rect.width()); p1.y(rect.y() + rect.height()); cvDrawRect(itemp2, p0, p1, CvScalar.RED, 1, 8, 0); } } isMinArea = true; isMaxArea = true; // ++cnt; } contour = contour.h_next(); } // while (contour != null && !contour.isNull()) invoke("publish", (Object) nodes); } // if (publishNodes) cvClearMemStorage(cvStorage); // find contours ---- end -------------------------------------- return itemp2; } }