利用OpenCV定位目標區域並剪下
阿新 • • 發佈:2019-01-08
軟體環境:Qt5.5.1,msvc2012編譯器,OpenCV2.4.9
處理影象:CCD相機採集的一個綠色光斑,背景色是黑色。
(PS:影象存在很多噪聲,暫時不做處理)
目的:定位光斑所在位置,並裁剪。
將實現函式寫在Qt一個按鍵上,點選按鍵呼叫函式;
1、程式碼分段解釋:
定位目標區域的核心演算法是僅僅找出大綠斑影象輪廓線,黑色背景存在許多小綠斑,影響輪廓線的採集,三種常用的濾波全用上,效果可以。IplImage* src = cvLoadImage("D:/1.bmp",-1); cvSmooth(src,src,CV_BLUR,5,5,0,0); //均值濾波 cvSmooth(src,src,CV_MEDIAN,5,5,0,0); //中值濾波 cvSmooth(src,src,CV_GAUSSIAN,5,5,0,0); //維納濾波
2、對影象進行二值化處理,設定一個閾值25,綠色通道大於25的畫素點設定為(0,255,0),綠色通道小於25的畫素點設定為(0,0,0).
處理後圖像效果是這樣滴:CvScalar s; //存放4個double值 for(int i=0;i<src->height;i++) { for(int j=0;j<src->width;j++) { s = cvGet2D(src,i,j); if(s.val[1]>25) { s.val[0] = 0; s.val[1] = 255; s.val[2] = 0; } else { s.val[0] = 0; s.val[1] = 0; s.val[2] = 0; } cvSet2D(src,i,j,s); //設定畫素 } }
3、
cvFindContours函式要求輸入的影象是灰度圖,將綠色光斑轉為灰色光斑最後呼叫函式,找到影象輪廓。IplImage *dst_gray; dst_gray = cvCreateImage(cvGetSize(src),8,1); cvCvtColor(src,dst_gray,CV_BGR2GRAY); CvMemStorage *storage = cvCreateMemStorage(0); CvSeq* contours = 0; cvFindContours(dst_gray,storage,&contours,sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE,cvPoint(0,0)); //找出輪廓
4、
for(int i=0;i<contours->total;i++) //遍歷輪廓的座標
{
CvPoint* p = CV_GET_SEQ_ELEM(CvPoint,contours,i);//指標指向輪廓點座標
if(p->x<x0)
{
x0 = p->x;
y0 = p->y;
}
if(p->y<y1)
{
x1 = p->x;
y1 = p->y;
}
}
將輪廓點座標取出來,遍歷所有座標,用類似冒泡法,提取圓輪廓左邊邊界座標值,上邊邊界座標值。
5、
int range = 2*(x1-x0);
cvNamedWindow("src",0); //1或者CV_WIMDOW_AUTOSIZE是圖片本來大小,0是鋪滿螢幕
cvShowImage("src",src);
cvReleaseImage(&src); //釋放記憶體
IplImage* dst = cvLoadImage("D:/1.bmp",-1); //原通道讀取圖片
cvSetImageROI(dst,cvRect(x0,y1,range,range));//設定源影象ROI
IplImage* img = cvCreateImage(cvSize(range,range),dst->depth,dst->nChannels);//建立目標影象
cvCopy(dst,img); //複製影象
cvReleaseImage(&dst);
cvNamedWindow("image",0); //1或者CV_WIMDOW_AUTOSIZE是圖片本來大小,0是鋪滿螢幕
cvShowImage("image",img);
收尾工作計算要裁剪的矩形區域的座標與邊長,進行裁剪顯示,最後注意IplImage容器不能自動釋放記憶體,需要手動釋放。
最後上結果圖(圓斑不是很圓,不能正好裁剪).
6、完整程式碼還是得有的:
void MainWindow::on_pushButton_clicked() //The first button
{
// Mat src = imread("D:/1.bmp");
// int height = src.rows;
// int width = src.cols;
IplImage* src = cvLoadImage("D:/1.bmp",-1);
cvSmooth(src,src,CV_BLUR,5,5,0,0); //均值濾波
cvSmooth(src,src,CV_MEDIAN,5,5,0,0); //中值濾波
cvSmooth(src,src,CV_GAUSSIAN,5,5,0,0); //維納濾波
CvScalar s; //存放4個double值
for(int i=0;i<src->height;i++)
{
for(int j=0;j<src->width;j++)
{
s = cvGet2D(src,i,j);
if(s.val[1]>25)
{
s.val[0] = 0;
s.val[1] = 255;
s.val[2] = 0;
}
else
{
s.val[0] = 0;
s.val[1] = 0;
s.val[2] = 0;
}
cvSet2D(src,i,j,s); //設定畫素
}
}
IplImage *dst_gray;
dst_gray = cvCreateImage(cvGetSize(src),8,1);
cvCvtColor(src,dst_gray,CV_BGR2GRAY);
CvMemStorage *storage = cvCreateMemStorage(0);
CvSeq* contours = 0;
cvFindContours(dst_gray,storage,&contours,sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE,cvPoint(0,0)); //找出輪廓
int x0=50000,y0,x1,y1=50000;
for(int i=0;i<contours->total;i++) //遍歷輪廓的座標
{
CvPoint* p = CV_GET_SEQ_ELEM(CvPoint,contours,i);
if(p->x<x0)
{
x0 = p->x;
y0 = p->y;
}
if(p->y<y1)
{
x1 = p->x;
y1 = p->y;
}
}
// qDebug()<<x0;
// qDebug()<<y0;
// qDebug()<<x1;
// qDebug()<<y1;
int range = 2*(x1-x0);
cvNamedWindow("src",0); //1或者CV_WIMDOW_AUTOSIZE是圖片本來大小,0是鋪滿螢幕
cvShowImage("src",src);
cvReleaseImage(&src); //釋放記憶體
IplImage* dst = cvLoadImage("D:/1.bmp",-1); //原通道讀取圖片
cvSetImageROI(dst,cvRect(x0,y1,range,range));//設定源影象ROI
IplImage* img = cvCreateImage(cvSize(range,range),dst->depth,dst->nChannels);//建立目標影象
cvCopy(dst,img); //複製影象
cvReleaseImage(&dst);
cvNamedWindow("image",0); //1或者CV_WIMDOW_AUTOSIZE是圖片本來大小,0是鋪滿螢幕
cvShowImage("image",img);
// qDebug()<<num; //輸出輪廓數目
}