工業(yè)相機(jī)二次開(kāi)發(fā)是機(jī)器視覺(jué)行業(yè)必不可少的技能之一。
而如何實(shí)現(xiàn)一個(gè)框架,能夠兼容所有工業(yè)相機(jī)二次開(kāi)發(fā),從而支持多種類(lèi)型的工業(yè)相機(jī),就是機(jī)器視覺(jué)行業(yè)的進(jìn)階技能了。
重明工業(yè)相機(jī)二次開(kāi)發(fā)項(xiàng)目就是在實(shí)現(xiàn)相機(jī)二開(kāi)框架的基礎(chǔ)上,完成了海康工業(yè)相機(jī)的二次開(kāi)發(fā)。
項(xiàng)目源碼下載地址:
https://www.roundvision.cc/softwaredevelopment/qt/chongming/
技術(shù)棧:
1、C++
2、 QT 5.14.2
3、Opencv 4.5.5
4、工業(yè)相機(jī)SDK二次開(kāi)發(fā)
重明工業(yè)相機(jī)二次開(kāi)發(fā)項(xiàng)目框架如下圖所示:
整個(gè)項(xiàng)目分前端部分的界面設(shè)計(jì),和后端部分的工業(yè)相機(jī)框架設(shè)計(jì)。
1、界面GUI實(shí)現(xiàn)
重明的界面實(shí)現(xiàn)非常簡(jiǎn)潔,主要為三個(gè)部分:
左側(cè)的相機(jī)列表,中間的圖像顯示,右側(cè)的相機(jī)參數(shù)屬性列表。
控制窗口的實(shí)現(xiàn)非常簡(jiǎn)單,其實(shí)就是一排按鈕加一個(gè)QListWidget列表,用來(lái)顯示所有檢測(cè)到的工業(yè)相機(jī)。
視覺(jué)窗口用來(lái)顯示圖像,采用QT的視圖模型框架,采用QGrapicsScene來(lái)實(shí)現(xiàn)的。
屬性窗口主要涉及到了QT的MVD框架,即Model-View-Delegate框架,模型-視圖-代理,通過(guò)視圖代理,完成了對(duì)各個(gè)不同屬性參數(shù)類(lèi)型的支持,完成了相機(jī)參數(shù)屬性Int,double,bool,cmd,string等多種類(lèi)型的顯示。
2、后端框架接口
實(shí)現(xiàn)了前端界面,現(xiàn)在我們可以考慮,如何抽象工業(yè)相機(jī)接口類(lèi),實(shí)現(xiàn)對(duì)不同工業(yè)相機(jī)的無(wú)差別接入,達(dá)到工業(yè)相機(jī)二次開(kāi)發(fā)框架的效果呢?
這里可以借用QT插件的便利性,來(lái)設(shè)計(jì)工業(yè)相機(jī)抽象插件接口:
//相機(jī)接口類(lèi)
class CameraInterface
{
public:
CameraInterface(const CameraMetaInfo& info)
{
m_cameraInfo = info;
}
virtual ~CameraInterface() {}
//獲取相機(jī)用戶(hù)定義名稱(chēng)
virtual std::string UserName()
{
return m_cameraInfo.UserDefineID;
}
//獲取相機(jī)序列號(hào)
virtual std::string Serial()
{
return m_cameraInfo.Serial;
}
//獲取相機(jī)參數(shù)列表
virtual uint32_t getParamList(std::vector<CameraParam>& paramList) = 0;
//判斷相機(jī)是否連接
virtual bool isConnect() = 0;
//判斷相機(jī)是否拉流
virtual bool isGrabbing() = 0;
//初始化相機(jī)對(duì)象
virtual uint32_t acquire() = 0;
//釋放相機(jī)
virtual uint32_t release() = 0;
//連接相機(jī)
virtual uint32_t connect() = 0;
//斷開(kāi)連接
virtual uint32_t disconnect() = 0;
//創(chuàng)建拉流資源
virtual uint32_t creatStream() = 0;
//銷(xiāo)毀拉流資源
virtual uint32_t destroyStream() = 0;
//開(kāi)啟拉流
virtual uint32_t startGrabbing() = 0;
//停止拉流
virtual uint32_t stopGrabbing() = 0;
//導(dǎo)入配置文件
virtual uint32_t loadConfig(const std::string path) = 0;
//導(dǎo)出配置文件
virtual uint32_t saveConfig(const std::string path) = 0;
//獲取配置文件格式
virtual std::string configFormat() = 0;
//讀取相機(jī)參數(shù)
virtual uint32_t readParam(CameraParam& param) = 0;
//寫(xiě)入相機(jī)參數(shù)
virtual uint32_t writeParam(CameraParam& param) = 0;
//獲取實(shí)時(shí)圖像
virtual uint32_t getImageLast(cv::Mat& image) = 0;
//獲取圖像隊(duì)列
virtual CameraImageQueue& ImageQueue()
{
return m_imageQueue;
}
protected:
CameraImageQueue m_imageQueue;//圖像隊(duì)列
std::vector<CameraParam> m_cameraParams;//相機(jī)參數(shù)列表
CameraMetaInfo m_cameraInfo;//相機(jī)元信息
};
通過(guò)抽象設(shè)計(jì)統(tǒng)一的相機(jī)行為接口,在通過(guò)層層封裝,即可達(dá)到框架效果。
如何實(shí)現(xiàn)相機(jī)圖像隊(duì)列
相機(jī)出圖速度是有差異的,而我們處理相機(jī)出圖也會(huì)有所耗時(shí),如果你是出一張圖像處理一張,然后再去拿一張圖像,那很容易造成丟幀的問(wèn)題。所以設(shè)計(jì)一個(gè)緩沖隊(duì)列是非常有必要的。
我們的圖像隊(duì)列內(nèi)部會(huì)包含兩個(gè)隊(duì)列,一個(gè)空閑隊(duì)列,一個(gè)工作隊(duì)列。
在我們相機(jī)圖像隊(duì)列這個(gè)應(yīng)用場(chǎng)景下,生產(chǎn)者就是相機(jī)SDK的回調(diào)函數(shù),該回調(diào)函數(shù)會(huì)生成相機(jī)的原始圖像數(shù)據(jù),我們?cè)诨卣{(diào)函數(shù)內(nèi)將原始圖像數(shù)據(jù)加入到隊(duì)列中。
加入到隊(duì)列是先看空閑隊(duì)列有沒(méi)有位置,如果有則加入到空閑隊(duì)列,然后觸發(fā)信號(hào)量激活消費(fèi)者。如果空閑隊(duì)列沒(méi)有位置,則從工作隊(duì)列取出最舊的圖像,將原始數(shù)據(jù)加入到該位置。
我們的消費(fèi)者,就是我們的取圖線程,我們軟件會(huì)不停的從隊(duì)列中的工作隊(duì)列中嘗試取出圖像,當(dāng)工作隊(duì)列為空時(shí),會(huì)阻塞在信號(hào)量中,當(dāng)生產(chǎn)者生產(chǎn)了一張圖像后,會(huì)激活該信號(hào)量使取圖線程取到圖像。
圖像隊(duì)列代碼實(shí)現(xiàn):文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-785790.html
#define TIME_OUT_MS 5000 //取圖超時(shí)時(shí)間
#define ImageQueueSize 10 //圖像隊(duì)列長(zhǎng)度宏定義
class CameraImageQueue
{
public:
CameraImageQueue();
CameraImageQueue(int maxSize);
//向圖像隊(duì)列中加入圖像
uint32_t Put(const cv::Mat& m);
//從圖像隊(duì)列中取出圖像
uint32_t Take(cv::Mat& m);
//隊(duì)列是否為空
bool Empty();
//隊(duì)列是否為滿
bool Full();
//隊(duì)列當(dāng)前長(zhǎng)度
size_t Size();
private:
bool isFull() const
{
bool full = workImageQueue.size() >= m_queueSize;
return full;
}
bool isEmpty() const
{
bool empty = workImageQueue.empty();
return empty;
}
bool NotFull() const
{
bool full = workImageQueue.size() >= m_queueSize;
return !full;
}
bool NotEmpty() const
{
bool empty = workImageQueue.empty();
return !empty;
}
private:
std::mutex m_mutex;
std::condition_variable m_condition;
std::queue<cv::Mat> freeImageQueue;//空閑隊(duì)列
std::queue<cv::Mat> workImageQueue;//工作隊(duì)列
uint8_t m_queueSize;
bool m_needStop;
};
THE END
項(xiàng)目源碼下載地址:
https://www.roundvision.cc/softwaredevelopment/qt/chongming/
項(xiàng)目由豐富的視頻教程,見(jiàn)BiliBili:
視頻鏈接:https://www.bilibili.com/video/BV1pp4y1n7X9文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-785790.html
到了這里,關(guān)于【重明】機(jī)器視覺(jué)QT/C++實(shí)現(xiàn)工業(yè)相機(jī)二次開(kāi)發(fā)框架的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!