OpenCVライブラリの基礎知識

16564 ワード

ライブラリの使用に関する技術的な問題
画像ピクセルへのアクセス方法
(座標は0から始まり、画像原点に対する位置.画像原点または左上隅(img->origin=IPL_ORIGIN_TL)または左下隅(img->origin=IPL_ORIGIN_BL))
  • 偽8-bit 1-チャンネルの画像I(IplImage*img):
  • I(x,y) ~ ((uchar*)(img->imageData + img->widthStep*y))[x]
  • 偽8-bit 3-チャンネルの画像I(IplImage*img):
  • 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]

    例えば、点(100100)の輝度を30増加させると、以下のようにすることができる.
    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;
  • ダミー32-bit浮動小数点数、1-チャネル画像I(IplImage*img):
  • I(x,y) ~ ((float*)(img->imageData + img->widthStep*y))[x]
  • 現在、一般的な場合、N-チャネルがあると仮定し、タイプTの画像:
  • I(x,y)c ~ ((T*)(img->imageData + img->widthStep*y))[x*N + c]

    マクロCV_を使用できますIMAGE_ELEM( image_header, elemtype, y, x_Nc )
    I(x,y)c ~ CV_IMAGE_ELEM( img, T, y, x*N + c )

    4チャネル画像を含む種々の画像と行列に対する関数(cvGet 2 D,cvSet 2 D)もあるが,それらは非常に遅い.
    マトリクス要素へのアクセス方法
    方法は似ています(次の例はいずれも0の始点の列と行についてです)
  • 32-bit浮動小数点数がある実数行列M(CvMat*mat):
  • M(i,j) ~ ((float*)(mat->data.ptr + mat->step*i))[j]
  • 64-bit浮動小数点数を有する複素行列M(CvMat*mat):
  • 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]
  • シングルチャネルマトリクスに対して、マクロCV_があるMAT_MELEM(matrix,elemtype,row,col)、例えば32-bit浮動小数点数に対する実数行列:
  • M(i,j) ~ CV_MAT_ELEM( mat, float, i, j ),

    たとえば、ここでは3 x 3単位マトリクスの初期化です.
    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;

    OpenCVで自分のデータを処理する方法
    300 x 200 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でカメラをスケーリングする
    /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 []
    /* 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パラメータを しない の の が きく、 にu 0、v 0に する が きいことが したため、 に-pパラメータを えることを する