图像识别并用机械手进行抓取
最近項目,記錄下來以防將來忘記
一.建立開發(fā)環(huán)境
采用技術(shù)opencv2.4.0
VS2010
1.下載opencv for windows安裝包,程序采用的是opencv-2.4.0版本。雙擊打開解壓到C:\Users\teng\working\opencv目錄下,頭文件目錄為build\install\include,庫文件目錄為build\install\lib
2、建立工程名為Camera_Select_Card,將文件和庫文件的路徑分別加到工程的目錄,就可利用其提供的函數(shù)進行開發(fā)了.
?
二.目前已實現(xiàn)的功能
1.從攝像頭讀取數(shù)據(jù)
Windows版本opencv提供了VideoCapture類進行攝像操作.
使用函數(shù)g_cap.open(0)打開攝像頭,使用
Mat frame;
?????g_cap>> frame;
獲取攝像頭當(dāng)前幀圖像,并存放在Mat矩陣變量frame里.
2.對工業(yè)相機生成的變形圖像進行校正
采用短焦距相機,圖像發(fā)生了畸變,圖像靠近邊框的部分發(fā)生了明顯的彎曲,需要進行校正,過程如下:
2.1對相機進行定標
?????定標的實際就是獲取圖像發(fā)生畸變的參數(shù),根據(jù)這些參數(shù)對獲取的圖像進行校正.opencv自帶了定標的源碼以及方法.
2.1.1首先在samples\cpp目錄下獲取calibration.cpp源碼文件。為該文件建一個工程,把其編譯成可執(zhí)行文件calibration.exe。
2.1.2在A4紙上打印一張10*7格黑白相間的棋盤紙,每個格子的長度是27mm*27mm。用這張紙在攝像頭上晃動取取圖像保存到文件,圖像越多越準確。把這些圖像文件名列在list_of_views.xml文件里面,格式如下:
<?xml version="1.0"?>
?????< opencv_storage>
?????<images>
?????left02.bmp
?????left03.bmp
?????left04.bmp
?????…
?????</images>
</opencv_storage>
2.1.3有了圖像文件,就可以運行calibration.exe程序生成校正參數(shù)文件了:alibration.exe-w 9 -h 6 -p -o camera.yml -op -oe -s 2 list_view.xml
。這里需要注意的是 -w -h參數(shù)指的是棋盤格在長寬兩個方向上的角點個數(shù)而不是棋盤格在兩個方向上的方格個數(shù)。運行命令過后就會在目錄下生成camera.yml,要的就是這個文件。
把這個復(fù)制到工程下面。
2.1.4在打開攝像的地方加入代碼
?????Mat img;
?????g_cap>>img;
?????FileStorage fs2("config/camera.yml",FileStorage::READ);
?????intframeCount = (int)fs2["nframes"];
?????std::string date;
?????fs2["calibration_time"]>> date;
?????Mat cameraMatrix, distCoeffs;
?????fs2["camera_matrix"]>> cameraMatrix;
?????fs2["distortion_coefficients"]>> distCoeffs;
?????Mat view,rview, map1, map2;
?????initUndistortRectifyMap(cameraMatrix,distCoeffs, Mat(),getOptimalNewCameraMatrix(cameraMatrix, distCoeffs,img.size(), 1, img.size(), 0),img.size(), CV_16SC2, map1, map2);
?????這樣就可以得到攝像頭的校正矩陣map1,map2。獲取圖像的地方隊獲取的圖像進行處理:
??????????g_cap>>frame;
??????????Mat rview;
??????????Mat m;
??????????remap(frame, m, map1, map2,INTER_LINEAR);
?????m矩陣就是經(jīng)過校正的圖像了。
3.把圖像數(shù)據(jù)轉(zhuǎn)換成BITMAPINFO在vs界面上顯示
Opencv雖然提供了imshow等函數(shù)顯示圖像,但在具體的應(yīng)用中往往需要把圖像顯示在自己的界面控件(如:Picture Control)中,用如下函數(shù)可以實現(xiàn):
voidshowMatImgToWnd(CWnd* pWnd, const cv::Mat& img)
{
?????if(img.empty()) return;
?????static BITMAPINFO *bitMapinfo = NULL;
?????static bool First=TRUE;
?????if(First)
?????{
??????????BYTE *bitBuffer = newBYTE[40+4*256];//開辟一個內(nèi)存區(qū)域
??????????if(bitBuffer == NULL)
??????????{
????????????????return;
??????????}
??????????First=FALSE;
??????????memset(bitBuffer, 0, 40+4*256);
??????????bitMapinfo = (BITMAPINFO *)bitBuffer;
??????????bitMapinfo->bmiHeader.biSize??= sizeof(BITMAPINFOHEADER);
??????????bitMapinfo->bmiHeader.biPlanes??= 1;
??????????for(int i=0; i<256; i++)
??????????{ //顏色的取值范圍 (0-255)
????????????????bitMapinfo->bmiColors[i].rgbBlue?=bitMapinfo->bmiColors[i].rgbGreen =bitMapinfo->bmiColors[i].rgbRed??=(BYTE) i;
??????????}
?????}
?????bitMapinfo->bmiHeader.biHeight =-img.rows;
???bitMapinfo->bmiHeader.biWidth =img.cols;
?????bitMapinfo->bmiHeader.biBitCount=img.channels() *8;
?
?????CRect drect;??????
?????pWnd->GetClientRect(drect);???//pWnd指向CWnd類的一個指針
?????CClientDC dc(pWnd);
?????HDC hDC =dc.GetSafeHdc();?????????????????//HDC是Windows的一種數(shù)據(jù)類型,是設(shè)備描述句柄;
?????SetStretchBltMode(hDC, COLORONCOLOR);???
?????StretchDIBits(hDC,0,0,
??????????drect.right,?//顯示窗口寬度
??????????drect.bottom,?//顯示窗口高度
??????????0,
??????????0,
??????????img.cols,????//圖像寬度
??????????img.rows,????//圖像高度
??????????img.data,??
??????????bitMapinfo,??
??????????DIB_RGB_COLORS,
??????????SRCCOPY
?????);
}
?
4.把圖像轉(zhuǎn)化成灰度圖
?????Mat gray;
cvtColor(img,gray,CV_BGR2GRAY);
將彩色圖像img轉(zhuǎn)成灰度圖矩陣。
5.對灰度圖進行邊界增強處理。
邊界增強處理的目的就是讓物體的邊界分明,便于輪廓查找,圖像學(xué)算法中有Sobel算子,Laplacian算子(二階微分)等,本程序采用Canny算子進行邊緣增強。Opencv提供的函數(shù)
CV_EXPORTS_W voidCanny( InputArray image,
OutputArrayedges,double threshold1, double threshold2,
int apertureSize=3, bool L2gradient=false );
Canny算法包含許多可以調(diào)整的參數(shù),它們將影響到算法的計算的時間與實效。
閾值:使用兩個閾值比使用一個閾值更加靈活,但是它還是有閾值存在的共性問題。設(shè)置的閾值過高,可能會漏掉重要信息;閾值過低,將會把枝節(jié)信息看得很重要。
經(jīng)過檢驗采用如下參數(shù):
Canny(detected_edges, detected_edges, 80, 80*2.5, 3 );
6.對邊界增強處理過的圖像進行二值化
二值化處理的目的是讓輪廓黑白分明,便于后續(xù)的處理。Opencv提供的函數(shù)如下:
Mat img_bin;
?????threshold(detected_edges,img_bin,0,255,CV_THRESH_BINARY|CV_THRESH_OTSU);
7.對二值圖像進行形態(tài)學(xué)處理
形態(tài)學(xué)處理的目的實現(xiàn)消除噪聲,分割(isolate)出獨立的圖像元素,在圖像中連接(join)相鄰的元素。程序采用opencv提供的2個函數(shù):???
dilate(img_bin,m_ResImg,elementX,Point(-1,-1),1);
erode(m_ResImg,m_ResImg,elementX,Point(-1,-1),1);
?????先對圖像進行膨脹處理,將異型卡的邊界輪廓連接起來并且加粗,再進行腐蝕處理,可以把卡上的圖案等去除。
8.經(jīng)過以上處理以后就可以對圖像進行輪廓提取了
使用函數(shù)?????findContours(gray_bi, contours, hierarchy,
??????CV_RETR_EXTERNAL,
??????CV_CHAIN_APPROX_SIMPLE,
??????Point(0, 0) );
所有的輪廓以點集合的形式存放在變量contours,以下處理過程就是遍歷這個集合進行識別了。
9.遍歷集合取出各個元素進行處理
獲取集合的頭元素
vector<vector<Point>>::const_iterator itc=contours.begin();
10.從集合中取出輪廓點進行處理
計算出異型卡輪廓的重心點坐標,外接圓半徑,最小外接矩形4個點。
?????RotatedRect minRect = minAreaRect(*itc);
Point2f vertices[4];
?????minRect.points(vertices); //獲得最小外接矩形4個點
?????Point2f center;
?????float radius;
?????minEnclosingCircle(*itc, center, radius);?
11.計算機械手坐標與圖像平面坐標的映射關(guān)系
將圖像坐標轉(zhuǎn)換成機械手坐標,其中fRe為機械手坐標與攝像頭圖像坐標的比。
CDobotPoint p1;
p1.x = g_center_point.x- (g_height/2.0 - c3f.cPiont.y) * fRe;
p1.y = g_center_point.y- (g_width/2.0 - c3f.cPiont.x) * fRe;
?????p1.z = g_center_point.z + 50;
12.發(fā)送指令給機械手去抓取異型卡
?
以上就是整個應(yīng)用程序的處理過程.
總結(jié)
以上是生活随笔為你收集整理的图像识别并用机械手进行抓取的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第十六课:libcurl库访问人工智能平
- 下一篇: 人工智能 图片识别 图像识别