basler工業(yè)相機做雙目視覺用,出現很多問題記錄一下:
首先是多看手冊:https://zh.docs.baslerweb.com/software
手冊內有所有的源碼和參考示例,實際上在使用過程中,大部分都是這些源碼,具體項目選擇對應的示例代碼。
一、相機和鏡頭選型
可以通過balser的鏡頭選型工具,按照自己需要測量目標的距離,目標大小等信息進行配置選擇,地址在這;界面如下:
相機的焦距大小一般和測量的目標距離有關系,一般對應的選擇方式總結如下:
(1)焦距越小,測量的范圍越大,相應的,目標一般都看起來很小,類似于手機拍照的最小倍數拍攝目標;
(2)焦距越大,測量范圍就越窄,對遠距離小目標的檢查就比較好,但是太大的焦距會導致大目標容易拍不全,類似與手機拍照放大倍數拍攝目標;
(3)具體有計算公式,可以參考,建議直接通過basler的配置工具進行選擇
二、相機安裝和使用
(1)balser相機使用需要網線和電源線(12V供電),可以在官網找對應的線材;
(2)相機接上電源,網線連接計算機后,去官網下載相機軟件和驅動,一般windows下安裝后,會在目錄下生成對應的文件夾,包括C++對應的庫和參考代碼示例等,linux下直接下載tar.gz包,解壓防止到對應的文件目錄下,執(zhí)行:source pylon目錄/bin/pylon-setup-env.sh ./pylon目錄 即可,例如我安裝的是pylon7.3.0,解壓后的目錄為:/opt/pylon7,里面直接就是inlcude這些文件夾,在linux下目錄執(zhí)行:
source /opt/pylon7/bin/pylon-setup-env.sh /opt/pylon7
完成linux下相機驅動和環(huán)境的安裝。
(3)配置相機IP,windows下配置相機IP可以使用basler的工具:
ipconfigurator,Linux下如果安裝的系統(tǒng)有GUI界面,一樣可以使用,配置相機IP地址,保證IP地址和接計算機的接口IP地址在同一網段即可,子網掩碼推薦255。255.255.0,廠家說其他的可能會出現異常斷開錯誤;
(4)IP配置完成后,在windows下啟動pylon Viewer工具,查看相機,能找到相機說明IP配置正確,確保計算機和相機處于同一個網段內
(5)要保持basler相機的幀率,需要保證千兆網,如果是兩個相機,連交換機之后就要求是2000M的網,依次類推,才可以達到最大幀率,否則會出現相機丟幀等問題,直連相機到計算機不影響,開啟巨幀數就行了。
三、C++調用相機環(huán)境部署
1.相機驅動和軟件安裝完成后,有以下文件夾:
開發(fā)環(huán)境在development文件夾下,linux下解壓之后是:
2.可以使用visua studio等C++ IDE開發(fā)工具進行編程,將依賴庫和頭文件等信息通過鏈接include和lib文件,即可開始相機調用;
四、C++相機調用
1.相機初始化:
相機初始化包括尋找相機,匹配對應相機,還可以設置相機的曝光,幀率,增益等,兩個相機的初始化,依據API文檔整理如下:
參加API:Grab_MultipleCameras
void initCamera()
{
try
{
PylonInitialize(); //初始化
CTlFactory& tlFactory = CTlFactory::GetInstance();
pTL = dynamic_cast<IGigETransportLayer*>(tlFactory.CreateTl( BaslerGigEDeviceClass ));
if (pTL == NULL)
{
throw RUNTIME_EXCEPTION( "No GigE cameras available." );
}
DeviceInfoList_t allDeviceInfos;
if (pTL->EnumerateDevices( allDeviceInfos ) == 0)
{
throw RUNTIME_EXCEPTION( "No GigE cameras available." );
}
DeviceInfoList_t usableDeviceInfos;
string left_camera_ip="172.16.105.21"
//left_camera_ip 用于區(qū)分兩個相機,可以通過配置的IP,序列號等進行區(qū)分
if (string(allDeviceInfos[0].GetIpAddress()) == left_camera_ip) {
usableDeviceInfos.push_back(allDeviceInfos[0]);
subnet = allDeviceInfos[0].GetSubnetAddress();//主相機
usableDeviceInfos.push_back(allDeviceInfos[1]);
LOG(INFO)<<"主相機:"<<allDeviceInfos[0].GetIpAddress()<<endl;
LOG(INFO)<<"副相機:"<<allDeviceInfos[1].GetIpAddress()<<endl;
}
else if(string(allDeviceInfos[1].GetIpAddress()) == left_camera_ip) {
usableDeviceInfos.push_back(allDeviceInfos[1]);
subnet = allDeviceInfos[1].GetSubnetAddress();//主相機
usableDeviceInfos.push_back(allDeviceInfos[0]);
LOG(INFO)<<"主相機IP:"<<allDeviceInfos[1].GetIpAddress()<<endl;
LOG(INFO)<<"SubnetAddress:"<<allDeviceInfos[1].GetSubnetAddress()<<endl;
LOG(INFO)<<"DefaultGateway:"<<allDeviceInfos[1].GetDefaultGateway()<<endl;
LOG(INFO)<<"SubnetMask:"<<allDeviceInfos[1].GetSubnetMask()<<endl;
LOG(INFO)<<"副相機IP:"<<allDeviceInfos[0].GetIpAddress()<<endl;
LOG(INFO)<<"SubnetAddress:"<<allDeviceInfos[0].GetSubnetAddress()<<endl;
LOG(INFO)<<"DefaultGateway:" <<allDeviceInfos[0].GetDefaultGateway()<<endl;
LOG(INFO)<<"SubnetMask:"<<allDeviceInfos[0].GetSubnetMask()<<endl;
}
else{
LOG(INFO) << "Camera IP is error ,please set IP" << endl;
}
// CInstantCameraArray cameras = { 2 };
//初始化兩個相機
for (size_t i = 0; i < 2; ++i)
{
cameras[i].Attach(tlFactory.CreateDevice(usableDeviceInfos[i]));
const CBaslerGigEDeviceInfo& di = cameras[i].GetDeviceInfo();
LOG(INFO) << "Camera serial: " << di.GetSerialNumber() << endl;
}
// srand( (unsigned) time( NULL ) );
// DeviceKey = rand();
// GroupKey = 0x112233;
for (size_t i = 0; i < cameras.GetSize(); ++i)
{
cameras[i].Attach( tlFactory.CreateDevice( usableDeviceInfos[i] ) );
//cameras[i].RegisterConfiguration( new CActionTriggerConfiguration( DeviceKey, GroupKey, AllGroupMask ), RegistrationMode_Append, Cleanup_Delete );
//cameras[i].SetCameraContext( i );
const CBaslerGigEDeviceInfo& di = cameras[i].GetDeviceInfo();
cout << "Using camera " << i << ": " << di.GetSerialNumber() << " (" << di.GetIpAddress() << ")" << endl;
}
cameras.Open();
//相機基本設置
SetCamera(cameras[0], Type_Basler_ExposureTimeAbs, expore_time_l); //曝光時間
SetCamera(cameras[0], Type_Basler_GainRaw, gain_l); //增益
SetCamera(cameras[0], Type_Basler_AcquisitionFrameRateAbs, fps_l); //頻率
SetCamera(cameras[0], Type_Basler_Width, 2448);
SetCamera(cameras[0], Type_Basler_Height, 2048);
SetCamera(cameras[1], Type_Basler_ExposureTimeAbs, expore_time_r); //曝光時間
SetCamera(cameras[1], Type_Basler_GainRaw, gain_r); //增益
SetCamera(cameras[1], Type_Basler_AcquisitionFrameRateAbs, fps_r); //頻率
SetCamera(cameras[1], Type_Basler_Width, 2448);
SetCamera(cameras[1], Type_Basler_Height, 2048);
//設置相機觸發(fā)模式 TriggerSelector
//TriggerSoftware
//主相機設置為軟件觸發(fā),輸出設置為exposure active
//SetCamera(cameras[0], Type_Basler_Freerun, 0);
//從相機設置:觸發(fā)模式為外觸發(fā),IO設置為1
//SetCamera(cameras[1], Type_Basler_Line1, 0);
}
catch (const GenericException& e)
{
if(cameras.IsGrabbing())
cameras.StopGrabbing();
// Error handling
LOG(INFO) << "init,An exception occurred." << endl
<< e.GetDescription() << endl;
}
}
2.調用相機
調用相機時,最容易出現的問題是,grab image丟幀,在抓取圖像丟幀的原因中,主要是由相機幀率設置過大,帶寬不足等問題導致。
其中:
if(cameras.IsGrabbing()) 這句可以改成while循環(huán),這樣就可以持續(xù)輸出,if表示就近輸出了,根據實際使用情況而定,基本上抓取一幀在50ms左右。其中 cameras.StartGrabbing()可以放在初始化中,這樣就不停的抓取,能夠保證1秒20幀,不用頻繁開始抓取和停止抓取,實際上很耗時。
void GetCameraImage() {
try {
//pTL->IssueActionCommand(DeviceKey, GroupKey, AllGroupMask, subnet );
//1秒內抓取了多少張圖,全部存下來
int skiptime = 1000;
//LOG(INFO)<<"采集圖像的最長時間:"<<skiptime<<" ms"<<endl;
cameras.StartGrabbing(GrabStrategy_OneByOne,GrabLoop_ProvidedByUser);
if(cameras.IsGrabbing()) {
std::chrono::high_resolution_clock::time_point tStartTime(std::chrono::high_resolution_clock::now());
int lTimeAloInterval = 0;
count_grab_once++;
cameras[0].RetrieveResult(skiptime, ptrGrabResultl, TimeoutHandling_ThrowException);
cameras[1].RetrieveResult(skiptime, ptrGrabResultr, TimeoutHandling_ThrowException);
if (ptrGrabResultl->GrabSucceeded() && ptrGrabResultr->GrabSucceeded() ) {
intptr_t cameraContextValuel = ptrGrabResultl->GetCameraContext();
intptr_t cameraContextValuer = ptrGrabResultr->GetCameraContext();
const uint8_t *pImageBufferl = (uint8_t *) ptrGrabResultl->GetBuffer();
const uint8_t *pImageBufferr = (uint8_t *) ptrGrabResultr->GetBuffer();
// 將 pylon image轉成OpenCV image.
Mat SaveImagel = cv::Mat(ptrGrabResultl->GetHeight(), ptrGrabResultl->GetWidth(), CV_8UC1,
(uint8_t *) pImageBufferl);
Mat SaveImager = cv::Mat(ptrGrabResultr->GetHeight(), ptrGrabResultr->GetWidth(), CV_8UC1,
(uint8_t *) pImageBufferr);
}
lTimeAloInterval =std::chrono::duration_cast<std::chrono::duration<double, std::ratio<1, 1000> >>(std::chrono::high_resolution_clock::now() - tStartTime).count();
LOG(INFO) << "------------ single Grab image cost time:----------------" << lTimeAloInterval << " ms" << endl;
}
cameras.StopGrabbing();
}
catch (const GenericException& e)
{
if(cameras.IsGrabbing())
cameras.StopGrabbing();
// Error handling
LOG(INFO) << "An exception occurred." << endl
<< e.GetDescription() << endl;
}
}
3.關閉相機
相機及時關閉:
void CloseCamera()
{
//最后終止Pylon相機,即調用PylonTerminate。//關閉攝像頭
try
{
if (cameras.IsOpen()) {
cameras.DetachDevice();
cameras.Close();
cameras.DestroyDevice();
//關閉庫
LOG(INFO) << "SBaslerCameraControl deleteAll: PylonTerminate";
PylonTerminate();
}
}
catch (const Pylon::GenericException& e)
{
LOG(INFO) << "close camera failed..." << e.what();
}
}
五、常見問題
1.相機連不上
IP配置不正確,確保在同一網段,子網掩碼相同。
2.連接后丟幀
Error: e1004 The bufer was incopletely gratbed. This can be caused by perfomnane problens of the metwork hardware used,fer underuns can also case ina loss.To fix this, us the pylonbioEtonfigurator tol to optinize your setip and use more uffers for aratbin in your aplication to prerent buferunderruns
常見于連接多個相機的時候出現,確保開啟巨幀,相機幀率和網絡傳輸的幀率是否滿足要求,參加API手冊
3.相機連接后,使用過程中出現找得到相機,但卡住不動了
這種問題不知道是什么原因導致的,因為可以找到相機,而且也能連上相機,所以大概率是以下幾種可能:
(1)可能是長時間沒調用導致相機休眠,關機重啟下可解決。
(2)相機打開過程中異常中斷,即句柄沒有被釋放,這種情況使用官方給的軟件pylon Viewer重新打開和關閉一下即可恢復。
4.grab time out 抓取超時
一般是設置waittime時間太短導致,可以改大一些:文章來源:http://www.zghlxwxcb.cn/news/detail-732318.html
cameras[1].RetrieveResult(waittime, ptrGrabResultr, TimeoutHandling_ThrowException);
還有一種可能是相機連上之后一直么有抓取成功,導致等待時間過長,需要檢查代碼,常見有時候做觸發(fā)的操作導致。文章來源地址http://www.zghlxwxcb.cn/news/detail-732318.html
到了這里,關于機器視覺之Basler工業(yè)相機使用和配置方法(C++)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!