modified data matrix detection interface (that does not use any new data structures). Added Python sample for data matrix detection. Ticket #1664

This commit is contained in:
Vadim Pisarevsky 2012-04-27 16:10:10 +00:00
parent 1046f50acb
commit 9b382d07f6
5 changed files with 215 additions and 129 deletions

View File

@ -2142,11 +2142,11 @@ CV_EXPORTS Mat repeat(const Mat& src, int ny, int nx);
CV_EXPORTS void hconcat(const Mat* src, size_t nsrc, OutputArray dst); CV_EXPORTS void hconcat(const Mat* src, size_t nsrc, OutputArray dst);
CV_EXPORTS void hconcat(InputArray src1, InputArray src2, OutputArray dst); CV_EXPORTS void hconcat(InputArray src1, InputArray src2, OutputArray dst);
CV_EXPORTS_W void hconcat(InputArray src, OutputArray dst); CV_EXPORTS_W void hconcat(InputArrayOfArrays src, OutputArray dst);
CV_EXPORTS void vconcat(const Mat* src, size_t nsrc, OutputArray dst); CV_EXPORTS void vconcat(const Mat* src, size_t nsrc, OutputArray dst);
CV_EXPORTS void vconcat(InputArray src1, InputArray src2, OutputArray dst); CV_EXPORTS void vconcat(InputArray src1, InputArray src2, OutputArray dst);
CV_EXPORTS_W void vconcat(InputArray src, OutputArray dst); CV_EXPORTS_W void vconcat(InputArrayOfArrays src, OutputArray dst);
//! computes bitwise conjunction of the two arrays (dst = src1 & src2) //! computes bitwise conjunction of the two arrays (dst = src1 & src2)
CV_EXPORTS_W void bitwise_and(InputArray src1, InputArray src2, CV_EXPORTS_W void bitwise_and(InputArray src1, InputArray src2,

View File

@ -586,16 +586,13 @@ public:
}; };
CV_EXPORTS_W void findDataMatrix(InputArray image,
CV_OUT vector<string>& codes,
struct CV_EXPORTS DataMatrixCode { OutputArray corners=noArray(),
char msg[4]; //TODO std::string OutputArrayOfArrays dmtx=noArray());
Mat original; CV_EXPORTS_W void drawDataMatrixCodes(InputOutputArray image,
Point corners[4]; //TODO vector const vector<string>& codes,
}; InputArray corners);
CV_EXPORTS void findDataMatrix(const Mat& image, std::vector<DataMatrixCode>& codes);
CV_EXPORTS void drawDataMatrixCodes(const std::vector<DataMatrixCode>& codes, Mat& drawImage);
} }
/****************************************************************************************\ /****************************************************************************************\

View File

@ -496,60 +496,80 @@ endo: ; // end search for this o
namespace cv namespace cv
{ {
namespace
void findDataMatrix(InputArray _image,
vector<string>& codes,
OutputArray _corners,
OutputArrayOfArrays _dmtx)
{ {
struct CvDM2DM_transform Mat image = _image.getMat();
{ CvMat m(image);
DataMatrixCode operator()(CvDataMatrixCode& cvdm) deque <CvDataMatrixCode> rc = cvFindDataMatrix(&m);
int i, n = (int)rc.size();
Mat corners;
if( _corners.needed() )
{ {
DataMatrixCode dm; _corners.create(n, 4, CV_32SC2);
memcpy(dm.msg,cvdm.msg,sizeof(cvdm.msg)); corners = _corners.getMat();
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;
} }
};
if( _dmtx.needed() )
struct DrawDataMatrixCode _dmtx.create(n, 1, CV_8U);
{
DrawDataMatrixCode(cv::Mat& image):image(image){} codes.resize(n);
void operator()(const DataMatrixCode& code)
for( i = 0; i < n; i++ )
{ {
Scalar c(0, 255, 0); CvDataMatrixCode& rc_i = rc[i];
Scalar c2(255, 0,0); codes[i] = string(rc_i.msg);
line(image, code.corners[0], code.corners[1], c);
line(image, code.corners[1], code.corners[2], c); if( corners.data )
line(image, code.corners[2], code.corners[3], c); {
line(image, code.corners[3], code.corners[0], c); const Point* srcpt = (Point*)rc_i.corners->data.ptr;
string code_text(code.msg,4); Point* dstpt = (Point*)corners.ptr(i);
//int baseline = 0; for( int k = 0; k < 4; k++ )
//Size sz = getTextSize(code_text, CV_FONT_HERSHEY_SIMPLEX, 1, 1, &baseline); dstpt[k] = srcpt[k];
putText(image, code_text, code.corners[0], CV_FONT_HERSHEY_SIMPLEX, 0.8, c2, 1, CV_AA, false); }
cvReleaseMat(&rc_i.corners);
if( _dmtx.needed() )
{
_dmtx.create(rc_i.original->rows, rc_i.original->cols, rc_i.original->type, i);
Mat dst = _dmtx.getMat(i);
Mat(rc_i.original).copyTo(dst);
}
cvReleaseMat(&rc_i.original);
} }
cv::Mat& image;
DrawDataMatrixCode& operator=(const DrawDataMatrixCode&);
};
} }
void findDataMatrix(const cv::Mat& image, std::vector<DataMatrixCode>& codes) void drawDataMatrixCodes(InputOutputArray _image,
const vector<string>& codes,
InputArray _corners)
{ {
CvMat m(image); Mat image = _image.getMat();
deque <CvDataMatrixCode> rc = cvFindDataMatrix(&m); Mat corners = _corners.getMat();
codes.clear(); int i, n = corners.rows;
codes.resize(rc.size());
std::transform(rc.begin(),rc.end(),codes.begin(),CvDM2DM_transform()); if( n > 0 )
{
CV_Assert( corners.depth() == CV_32S &&
corners.cols*corners.channels() == 8 &&
n == (int)codes.size() );
}
for( i = 0; i < n; i++ )
{
Scalar c(0, 255, 0);
Scalar c2(255, 0,0);
const Point* pt = (const Point*)corners.ptr(i);
for( int k = 0; k < 4; k++ )
line(image, pt[k], pt[(k+1)%4], c);
//int baseline = 0;
//Size sz = getTextSize(code_text, CV_FONT_HERSHEY_SIMPLEX, 1, 1, &baseline);
putText(image, codes[i], pt[0], CV_FONT_HERSHEY_SIMPLEX, 0.8, c2, 1, CV_AA, false);
}
} }
void drawDataMatrixCodes(const std::vector<DataMatrixCode>& codes, Mat& drawImage)
{
std::for_each(codes.begin(),codes.end(),DrawDataMatrixCode(drawImage));
}
} }

View File

@ -21,80 +21,81 @@ using namespace std;
//hide the local functions in an anon namespace //hide the local functions in an anon namespace
namespace namespace
{ {
void help(char** av) 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"
<< "\n"
<< "DATA:\n"
<< "Generate a datamatrix from from http://datamatrix.kaywa.com/ \n"
<< " NOTE: This only handles strings of len 3 or less\n"
<< " Resize the screen to be large enough for your camera to see, and it should find an read it.\n\n"
<< 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())
break;
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': cout << "\nThis program justs gets you started reading images from video\n"
case 'Q': "Usage:\n./" << av[0] << " <video device number>\n" << "q,Q,esc -- quit\n"
case 27: //escape key << "space -- save frame\n\n"
return 0; << "\tThis is a starter sample, to get you up and going in a copy pasta fashion\n"
case ' ': //Save an image << "\tThe program captures frames from a camera connected to your computer.\n"
sprintf(filename, "filename%.3d.jpg", n++); << "\tTo find the video device number, try ls /dev/video* \n"
imwrite(filename, frame); << "\tYou may also pass a video file, like my_vide.avi instead of a device number"
cout << "Saved " << filename << endl; << "\n"
break; << "DATA:\n"
default: << "Generate a datamatrix from from http://datamatrix.kaywa.com/ \n"
break; << " NOTE: This only handles strings of len 3 or less\n"
<< " Resize the screen to be large enough for your camera to see, and it should find an read it.\n\n"
<< endl;
} }
}
return 0; int process(VideoCapture& capture)
} {
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())
break;
cv::Mat gray;
cv::cvtColor(frame,gray,CV_RGB2GRAY);
vector<string> codes;
Mat corners;
findDataMatrix(gray, codes, corners);
drawDataMatrixCodes(frame, codes, corners);
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) int main(int ac, char** av)
{ {
if (ac != 2) if (ac != 2)
{ {
help(av); help(av);
return 1; return 1;
} }
std::string arg = av[1]; std::string arg = av[1];
VideoCapture capture(arg); //try to open string, this will attempt to open it as a video file 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 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())); capture.open(atoi(arg.c_str()));
if (!capture.isOpened()) if (!capture.isOpened())
{ {
cerr << "Failed to open a video device or video file!\n" << endl; cerr << "Failed to open a video device or video file!\n" << endl;
help(av); help(av);
return 1; return 1;
} }
return process(capture); return process(capture);
} }

View File

@ -0,0 +1,68 @@
help='''
Data matrix detector sample.
Usage:
video_dmtx {<video device number>|<video file name>}
Generate a datamatrix from from http://datamatrix.kaywa.com/ and print it out.
NOTE: This only handles data matrices, generated for text strings of max 3 characters
Resize the screen to be large enough for your camera to see, and it should find an read it.
Keyboard shortcuts:
q or ESC - exit
space - save current image as datamatrix<frame_number>.jpg
'''
import cv2
import numpy as np
import sys
def data_matrix_demo(cap):
window_name = "Data Matrix Detector"
frame_number = 0
need_to_save = False
while 1:
ret, frame = cap.read()
if not ret:
break
gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)
codes, corners, dmtx = cv2.findDataMatrix(gray)
cv2.drawDataMatrixCodes(frame, codes, corners)
cv2.imshow(window_name, frame)
key = cv2.waitKey(30)
c = chr(key & 255)
if c in ['q', 'Q', chr(27)]:
break
if c == ' ':
need_to_save = True
if need_to_save and codes:
filename = ("datamatrix%03d.jpg" % frame_number)
cv2.imwrite(filename, frame)
print "Saved frame to " + filename
need_to_save = False
frame_number += 1
if __name__ == '__main__':
print help
if len(sys.argv) == 1:
cap = cv2.VideoCapture(0)
else:
cap = cv2.VideoCapture(sys.argv[1])
if not cap.isOpened():
cap = cv2.VideoCapture(int(sys.argv[1]))
if not cap.isOpened():
print 'Cannot initialize video capture'
sys.exit(-1)
data_matrix_demo(cap)