1. 程式人生 > >利用OpenCV定位目標區域並剪下

利用OpenCV定位目標區域並剪下

軟體環境: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、

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));  //找出輪廓
cvFindContours函式要求輸入的影象是灰度圖,將綠色光斑轉為灰色光斑最後呼叫函式,找到影象輪廓。

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;  //輸出輪廓數目
}