Barry Thomas

Java Source Code

These snippets of code are from my demo Android app for machine vision, using OpenCV v2.4.4. The snippets on this site are intended to help you see how easy it is to use many of the features of OpenCV. I assume you have installed the OpenCV v2.4.4 library and the samples which accompany it. These snippets should drop reasonably neatly into the sample apps' code from the OpenCV 2.4.4 sdk.

Feel free to use this code for any purpose. I don't guarantee it works. The code isn't written for speed or efficiency, just so it works and you can see what is going on. Feel free to improve it.

Other advice: Get a copy of "Learning OpenCV". Read it. Read it again because you probably skipped a lot of it first time through. It does get easier the more you do. Find lots of snippets of test code here. Use StackOverflow. Read Marcos Nieto's blog.

Canny Edge Detection

  1. case VIEW_MODE_CANNY:  
  2.               
  3.     Imgproc.cvtColor(mRgba, mGray, Imgproc.COLOR_RGBA2GRAY);  
  4.   
  5.     // doing a gaussian blur prevents getting a lot of false hits  
  6.     Imgproc.GaussianBlur(mGray, mGray, new Size(55), 22);  
  7.     
  8.     iCannyLowerThreshold = 35;  
  9.     iCannyUpperThreshold = 75;  
  10.                   
  11.     Imgproc.Canny(mGray, mIntermediateMat, iCannyLowerThreshold, iCannyUpperThreshold);  
  12.   
  13.     Imgproc.cvtColor(mIntermediateMat, mRgba, Imgproc.COLOR_GRAY2BGRA, 4);  
  14.   
  15.     if (bDisplayTitle)  
  16.         ShowTitle ("Canny Edges"1);  
  17.   
  18.     break;  

Hough Circles

  1. case VIEW_MODE_HOUGH_CIRCLES:  
  2.   
  3.     // the lower this figure the more spurious circles you get  
  4.     // 50 looks good in CANNY, but 100 is better when converting that into Hough circles  
  5.     iCannyUpperThreshold = 100;  
  6.                   
  7.     Imgproc.HoughCircles(mGray, mIntermediateMat, Imgproc.CV_HOUGH_GRADIENT, 2.0, mGray.rows() / 8,   
  8.                 iCannyUpperThreshold, iAccumulator, iMinRadius, iMaxRadius);  
  9.                   
  10.     if (mIntermediateMat.cols() > 0)  
  11.         for (int x = 0; x < Math.min(mIntermediateMat.cols(), 10); x++)   
  12.             {  
  13.             double vCircle[] = mIntermediateMat.get(0,x);  
  14.   
  15.             if (vCircle == null)  
  16.                 break;  
  17.   
  18.             pt = new Point(Math.round(vCircle[0]), Math.round(vCircle[1]));  
  19.             radius = (int)Math.round(vCircle[2]);  
  20.             // draw the found circle  
  21.             Core.circle(mRgba, pt, radius, colorRed, iLineThickness);  
  22.                           
  23.             // draw a cross on the centre of the circle  
  24.             DrawCross (mRgba, pt);  
  25.             }  
  26.                   
  27.         if (bDisplayTitle)  
  28.             ShowTitle ("Hough Circles"1);  
  29.               
  30.     break;  

Hough Lines

I limit the results to 50 lines, otherwise on very busy textured surfaces you can get a LOT of spurious results.

  1. case VIEW_MODE_HOUGH_LINES:  
  2.   
  3.     // the lower this figure the more spurious circles you get  
  4.     // 50 upper looks good in CANNY, but 75 is better when converting that into Hough circles  
  5.     iCannyLowerThreshold = 45;  
  6.     iCannyUpperThreshold = 75;  
  7.                   
  8.     Imgproc.Canny(mGray, mGray, iCannyLowerThreshold, iCannyUpperThreshold);  
  9.   
  10.     Imgproc.HoughLinesP(mGray, lines, 1, Math.PI/180, iHoughLinesThreshold, iHoughLinesMinLineSize, iHoughLinesGap);  
  11.                   
  12.     for (int x = 0; x < Math.min(lines.cols(), 50); x++)   
  13.         {  
  14.         double[] vec = lines.get(0, x);  
  15.                       
  16.         if (vec == null)  
  17.             break;  
  18.                       
  19.         double x1 = vec[0], y1 = vec[1], x2 = vec[2], y2 = vec[3];  
  20.         Point start = new Point(x1, y1);  
  21.         Point end = new Point(x2, y2);  
  22.   
  23.         Core.line(mRgba, start, end, colorRed, 3);  
  24.         }  
  25.        
  26.     if (bDisplayTitle)  
  27.         ShowTitle ("Hough Lines"1);  
  28.   
  29.     break;          

Colour Searching, with Bounding Contour

Convert to HSV, get the colours in range (here I'm looking for a nice bright yellow), erode the result a little to simplify it and reduce the resulting data set, get the contour, draw the contour (polygon).

  1.     case VIEW_MODE_COLCONTOUR:  
  2.               
  3.     // Convert the image into an HSV image  
  4.               
  5.     Imgproc.cvtColor(mRgba, mHSVMat, Imgproc.COLOR_RGB2HSV, 3);  
  6.               
  7.     Core.inRange(mHSVMat, new Scalar(byteColourTrackCentreHue[0] - 10100100),   
  8.                      new Scalar(byteColourTrackCentreHue[0] + 10255255), mHSVMat);  
  9.               
  10.     // Here i'm only using the external contours and by  
  11.     // eroding we make the draw a teeny bit faster and the result a lot smoother  
  12.     // on the rough edges where the colour fades out of range by losing a lot  
  13.     // of the little spiky corners.  
  14.   
  15.     Imgproc.erode(mHSVMat, mHSVMat, mErodeKernel);  
  16.     contours.clear();  
  17.   
  18.     Imgproc.findContours(mHSVMat, contours, mContours, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);  
  19.   
  20.     for (x = 0; x < contours.size(); x++) {  
  21.             d = Imgproc.contourArea (contours.get(x));  
  22.   
  23.     // get an approximation of the contour (last but one param is the min required  
  24.     // distance between the real points and the new approximation (in pixels)  
  25.               
  26.     // contours is a List<matofpoint>  
  27.     // so contours.get(x) is a single MatOfPoint  
  28.     // but to use approxPolyDP we need to pass a MatOfPoint2f  
  29.     // so we need to do a conversion   
  30.               
  31.     contours.get(x).convertTo(mMOP2f1, CvType.CV_32FC2);  
  32.                   
  33.     if (d > iContourAreaMin) {  
  34.   
  35.         Imgproc.approxPolyDP(mMOP2f1, mMOP2f2, 2true);  
  36.                       
  37.         // convert back to MatOfPoint and put it back in the list  
  38.         mMOP2f2.convertTo(contours.get(x), CvType.CV_32S);  
  39.                       
  40.         // draw the contour itself  
  41.         Imgproc.drawContours(mRgba, contours, x, colorRed, iLineThickness);  
  42.         }  
  43.     }  
  44.   
  45.     if (bDisplayTitle)  
  46.         ShowTitle ("In-range + Contours"1);  
  47.   
  48.     break;  
  49.   
  50. </matofpoint>  

Colour Searching, with Quadrilateral

As above, except we simplify the boundary of the contour by allowing a much bigger gap between the actual edge of the block of colour and the bounding contour (15 pixels). If after that the resulting polygon has four corners we know we have a quadrilateral. In addition to drawing the contour, we draw in the diagonals of the quad.

  1. case VIEW_MODE_YELLOW_QUAD_DETECT:  
  2.   
  3.     // Convert the image into an HSV image  
  4.   
  5.     Imgproc.cvtColor(mRgba, mHSVMat, Imgproc.COLOR_RGB2HSV, 3);  
  6.               
  7.     Core.inRange(mHSVMat, new Scalar(byteColourTrackCentreHue[0] - 12100100),   
  8.                      new Scalar(byteColourTrackCentreHue[0] + 12255255), mHSVMat);  
  9.   
  10.     contours.clear();  
  11.               
  12.     Imgproc.findContours(mHSVMat, contours, mContours, Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);  
  13.               
  14.     for (x = 0; x < contours.size(); x++) {  
  15.         d = Imgproc.contourArea (contours.get(x));  
  16.   
  17.         if (d > iContourAreaMin) {  
  18.             // get an approximation of the contour (last but one param is the min required  
  19.             // distance between the real points and the new approximation (in pixels)  
  20.                       
  21.             contours.get(x).convertTo(mMOP2f1, CvType.CV_32FC2);  
  22.                       
  23.             Imgproc.approxPolyDP(mMOP2f1, mMOP2f2, 15true);  
  24.                       
  25.             // convert back to MatOfPoint and put it back in the list  
  26.             mMOP2f2.convertTo(contours.get(x), CvType.CV_32S);  
  27.                       
  28.             if (contours.get(x).rows() == 4) {  
  29.                           
  30.             Converters.Mat_to_vector_Point2f(contours.get(x), pts);  
  31.                           
  32.             Imgproc.drawContours(mRgba, contours, x, colorRed, iLineThickness);  
  33.   
  34.             Core.line(mRgba, pts.get(0), pts.get(2), colorRed, iLineThickness);  
  35.             Core.line(mRgba, pts.get(1), pts.get(3), colorRed, iLineThickness);  
  36.             }  
  37.         }  
  38.     }  
  39.   
  40.     if (bDisplayTitle)  
  41.         ShowTitle ("Colour quadrilateral"1);  
  42.   
  43.     break;  

Face Detection

This section uses some code from the OpenCV sample "face-detection" and uses the LBP cascade file

  1. try {  
  2.     // DO FACE CASCADE SETUP  
  3.                           
  4.     Context context = getApplicationContext();  
  5.     InputStream is3 = context.getResources().openRawResource(R.raw.lbpcascade_frontalface);  
  6.     File cascadeDir = context.getDir("cascade", Context.MODE_PRIVATE);  
  7.     File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");  
  8.   
  9.     FileOutputStream os = new FileOutputStream(cascadeFile);  
  10.   
  11.     byte[] buffer = new byte[4096];  
  12.     int bytesRead;  
  13.                       
  14.     while ((bytesRead = is3.read(buffer)) != -1) {  
  15.         os.write(buffer, 0, bytesRead);  
  16.         }  
  17.                       
  18.     is3.close();  
  19.     os.close();  
  20.   
  21.     mCascade = new CascadeClassifier(cascadeFile.getAbsolutePath());  
  22.                                       
  23.     if (mCascade.empty()) {  
  24.         Log.d("OpenCV""Failed to load cascade classifier");  
  25.         mCascade = null;  
  26.         }    
  27.   
  28.     cascadeFile.delete();  
  29.     cascadeDir.delete();  
  30.   
  31.     }   
  32. catch (IOException e) {  
  33.     e.printStackTrace();  
  34.     Log.d("OpenCV""Failed to load cascade. Exception thrown: " + e);  
  35.     }  

I first draw a rectangle around each face, and check to see if the current face is larger than the rest so far. I then copy the largest face to the top left of the screen. This just shows how, having found a face, you can take just that part of the image and do something else with it.

  1. case VIEW_MODE_FACEDETECT:  
  2.   
  3.     // Convert the image into a gray image  
  4.   
  5.     Imgproc.cvtColor(mRgba, mGray, Imgproc.COLOR_RGBA2GRAY);  
  6.               
  7.     if (mCascade != null) {  
  8.         int height = mGray.rows();  
  9.         int faceSize = Math.round(height * 0.2f);  
  10.                   
  11.         mCascade.detectMultiScale(mGray, faces, 1.122new Size(faceSize, faceSize), new Size());  
  12.   
  13.         for (Rect r : faces.toArray()) {  
  14.                       
  15.             // draw the rectangle itself  
  16.             Core.rectangle(mRgba, r.tl(), r.br(), colorRed, 3);  
  17.             if (iMaxFaceHeight < r.height) {  
  18.                 iMaxFaceHeight = r.height;  
  19.                 iMaxFaceHeightIndex++;  
  20.                 }  
  21.             }  
  22.   
  23.         if (iMaxFaceHeight > 0) {  
  24.             // we have at least one face  
  25.             Rect[] facesArray = faces.toArray();  
  26.                       
  27.             rect = facesArray[iMaxFaceHeightIndex];  
  28.   
  29.             // get the submat of the rect containing the face  
  30.             mROIMat = mRgba.submat(rect);  
  31.             // resize it to the dest rect size (100x100)  
  32.             Imgproc.resize(mROIMat, mFaceResized, sSize);  
  33.             // copy it to dest rect in main image  
  34.                       
  35.             mFaceResized.copyTo(mFaceDest);  
  36.             mROIMat.release();  
  37.             }  
  38.         }  
  39.     }  
  40.   
  41. if (bDisplayTitle)  
  42.     ShowTitle ("Face Detection"1);  
  43.               
  44. break;  

Good Features to Track

This is the first stage of the process of tracking objects - first find good (ie strong) features to track and then track existing objects through subsequent frames.

  1. case VIEW_MODE_GFTT:  
  2.     // DON'T do a gaussian blur here, it makes the results poorer and  
  3.     // takes 0.5 off the fps rate  
  4.     // Imgproc.GaussianBlur(mGray, mGray, new Size(5, 5), 2, 2);  
  5.   
  6.     Imgproc.goodFeaturesToTrack(mGray, MOPcorners, 500.0130);  
  7.               
  8.     y = MOPcorners.rows();  
  9.               
  10.     corners = MOPcorners.toList();  
  11.               
  12.     for (int x = 0; x < y; x++)   
  13.         // Core.circle(mRgba, corners.get(x), 8, colorRed, iLineThickness - 1);  
  14.         DrawCross (mRgba, corners.get(x));  
  15.   
  16.     if (bDisplayTitle)  
  17.         ShowTitle ("Track Features"1);  
  18.               
  19.     break;  

Optical Flow

Compares "good features to track" from one frame to the next. Currently limited to 40 features or fewer (poor quality features are ignored). Read more here.

  1. case VIEW_MODE_OPFLOW:  
  2.   
  3.     if (mMOP2fptsPrev.rows() == 0) {  
  4.         // first time through the loop so we need prev and this mats  
  5.         // plus prev points  
  6.         // get this mat  
  7.         Imgproc.cvtColor(mRgba, matOpFlowThis, Imgproc.COLOR_RGBA2GRAY);  
  8.   
  9.         // copy that to prev mat  
  10.         matOpFlowThis.copyTo(matOpFlowPrev);  
  11.                   
  12.         // get prev corners  
  13.         Imgproc.goodFeaturesToTrack(matOpFlowPrev, MOPcorners, iGFFTMax, 0.0120);  
  14.         mMOP2fptsPrev.fromArray(MOPcorners.toArray());  
  15.                   
  16.         // get safe copy of this corners  
  17.         mMOP2fptsPrev.copyTo(mMOP2fptsSafe);  
  18.         }  
  19.     else  
  20.         {  
  21.         // we've been through before so  
  22.         // this mat is valid. Copy it to prev mat  
  23.         matOpFlowThis.copyTo(matOpFlowPrev);  
  24.   
  25.         // get this mat  
  26.         Imgproc.cvtColor(mRgba, matOpFlowThis, Imgproc.COLOR_RGBA2GRAY);  
  27.                   
  28.         // get the corners for this mat  
  29.         Imgproc.goodFeaturesToTrack(matOpFlowThis, MOPcorners, iGFFTMax, 0.0120);  
  30.         mMOP2fptsThis.fromArray(MOPcorners.toArray());  
  31.                   
  32.         // retrieve the corners from the prev mat  
  33.         // (saves calculating them again)  
  34.         mMOP2fptsSafe.copyTo(mMOP2fptsPrev);  
  35.                   
  36.         // and save this corners for next time through  
  37.                   
  38.         mMOP2fptsThis.copyTo(mMOP2fptsSafe);  
  39.         }  
  40.               
  41.     Video.calcOpticalFlowPyrLK(matOpFlowPrev, matOpFlowThis, mMOP2fptsPrev, mMOP2fptsThis, mMOBStatus, mMOFerr);  
  42.   
  43.     cornersPrev = mMOP2fptsPrev.toList();  
  44.     cornersThis = mMOP2fptsThis.toList();  
  45.     byteStatus = mMOBStatus.toList();  
  46.               
  47.     for (x = 0; x < byteStatus.size() - 1; x++) {  
  48.         if (byteStatus.get(x) == 1) {  
  49.         pt = cornersThis.get(x);  
  50.         pt2 = cornersPrev.get(x);  
  51.                       
  52.         Core.circle(mRgba, pt, 5, colorRed, iLineThickness - 1);  
  53.         Core.line(mRgba, pt, pt2, colorRed, iLineThickness);  
  54.         }  
  55.     }  
  56.               
  57.             if (bDisplayTitle)  
  58.                 ShowTitle ("Optical Flow"1, colorGreen);  
  59.   
  60.             break;  
StatCounter - Free Web Tracker and Counter