攝像頭距離標定方法研究(得到像素和毫米的轉換比)


     一般在高精度測量時需要做以下幾個標定,一光學畸變標定(如果您不是用的軟件鏡頭,一般都必須標定),二投影畸變的標定,也就是因為您安裝位置誤差代表的圖像畸變校正,三物像空間的標定,也就是具體算出每個像素對應物空間的尺寸。

      前兩者應該都可以通過“張正友”標定方法進行解決;對於空間的標定,基本上都是通過獲得比對現實中的已經知道長度的物體,獲得像素當量到長度的轉化。
      現實拍攝的物體,或多或少會有噪音干擾,在標定的過程中還需要圖像處理算法進行糾正。

     比如我獲得這樣的圖片。這幅圖片的獲取,基於我自己改造的圖像處理支架,對於普通的實驗來說,已經比較純凈了。由於使用的是鋼尺,反光比較厲害。為了便於標定,我將10厘米和20厘米兩個地方用綠色膠帶纏繞住。
    下一步,就是要獲得關鍵區域。通過GOPre的分析,原始圖像在YUV域下,比較方便分割
編寫代碼分割,閾值分析
    Mat src = imread("E:\\sandbox\\1.bmp");
    Mat dst;
    Mat tmp;
    vector<MatmatSplit;
    cvtColor(src,tmp,COLOR_BGR2YUV);
    split(tmp,matSplit);
    dst = matSplit[1];
    threshold(dst,dst,100,255, COLOR_BGR2Lab)   );
    cv::waitKey();
這個時候還是有噪音的,但是已經比較理想了。最合適的方法就是投影分析。由於GOCVHelper中的投影分析本來是對字符投影進行分割的,所以需要適當地修正。
void projection4ruler(Mat srcintdown1,intup2 ,int direction){
    Mat tmp = src.clone();
    vector<intvdate;
    if (DIRECTION_X == direction){
        for (int i=0;i<tmp.cols;i++){
            Mat data = tmp.col(i);
            int itmp = countNonZero(data);
            if (itmp > 10)
            {
                int jjj=0;
            }
            vdate.push_back(itmp);
        }
    }else{
        for (int i=0;i<tmp.rows;i++){
            Mat data = tmp.row(i);
            int itmp = countNonZero(data);
            vdate.push_back(itmp);
        }
    }
    //過濾掉所有噪音
    //尋找第一個下邊沿和第二個上邊沿
    down1 = 1;
    up2   = src.cols - 1;
    for (int i=0;i<tmp.cols-1;i++)
    {
        if (vdate[i] >=  100 && vdate[i+1] < 100)
        {
          down1 = i;
          break;
        }
    }
    for (int idown1;i<tmp.cols - 1;i++)
    {
        if (vdate[i] < 100 && vdate[i+1] >= 100)
        {
            up2 = i;
            return;
        }
    }
}
尋找並且標注出來,非常准確。
圖上(1767 - 771  =  996)對於10厘米,那么,那么1個像素相當於0.1毫米(這個整數只是巧合)
 
多次測量,驗證算法的穩定性,並運用於實際項目。
 
小結
基於算法庫和成熟的思路,能夠加速解決問題速度。
比較好的視覺環境也很重要。
附全部代碼
//GoCvHelper的demo程序
#include "stdafx.h"
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "GoCvHelper.h"
 
using namespace std;
using namespace cv;
using namespace GO;
#define  VP  vector<cv::Point>  //用VP符號代替 vector<point>
 
void projection4ruler(Mat srcintdown1,intup2 ,int direction){
    Mat tmp = src.clone();
    vector<intvdate;
    if (DIRECTION_X == direction){
        for (int i=0;i<tmp.cols;i++){
            Mat data = tmp.col(i);
            int itmp = countNonZero(data);
            if (itmp > 10)
            {
                int jjj=0;
            }
            vdate.push_back(itmp);
        }
    }else{
        for (int i=0;i<tmp.rows;i++){
            Mat data = tmp.row(i);
            int itmp = countNonZero(data);
            vdate.push_back(itmp);
        }
    }
    //過濾掉所有噪音
    //尋找第一個下邊沿和第二個上邊沿
    down1 = 1;
    up2   = src.cols - 1;
    for (int i=0;i<tmp.cols-1;i++)
    {
        if (vdate[i] >=  100 && vdate[i+1] < 100)
        {
          down1 = i;
          break;
        }
    }
    for (int idown1;i<tmp.cols - 1;i++)
    {
        if (vdate[i] < 100 && vdate[i+1] >= 100)
        {
            up2 = i;
            return;
        }
    }
}
 
int _tmain(int argc_TCHARargv[])
{    
    Mat src = imread("E:\\sandbox\\1.bmp");
    Mat dst;
    Mat tmp;
    int up1 = 0;
    int down2 = 0;
 
    vector<MatmatSplit;
    cvtColor(src,tmp,COLOR_BGR2Lab);
    split(tmp,matSplit);
    dst = matSplit[1];
    threshold(dst,dst,100,255,THRESH_OTSU);
    threshold(dst,dst,0,255,THRESH_BINARY_INV);//以白色為有數據
 
    projection4ruler(dst,up1,down2,DIRECTION_X);
    line(src,Point(up1,0),Point(up1,src.rows-1),Scalar(0,0,255),1);
    line(src,Point(down2,0),Point(down2,src.rows-1),Scalar(0,0,255),1);
    cv::waitKey();
    return 0;
}
 





附件列表

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM