(坐标是从0开始的,并且是相对图像原点的位置。图像原点或者是左上角 (img->origin=IPL_ORIGIN_TL) 或者是左下角 (img->origin=IPL_ORIGIN_BL) )
I(x,y) ~ ((uchar*)(img->imageData + img->widthStep*y))[x]
I(x,y)blue ~ ((uchar*)(img->imageData + img->widthStep*y))[x*3]
I(x,y)green ~ ((uchar*)(img->imageData + img->widthStep*y))[x*3+1]
I(x,y)red ~ ((uchar*)(img->imageData + img->widthStep*y))[x*3+2]
CvPoint pt = {100,100};
((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3] += 30;
((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3+1] += 30;
((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3+2] += 30;
CvPoint pt = {100,100};
uchar* temp_ptr = &((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3];
temp_ptr[0] += 30;
temp_ptr[1] += 30;
temp_ptr[2] += 30;
I(x,y) ~ ((float*)(img->imageData + img->widthStep*y))[x]
I(x,y)c ~ ((T*)(img->imageData + img->widthStep*y))[x*N + c]
I(x,y)c ~ CV_IMAGE_ELEM( img, T, y, x*N + c )
方法是类似的(下面的例子都是针对 0 起点的列和行)
M(i,j) ~ ((float*)(mat->data.ptr + mat->step*i))[j]
Re M(i,j) ~ ((double*)(mat->data.ptr + mat->step*i))[j*2]
Im M(i,j) ~ ((double*)(mat->data.ptr + mat->step*i))[j*2+1]
M(i,j) ~ CV_MAT_ELEM( mat, float, i, j ),
CV_MAT_ELEM( mat, float, 0, 0 ) = 1.f;
CV_MAT_ELEM( mat, float, 0, 1 ) = 0.f;
CV_MAT_ELEM( mat, float, 0, 2 ) = 0.f;
CV_MAT_ELEM( mat, float, 1, 0 ) = 0.f;
CV_MAT_ELEM( mat, float, 1, 1 ) = 1.f;
CV_MAT_ELEM( mat, float, 1, 2 ) = 0.f;
CV_MAT_ELEM( mat, float, 2, 0 ) = 0.f;
CV_MAT_ELEM( mat, float, 2, 1 ) = 0.f;
CV_MAT_ELEM( mat, float, 2, 2 ) = 1.f;
设你有 300x200 32-bit 浮点数 image/array, 也就是对一个有 60000 个元素的数组。
int cols = 300, rows = 200;
float* myarr = new float[rows*cols];
// 第一步,初始化 CvMat 头
CvMat mat = cvMat( rows, cols,
CV_32FC1, // 32 位浮点单通道类型
myarr // 用户数据指针(数据没有被复制)
);
// 第二步,使用 cv 函数, 例如计算 l2 (Frobenius) 模
double norm = cvNorm( &mat, 0, CV_L2 );
...
delete myarr;
其它情况在参考手册中有描述。 见 cvCreateMatHeader,cvInitMatHeader,cvCreateImageHeader, cvSetData 等
/* usage: prog <image_name> */ #include <cv.h> #include <highgui.h> #pragma comment(lib, "cv.lib") #pragma comment(lib, "cxcore.lib") #pragma comment(lib, "highgui.lib") int main( int argc, char** argv ) { IplImage* img; if( argc == 2 && (img = cvLoadImage( argv[1], 1)) != 0 ) { cvNamedWindow( "Image view", 1 ); cvShowImage( "Image view", img ); cvWaitKey(0); // 非常重要,内部包含事件处理循环 cvDestroyWindow( "Image view" ); cvReleaseImage( &img ); return 0; } return -1; }
参考 squares demo
/* 在程序里找寻矩形 */ #include <cv.h> #include <highgui.h> #include <stdio.h> #include <math.h> #include <string.h> #pragma comment(lib, "cv.lib") #pragma comment(lib, "cxcore.lib") #pragma comment(lib, "highgui.lib") int thresh = 50; IplImage* img = 0; IplImage* img0 = 0; CvMemStorage* storage = 0; CvPoint pt[4]; const char* wndname = "Square Detection Demo"; // helper function: // finds a cosine of angle between vectors // from pt0->pt1 and from pt0->pt2 double angle( CvPoint* pt1, CvPoint* pt2, CvPoint* pt0 ) { double dx1 = pt1->x - pt0->x; double dy1 = pt1->y - pt0->y; double dx2 = pt2->x - pt0->x; double dy2 = pt2->y - pt0->y; return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); } // returns sequence of squares detected on the image. // the sequence is stored in the specified memory storage CvSeq* findSquares4( IplImage* img, CvMemStorage* storage ) { CvSeq* contours; int i, c, l, N = 11; CvSize sz = cvSize( img->width & -2, img->height & -2 ); IplImage* timg = cvCloneImage( img ); // make a copy of input image IplImage* gray = cvCreateImage( sz, 8, 1 ); IplImage* pyr = cvCreateImage( cvSize(sz.width/2, sz.height/2), 8, 3 ); IplImage* tgray; CvSeq* result; double s, t; // create empty sequence that will contain points - // 4 points per square (the square's vertices) CvSeq* squares = cvCreateSeq( 0, sizeof(CvSeq), sizeof(CvPoint), storage ); // select the maximum ROI in the image // with the width and height divisible by 2 cvSetImageROI( timg, cvRect( 0, 0, sz.width, sz.height )); // down-scale and upscale the image to filter out the noise cvPyrDown( timg, pyr, 7 ); cvPyrUp( pyr, timg, 7 ); tgray = cvCreateImage( sz, 8, 1 ); // find squares in every color plane of the image for( c = 0; c < 3; c++ ) { // extract the c-th color plane cvSetImageCOI( timg, c+1 ); cvCopy( timg, tgray, 0 ); // try several threshold levels for( l = 0; l < N; l++ ) { // hack: use Canny instead of zero threshold level. // Canny helps to catch squares with gradient shading if( l == 0 ) { // apply Canny. Take the upper threshold from slider // and set the lower to 0 (which forces edges merging) cvCanny( tgray, gray, 0, thresh, 5 ); // dilate canny output to remove potential // holes between edge segments cvDilate( gray, gray, 0, 1 ); } else { // apply threshold if l!=0: // tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 cvThreshold( tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY ); } // find contours and store them all as a list cvFindContours( gray, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) ); // test each contour while( contours ) { // approximate contour with accuracy proportional // to the contour perimeter result = cvApproxPoly( contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0 ); // square contours should have 4 vertices after approximation // relatively large area (to filter out noisy contours) // and be convex. // Note: absolute value of an area is used because // area may be positive or negative - in accordance with the // contour orientation if( result->total == 4 && fabs(cvContourArea(result,CV_WHOLE_SEQ)) > 1000 && cvCheckContourConvexity(result) ) { s = 0; for( i = 0; i < 5; i++ ) { // find minimum angle between joint // edges (maximum of cosine) if( i >= 2 ) { t = fabs(angle( (CvPoint*)cvGetSeqElem( result, i ), (CvPoint*)cvGetSeqElem( result, i-2 ), (CvPoint*)cvGetSeqElem( result, i-1 ))); s = s > t ? s : t; } } // if cosines of all angles are small // (all angles are ~90 degree) then write quandrange // vertices to resultant sequence if( s < 0.3 ) { for( i = 0; i < 4; i++ ) { cvSeqPush( squares, (CvPoint*)cvGetSeqElem( result, i )); } } } // take the next contour contours = contours->h_next; } } } // release all the temporary images cvReleaseImage( &gray ); cvReleaseImage( &pyr ); cvReleaseImage( &tgray ); cvReleaseImage( &timg ); return squares; } // the function draws all the squares in the image void drawSquares( IplImage* img, CvSeq* squares ) { CvSeqReader reader; IplImage* cpy = cvCloneImage( img ); int i; // initialize reader of the sequence cvStartReadSeq( squares, &reader, 0 ); // read 4 sequence elements at a time (all vertices of a square) for( i = 0; i < squares->total; i += 4 ) { CvPoint* rect = pt; int count = 4; // read 4 vertices memcpy( pt, reader.ptr, squares->elem_size ); CV_NEXT_SEQ_ELEM( squares->elem_size, reader ); memcpy( pt + 1, reader.ptr, squares->elem_size ); CV_NEXT_SEQ_ELEM( squares->elem_size, reader ); memcpy( pt + 2, reader.ptr, squares->elem_size ); CV_NEXT_SEQ_ELEM( squares->elem_size, reader ); memcpy( pt + 3, reader.ptr, squares->elem_size ); CV_NEXT_SEQ_ELEM( squares->elem_size, reader ); // draw the square as a closed polyline cvPolyLine( cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0 ); } // show the resultant image cvShowImage( wndname, cpy ); cvReleaseImage( &cpy ); } void on_trackbar( int a ) { if( img ) { drawSquares( img, findSquares4( img, storage ) ); } } char* names[] = { "pic1.png", "pic2.png", "pic3.png", "pic4.png", "pic5.png", "pic6.png", 0 }; int main(int argc, char** argv) { int i, c; // create memory storage that will contain all the dynamic data storage = cvCreateMemStorage(0); for( i = 0; names[i] != 0; i++ ) { // load i-th image img0 = cvLoadImage( names[i], 1 ); if( !img0 ) { printf("Couldn't load %s/n", names[i] ); continue; } img = cvCloneImage( img0 ); // create window and a trackbar (slider) with parent "image" and set callback // (the slider regulates upper threshold, passed to Canny edge detector) cvNamedWindow( wndname, 1 ); cvCreateTrackbar( "canny thresh", wndname, &thresh, 1000, on_trackbar ); // force the image processing on_trackbar(0); // wait for key. // Also the function cvWaitKey takes care of event processing c = cvWaitKey(0); // release both images cvReleaseImage( &img ); cvReleaseImage( &img0 ); // clear memory storage - reset free space position cvClearMemStorage( storage ); if( c == 27 ) { break; } } cvDestroyWindow( wndname ); return 0; }
可以使用/OpenCV/samples/c目录下的calibration.cpp这个程序,程序的输入支持USB摄像机,avi文件或者图片
1。使用说明
a.输入为图片时:
// example command line (for copy-n-paste):
// calibration -w 6 -h 8 -s 2 -n 10 -o camera.yml -op -oe [<list_of_views.txt>]
/* The list of views may look as following (discard the starting and ending ------ separators):
-------------------
view000.png
view001.png
#view002.png
view003.png
view010.png
one_extra_view.jpg
-------------------
that is, the file will contain 6 lines, view002.png will not be used for calibration,
other ones will be (those, in which the chessboard pattern will be found)
b.输入为摄像机或者avi文件时
"When the live video from camera is used as input, the following hot-keys may be used:/n"
" <ESC>, 'q' - quit the program/n"
" 'g' - start capturing images/n"
" 'u' - switch undistortion on/off/n";
c。输入参数说明
"Usage: calibration/n"
" -w <board_width> # the number of inner corners per one of board dimension/n"
" -h <board_height> # the number of inner corners per another board dimension/n"
" [-n <number_of_frames>] # the number of frames to use for calibration/n"
" # (if not specified, it will be set to the number/n"
" # of board views actually available)/n"
" [-d <delay>] # a minimum delay in ms between subsequent attempts to capture a next view/n"
" # (used only for video capturing)/n"
" [-s <square_size>] # square size in some user-defined units (1 by default)/n"
" [-o <out_camera_params>] # the output filename for intrinsic [and extrinsic] parameters/n"
" [-op] # write detected feature points/n"
" [-oe] # write extrinsic parameters/n"
" [-zt] # assume zero tangential distortion/n"
" [-a <aspect_ratio>] # fix aspect ratio (fx/fy)/n"
" [-p] # fix the principal point at the center/n"
" [-v] # flip the captured images around the horizontal axis/n"
" [input_data] # input data, one of the following:/n"
" # - text file with a list of the images of the board/n"
" # - name of video file with a video of the board/n"
" # if input_data not specified, a live view from the camera is used/n"
2.经多次使用发现,不指定 -p参数时计算的结果误差较大,主要表现在对u0,v0的估计误差较大,因此建议使用时加上-p参数