精华内容
下载资源
问答
  • key = False x1 = -1 y1 = -1 m = True def done(event,x,y,flags,param): global key,x1,y1,r if(event == cv2.EVENT_LBUTTONDOWN): key = True x1 = x y1 = y elif(event == cv2.EVENT_MOUSEMOVE and flags ...
    key = False
    x1 = -1
    y1 = -1
    m = True
    def done(event,x,y,flags,param):
        global key,x1,y1,r
        if(event == cv2.EVENT_LBUTTONDOWN):
            key = True
            x1 = x
            y1 = y
        elif(event == cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON):
            pf = pd.copy()
            if(m):
                cv2.rectangle(pf,(x1,y1),(x,y),(0,255,0),1)
                cv2.imshow('f',pf)
            elif(not m):
                r = int(math.sqrt((x1-x)**2 + (y1-y)**2))
                cv2.circle(pf,(x1,y1),r,(0,255,0),1)
                cv2.imshow('f',pf)
        elif(event == cv2.EVENT_LBUTTONUP):
            if(m):
                cv2.rectangle(pd,(x1,y1),(x,y),(0,255,0),2)
            elif(not m):
                cv2.circle(pd,(x1,y1),r,(0,255,0),2)
            key = False
    pd = np.zeros((256,256,3),np.uint8)
    
    cv2.namedWindow('f')
    
    while(1):
        cv2.setMouseCallback('f',done)
        cv2.imshow('f',pd)
        f = cv2.waitKey(25) & 0xFF
        if(f == 27):
            break
        if(f == ord('m')):
            m = not m
    cv2.destroyAllWindows()
    
    展开全文
  • opencv 椭圆拟合

    千次阅读 2014-08-15 15:57:16
    // 当连通域的中心点为黑色时,而且面积较小则用白色进行填充 pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*(rect.y+rect.height/2)+rect.x+rect.width/2); if (pp[0]==255) { for(int y = ...
    #include "cv.h"  
    #include "highgui.h"  
    #include <iostream>
    using namespace std;
    int slider_pos=23;//阈值  
    
    IplImage *image02 =0,*image03 = 0,*image04 = 0;  
    void process_image(int h);  
     
    int main(int argc ,char **argv)  
    {  
        const char *filename ="D:\\test\\18.jpg";  
    	cout<<slider_pos<<" ";
        if ((image03 = cvLoadImage(filename,0))==0)//读入图像为灰度图像  
        {  
            return -1;  
        }  
        image02 = cvCloneImage(image03);  
       image04 = cvCloneImage(image03);  
          
        cvNamedWindow("Source",1);  
       cvNamedWindow("Result",1);  
      
        cvShowImage("Source",image03);  
      
        cvCreateTrackbar("Threshold","Result",&slider_pos,255,process_image);  
     
        process_image(0);  
      
        cvWaitKey(0);  
        cvSaveImage("1.jpg",image04);  
      
        cvReleaseImage(&image02);  
        cvReleaseImage(&image03);  
      
       cvDestroyWindow("Source");  
        cvDestroyWindow("Result");  
       return 0;  
     
    }  
    
    // 删除小面积图形
    IplImage* bwareaopen(IplImage *img, int areaThreshold)
    {	
    	CvSeq* contour = NULL;      
        double tmparea = 0.0;   
        CvMemStorage* storage = cvCreateMemStorage(0);   
           
        // IplImage* img= cvLoadImage(dlg.GetPathName(),CV_LOAD_IMAGE_ANYCOLOR);   
        IplImage* img_Clone=cvCloneImage(img);   
        // 访问二值图像每个点的值   
        uchar *pp;    
           
        //------------搜索二值图中的轮廓,并从轮廓树中删除面积小于某个阈值minarea的轮廓-------------//   
        CvScalar color = cvScalar(255,0,0);//CV_RGB(128,0,0);   
        CvContourScanner scanner = NULL;   
        scanner = cvStartFindContours(img,storage,sizeof(CvContour),CV_RETR_CCOMP,CV_CHAIN_APPROX_NONE,cvPoint(0,0));   
        // 开始遍历轮廓树   
        CvRect rect;   
        while (contour=cvFindNextContour(scanner))   
        {   
            tmparea = fabs(cvContourArea(contour));   
                rect = cvBoundingRect(contour,0);      
            if (tmparea < areaThreshold)   
            {   
    			// 当连通域的中心点为黑色时,而且面积较小则用白色进行填充   
                pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*(rect.y+rect.height/2)+rect.x+rect.width/2);   
                if (pp[0]==255)   
                {   
                    for(int y = rect.y;y<rect.y+rect.height;y++)   
                    {   
                        for(int x =rect.x;x<rect.x+rect.width;x++)   
                        {   
                            pp=(uchar*)(img_Clone->imageData + img_Clone->widthStep*y+x);   
                               
                            if (pp[0]==255)   
                            {   
                                pp[0]=0;   
                            }   
                        }   
                    }   
                }         
    		} 
    	}
    	return img_Clone;
    }
    
    // 对图像进行闭操作
    IplImage* imclose(IplImage* img)
    {
    	// 创建5*5结构元素等同于strel('disk',2)的效果
    	int mask[25]={0, 0, 1, 0, 0,
    	              0, 1, 1, 1, 0,
    	              1, 1, 1, 1, 1,
    	              0, 1, 1, 1, 0,
    	              0, 0, 1, 0, 0};
    	IplConvKernel* element=cvCreateStructuringElementEx( 5, 5, 0, 0,CV_SHAPE_CUSTOM, mask);
        // 先膨胀
    	cvDilate(img,img,element,1);
    	// 后腐蚀
    	cvErode(img,img,element,1);
    	return img;
    }
    
    // 对图像空洞进行填充
    IplImage* imfill(IplImage* img)
    {
        CvScalar white = CV_RGB( 255, 255, 255 );
    
        IplImage* dst = cvCreateImage( cvGetSize(img), 8, 3);
        CvMemStorage* storage = cvCreateMemStorage(0);
        CvSeq* contour = 0;
    
        cvFindContours(img, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE );
        cvZero( dst );
    
        for( ; contour != 0; contour = contour->h_next )
        {
            cvDrawContours( dst, contour, white, white, 0, CV_FILLED);
        }
    
        IplImage* bin_imgFilled = cvCreateImage(cvGetSize(img), 8, 1);
        cvInRangeS(dst, white, white, bin_imgFilled);
    
        return bin_imgFilled;
    }
    
    //这个函数寻找出轮廓、用椭圆拟合画出  
    void process_image(int h)  
    {  
        CvMemStorage *stor;  
        CvSeq *cont;  
        CvBox2D32f *box;  
        CvPoint *PointArray;  
       CvPoint2D32f *PointArray2D32f;  
      
        stor = cvCreateMemStorage(0);  
        cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor);  
      
        cvThreshold(image03,image02,slider_pos,255,CV_THRESH_BINARY);  
        
    	// 删除小面积
    	bwareaopen(image02,100);
    	// 闭操作
        imclose(image02);
    	// 填充
    	imfill(image02);
    
        cvFindContours(image02,stor,&cont,sizeof(CvContour),  
            CV_RETR_LIST,CV_CHAIN_APPROX_NONE,cvPoint(0,0));  
      
       cvZero(image02);  
        cvZero(image04);  
      
        //绘制所有轮廓并用椭圆拟合  
       for (;cont;cont = cont ->h_next)  
        {  
            int i;  
            int count= cont->total;//轮廓个数  
            CvPoint center;  
           CvSize size;  
      
            /*个数必须大于6,这是cvFitEllipse_32f的要求*/  
            if (count<6)  
           {  
                continue;  
            }  
            //分配内存给点集  
            PointArray = (CvPoint *)malloc(count*sizeof(CvPoint));  
           PointArray2D32f = (CvPoint2D32f*)malloc(count*sizeof(CvPoint2D32f));  
          
          //分配内存给椭圆数据  
            box = (CvBox2D32f *)malloc(sizeof(CvBox2D32f));  
      
            //得到点集(这个方法值得借鉴)  
           cvCvtSeqToArray(cont,PointArray,CV_WHOLE_SEQ);  
          
           //将CvPoint点集转化为CvBox2D32f集合  
            for (i=0;i<count;i++)  
            {  
               PointArray2D32f[i].x=(float)PointArray[i].x;  
                PointArray2D32f[i].y=(float)PointArray[i].y;  
           }  
     
           //拟合当前轮廓  
            cvFitEllipse(PointArray2D32f,count,box);  
    		double c=sqrt((box->size.height)*(box->size.height)/4-(box->size.width)*(box->size.width)/4);
    		double lxl=2*c/box->size.height;
    		if(box->size.height>50 || box->size.width>50){
    		cout<<"离心率:"<<lxl<<" ";
    		std::cout<<box->size.height<<" ";
    		std::cout<<box->size.width<<" ";
    		std::cout<<box->size.height/box->size.width<<endl;}
           //绘制当前轮廓  
          cvDrawContours(image04,cont,CV_RGB(255,255,255),CV_RGB(255,255,255),  
                0,1,8,cvPoint(0,0));  
     
           //将椭圆数据从浮点转化为整数表示  
          center.x = cvRound(box->center.x);  
           center.y = cvRound(box->center.y);  
           size.width = cvRound(box->size.width*0.5);  
           size.height = cvRound(box->size.height*0.5);  
           box->angle = -box->angle;  
      
            //画椭圆  
           cvEllipse(image04,center,size,box->angle,0,360,CV_RGB(0,0,255),1,CV_AA,0);  
      
           free(PointArray);  
           free(PointArray2D32f);  
           free(box);  
        }  
        cvShowImage("Result",image04);  
    } 
    
    
    


     

    展开全文
  • 基于opencv椭圆识别算法的改进

    千次阅读 2019-04-10 09:08:04
    但是,实际生活中,二值化的取值相对来说不稳定,很难将椭圆或者完整的过滤出来,所以,这里首先得一步,是不进行二值化处理,直接将灰度处理后的图片,进行椭圆识别处理。 1.用canny调参数时,会直接过滤掉识别...

    其实网上有一大堆椭圆识别的例子,不管是基于霍夫算法,或者是直接ellipse,都会遇到一些问题。当然,有那种上千行代码的例子,我也没仔细看。下面就是百来行代码对算法的改进。
    这里主要是针对在比较复杂的场景,直接对ellipse算法的改进,再具体一点,就是在椭圆过滤上加上一些其他的算法。但是由于不同场景亮度,椭圆大小,场景复杂度不同,这些算法不确保每种场景都适用,具体场景需要设置不同的参数。
    遇到的问题主要如下,都是针对比较复杂的场景,干扰因素较多的情况:
    首先,在许多人选择识别椭圆时会首先将图片灰度处理,然后进行threshold二值化处理。但是,实际生活中,二值化的取值相对来说不稳定,很难将椭圆或者圆完整的过滤出来,所以,这里首先得一步,是不进行二值化处理,直接将灰度处理后的图片,进行椭圆识别处理。
    1.用canny调参数时,会直接过滤掉识别的椭圆,这里主要采取的做法是,调低最大和最低threshold值,使原始图片过滤后尽可能有椭圆的轮廓,其他过滤放在后面进行。
    2.传统过滤方式会采用点数量过滤,轮廓面积过滤,但是,在这里,点的数量和轮廓面积是极其不靠谱的。主要是由于上述步骤得到轮廓点后,并不能完全保证闭合,所以点的数量不能保证,并且面积也只是起点到终点连线的轮廓面积。解决方法是在第一轮过滤的基础上再加一轮过滤,下面再讲具体实现。这一步只是放宽过滤条件,确保要识别的椭圆能不被过滤掉。
    3.上述过滤完后,会采取椭圆长短轴比较。随后,就用ellipse函数将椭圆画出来。但是,在较复杂的场景中,矩形通常也会被识别为椭圆,所以这里需要加一步过滤方式,有两种选择,第一种,采用凹凸性原理。第二种,采用直线斜率处处相等原则。
    4.上述过滤完后,会发现有许多大大小小的椭圆被识别出来,所以这里需要加第二轮椭圆过滤,需要一张黑色背景,将第一轮得到的椭圆画在黑色背景上,椭圆必须得填充,不能只留有线性,因为在后面过滤中,canny算子会识别出内外两个轮廓。然后再进行过滤。
    这些提到的东西都是目前项目里面涉及到的,并且还涉及一些专利和论文。所以要用到这些东西,务必留言,代码就放这了,参数需要自己改,就不多解释了,后面可能会删除这文章。你们可以用这段代码,修改参数,识别下图中的椭圆。

    #include<iostream>
    #include"opencv.hpp"
    
    using namespace std;
    using namespace cv;
    
    
    void drawCross(Mat &img, Point2f point, Scalar color, int size, int thickness = 1)
    {
    	//绘制横线  
    	line(img, cvPoint(point.x - size / 2, point.y), cvPoint(point.x + size / 2, point.y), color, thickness, 8, 0);
    	//绘制竖线  	
    	line(img, cvPoint(point.x, point.y - size / 2), cvPoint(point.x, point.y + size / 2), color, thickness, 8, 0);
    	return;
    }
    
    
    //提取单幅图像的特征点
    void FeaturePoint(Mat &img, Mat &img2)
    {
    	//threshold(img, img, 40, 255, CV_THRESH_BINARY_INV);
    	//将图片换为其它颜色
    	Point2f center; //定义变量
    	Point2f center1; //定义变量
    	Mat edges;
    	GaussianBlur(img, edges, Size(5, 5), 0, 0);
    	//Canny(edges, edges, 35, 120, 3);
    	Canny(edges, edges,35, 70, 3);
    	Mat mm = img2(Rect(0, 0, img2.cols , img2.rows));//ROI设置
    	mm = { Scalar(0, 0, 0) };//把ROI中的像素值改为黑色
    	vector<vector<Point> > contours;// 创建容器,存储轮廓
    	vector<Vec4i> hierarchy;// 寻找轮廓所需参数
    
    	findContours(edges, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    	Mat imageContours = Mat::zeros(edges.size(), CV_8UC1);//轮廓
    	for (int i = 0; i < contours.size(); i++)
    	{
    		//绘制轮廓 
    		drawContours(imageContours, contours, i, Scalar(255), 1, 8, hierarchy);
    	}
    
    	//过滤
    	for (int i = 0; i < contours.size(); i++)
    	{
    		if (contours[i].size() <= 100 || contours[i].size() >= 1000){
    			continue;
    		}
    		
    		if (contourArea(contours[i]) < 10 || contourArea(contours[i]) > 40000){
    			continue;
    		}
    		//利用直线斜率处处相等的原理
    		/*if (abs(((double)(contours[i][0].y - contours[i][20].y) / (double)(contours[i][0].x - contours[i][20].x) -
    			(double)(contours[i][20].y - contours[i][40].y) / (double)(contours[i][20].x - contours[i][40].x)))<0.2)
    				continue;*/
    		//利用凹凸性的原理
    		if (!abs((contours[i][0].y + contours[i][80].y) / 2 - contours[i][40].y))
    			continue;
    
    		RotatedRect m_ellipsetemp;  // fitEllipse返回值的数据类型
    		m_ellipsetemp = fitEllipse(contours[i]);  //找到的第一个轮廓,放置到m_ellipsetemp
    		if (m_ellipsetemp.size.width / m_ellipsetemp.size.height < 0.3)
    		{
    			continue;
    		}
    		cout << "1:" << contourArea(contours[i]) << endl;
    		cout << "2:" << contours[i].size() << endl;
    		//drawCross(img, center, Scalar(255, 0, 0), 30, 2);
    		//ellipse(img, m_ellipsetemp, cv::Scalar(255, 255, 255));   //在图像中绘制椭圆
    		ellipse(mm, m_ellipsetemp, cv::Scalar(255, 255, 255), CV_FILLED);   //在图像中绘制椭圆
    	}
    	
    	Mat edges1;
    	GaussianBlur(mm, edges1, Size(5, 5), 0, 0);
    	Canny(edges1, edges1, 50, 150, 3);
    	//vector<vector<Point> > contours1;// 创建容器,存储轮廓
    	//vector<Vec4i> hierarchy1;// 寻找轮廓所需参数
    	findContours(edges1, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
    	Mat imageContours1 = Mat::zeros(edges1.size(), CV_8UC1);//轮廓
    
    	for (int i = 0; i < contours.size(); i++)
    	{
    		drawContours(imageContours1, contours, i, Scalar(255), 1, 8, hierarchy);
    		//绘制轮廓 
    	}
    	for (int i = 0; i < contours.size(); i++)
    	{
    		if (contours[i].size() <= 100 || contours[i].size() >= 1000){
    			continue;
    		}
    		//利用凹凸性的原理
    		/*if (!abs((contours[i][0].y + contours[i][20].y) / 2 - contours[i][10].y))
    			continue;*/
    
    		if (contourArea(contours[i]) < 3000 || contourArea(contours[i]) > 20000){
    			continue;
    		}
    		RotatedRect m_ellipsetemp1;  // fitEllipse返回值的数据类型
    		m_ellipsetemp1 = fitEllipse(contours[i]);  //找到的第一个轮廓,放置到m_ellipsetemp
    		ellipse(img, m_ellipsetemp1, cv::Scalar(255, 0, 0));   //在图像中绘制椭圆
    		cout << "mianji" << contourArea(contours[i]) << endl;
    		cout << "dianshu" << contours[i].size() << endl;
    		/*cout << (float)contours[i][0].x << endl;
    		cout << contours[i][0].y << endl;*/
    		center1 = m_ellipsetemp1.center;//读取椭圆中心
    		drawCross(img, center1, Scalar(255, 0, 0), 30, 2);
    		cout << center1.x << ends << center1.y << endl;
    	}
    	/*imshow("image", img1);
    	waitKey(0);*/
    	//return ;//返回椭圆中心坐标
    
    }
    
    int main(int argc, char* argv[])
    {
    	const char* imagename = "pixmap.png";
    
    	//从文件中读入图像
    	Mat img = imread(imagename, 1);
    	Mat img2 = imread(imagename, 1);
    	//如果读入图像失败
    	if (img.empty())
    	{
    		fprintf(stderr, "Can not load image %s\n", imagename);
    		return -1;
    	}
    	FeaturePoint(img ,img2);
    	//显示图像
    	imshow("image", img);
    	//此函数等待按键,按键盘任意键就返回
    	waitKey();
    	return 0;
    }
    
    
    
    
    

    通过上面代码过滤,识别图中椭圆

    展开全文
  • OpenCV漫水填充

    千次阅读 2013-08-29 21:39:15
    漫水填充就是用一定颜色填充联通区域,通过设置可连通像素的上下限以及连通方式来达到不同的填充效果;漫水填充经常被用来标记或分离图像的一部分以便对其进行进一步处理或分析,也可以用来从输入图像获取掩码区域,...

    引言

    漫水填充是用一定颜色填充联通区域,通过设置可连通像素的上下限以及连通方式来达到不同的填充效果;漫水填充经常被用来标记或分离图像的一部分以便对其进行进一步处理或分析,也可以用来从输入图像获取掩码区域,掩码会加速处理过程,或只处理掩码指定的像素点,操作的结果总是某个连续的区域。

    基本思想

    种子填充算法是从多边形区域内部的一点开始,由此出发找到区域内的所有像素。它采用的边界定义是区域边界上所有像素具有某个特定的颜色值,区域内部所有像素均不取这一特定颜色,而边界外的像素则可具有与边界相同的颜色值。具体算法步骤如下所示:

    1. 标记种子(x,y)的像素点 ;
    2. 检测该点的颜色,若他与边界色和填充色均不同,就用填充色填   充该点,否则不填充 ;
    3. 检测相邻位置,继续 2。这个过程延续到已经检测区域边界范围内的所有像素为止。

    当然在搜索的时候有两种检测相邻像素:四向连通和八向连通。四向连通即从区域上一点出发,通过四个方向上、下、左、右来检索。而八向连通加上了左上、左下、右上、右下四个方向。这种算法的有点是算法简单,易于实现,也可以填充带有内孔的平面区域。但是此算法需要更大的存储空间以实现栈结构,同一个像素多次入栈和出栈,效率低,运算量大。而扫描线种子填充算法属于种子填充算法,它是以扫描线上的区段为单位操作。所谓区段,就是一条扫描线上相连着的若干内部象素的集合。扫描线种子填充算法思想:首先填充当前扫描线上的位于给定区域的一区段,然后确定于这一区段相邻的上下两条线上位于该区域内是否存在需要填充的新区段,如果存在,则依次把他们保存起来,反复这个过程,直到所保存的各区段都填充完毕。借助于堆栈,上述算法实现步骤如下:

    初始化堆栈。
    种子压入堆栈。
    while(堆栈非空){
       从堆栈弹出种子象素。
       如果种子象素尚未填充,则:
         求出种子区段:xleft、xright;
         填充整个区段。
         检查相邻的上扫描线的xleft <= x <= xright区间内,是否存在需要填充的新区段,如果存在的话,则把每个新区段在xleft <= x <= xright范围内的最右边的象素,作为新的种子象素依次压入堆栈。
         检查相邻的下扫描线的xleft <= x <= xright区间内,是否存在需要填充的新区段,如果存在的话,则把每个新区段在xleft <= x <= xright范围内的最右边的象素,作为新的种子象素依次压入堆栈。
    }

    更进一步算法,在原算法中, 种子虽然代表一个区段, 但种子实质上仍是一个象素, 我们必须在种子出栈的时候计算种子区段, 而这里有很大一部分计算是重复的. 而且, 原算法的扫描过程如果不用mask的话, 每次都会重复扫描父种子区段所在的扫描线, 而用mask的话又会额外增加开销。所以, 对原算法的一个改进就是让种子携带更多的信息, 让种子不再是一个象素, 而是一个结构体. 该结构体包含以下信息: 种子区段的y坐标值, 区段的x开始与结束坐标, 父种子区段的方向(上或者下), 父种子区段的x开始与结束坐标.

    struct seed{
        int y,
        int xleft,
        int xright,
        int parent_xleft,
        int parent_xright,
        bool is_parent_up
    };
    这样算法的具体实现变动如下
    初始化堆栈.
    将种子象素扩充成为种子区段(y, xleft, xright, xright+1, xrihgt, true), 填充种子区段, 并压入堆栈. (这里有一个构造父种子区段的技巧)
    while(堆栈非空){
       从堆栈弹出种子区段。
       检查父种子区段所在的扫描线的xleft <= x <= parent_xleft和parent_xright <= x <= xright两个区间, 如果存在需要填充的新区段, 则将其填充并压入堆栈.
       检查非父种子区段所在的扫描线的xleft <= x <= xright区间, 如果存在需要填充的新区段, 则将其填充并压入堆栈.
    }

    另外, opencv里的种子填充算法跟以上方法大致相同, 不同的地方是opencv用了队列不是堆栈, 而且是由固定长度的数组来实现的循环队列, 其固定长度为 max(img_width, img_height)*2. 并且push与pop均使用宏来实现而没有使用函数. 用固定长度的数组来实现队列(或堆栈)意义是显然的, 能大大减少构造结构, 复制结构等操作, 可以大大提高效率.

    参考代码

    CVAPI(void)  cvFloodFill( CvArr* image, CvPoint seed_point,
                              CvScalar new_val, CvScalar lo_diff CV_DEFAULT(cvScalarAll(0)),
                              CvScalar up_diff CV_DEFAULT(cvScalarAll(0)),
                              CvConnectedComp* comp CV_DEFAULT(NULL),
                              int flags CV_DEFAULT(4),
                              CvArr* mask CV_DEFAULT(NULL));
    其中函数参数:
    • image为待处理图像
    • seed_point为种子坐标
    • new_val为填充值
    • lo_diff为像素值的下限差值
    • up_diff为像素值的上限差值
    • 从函数形式可看出,该函数可处理多通道图像。
    • mask为掩码, 注意: 设输入图像大小为width * height, 则掩码的大小必须为 (width+2) * (height+2) ,  mask可为输出,也可作为输入 ,由flags决定
    • flags参数 :  0~7位为0x04或者0x08 即 4连通或者8 连通 
    • 8~15位为填充mask的值大小 , 若为0 , 则默认用1填充
    • 16~23位为 : CV_FLOODFILL_FIXED_RANGE =(1 << 16), CV_FLOODFILL_MASK_ONLY   =(1 << 17)
    • flags参数通过位与运算处理

    当为CV_FLOODFILL_FIXED_RANGE 时,待处理的像素点与种子点作比较,如果满足(s - lodiff , s + updiff)之间(s为种子点像素值),则填充此像素 .  若无此位设置,则将待处理点与已填充的相邻点作此比较

    CV_FLOODFILL_MASK_ONLY   此位设置填充的对像,  若设置此位,则mask不能为空,此时,函数不填充原始图像img,而是填充掩码图像.   若无此位设置,则在填充原始图像的时候,也用flags的8~15位标记对应位置的mask.

    OpenCV版漫水填充实现

    #include <cv.h>  
    #include <cxcore.h>  
    #include <highgui.h>  
    #include <iostream>  
      
    using namespace std;  
      
    int main() {  
        cvNamedWindow("source");  
        cvNamedWindow("dest1");  
        cvNamedWindow("dest2");  
        cvNamedWindow("mask0");  
        cvNamedWindow("mask1");  
    
        IplImage * src = cvLoadImage("test.jpg");  
        IplImage * img=cvCreateImage(cvGetSize(src), 8, 3);  
        IplImage *img2=cvCreateImage(cvGetSize(src),8,3);  
        IplImage *pMask = cvCreateImage(cvSize(src->width +2 ,src->height +2),8,1);  
    
        cvSetZero(pMask);  
        cvCopyImage(src, img);  
        cvCopyImage(src,img2);  
      
        cvFloodFill( img, cvPoint(300,310),CV_RGB(255,0,0),cvScalar(20,30,40,0),  
            cvScalar(5,30,40,0), NULL,  CV_FLOODFILL_FIXED_RANGE | (0x9f<<8),pMask); 
     
        cvShowImage("mask0",pMask);  
        cvSetZero(pMask);  
        cvFloodFill(img2,cvPoint(80,80),CV_RGB(255,0,0),cvScalarAll(29),cvScalarAll(10),  
            NULL, CV_FLOODFILL_MASK_ONLY | (47<<8) ,pMask);  
      
        cvShowImage("source",src);  
        cvShowImage("dest1", img);  
        cvShowImage("dest2",img2);  
        cvShowImage("mask1",pMask);
    
        cvWaitKey(0);  
        cvReleaseImage(&src);  
        cvReleaseImage(&img);  
        cvReleaseImage(&img2);
    
        cvReleaseImage(&pMask);  
        cvDestroyAllWindows();  
        return 0;  
    }

    Python版漫水填充实现

    #decoding:utf-8
    import numpy as np  
    import cv2  
    import random
    
    help_message ='''''USAGE: floodfill.py [<image>] 
    Click on the image to set seed point 
    
    Keys: 
      f     - toggle floating range 
      c     - toggle 4/8 connectivity 
      ESC   - exit 
    '''  
      
    if __name__ == '__main__':  
        import sys  
        try: fn = sys.argv[1]  
        except: fn = '../test.jpg'  
        print help_message  
      
        img = cv2.imread(fn, True)  
        h, w = img.shape[:2]                 #得到图像的高和宽  
        mask = np.zeros((h+2, w+2), np.uint8)#掩码单通道8比特,长和宽都比输入图像多两
                                             #个像素点,满水填充不会超出掩码的非零边缘  
        seed_pt = None  
        fixed_range = True  
        connectivity = 4  
      
        def update(dummy=None):  
            if seed_pt is None:  
                cv2.imshow('floodfill', img)  
                return  
            flooded = img.copy()                      #以副本的形式进行填充,这样每次  
            mask[:] = 0                               #掩码初始为全0  
            lo = cv2.getTrackbarPos('lo', 'floodfill')#观察点像素邻域负差最大值  
            hi = cv2.getTrackbarPos('hi', 'floodfill')#观察点像素邻域正差最大值  
            flags = connectivity                      #低位比特包含连通值, 4 (缺省) 或 8  
            if fixed_range:  
                flags |= cv2.FLOODFILL_FIXED_RANGE    #考虑当前象素与种子象素之间的差(高比特也可以为0)  
            #以白色进行漫水填充  
            cv2.floodFill(flooded, mask, seed_pt, (random.randint(0,255), 
                         random.randint(0,255), random.randint(0,255)), 
                         (lo,)*3, (hi,)*3, flags)  
              
            cv2.circle(flooded, seed_pt, 2, (0, 0, 255), -1)#选定基准点用红色圆点标出  
            cv2.imshow('floodfill', flooded)  
      
        def onmouse(event, x, y, flags, param):  #鼠标响应函数  
            global seed_pt  
            if flags & cv2.EVENT_FLAG_LBUTTON:   #鼠标左键响应,选择漫水填充基准点  
                seed_pt = x, y  
                update()  
      
        update()  
        cv2.setMouseCallback('floodfill', onmouse)  
        cv2.createTrackbar('lo', 'floodfill', 20, 255, update)  
        cv2.createTrackbar('hi', 'floodfill', 20, 255, update)  
      
        while True:  
            ch = 0xFF & cv2.waitKey()  
            if ch == 27:  
                break  
            if ch == ord('f'):  
                fixed_range = not fixed_range   #选定时flags的高位比特位0,也就是邻域的
                                                #选定为当前像素与相邻像素的的差,这样的效果就是联通区域会很大  
                print 'using %s range' % ('floating', 'fixed')[fixed_range]  
                update()  
            if ch == ord('c'):  
                connectivity = 12-connectivity  #选择4方向或则8方向种子扩散  
                print 'connectivity =', connectivity  
                update()  
        cv2.destroyAllWindows()  
    

    关于Image Engineering & Computer Vision的更多讨论与交流,敬请关注本博客和新浪微博songzi_tea.

    展开全文
  • 圆形的绘制 :OpenCV中使用circle(img,center,radius,color,thickness=None,lineType=None,shift=None)函数来绘制圆形import cv2import numpy as npimage=np.zeros((400,400,3),np.uint8)cv2.circle(image,...
  • opencv2/opencv.hpp&gt; #include &lt;iostream&gt; using namespace cv; using namespace std; void DrawLine();//线段 void DrawRectangle(int x, int y, int width, int height);//矩形 void ...
  • 圆形的绘制 :OpenCV中使用circle(img,center,radius,color,thickness=None,lineType=None,shift=None)函数来绘制圆形import cv2import numpy as npimage=np.zeros((400,400,3),np.uint8)cv2.circle(image,...
  • openCV绘制与填充

    2019-06-18 14:45:49
    使用OpenCV进行图形检查测和识别,我们需要在输出的图像上对处理结果加上醒目的轮廓或者以边框矩形绘制或者颜色填充,所以API可以提供相关的操作 ####在MAT上绘制集合形状与文本 绘制直线: //img:表示绘制对象是...
  • 如何检测填充的圆圈+ OpenCV + Python我已经确定了中心坐标中的每个。 如何检测哪个圆圈是空的&填充了哪个圆圈?我已经开发这个代码import numpy as npimport cv2import mathimg = cv2.imread("small.jpg",0) img ...
  • 目录cv::Pointcv::Scalar绘图绘制直线API代码效果绘制矩形API代码效果绘制椭圆API代码效果绘制API代码效果设置填充API代码效果绘制文字API代码效果 cv::Point opencv中的一种数据结构,表示在2D平面上的一个点,...
  • OpenCV 【十五】
  • 生成直线、矩形、椭圆、填充图形、添加文字、生成随机直线代码各种函数使用方法的介绍各种处理后的结果图片对比: 代码 先上代码。 我自学的方式是先看代码,然后在代码中遇到不懂的再逐个查询资料,深入学习,...
  • OpenCV--填充图像孔洞

    千次阅读 2019-11-05 12:59:28
    1)、要填充的区域需要连通; 2)、图像前后景的像素值差值最好比较大; 2、代码 #include "opencv2/opencv.hpp" #include "vector" #include <QDebug> using namespace std; using namespace cv; void main...
  • import numpy as np ...'OpenCV' ,( 10 , 500 ),font, 4 ,( 255 , 255 , 255 ), 2 ) winname = 'example' cv2.namedWindow(winname) cv2.imshow(winname,img) cv2.waitKey( 0 ) cv2.destroyAllWindows(winname)
  • w/32, //半径 Scalar( 0, 0, 255 ), //颜色 FILLED, //线粗细 LINE_8 ); //线型 画矩形和填充矩形 void drawpoly() { Mat img(500, 500, CV_8U, Scalar(0)); Point root_points[1][4]; root_...
  • OpenCV中绘制直线、正方形、椭圆、圆形、方形填充、随机生成直线 /* 绘制形状与文字 */ #include <iostream> #include <opencv2/opencv.hpp> using namespace cv; using namespace std; Mat bgImage;...
  • 2、根据定位得到的椭圆信息绘制外椭圆并且填充为255像素的实心椭圆,再绘制内椭圆且填充为0像素的实心椭圆,这样便形成了白色的椭圆环mask图像。调用opencv函数ellipse()绘制椭圆; 3、最后调用opencv
  • OpenCV学习笔记4.0(7)绘制图像与文字
  • thickness,//线条厚度值-1表示将被填充 lineType ); } /** * @function MyPolygon * @function Draw a simple concave polygon (rook) */ void MyPolygon( Mat img ) { int lineType = 8; /** Create ...
  • opencv-python填充算法(水漫填充

    万次阅读 2017-07-27 13:54:13
    水漫填充算法实现 help(cv2.floodFill)floodFill(image, mask, seedPoint, newVal[, loDiff[, upDiff[, flags]]]) -> retval, image, mask, rect 参数解释: image: mask:掩码图像,大小比原图多两个像素点...
  • Opencv C++ 绘制椭圆/圆形 #include <iostream> #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> using namespace cv; using namespace std;...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,206
精华内容 1,682
关键字:

opencv圆填充