• 数米粒--函数调用


    1.函数了解-->

    读取图片:IplImage* cvLoadImage( const char* filename, int flags=CV_LOAD_IMAGE_COLOR );

    创建结构元:IplConvKernel* cvCreateStructuringElementEx( int cols, int rows, int anchor_x, int anchor_y,int shape, int* values=NULL );

      shape是自定义核的形状,具体为

      1.CV_SHAPE_RECT  核是矩形

      2.CV_SHAPE_CROSS 核是勺子交叉形

      3.CV_SHAPE_ELLIPSE 核是椭圆形

      4.CV_SHAPE_CUSTOM 核是用户自定义类型

    二值化(相当于阈值处理):void cvThreshold( const CvArr* src, CvArr* dst, double threshold, double max_value, int threshold_type );

    腐蚀void cvErode( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );

    膨胀:void cvDilate( const CvArr* src, CvArr* dst, IplConvKernel* element=NULL, int iterations=1 );   (最后一个参数表示腐蚀/膨胀的次数)

    顶帽变换:原始图像减去其开运算的图像 而开运算可用于补偿不均匀的背景亮度,所以用一个大的结构元素做开运算后 然后用原图像减去这个开运算,就得到了背景均衡的图像。

    开操作:先腐蚀,后膨胀。

    二值图像中检索轮廓,并返回检测到的轮廓的个数(百度):int cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,int header_size=sizeof(CvContour),int mode=CV_RETR_LIST,int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );

    轮廓绘制:void cvDrawContours( CvArr *img, CvSeq* contour,CvScalar external_color, CvScalar hole_color,int max_level, int thickness=1,int line_type=8, CvPoint offset=cvPoint(0,0) );

    轮廓面积计算:double cvContourArea( const CvArr* contour, CvSliceslice=CV_WHOLE_SEQ );

    轮廓周长计算:double cvArcLength( const void* curve, CvSlice slice=CV_WHOLE_SEQ, int is_closed=-1 );

    2.实验步骤:

      1.得到原始图片;

      2.去除背景干扰(顶帽变换);

      3.二值化(阈值处理);

      4.开操作(去除噪声,删除较小的噪声点);

      5.寻找连通域,计算米粒个数(可以认为合适的处理之后,一个连通域就代表着一个米粒);

      6.查找最大面积的米粒(认为是最大的米粒),对所有轮廓进行标记,对最大轮廓描红标记;

      7.输出米粒个数、最大米粒面积和周长。

    3.结果:

            原图                背景图            去背景图

                      
          二值化后图            开操作处理后              轮廓图

        结果图

    4.代码(VC6.0,OpenCV):

     1 #include "stdio.h"
     2 #include "cv.h"
     3 #include "highgui.h"
     4 
     5 
     6 int main(int arge,char * argv[])
     7 {
     8     char root_path[150];    // 米粒图片路径
     9     IplImage *src, *backImg, *backRImg, *cutImg, *finallyImg, *dst_contours;
    10     // 获取原图像
    11     sprintf(root_path, "E:\4_大三下\机器视觉\实验图片\rice.jpg");
    12     src = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE);            // 原始图片--灰度方式读取
    13     backImg = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE);        // 背景图片
    14     backRImg = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE);        // 存放去背景图片
    15     cutImg = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE);
    16     finallyImg = cvLoadImage(root_path,CV_LOAD_IMAGE_GRAYSCALE);
    17     dst_contours = cvLoadImage(root_path);
    18 
    19 
    20     // 图像处理
    21     IplConvKernel * element = cvCreateStructuringElementEx(4,4,1,1,CV_SHAPE_ELLIPSE,0);        // 形态学构建指针[创建结构元素,4*4,椭圆形]
    22     cvErode(src,backImg,element,5);                // 腐蚀
    23     cvDilate(backImg,backImg,element,5);        // 膨胀
    24     cvSub(src,backImg,backRImg,0);                // 去背景--综合为顶帽变换
    25     cvThreshold(backRImg,cutImg,50,255,CV_THRESH_BINARY);        // 二值化函数
    26     cvErode(cutImg,finallyImg,element,1);            // 腐蚀
    27     cvDilate(finallyImg,finallyImg,element,1);        // 膨胀--综合为一次开操作,去除噪声(较小突出部分)
    28     // 寻找连通域,计算米粒个数
    29     CvMemStorage * stor = cvCreateMemStorage(0);        // 容器
    30     CvSeq * cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor);
    31     CvSeq * cont1 = cvCreateSeq(CV_SEQ_ELTYPE_POINT,sizeof(CvSeq),sizeof(CvPoint),stor);
    32     // 二值图像中提取轮廓,返回值为轮廓的数目
    33     int numberOfObject = cvFindContours(finallyImg,stor,&cont,sizeof(CvContour),CV_RETR_TREE);
    34     printf("米粒数目为 :%d 
    ",numberOfObject);
    35     // 遍历轮廓,并画出外轮廓
    36     int max_area = 0;
    37     int max_length = 0;
    38     for(;cont != NULL;cont = cont->h_next) {
    39         CvRect rect = cvBoundingRect(cont,0);
    40         double tmpArea = fabs(cvContourArea(cont,CV_WHOLE_SEQ));
    41         double tmpLength = cvArcLength(cont);
    42         if(max_area < tmpArea) {
    43             max_area = tmpArea;
    44             max_length = tmpLength;
    45             cont1 = cont;
    46         }
    47 //        if(tmpArea > 0) {
    48             cvDrawContours(dst_contours,cont,CV_RGB(0,255,0),CV_RGB(255,0,0),0,1,8,cvPoint(0,0));
    49 //        }
    50     }
    51     cvDrawContours(dst_contours,cont1,CV_RGB(255,0,0),CV_RGB(255,0,0),0,1,8,cvPoint(0,0));
    52     printf("最大米粒的面积 area = %d , 周长 perimeter = %d 
    ",max_area,max_length);
    53 
    54 
    55     // 图像显示
    56     cvNamedWindow("src");
    57     cvShowImage("src",src);
    58 //    cvNamedWindow("back");
    59 //    cvShowImage("back",backImg);
    60 //    cvNamedWindow("backR");
    61 //    cvShowImage("backR",backRImg);
    62     cvNamedWindow("cut");
    63     cvShowImage("cut",cutImg);
    64 //    cvNamedWindow("finallyImg");
    65 //    cvShowImage("finallyImg",finallyImg);
    66     cvNamedWindow("dst_contours");
    67     cvShowImage("dst_contours",dst_contours);
    68 
    69     cvWaitKey(0);
    70     return 0;
    71 }
    View Code

    2021-05-01

  • 相关阅读:
    [微软官方]SQLSERVER的兼容级别
    使用 OPENJSON 分析和转换 JSON 数据 (SQL Server)
    WPF 解决TreeViewItem上为IsMouseOver 时 父级Item也会 受影响
    依赖注入
    关于编译告警 C4819 的完整解决方案
    你想知道的 std::vector::push_back 和 std::vector::emplace_back
    如何使用 Dump 文件?
    关于 PDB 文件你需要知道什么?
    图解哈希表及其原理
    C++ 中的虚函数表及虚函数执行原理
  • 原文地址:https://www.cnblogs.com/2015-16/p/14724252.html
Copyright © 2020-2023  润新知