adding c++ interface to the datamtrix codes of j.
authorEthan Rublee <no@email>
Wed, 25 May 2011 00:23:50 +0000 (00:23 +0000)
committerEthan Rublee <no@email>
Wed, 25 May 2011 00:23:50 +0000 (00:23 +0000)
modules/objdetect/include/opencv2/objdetect/objdetect.hpp
modules/objdetect/src/datamatrix.cpp
modules/python/src1/cv.cpp
samples/cpp/video_dmtx.cpp [new file with mode: 0644]

index 5309ae5..97c75e6 100644 (file)
@@ -690,7 +690,14 @@ protected:
     std::vector<std::string> objectClassNames;
     std::vector<DOTTemplate> dotTemplates;
 };
+struct CV_EXPORTS DataMatrixCode {
+  char msg[4]; //TODO std::string
+  Mat original;
+  Point corners[4]; //TODO vector
+};
 
+CV_EXPORTS void findDataMatrix(const Mat& image, std::vector<DataMatrixCode>& codes);
+void drawDataMatrixCodes(const std::vector<DataMatrixCode>& codes, Mat& drawImage);
 }
 
 /****************************************************************************************\
@@ -699,15 +706,14 @@ protected:
 
 typedef unsigned char uint8;
 
-class CV_EXPORTS DataMatrixCode {
-public:
+struct CV_EXPORTS CvDataMatrixCode {
   char msg[4];
   CvMat *original;
   CvMat *corners;
 };
-#include <deque>
-CV_EXPORTS std::deque<DataMatrixCode> cvFindDataMatrix(CvMat *im);
 
+#include <deque>
+CV_EXPORTS std::deque<CvDataMatrixCode> cvFindDataMatrix(CvMat *im);
 #endif
 
 #endif
index 15cdc80..7f051a2 100644 (file)
@@ -5,11 +5,15 @@
 #endif
 
 #include <deque>
+#include <algorithm>
+
 using namespace std;
 
 #undef NDEBUG
 #include <assert.h>
 
+
+
 class Sampler {
 public:
   CvMat *im;
@@ -18,7 +22,6 @@ public:
   CvMat *perim;
   CvPoint fcoord(float fx, float fy);
   CvPoint coord(int ix, int iy);
-  Sampler() {}
   Sampler(CvMat *_im, CvPoint _o, CvPoint _c, CvPoint _cc);
   uint8 getpixel(int ix, int iy);
   int isinside(int x, int y);
@@ -26,6 +29,8 @@ public:
   int hasbars();
   void timing();
   CvMat *extract();
+  Sampler():im(0),perim(0){}
+  ~Sampler(){}
 };
 
 class code {    // used in this file only
@@ -128,16 +133,21 @@ CvPoint Sampler::coord(int ix, int iy)
 uint8 Sampler::getpixel(int ix, int iy)
 {
   CvPoint pt = coord(ix, iy);
-  // printf("%d,%d\n", pt.x, pt.y);
-  return *cvPtr2D(im, pt.y, pt.x);
+  if ((0 <= pt.x) && (pt.x < im->cols) && (0 <= pt.y) && (pt.y < im->rows))
+    return *cvPtr2D(im, pt.y, pt.x);
+  else
+    return 0;
 }
 
 int Sampler::isinside(int x, int y)
 {
-  CvPoint2D32f fp;
-  fp.x = (float)x;
-  fp.y = (float)y;
-  return cvPointPolygonTest(perim, fp, 0) < 0;
+  CvPoint2D32f pt;
+  pt.x = (float)x;
+  pt.y = (float)y;
+  if ((0 <= pt.x) && (pt.x < im->cols) && (0 <= pt.y) && (pt.y < im->rows))
+    return cvPointPolygonTest(perim, pt, 0) < 0;
+  else
+    return 0;
 }
 
 int Sampler::overlap(Sampler &other)
@@ -329,7 +339,7 @@ static deque<CvPoint> trailto(CvMat *v, int x, int y, CvMat *terminal)
   return r;
 }
 
-deque <DataMatrixCode> cvFindDataMatrix(CvMat *im)
+deque <CvDataMatrixCode> cvFindDataMatrix(CvMat *im)
 {
 #if CV_SSE2
   int r = im->rows;
@@ -411,7 +421,7 @@ deque <DataMatrixCode> cvFindDataMatrix(CvMat *im)
         __m128 iscand = _mm_and_ps(_mm_cmpgt_ps(cmag, Kf(30)), _mm_cmpgt_ps(ccmag, Kf(30)));
 
         iscand = _mm_and_ps(iscand, _mm_cmpgt_ps(_mm_mul_ps(_mm_min_ps(cmag, ccmag), Kf(1.1f)), _mm_max_ps(cmag, ccmag)));
-           iscand = _mm_and_ps(iscand, _mm_cmplt_ps(_mm_abs_ps(dot),  Kf(0.25f)));
+        iscand = _mm_and_ps(iscand, _mm_cmplt_ps(_mm_abs_ps(dot),  Kf(0.25f)));
 
         unsigned int CV_DECL_ALIGNED(16) result[4];
         _mm_store_ps((float*)result, iscand);
@@ -441,7 +451,10 @@ deque <DataMatrixCode> cvFindDataMatrix(CvMat *im)
         Sampler sa(im, o, ptc[j], ptcc[k]);
         for (i = 0; i < codes.size(); i++) {
           if (sa.overlap(codes[i].sa))
+          {
+            cvReleaseMat(&sa.perim);
             goto endo;
+          }
         }
         if (codes.size() > 0) {
           printf("searching for more\n");
@@ -450,21 +463,23 @@ deque <DataMatrixCode> cvFindDataMatrix(CvMat *im)
           codes.push_back(cc);
           goto endo;
         }
+
+        cvReleaseMat(&sa.perim);
       }
     }
 endo: ; // end search for this o
   }
 
-  cvFree(&thresh);
-  cvFree(&vecpic);
-  cvFree(&vc);
-  cvFree(&vcc);
-  cvFree(&cxy);
-  cvFree(&ccxy);
+  cvReleaseMat(&thresh);
+  cvReleaseMat(&vecpic);
+  cvReleaseMat(&vc);
+  cvReleaseMat(&vcc);
+  cvReleaseMat(&cxy);
+  cvReleaseMat(&ccxy);
 
-  deque <DataMatrixCode> rc;
+  deque <CvDataMatrixCode> rc;
   for (i = 0; i < codes.size(); i++) {
-    DataMatrixCode cc;
+    CvDataMatrixCode cc;
     strcpy(cc.msg, codes[i].msg);
     cc.original = codes[i].original;
     cc.corners = codes[i].sa.perim;
@@ -472,7 +487,68 @@ endo: ; // end search for this o
   }
   return rc;
 #else
-  deque <DataMatrixCode> rc;
+  deque <CvDataMatrixCode> rc;
   return rc;
 #endif
 }
+
+#include <opencv2/imgproc/imgproc.hpp>
+#include <opencv2/highgui/highgui.hpp>
+
+namespace cv
+{
+namespace
+{
+  struct CvDM2DM_transform
+  {
+    DataMatrixCode operator()(CvDataMatrixCode& cvdm)
+    {
+      DataMatrixCode dm;
+      std::memcpy(dm.msg,cvdm.msg,sizeof(cvdm.msg));
+      dm.original = cv::Mat(cvdm.original,true);
+      cvReleaseMat(&cvdm.original);
+      cv::Mat c(cvdm.corners,true);
+      dm.corners[0] = c.at<Point>(0,0);
+      dm.corners[1] = c.at<Point>(1,0);
+      dm.corners[2] = c.at<Point>(2,0);
+      dm.corners[3] = c.at<Point>(3,0);
+      cvReleaseMat(&cvdm.corners);
+      return dm;
+    }
+  };
+  
+  struct DrawDataMatrixCode
+  {
+    DrawDataMatrixCode(cv::Mat& image):image(image){}
+    void operator()(const DataMatrixCode& code)
+    {
+      Scalar c(0, 255, 0);
+      Scalar c2(255, 0,0);
+      line(image, code.corners[0], code.corners[1], c);
+      line(image, code.corners[1], code.corners[2], c);
+      line(image, code.corners[2], code.corners[3], c);
+      line(image, code.corners[3], code.corners[0], c);
+      string code_text(code.msg,4);
+      int baseline = 0;
+      Size sz = getTextSize(code_text, CV_FONT_HERSHEY_SIMPLEX, 1, 1, &baseline);
+      putText(image, code_text, code.corners[0], CV_FONT_HERSHEY_SIMPLEX, 0.8, c2, 1, CV_AA, false);
+    }
+    cv::Mat& image;
+  };
+}
+
+void findDataMatrix(const cv::Mat& image, std::vector<DataMatrixCode>& codes)
+{
+  CvMat m(image);
+  deque <CvDataMatrixCode> rc = cvFindDataMatrix(&m);
+  codes.clear();
+  codes.resize(rc.size());
+  std::transform(rc.begin(),rc.end(),codes.begin(),CvDM2DM_transform());  
+}
+
+void drawDataMatrixCodes(const std::vector<DataMatrixCode>& codes, Mat& drawImage)
+{
+  std::for_each(codes.begin(),codes.end(),DrawDataMatrixCode(drawImage));
+}
+
+}
index 3ed49e4..7a65891 100644 (file)
@@ -3686,12 +3686,12 @@ static PyObject *pyfinddatamatrix(PyObject *self, PyObject *args)
   CvMat *image;
   if (!convert_to_CvMat(pyim, &image, "image")) return NULL;
 
-  std::deque <DataMatrixCode> codes;
+  std::deque <CvDataMatrixCode> codes;
   ERRWRAP(codes = cvFindDataMatrix(image));
 
   PyObject *pycodes = PyList_New(codes.size());
   for (size_t i = 0; i < codes.size(); i++) {
-    DataMatrixCode *pc = &codes[i];
+    CvDataMatrixCode *pc = &codes[i];
     PyList_SetItem(pycodes, i, Py_BuildValue("(sOO)", pc->msg, FROM_CvMat(pc->corners), FROM_CvMat(pc->original)));
   }
 
diff --git a/samples/cpp/video_dmtx.cpp b/samples/cpp/video_dmtx.cpp
new file mode 100644 (file)
index 0000000..ea2a575
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * starter_video.cpp
+ *
+ *  Created on: Nov 23, 2010
+ *      Author: Ethan Rublee
+ *
+ * A starter sample for using opencv, get a video stream and display the images
+ * easy as CV_PI right?
+ */
+#include "opencv2/highgui/highgui.hpp"
+#include <opencv2/objdetect/objdetect.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+#include <iostream>
+#include <vector>
+#include <stdio.h>
+
+using namespace cv;
+using namespace std;
+
+//hide the local functions in an anon namespace
+namespace
+{
+void help(char** av)
+{
+  cout << "\nThis program justs gets you started reading images from video\n"
+    "Usage:\n./" << av[0] << " <video device number>\n" << "q,Q,esc -- quit\n"
+      << "space   -- save frame\n\n"
+      << "\tThis is a starter sample, to get you up and going in a copy pasta fashion\n"
+      << "\tThe program captures frames from a camera connected to your computer.\n"
+      << "\tTo find the video device number, try ls /dev/video* \n"
+      << "\tYou may also pass a video file, like my_vide.avi instead of a device number"
+      << endl;
+}
+
+int process(VideoCapture& capture)
+{
+  std::vector<DataMatrixCode> codes;
+  int n = 0;
+  char filename[200];
+  string window_name = "video | q or esc to quit";
+  cout << "press space to save a picture. q or esc to quit" << endl;
+  namedWindow(window_name, CV_WINDOW_KEEPRATIO); //resizable window;
+  Mat frame;
+  for (;;)
+  {
+    capture >> frame;
+    if (frame.empty())
+      continue;
+    cv::Mat gray;
+    cv::cvtColor(frame,gray,CV_RGB2GRAY);
+    findDataMatrix(gray, codes);
+    drawDataMatrixCodes(codes, frame);
+    imshow(window_name, frame);
+    char key = (char) waitKey(5); //delay N millis, usually long enough to display and capture input
+    switch (key)
+    {
+    case 'q':
+    case 'Q':
+    case 27: //escape key
+      return 0;
+    case ' ': //Save an image
+      sprintf(filename, "filename%.3d.jpg", n++);
+      imwrite(filename, frame);
+      cout << "Saved " << filename << endl;
+      break;
+    default:
+      break;
+    }
+  }
+  return 0;
+}
+
+}
+
+int main(int ac, char** av)
+{
+
+  if (ac != 2)
+  {
+    help(av);
+    return 1;
+  }
+  std::string arg = av[1];
+  VideoCapture capture(arg); //try to open string, this will attempt to open it as a video file
+  if (!capture.isOpened()) //if this fails, try to open as a video camera, through the use of an integer param
+    capture.open(atoi(arg.c_str()));
+  if (!capture.isOpened())
+  {
+    cerr << "Failed to open a video device or video file!\n" << endl;
+    help(av);
+    return 1;
+  }
+  return process(capture);
+}