利用OpenCV定位目标区域并剪切

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_35759050/article/details/52791654

软件环境: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;  //输出轮廓数目
}


猜你喜欢

转载自blog.csdn.net/qq_35759050/article/details/52791654