• opencv学习系列:连通域参考处理


    OpenCV里提取目标轮廓的函数是findContours,它的输入图像是一幅二值图像,输出的是每一个连通区域的轮廓点的集合:vector<vector<Point>>。
    外层vector的size代表了图像中轮廓的个数,里面vector的size代表了轮廓上点的个数。
    
    hiararchy参数和轮廓个数相同,每个轮廓contours[ i ]对应4个hierarchy元素hierarchy[ i ][ 0 ] ~hierarchy[ i ][ 3 ],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,该值设置为负数。
    第六个参数传入CV_CHAIN_CODE时,要设置成sizeof(CvChain),其它情况统一设置成sizeof(CvContour)
    CV_CHAIN_CODE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
    CV_CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。例如一个矩形轮廓只需4个点来保存轮廓信息
    CV_RETR_EXTERNAL:只检索最外面的轮廓;
    CV_RETR_LIST:检测的轮廓不建立等级关系,检索所有的轮廓,并将其保存到一条链表当中;
    CV_RETR_CCOMP:建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
    CV_RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次,可以参见下图。
    加滚动条确定阈值化的合适阈值!:http://blog.csdn.net/augusdi/article/details/9021467
    ****************************************************************************************
    //做一下膨胀,x与y方向都做,但系数不同
                var kernal = Cv.CreateStructuringElementEx(5, 2, 1, 1, ElementShape.Rect);
                Cv.Erode(gray, gray, kernal, 2);
    
                //二值化
                Cv.Threshold(gray, gray, 0, 255, ThresholdType.BinaryInv | ThresholdType.Otsu);
    
                //检测连通域,每一个连通域以一系列的点表示,FindContours方法只能得到第一个域
                var storage = Cv.CreateMemStorage();
                CvSeq<CvPoint> contour = null;
                Cv.FindContours(gray, storage, out contour, CvContour.SizeOf, ContourRetrieval.CComp, ContourChain.ApproxSimple);
                var color = new CvScalar(0, 0, 255);
    
                //开始遍历
                while (contour != null)
                {
                    //得到这个连通区域的外接矩形
                    var rect = Cv.BoundingRect(contour);
    
                    //如果高度不足,或者长宽比太小,认为是无效数据,否则把矩形画到原图上
                    if(rect.Height > 10 && (rect.Width * 1.0 / rect.Height) > 0.2)
                        Cv.DrawRect(src, rect, color);
    
                    //取下一个连通域
                    contour = contour.HNext;
                }
    
    ***************************************************************
    
    
    
    
    
    
    ***********************************************************************************************************
    // 移除过小或过大的轮廓  
    void getSizeContours(vector<vector<Point>> &contours)  
    {  
        int cmin = 100;   // 最小轮廓长度  
        int cmax = 1000;   // 最大轮廓长度  
        vector<vector<Point>>::const_iterator itc = contours.begin();  
        while(itc != contours.end())  
        {  
            if((itc->size()) < cmin || (itc->size()) > cmax)  
            {  
                itc = contours.erase(itc);  
            }  
            else ++ itc;  
        }  
    }  
    ****************************************************************************
    while(contour) {
      /*area = cvContourArea(contour, CV_WHOLE_SEQ);*/
      area = fabs(cvContourArea( contour, CV_WHOLE_SEQ )); //获取当前轮廓面积
      printf("area == %lf
    ", area);
      //画轮廓
      //画外接矩形
      CvRect r = ((CvContour*)contour)->rect;
      if (r.height * r.width > size)
      {
       cvRectangle(pimg, cvPoint(r.x, r.y), cvPoint(r.x + r.width, r.y + r.height),CV_RGB(255, 0, 0), 1, CV_AA, 0);
    
    
      }
      contour = contour->h_next;
    
     }
    
    *********************************************************************************************************
    // Get the contours of the connected components  
        std::vector<std::vector<cv::Point>> contours;  
    
        cv::findContours(gray,   
            contours, // a vector of contours   
            CV_RETR_EXTERNAL , // retrieve the external contours  
            CV_CHAIN_APPROX_NONE); // retrieve all pixels of each contours  
    
        // Print contours' length  
        std::cout << "Contours: " << contours.size() << std::endl;  
        std::vector<std::vector<cv::Point>>::const_iterator itContours= contours.begin();  
        for ( ; itContours!=contours.end(); ++itContours)   
        {  
    
            std::cout << "Size: " << itContours->size() << std::endl;  
        }  
    
        // draw black contours on white image  
        cv::Mat result(image.size(),CV_8U,cv::Scalar(255));  
        cv::drawContours(result,contours,  
            -1, // draw all contours  
            cv::Scalar(0), // in black  
            2); // with a thickness of 2  
    
    ************************************************************************
     double maxarea = 0;  
        double minarea = 100;  
        int m = 0;  
        for( ; contour != 0; contour = contour->h_next )    
        {    
    
            double tmparea = fabs(cvContourArea(contour));  
            if(tmparea < minarea)     
            {    
                cvSeqRemove(contour, 0); // 删除面积小于设定值的轮廓  
                continue;  
            }    
            CvRect aRect = cvBoundingRect( contour, 0 );   
            if ((aRect.width/aRect.height)<1)    
            {    
                cvSeqRemove(contour, 0); //删除宽高比例小于设定值的轮廓  
                continue;  
            }    
            if(tmparea > maxarea)    
            {    
                maxarea = tmparea;  
            }    
            m++;  
            // 创建一个色彩值  
            CvScalar color = CV_RGB( 0, 255, 255 );  
    
            //max_level 绘制轮廓的最大等级。如果等级为0,绘制单独的轮廓。如果为1,绘制轮廓及在其后的相同的级别下轮廓  
            //如果值为2,所有的轮廓。如果等级为2,绘制所有同级轮廓及所有低一级轮廓,诸此种种  
            //如果值为负数,函数不绘制同级轮廓,但会升序绘制直到级别为abs(max_level)-1的子轮廓  
            cvDrawContours(dst, contour, color, color, -1, 1, 8);   //绘制外部和内部的轮廓  
        }    
        contour = _contour;  
        int count = 0;  
        for(; contour != 0; contour = contour->h_next)  
        {    
            count++;  
            double tmparea = fabs(cvContourArea(contour));  
            if (tmparea == maxarea)    
            {    
                CvScalar color = CV_RGB( 255, 0, 0);  
                cvDrawContours(dst, contour, color, color, -1, 1, 8);  
            }    
        }    
    *************************************************************************************
    在提取之前还可以调用一个函数:   
             contour = cvApproxPoly( contour, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 3, 1 );   
             可能是拟合,有这一句找出的轮廓线更直。   contour里面包含了很多个轮廓,每个轮廓是单独存放的.  
    
    输出轮廓位置!
     printf(" %d elements:
    ", c->total );  
         for( int i=0; i<c->total; ++i ) {  
         CvPoint* p = CV_GET_SEQ_ELEM( CvPoint, c, i );  
            printf("    (%d,%d)
    ", p->x, p->y );  
         }  
    输出轮廓面积!
    for( ; contour; contour = contour->h_next)  
        {  
            area = fabs(cvContourArea(contour, CV_WHOLE_SEQ)); //获取当前轮廓面积  
            printf("area == %lf
    ", area);  
            if(area > maxArea)  
            {  
                contmax = contour;  
                maxArea = area;  
            }  
        }  
    ***********************************************************************************************
    内轮廓填充   
    // 参数:   
    // 1. pBinary: 输入二值图像,单通道,位深IPL_DEPTH_8U。  
    // 2. dAreaThre: 面积阈值,当内轮廓面积小于等于dAreaThre时,进行填充。   
    void FillInternalContours(IplImage *pBinary, double dAreaThre)   
    {   
        double dConArea;   
        CvSeq *pContour = NULL;   
        CvSeq *pConInner = NULL;   
        CvMemStorage *pStorage = NULL;   
        // 执行条件   
        if (pBinary)   
        {   
            // 查找所有轮廓   
            pStorage = cvCreateMemStorage(0);   
            cvFindContours(pBinary, pStorage, &pContour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);   
            // 填充所有轮廓   
            cvDrawContours(pBinary, pContour, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 2, CV_FILLED, 8, cvPoint(0, 0));  
            // 外轮廓循环   
            for (; pContour != NULL; pContour = pContour->h_next)   
            {   
                // 内轮廓循环   
                for (pConInner = pContour->v_next; pConInner != NULL; pConInner = pConInner->h_next)   
                {   
                    // 内轮廓面积   
                    dConArea = fabs(cvContourArea(pConInner, CV_WHOLE_SEQ));   
                    if (dConArea <= dAreaThre)   
                    {   
                        cvDrawContours(pBinary, pConInner, CV_RGB(255, 255, 255), CV_RGB(255, 255, 255), 0, CV_FILLED, 8, cvPoint(0, 0));  
                    }   
                }   
            }   
            cvReleaseMemStorage(&pStorage);   
            pStorage = NULL;   
        }   
    }  
    
    ******************************************************************* *********************
    // Get the contours of the connected components
        std::vector<std::vector<cv::Point>> contours;
        cv::findContours(image, 
            contours, // a vector of contours 
            CV_RETR_EXTERNAL, // retrieve the external contours
            CV_CHAIN_APPROX_NONE); // retrieve all pixels of each contours
    
        // Print contours' length
        std::cout << "Contours: " << contours.size() << std::endl;
        std::vector<std::vector<cv::Point>>::const_iterator itContours= contours.begin();
        for ( ; itContours!=contours.end(); ++itContours) 
        {
    
            std::cout << "Size: " << itContours->size() << std::endl;
        }
    
    ***************************************************************************************
    // Eliminate too short or too long contours
        int cmin= 100;  // minimum contour length
        int cmax= 1000; // maximum contour length
        std::vector<std::vector<cv::Point>>::const_iterator itc= contours.begin();
        while (itc!=contours.end()) {
    
            if (itc->size() < cmin || itc->size() > cmax)
                itc= contours.erase(itc);
            else 
                ++itc;
        }
    
    输出所有轮廓的旋转角度
    CvBox2D     End_Rage2D;
    
        CvMemStorage *storage = cvCreateMemStorage(0);  //开辟内存空间
    
    
        CvSeq*      contour = NULL;     //CvSeq类型 存放检测到的图像轮廓边缘所有的像素值,坐标值特征的结构体以链表形式
    
        cvFindContours( pSrcImage, storage, &contour, sizeof(CvContour),CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE);//这函数可选参数还有不少
     for(; contour; contour = contour->h_next)   //如果contour不为空,表示找到一个以上轮廓,这样写法只显示一个轮廓
            //如改为for(; contour; contour = contour->h_next) 就可以同时显示多个轮廓
        {  
    
            End_Rage2D = cvMinAreaRect2(contour);  
            //代入cvMinAreaRect2这个函数得到最小包围矩形  这里已得出被测物体的角度,宽度,高度,和中点坐标点存放在CvBox2D类型的结构体中,
            //主要工作基本结束。
    
        std::cout <<" angle:
    "<<(float)End_Rage2D.angle << std::endl;      //被测物体旋转角度 
    
        }
    //函数形式画轮廓
    void DrawRec(IplImage* pImgFrame,IplImage* pImgProcessed,int MaxArea)  
    {  
        //pImgFrame:初始未处理的帧,用于最后标出检测结果的输出;  
        //pImgProcessed:处理完的帧,用于找运动物体的轮廓  
    
        stor = cvCreateMemStorage(0);  //创建动态结构和序列  
        cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint) , stor);  
    
        // 找到所有轮廓  
        cvFindContours( pImgProcessed, stor, &cont, sizeof(CvContour),   
                        CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));  
    
        // 直接使用CONTOUR中的矩形来画轮廓  
        for(;cont;cont = cont->h_next)  
        {  
                  CvRect r = ((CvContour*)cont)->rect;  
                  if(r.height * r.width > MaxArea) // 面积小的方形抛弃掉  
                  {  
                      cvRectangle( pImgFrame, cvPoint(r.x,r.y),   
                              cvPoint(r.x + r.width, r.y + r.height),  
                              CV_RGB(255,0,0), 1, CV_AA,0);  
                  }  
        }  
        cvShowImage("video", pImgFrame);  
    }  
    
    ***********************************************************************************************
    
    绍opencv 的基于面积区域过滤方法,这个对图像处理时去除小区域杂点是很有帮助的。基于区域宽度,高度等其他方式的过滤也可以根据这个方法类推。
    
    # 图片中找到我们需要的目标 一般是最大连通区域
    #获取当前轮廓面积
    area = abs(cv.cvContourArea( contour ))
    # 获取最大区域矩形块
    aRect = cv.cvBoundingRect( contmax, 0 )
    #原始区域的不加边框
    #rcenter = cv.cvPoint2D32f(aRect.x + aRect.width/2.0, aRect.y + aRect.height/2.0)
    
    *****************************************************************************************
    //移除过长或过短的轮廓  
        int cmin = 100; //最小轮廓长度  
        int cmax = 1000;    //最大轮廓  
        vector<vector<Point>>::const_iterator itc = contours.begin();  
        while (itc!=contours.end())  
        {  
            if (itc->size() < cmin || itc->size() > cmax)  
                itc = contours.erase(itc);  
            else  
                ++itc;  
        }  
    
        //在白色图像上绘制黑色轮廓  
        Mat result_erase(binaryImage.size(), CV_8U, Scalar(255));  
        drawContours(result_erase, contours,  
            -1, //绘制所有轮廓  
            Scalar(0),  //颜色为黑色  
            2); //轮廓线的绘制宽度为2  
    
     Rect r0 = boundingRect(Mat(contours[0]));  
        rectangle(result_erase, r0, Scalar(128), 2);  
        Rect r1 = boundingRect(Mat(contours[1]));  
        rectangle(result_erase, r1, Scalar(128), 2);  
    
    *****************************************************************************************************************
     //对前景先进行中值滤波,再进行形态学膨胀操作,以去除伪目标和连接断开的小目标
     69         medianBlur(mask, mask, 5);
     70         //morphologyEx(mask, mask, MORPH_DILATE, getStructuringElement(MORPH_RECT, Size(5, 5)));
     71 
     72         //测试:先开运算再闭运算
     73         morphologyEx(mask, mask, MORPH_CLOSE, getStructuringElement(MORPH_RECT, Size(5, 5)));
     74         morphologyEx(mask, mask, MORPH_OPEN, getStructuringElement(MORPH_RECT, Size(5, 5)));
    
    
     //外接矩阵
     93         Rect rct;
     94 
     95         //对轮廓进行外接矩阵之前先对轮廓按面积降序排序,目的为了去除小目标(伪目标)
     96         sort(contours.begin(), contours.end(), descSort);
     97 
     98         for (int i = 0; i < contours.size(); i++)
     99         {
    100             //当第i个连通分量的外接矩阵面积小于最大面积的1/6,则认为是伪目标
    101             if (contourArea(contours[i]) < contourArea(contours[0]) / 5)
    102                 break;
    103             //包含轮廓的最小矩阵
    104             rct = boundingRect(contours[i]);
    105             rectangle(result, rct, Scalar(0, 255, 0), 2);
    106 
    107         }
    
    **************************************************************************************************************
     Mat element(5,5,CV_8U,Scalar(1));  
     cvMorphologyEx(green, green, NULL, element, CV_MOP_OPEN);       // 开运算,去除比结构元素小的亮点  
    
    cvThreshold(green, green, 0.0, 255.0, CV_THRESH_BINARY | CV_THRESH_OTSU);   // OTSU法二值化  
    
    一般用:findContours(image,contours,CV_RETR_EXTERNAL,CV_CHAIN_APPROX_NONE);  
    int cmin=100;  
    
    int cmax=1000;  
    
    vector<std::vector<cv::Point> >::iterator itc = contours.begin();  
    
    while(itc!=contours.end())  
    
    {  
    
        if(itc->size()<cmin||itc->size()>cmax)  
    
            itc =contours.erase(itc);  
    
        else  
    
            itc++;  
    
    }   
    Mat image2=imread("E:\group.jpg");   
    drawContours(image2,contours,-1,Scalar(255,255,255),2);  
    imshow("image",image2);  
    

      

  • 相关阅读:
    JavaScript使用技巧精萃
    小谈js事件
    更深入地了解H1N1型流感病毒
    Oracle的一些常用操作
    JS刷新页面
    asp.net Excel导入&导出(转)
    [转]我的敏捷开发实践
    汉字转全拼,简拼组件
    深度复制
    无法删除注册表健值
  • 原文地址:https://www.cnblogs.com/qing123/p/9600688.html
Copyright © 2020-2023  润新知