OpenCV提取轮廓 去掉面积小的轮廓

转自:http://www.kaixuela.net/?p=23

 

#include <stdio.h>

#include "cv.h"

#include "cxcore.h"

#include "highgui.h"

#include <iostream>

using namespace std;

#pragma comment(lib,"cv.lib")

#pragma comment(lib,"cxcore.lib")

#pragma comment(lib,"highgui.lib")

 

struct Position

{

    int x,y;

};

 

double per[256];// 保存灰度概率

IplImage *FindCountours(IplImage* src,IplImage *pContourImg);

int ImageStretchByHistogram(IplImage *src,IplImage *dst);

IplImage* Hist_Equalization(IplImage *srcimg);

void proBorder(IplImage *src); // 边界的处理

void GetBackImage(IplImage* src,IplImage* src_back);

void Threshold(IplImage *src);

int GetThreshold(double *const prob);

void Getprobability(IplImage *src);

double Eccentricity(IplImage *src);

 

void main()

{

    //IplImage * src = cvLoadImage("C:\\image19\\A634.jpg",-1);//灰度图的方式载入

    IplImage * src = cvLoadImage("C:\\image19\\A857.jpg",-1);

    IplImage * dst = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,3);

    IplImage *src_back = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,src->nChannels);

    GetBackImage(src,src_back);

    dst = FindCountours(src_back,dst);

 

    cvNamedWindow("test",CV_WINDOW_AUTOSIZE);

    cvShowImage("test",dst);

    cvWaitKey(0);

    cvReleaseImage(&src);

    cvReleaseImage(&dst);

}

 

void GetBackImage(IplImage* src,IplImage* src_back)

{

    //cvCvtColor(src,src,CV_RGB2GRAY);//灰度化

    IplImage *tmp = cvCreateImage(cvGetSize(src),IPL_DEPTH_8U,3);

    // 创建结构元素

    IplConvKernel  *element = cvCreateStructuringElementEx( 2, 2, 0, 0, CV_SHAPE_ELLIPSE,0);

    //用该结构对源图象进行数学形态学的开操作后,估计背景亮度

    cvErode(src,tmp,element,9);

    //使用任意结构元素腐蚀图像

    cvDilate(tmp,src_back, element,9);

    //使用任意结构元素膨胀图像

}

 

 

IplImage *FindCountours(IplImage* src,IplImage *pContourImg)

{

    CvMemStorage *storage = cvCreateMemStorage(0); //提取轮廓需要的储存容量为默认KB

    CvSeq * pcontour = 0;  //提取轮廓的序列指针

    IplImage *temp = cvCreateImage(cvGetSize(src),src->depth,1);

 

    //cvSmooth(src,temp,CV_GAUSSIAN,3,1,0);

 

    cvSmooth(src,src,CV_GAUSSIAN,3,1,0);//平滑处理

    cvCvtColor(src,temp,CV_RGB2GRAY);//灰度化

 

    Getprobability(temp);

 

    printf("最好的阈值:%d\n",GetThreshold(per));

 

    //Threshold(temp);

 

    proBorder(temp);

    cvThreshold(temp,temp,GetThreshold(per),255,CV_THRESH_BINARY_INV);

 

    int contoursNum = 0; // 轮廓数量

    //int mode = CV_RETR_LIST;

    int mode = CV_RETR_EXTERNAL;// 提取最外层轮廓

    contoursNum = cvFindContours(temp,storage,&pcontour,sizeof(CvContour),mode,CV_CHAIN_APPROX_NONE);

    // contoursNum = cvFindContours(temp,storage,&pcontour,sizeof(CvContour),CV_RETR_LIST,CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0));

    //二值图, 得到轮廓存储,轮廓指针序列,header_size,提取模式,逼近方法

 

    CvScalar externalColor;// 保存颜色值

    CvScalar holeColor;

    //————–画轮廓—————-//

    for (; pcontour != 0; pcontour=pcontour -> h_next)

    {

        //holeColor=CV_RGB(rand()&255,rand()&255,rand()&255);

        //externalColor=CV_RGB(rand()&255,rand()&255,rand()&255);

        CvRect r = ((CvContour *)pcontour)->rect;

        if(r.height * r.width < 800)

        {

            holeColor=CV_RGB(0,0,0);

            externalColor=CV_RGB(0,0,0);

            cvDrawContours(pContourImg,pcontour,externalColor,holeColor,1,1,8);

        }

        else

        {

            //取得轮廓面积

            double contArea = fabs(cvContourArea(pcontour,CV_WHOLE_SEQ));

            //取得轮廓长度

            double contLenth = cvArcLength(pcontour,CV_WHOLE_SEQ,-1);

            // 圆形度

            double contcircularity = contLenth * contLenth / contArea

            double pxl =Eccentricity(temp);

            cout<<"面积为:"<<contArea<<endl;

            cout<<"周长为:"<<contLenth<<endl;

            cout<<"圆形度为:"<<contcircularity<<endl;

 

            holeColor=CV_RGB(255,255,255);

            externalColor=CV_RGB(255,255,255);

 

            cvDrawContours(pContourImg,pcontour,externalColor,holeColor,1,1,8);

        }

    }

    //IplConvKernel  *element = cvCreateStructuringElementEx( 2, 2, 0, 0, CV_SHAPE_ELLIPSE,0);

    //cvDilate(pContourImg,pContourImg, element,9);

    return pContourImg;

 

}

 

double Eccentricity(IplImage *src)//偏心率

{

    Position pos[4];

    int width = src->width;

    int height = src->height;

    int i,j;

 

    for(i = 0; i < height; i++)

    {

        for(j = 0; j < width; j++)

        {

            int pixel = (int)cvGet2D(src,i,j).val[0];

            if(pixel != 0)

            {

                pos[0].x = j;

                pos[0].y = i;//

                goto s;

            }

        }

    }

s:  

    for(i = height 1; i >= 0; i)

    {

        for(j = 0; j < width ; j++)

        {

            int pixel = (int)cvGet2D(src,i,j).val[0];

            if(pixel != 0)

            {

                pos[1].x = j;

                pos[1].y = i;//

                goto w;

            }

        }

    }

w:

    for(i = 0 ; i < width ; i++)

    {

        for(j = 0;j < height; j++)

        {

            int pixel = (int)cvGet2D(src,j,i).val[0];

            if(pixel != 0)

            {

                pos[2].x = j;//

                pos[2].y = i;

                goto e;

            }

        }

    }

e:

    for(i = width 1; i >= 0; i)

    {

        for(j = 0 ; j < height ; j++)

        {

            int pixel = (int)cvGet2D(src,j,i).val[0];

            if(pixel != 0)

            {

                pos[3].x = j;//

                pos[3].y = i;

                goto f;

            }

 

        }

    }

 

f:

    int l_dis = abs(pos[0].y pos[1].y);

    int s_dis = abs(pos[2].x pos[3].x);

    int tmp_dis;

    if(l_dis > s_dis)

    {

        printf("偏心率:%f\n",l_dis*1.0/s_dis);

    }

    else

    {

        tmp_dis = l_dis;

        l_dis = s_dis;

        s_dis = tmp_dis;

        printf("偏心率:%f\n",l_dis*1.0/s_dis);

    }

 

    return 0;

}

 

void Getprobability(IplImage *src)

{

    memset(per,0,sizeof(per));

    int width = src->width;

    int height = src->height;

    for(int i = 0; i < height; i++) {

        for(int j = 0; j < width; j++) {

            per[(int)cvGet2D(src,i,j).val[0]]++;

        }

    }

    int PixlNum = width * height;

    for(i = 0; i < 256; i++)

        per[i] = per[i] / PixlNum;

 

}

 

int GetThreshold(double *const prob)

{

    int threshold = 0;

    double maxf = 0;

    for (int crrctThrshld = 1; crrctThrshld < 256 1; ++crrctThrshld) {

        double W0 = 0, W1 = 0, U0 = 0, U1 = 0;

        int i = 0;

        for (i = 0; i <= crrctThrshld; ++i) { 

            U0 += i * prob[i];

            W0 += prob[i];

        }

        for (; i < 256; ++i) {

            U1 += i * prob[i];

            W1 += prob[i];

        }

        if (W1 == 0 || W1 == 0)

            continue;

        U0 /= W0;

        U1 /= W1;

        double D0 = 0, D1= 0;

        for (i = 0; i <= crrctThrshld; ++i

            D0 += pow((i U0) * prob[i], 2.0);

        for (; i < 256; ++i

            D1 += pow((i U1) * prob[i], 2.0);

        D0 /= W0;

        D1 /= W1;

        double Dw = pow(D0, 2.0) * W0 + pow(D1, 2.0) * W1;

        double Db = W0 * W1 * pow((U1 U0), 2.0);

        double f = Db / (Db + Dw);

        if (maxf < f) {

            maxf = f;

            threshold = crrctThrshld;

        }

    }

    return threshold;

}

 

void proBorder(IplImage *src) // 边界的处理

{

    int i,j;

    int height = src->height;

    int width = src->width;

 

    int N = 100;

 

    for(i = 0; i < N * width; i += width) // i表示向下走左上角

    {

        for(j = 0; j < N ; j++)

        {

            int index = i + j;

            src->imageData[index] = (char)255;

        }

    }

 

    int NN = 150;

    int sw = width * (height NN);// 左下角 三角形

    int  t = 1;

    for(i = sw; i < sw + NN * width; i += width,t++)

    {

        for(j = 0; j < t; j++)

        {

            int index = i + j;

            src->imageData[index] = (char)255;

        }

    }

 

    int se = (height NN 1) * width; // 右下角

    t = 0;

    for(i = se; i < width * height ; i += width,t++)

    {

        for(j = 0; j < t; j++)

        {

            int index = i + j t;

            src->imageData[index] = (char)255;

        }

    }

 

    int ne = width NN;                   // 右上角 三角形剪切

    t = 0;

    for(i = ne; i < NN * width; i +=width,t++)

    {

        for(j = 0; j < NN t; j++)

        {

            int index = i + j + t;

            src->imageData[index] = (char)255;

        }

    }

 

}

 

void Threshold(IplImage *src)

{

    int width = src->width;

    int height = src->height;

    float minpixel = cvGet2D(src,0,0).val[0];

    float maxpixel = cvGet2D(src,0,0).val[0];

    CvScalar s;

    for(int i = 0; i < height; i++){

        for(int j = 0; j < width; j++){

            s = cvGet2D(src,i,j);

            if(s.val[0] > maxpixel)

                maxpixel = s.val[0];

            if(s.val[0] < minpixel)

                minpixel = s.val[0];

        }

    }

    float firstgrey = (maxpixel + minpixel) / 2;

    printf("%f\n",firstgrey);

 

    float lastgrey;

    float sum1 = 0,sum2 = 0;

    int num1 = 0,num2 = 0;

    int result = 0;

    while(1)

    {

        result ++;

        for(i = 0; i < height; i++){

            for(int j = 0; j < width; j++){

                s = cvGet2D(src,i,j);

                if(s.val[0] < firstgrey)

                {

                    sum1 += s.val[0];

                    num1++;

                }

                if(s.val[0] < firstgrey)

                {

                    sum2 += s.val[0];

                    num2++;

                }

            }

        }

        lastgrey = (sum1/num1 + sum2/num2)/2;

 

        if((int)lastgrey == (int)firstgrey)

            break;

        else

        {

            firstgrey = lastgrey;

            sum1 = sum2 = 0;

            num1 = num2 = 0;

        }

    }

 

    lastgrey = (sum1/num1 + sum2/num2)/2;

    printf("%f %d\n",firstgrey,result);

}

再分享一下我老师大神的人工智能教程吧。零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow

猜你喜欢

转载自www.cnblogs.com/xkiwnchwhd/p/10316842.html