• Zedboard甲诊opencv图像处理(一)


    首先基于前面的工作,通过调整已经很好的把指甲边缘显示出来了,不曾想我却从那时开始走上了弯路,使用matlab去处理静态图片,以获得更好的指甲和特征提取效果,结果就是,效果不理想(光照影响)并且用到摄像头上来一点都不实用。辛辛苦苦的研究了n多的图像处理算法,几乎把边缘提取的算法全部过了一遍,阅读了不下100篇论文,还折腾出B样条曲线拟合进行边缘连接,现在想想太可笑了,其实OpenCV现有的图像处理方法已经可以满足我提取指甲的要求了,只不过我需要进行合理的组合搭配,从而实现我想要的效果。

    总有那么一句话叫:摸着石头过河。我今天算是体会到了,不过中间老板还让写创业计划,总之,该回归正道了!

    接着之前的canny提取的边缘,我想进一步提取出指甲,把其他背景都省略,这样就只留下指甲了,从而进一步提取特征。首先我想到的是findContours函数及其轮廓操作

    //! retrieves contours and the hierarchical information from black-n-white image.
    CV_EXPORTS_W void findContours( InputOutputArray image, OutputArrayOfArrays contours,
                                  OutputArray hierarchy, int mode,
                                  int method, Point offset=Point());

    //! retrieves contours from black-n-white image.
    CV_EXPORTS void findContours( InputOutputArray image, OutputArrayOfArrays contours,
                                  int mode, int method, Point offset=Point());

    其中image为输入的 binary image,输出是一个向量数组,每个向量是Points类型的指针向量数组。这个数组会用做后面的轮廓处理。

    mode代表提取轮廓的类型, 可以是以下几种类型 //CV_RETR_LIST, //  retrieve all contours
        //CV_RETR_EXTERNAL, // retrieve the external contours
        //CV_RETR_TREE, // retrieve all contours in tree format
        //CV_RETR_CCOMP is similar but limits the hierarchy at two levels.建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。

    method代表轮廓点的类型,可以有   //CV_CHAIN_APPROX_NONE // all pixels of each contours存储所有的轮廓点,相邻的两个点的像素位置差不超过1,即max(abs(x1-x2),abs(y2-y1))==1
        //CV_CHAIN_APPROX_SIMPLE //only the end points would be included for horizontal,vertical, or diagonal contours. 压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息

    最后一个不用管先,然后就是一个OutputArray hierarchy代表分层结构,hierarchy, // hierarchical representation

    接下来用    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

    出来的效果还不错,利用黑背景,能将指甲分离出来,但是接下来的分离过程除了错误。就是在我将多余的或者不符合要求的轮廓去除过程中报错了

        // 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;
        }

    错误如下:错误:no matching function for call to 'std::vector<std::vector<cv::Point_<int> > >::erase(std::vector<std::vector<cv::Point_<int> > >::const_iterator&)',我理解的意思是这里erase函数用的不对,但是我是照着OpenCVcookbook做的,网上也搜了很多,都是这样写的,感觉不同于他们的是我的实在QT中编写,用OpenCV2.3.1,不知到为什么会报错,

    然后就找他的定义,感觉用得也没错:

        iterator
        erase(iterator __position)
        {
          if (__position + 1 != end())
            std::copy(__position + 1, end(), __position);
          --this->_M_impl._M_finish;
          return __position;
        }

        iterator
        erase(iterator __first, iterator __last)
        {
          _M_erase_at_end(std::copy(__last, end(), __first));
          return __first;
        }

    后来仔细看了,iterator和const_iterator不一样,      typedef __gnu_cxx::__normal_iterator<pointer, vector> iterator;       typedef __gnu_cxx::__normal_iterator<const_pointer, vector> const_iterator;

    而我抄袭的程序里面都是const_iterator,该过来之后就可以了。

    现在的问题是,我该怎么取适当的值,使得只有指甲的轮廓保留下来,其余的省去。还是一步一步来吧,先把轮廓查找的过程搞清楚。

    findContours经常与drawContours配合使用,用来将轮廓绘制出来。其中第一个参数image表示目标图像,第二个参数contours表示输入的轮廓组,每一组轮廓由点vector构成,第三个参数contourIdx指明画第几个轮廓,如果该参数为负值,则画全部轮廓,第四个参数color为轮廓的颜色,第五个参数thickness为轮廓的线宽,如果为负值或CV_FILLED表示填充轮廓内部,第六个参数lineType为线型,第七个参数为轮廓结构信息,第八个参数为maxLevel。

    但是用在视频处理中,还是不行,所以我改为拍照处理,拍5张照片后重合为一张,效果如下:

    虽然还不是很好,但我也只能勉强的继续往下走着先。这过程中涉及到一些Mat图像基本容器的处理,因为我是存储了5张图片,所以不能直接赋值,需要用cvcopyto函数。

        capture.read(frame);
        ++flag;
        switch (flag)
        {
        case 1:
            frame.copyTo(image1);
            break;
        case 2:
            frame.copyTo(image2);
            break;
        case 3:
            frame.copyTo(image3);
            break;
        case 4:
            frame.copyTo(image4);
            break;
        default:
            flag=0;
            break;
        }
    

    后然处理重合吧:

        Mat edge1=edged(image1);
        Mat edge2=edged(image2);
        Mat edge3=edged(image3);
        Mat edge4=edged(image4);
        Mat edge;
        Mat result;
        cv::addWeighted(edge1,1,edge2,1,0.,edge);
        cv::addWeighted(edge,1,edge3,1,0.,edge);
        cv::addWeighted(edge,1,edge4,1,0.,edge);
    

    接下来我准备进行多边形逼近或者其他手段把,把背景去除,然后特征提取。比较慢哈,不过最近听说一位美国留学的博士师兄在做视网膜诊病,和我这个甲诊有点类似之处哈,好歹给了我一点鼓励吧。


     

  • 相关阅读:
    BZOJ 2006: [NOI2010]超级钢琴 [ST表+堆 | 主席树]
    CF 741D. Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths [dsu on tree 类似点分治]
    CF 716E. Digit Tree [点分治]
    CF 291E. Tree-String Problem [dfs kmp trie图优化]
    CF 208E. Blood Cousins [dsu on tree 倍增]
    CF 246E. Blood Cousins Return [dsu on tree STL]
    CF 570D. Tree Requests [dsu on tree]
    [dsu on tree]【学习笔记】
    测试markdown
    BZOJ 1969: [Ahoi2005]LANE 航线规划 [树链剖分 时间倒流]
  • 原文地址:https://www.cnblogs.com/preorder69/p/3113158.html
Copyright © 2020-2023  润新知