自制攝像頭測距裝置

如何用攝像頭來測距(opencv)

作者:郭世龍

   最近一直忙着找工作,blog都長草了,今天把以前作的一個東西放上來充充門面吧。記得在哪看到過老外做的這個東西,覺得很好玩,就自己也做了一個。在攝像頭下面固定一個激光筆,就構成了這個簡易的測距裝置。看一下圖吧。

這裏寫圖片描述

原 理

假設激光束是與攝像頭的光軸完全平行,激光束的中心落點在在攝像頭的視域中是最亮的點。激光束照射到攝像頭視域中的跟蹤目標上,那麼攝像頭可以捕捉到這個點,通過簡單的圖像處理的方法,可以在這偵圖像中找到激光束照射形成的最亮點,同時可以計算出Y軸上方向上從落點到圖像中心的象素的個數。這個落點越接近圖像的中心,被測物體距離機器人就越遠。由下圖圖可以計算距離D:

這裏寫圖片描述

(1)

等式中h是一個常量,是攝像頭與激光發射器之間的垂直距離,可以直接測量獲得。

θ可通過下式計算:
θ=Num*Rop+Offset (2)
其中:Num是從圖像中心到落點的像素個數
Rop是每個像素的弧度值
Offset是弧度誤差
合併以上等式可以得到:
這裏寫圖片描述(3)
Num可以從圖像上計算得到。Rop和Offset需要通過實驗計算獲得。首先測量出D的準確值,然後根據等式(1)可以計算出準確的θ,根據等式(2)可到只含有參數Rop和Offset的方程。在不同的距離多次測量D的準確值計算θ,求解方程組可以求出Rop和Offset。這裏Rop=0.0030354,Offset=0.056514344。
這裏寫圖片描述

頭文件:
class LaserRange  
{
public:
struct RangeResult * GetRange(IplImage * imgRange,IplImage * imgDst);
 LaserRange();
 virtual ~LaserRange();

private:
    unsigned   int maxW;
   unsigned   int maxH;
    unsigned   int MaxPixel;
    RangeResult * strctResult;

 // Values used for calculating range from captured image data
 const double gain; // Gain Constant used for converting pixel offset to angle in radians
 const double offset; // Offset Constant
 const double h_cm;  // Distance between center of camera and laser
    unsigned int pixels_from_center; // Brightest pixel location from center

 void Preprocess(void * img,IplImage * imgTemp);
};
cpp文件:

LaserRange::LaserRange():gain(0.0030354),offset(0),h_cm(4.542)
{
  maxW=0;
  maxH=0;
  MaxPixel=0;

  pixels_from_center=0;    // Brightest pixel location from center
  strctResult=new RangeResult;

  strctResult->maxCol=0;
  strctResult->maxRow=0;
  strctResult->maxPixel=0;
  strctResult->Range=0.0;
 }
LaserRange::~LaserRange()
{
  if(NULL!=strctResult) delete strctResult;
}
struct RangeResult * LaserRange::GetRange(IplImage * imgRange,IplImage * imgDst)
{  
    if(NULL==imgRange) return   strctResult;
       Preprocess(imgRange,imgDst);

    pixels_from_center = abs(120-maxH);
 // Calculate range in cm based on bright pixel location, and setup specific constants
     strctResult->Range= h_cm/tan(pixels_from_center * gain + offset);

    strctResult->PixfromCent=pixels_from_center;
       strctResult->maxCol=maxW;
       strctResult->maxRow=maxH;
       strctResult->maxPixel=MaxPixel;
       //strctResult->Range=0.0;
         return  strctResult;
}

void LaserRange::Preprocess(void *img, IplImage * imgTemp)
{
    MaxPixel=0;                //處理下一幀前 最大像素值清零;
   IplImage* image = reinterpret_cast<IplImage*>(img);

       cvCvtPixToPlane( image,0 ,0 ,imgTemp , 0);

      for( int j=((imgTemp->width-60)/2-1); j<(imgTemp->width-40)/2+59; j++)  
  {
    for(int i=5; i<imgTemp->height-5; i++)
    {

    if((imgTemp->imageData[i*imgTemp->widthStep+j])>MaxPixel)
    {
     if( ((imgTemp->imageData[(i-1)*imgTemp->widthStep+j])>MaxPixel) && ((imgTemp->imageData[(i-1)*imgTemp->widthStep+j+1])>MaxPixel) &&((imgTemp->imageData[(i-1)*imgTemp->widthStep+j-1])>MaxPixel)   )
     { 
      if( ((imgTemp->imageData[(i+1)*imgTemp->widthStep+j])>MaxPixel) && ((imgTemp->imageData[(i+1)*imgTemp->widthStep+j+1])>MaxPixel) &&((imgTemp->imageData[(i+1)*imgTemp->widthStep+j-1])>MaxPixel)   )
       {
       if((imgTemp->imageData[i*(imgTemp->widthStep)+j+1])>MaxPixel)
       {
       if((imgTemp->imageData[i*(imgTemp->widthStep)+j-1])>MaxPixel)
       {
         MaxPixel=imgTemp->imageData[i*imgTemp->widthStep+j] ;
         maxW=j;
         maxH=i;
       }
       }
       }
     }
    }
  }

}
調用函數:
int CLaserVisionDlg::CaptureImage()
{
   // CvCapture* capture = 0;

   // capture = cvCaptureFromCAM(0);  //0表示設備號
    if( !capture )
    {
        fprintf(stderr,"Could not initialize capturing.../n");
        return -1;
    }

   // cvNamedWindow( "LaserRangeImage", 1 );
  // cvvNamedWindow( "image", 1);
   cvvNamedWindow( "Dimage", 1);

   for(;;)
    {
        IplImage* frame = 0;

  if(isStop) break;
        frame = cvQueryFrame( capture ); //從攝像頭抓取一副圖像框架
        if( !frame )
            break;
       if( !imgOrign )
        {
            //allocate all the buffers 
            imgOrign = cvCreateImage( cvGetSize(frame), 8, 3 );    //創建一副圖像
            imgOrign->origin = frame->origin;

  }
        cvCopy( frame, imgOrign, 0 );  //將圖frame複製到image
  //cvShowImage("LaserRangeImage",imgOrign);  


       if(!imgDest) 
    {
   imgDest=cvCreateImage( cvSize( imgOrign->width,imgOrign->height),8,1);
      cvZero( imgDest );
    }
        struct RangeResult * temp= laservsion.GetRange(imgOrign,imgDest);

        cvLine( imgOrign,cvPoint(temp->maxCol,0), cvPoint(temp->maxCol,imgOrign->height),cvScalar(100,100,255,0),1,8,0);
        cvLine( imgOrign,cvPoint(0,temp->maxRow), cvPoint(imgOrign->width,temp->maxRow),cvScalar(100,100,255,0),1,8,0);


       // cvvShowImage( "image", imgOrign);
  cvSaveImage("image.bmp", imgOrign);

        cvvShowImage( "Dimage", imgDest);

        //在PictureBox上顯示圖片
  CDC* pDC = GetDlgItem(IDC_Picture)->GetDC();
        CDC dcmemory;
        BITMAP bm;
        dcmemory.CreateCompatibleDC(pDC);
        CBitmap* pBmp;
        CString szFileName = "image.bmp";
        HBITMAP hBk = (HBITMAP)::LoadImage(NULL,szFileName,IMAGE_BITMAP,0,0,LR_LOADFROMFILE);   
       if(NULL!=hBk)   
    {
        pBmp=CBitmap::FromHandle(hBk);
        pBmp->GetObject(sizeof(BITMAP), &bm);
        dcmemory.SelectObject(pBmp);
        pDC->BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcmemory, 0, 0, SRCCOPY);
    }


       char str[80];         // To print message
    CDC *pDCp= GetDC(); 
       char str2[80];

    // Display frame coordinates as well as calculated range
       sprintf(str, "Pix Max Value=%d  At x= %u, y= %u, PixfromCent= %d",temp->maxPixel,temp->maxCol, temp->maxRow, temp->PixfromCent);
       sprintf(str2, "Range= %f cm ",temp->Range);
       pDCp->TextOut(30, 33, str);
       pDCp->TextOut(50, 50, str2);
    ReleaseDC(pDCp);

      int  c = cvWaitKey(10);
      //  if( c == 'q' )
       //     break;

 }
//cvReleaseCapture( &capture );
//cvDestroyWindow("LaserRangeImage");
// cvDestroyWindow( "image");
 cvDestroyWindow( "Dimage");
return 0;
}

如果需要工程文件請留下郵箱地址

發佈了21 篇原創文章 · 獲贊 33 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章