文档章节

图像处理--自适应阈值代码分析

乱世中的单纯
 乱世中的单纯
发布于 2014/10/29 14:53
字数 1527
阅读 65
收藏 1

#include<opencv2/opencv.hpp>

#include<math.h>

using namespace cv;

using namespace std;

 

int rows,cols;

void domain(Mat img1) ;

void round(int xstart ,int ystart,int * num,bool * flag) ;

void first(int * num,bool * flag,Mat img2) ;

int number;

int  a(int T);

int get_value(uchar* ptr,int rows,int cols);

 

int main()

{

 

 int T;//阈值

 

    Mat img= imread("1.jpg",CV_LOAD_IMAGE_GRAYSCALE );

    rows=img.rows;

    cols=img.cols;

 

    uchar *result;               //数组和地址的关系

    result=new uchar[rows*cols];

    uchar *result1;//动态分配一个数组result,存每个点的强度值,new分配的数组最后要用delete释放空间

 

    int b;

    for(int j=0;j<(rows-1);j++)

    {

        for(int i=0;i<(cols-1);i++)

        {

        int x=img.data[j*cols+i]-img.data[(j+1)*cols+i+1];

        int y=img.data[(j+1)*cols+i]-img.data[j*cols+i+1];

        result[j*cols+i]=(uchar)sqrt(x*x+y*y);

   

        }

    }

    T=get_value(result,rows,cols);

    printf("%d ",T);

    for(int j=0;j<(rows-1);j++)

    {

        for(int i=0;i<(cols-1);i++)

        {

           

            if(result[j*cols+i]<T)

            {

                img.data[j*cols+i] =0;

            }

            else

            {

                img.data[j*cols+i]=255;

            }

 

        }

        }

    delete [] result ;

   

   

    domain (img );

    namedWindow("image0", CV_WINDOW_AUTOSIZE);

    imshow("image0",img);

   

    waitKey();

    return 0;

}

 //自适应阈值

int get_value(uchar* ptr,int rows,int cols)

{

   int T;//阈值

   double max_variance=0.0 ;//大的方差

   int max_T=0;//大的方差对应的阈值

  

   for(int m=0;m<=255;m++)

   {

     T=m;

     int foreground_gray=0;//前景总灰度值

     int background_gray=0;//背景总灰度值

     int fore_num=0,back_num=0;//计算个数

     double fore_aver=0;

     double back_aver=0;

 

     for(int j=1;j<rows-1;j++)

     {

        for(int i=1;i<cols-1;i++)

        {

          if(ptr[j*cols+i]>T)

          {

                   foreground_gray=ptr[j*cols+i]+foreground_gray;

             fore_num++;

          }      

          else

          {

             background_gray+=ptr[j*cols+i];

             back_num++;

          }

        }

     }

     if(fore_num!=0)

     {

         fore_aver=((double)foreground_gray)/((double)fore_num);

       

     }

     if(back_num!=0)

     {

         back_aver=(double)background_gray/(double)back_num;

     }

     double fore_proportion=(double)fore_num/(double)(rows*cols);

     double back_proportion=(double)back_num/(double)(rows*cols);

     double total_aver=fore_proportion*fore_aver+back_proportion*back_aver;

     double variance=(fore_aver-total_aver)*(fore_aver-total_aver)*fore_proportion+(back_aver-total_aver)*(back_aver-total_aver)*back_proportion;

     if(variance>max_variance)

     {

        max_variance=variance;

        max_T=T;

     }

   }

   return max_T;

}

 

总结:ostu算法就是计算方差D=(u1-u0)2*p1+(u2-u0)2*p2,u1代表前景图像的平均灰度值,u2代表背景图像的平均灰度值,u0代表总的平均灰度值,p1代表前景像素点占的比例,p2代表背景像素点占的比例。算出的方差越大,代表图像的灰度值离平均灰度值的波动越大。

注意:1)在计算总的灰度值时,一定要考虑边界问题,不要把边界灰度值加入总的灰度值里面,因为之前计算梯度值时,边界就没有参与,而且边界都是255的灰度值,所以加到一块,会将总体灰度值升高。2)当方差最大时,是最佳的阈值。因为方差描述稳定性,当方差最大,也就是前景的灰度值和背景的灰度值相差最大的时候,即前景和背景分的最清的时候,也就是阈值最佳的时候。

void domain(Mat img1)   //找出一片区域的白点个数

{

    //int n;   //记录连通域白点个数

    Mat img2=img1.clone();

//  img2.data[j*cols+i]=img1.data[j*cols+i];

      int * num;  

    num=new int[rows*cols];

    bool * flag;

    flag=new bool[rows*cols];

 

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

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

            if(img2.data[j*cols+i]==255)

            {

                num[j*cols+i]=1;

                flag[j*cols+i]=false;

            }

            else

            {

                num[j*cols+i]=0;

                flag[j*cols+i]=false;

            }

        }

    }

    for(int i=0;i<cols;i++)       //四个边,第一行

        {

            flag[i]=true;

    }

    for(int i=0,j=rows-1;i<cols;i++)       //四个边,最后一行

        {

            flag[j*cols+i]=true;

    }

    for(int j=0;j<rows;j++)       //四个边,左边一列

        {

            flag[j]=true;

    }

    for(int i=cols-1,j=0;j<rows;j++)       //四个边,右边一列

        {

            flag[j*cols+i]=true;

    }

 

    first(num,flag,img2);

    namedWindow("image1", CV_WINDOW_AUTOSIZE);

    imshow("image1",img2);

    delete [] num ;

    delete [] flag ;

 

}

void first(int * num,bool * flag,Mat img2)   //寻找连通域的第一个白点

{

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

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

            if(num[j*cols+i]==1&&!flag[j*cols+i])

            {

                //round(i,j,num,flag);

                num[j*cols+i]=2;

                number=0;

                flag[j*cols+i]=true;

                round(i,j,num,flag);

                if(number<80)

                {

                  for(int a=0;a<rows;a++){

                  for(int b=0;b<cols;b++){

                  if(num[a*cols+b]==2)

                  {

                      img2.data[a*cols+b]=0;

                  }

                 

                  }

                  }

                }

                 else

                {

                    for(int a=0;a<rows;a++){

                  for(int b=0;b<cols;b++){

                  if(num[a*cols+b]==2)

                  {

                      num[a*cols+b]=3;

                  }

                 

                  }

                  }

                   

                }

            }

        }

    }

 

}

 

 

 

void round(int xstart ,int ystart,int * num,bool * flag)    //寻找连通域的白点数

{

   

    if(num[(ystart-1)*cols+xstart-1]==1&&!flag[(ystart-1)*cols+xstart-1])  //左上

    {

        number++;

        flag[(ystart-1)*cols+xstart-1]=true;

        num[(ystart-1)*cols+xstart-1]=2;

        round(xstart-1,ystart-1,num,flag);

    }

    if(num[(ystart-1)*cols+xstart]==1&&!flag[(ystart-1)*cols+xstart])  //

    {

        number++;

        flag[(ystart-1)*cols+xstart]=true;

        num[(ystart-1)*cols+xstart]=2;

        round(xstart,ystart-1,num,flag);

    }

    if(num[(ystart-1)*cols+xstart+1]==1&&!flag[(ystart-1)*cols+xstart+1])  //右上

    {

        number++;

        flag[(ystart-1)*cols+xstart+1]=true;

        num[(ystart-1)*cols+xstart+1]=2;

        round(xstart+1,ystart-1,num,flag);

    }

    if(num[ystart*cols+xstart-1]==1&&!flag[ystart*cols+xstart-1])  //

    {

        number++;

        flag[ystart*cols+xstart-1]=true;

        num[ystart*cols+xstart-1]=2;

        round(xstart-1,ystart,num,flag);

    }

    if(num[ystart*cols+xstart+1]==1&&!flag[ystart*cols+xstart+1])  //

    {

        number++;

        flag[ystart*cols+xstart+1]=true;

        num[ystart*cols+xstart+1]=2;

        round(xstart+1,ystart,num,flag);

    }

    if(num[(ystart+1)*cols+xstart-1]==1&&!flag[(ystart+1)*cols+xstart-1])  //左下

    {

        number++;

        flag[(ystart+1)*cols+xstart-1]=true;

        num[(ystart+1)*cols+xstart-1]=2;

        round(xstart-1,ystart+1,num,flag);

    }

    if(num[(ystart+1)*cols+xstart]==1&&!flag[(ystart+1)*cols+xstart])  //

    {

        number++;

        flag[(ystart+1)*cols+xstart]=true;

        num[(ystart+1)*cols+xstart]=2;

        round(xstart,ystart+1,num,flag);

    }

    if(num[(ystart+1)*cols+xstart+1]==1&&!flag[(ystart+1)*cols+xstart+1])  //右下

    {

        number++;

        flag[(ystart+1)*cols+xstart+1]=true;

        num[(ystart+1)*cols+xstart+1]=2;

        round(xstart+1,ystart+1,num,flag);

    }

   

}

© 著作权归作者所有

乱世中的单纯
粉丝 12
博文 65
码字总数 36866
作品 0
广州
程序员
私信 提问
使用Numpy和Opencv完成图像的基本数据分析(Part IV)

图像 本文是使用python进行图像基本处理系列的第四部分,在本人之前的文章里介绍了一些非常基本的图像分析操作,见文章《使用Numpy和Opencv完成图像的基本数据分析Part I》、《使用Numpy和O...

【方向】
2018/10/10
0
0
我为什么要写《OpenCV Android 开发实战》这本书

我为什么要写《OpenCV Android 开发实战》这本书 2015年我出版了个人第一本关于图像处理方面的书籍《Java图像处理-编程技巧与应用实践》,这本书主要是从理论与编码上面详细阐述了图像处理基...

gloomyfish
2018/07/06
0
0
[Python图像处理] 七.图像阈值化处理及算法对比

版权声明:本文为博主原创文章,转载请注明CSDN博客源地址!共同学习,一起进步~ https://blog.csdn.net/Eastmount/article/details/83548652 该系列文章是讲解Python OpenCV图像处理知识,前...

Eastmount
2018/10/30
0
0
[Python图像处理] 十九.图像分割之基于K-Means聚类的区域分割

版权声明:本文为博主原创文章,转载请注明CSDN博客源地址!共同学习,一起进步~ https://blog.csdn.net/Eastmount/article/details/89218513 该系列文章是讲解Python OpenCV图像处理知识,前...

Eastmount
04/11
0
0
[Python图像处理] 十八.图像锐化与边缘检测之Scharr算子、Canny算子和LOG算子

版权声明:本文为博主原创文章,转载请注明CSDN博客源地址!共同学习,一起进步~ https://blog.csdn.net/Eastmount/article/details/89056240 该系列文章是讲解Python OpenCV图像处理知识,前...

Eastmount
04/06
0
0

没有更多内容

加载失败,请刷新页面

加载更多

springboot 整合redis

springboot整合redis官方是有文档的: 英文看不懂可以翻译,代码应该看得懂, 这个是自动注入的。当然也可以xml注入,手动配置。 整合步骤: pom文件: <!-- spring boot web --> ...

jason_kiss
4分钟前
0
0
手机耗电问题,大部分是没有正确使用这个“锁”

当安卓设备闲置时,设备很快会进入休眠状态,以达到省电和减少CPU占用的目的。但有些应用在手机灭屏甚至系统休眠时,依然频繁占用CPU处理事件或唤醒屏幕提示用户消息,这类行为会导致手机耗电...

安卓绿色联盟
6分钟前
0
0
UI 设计中的渐变

>**简评:**渐变是通过两种或多种不同的色彩来绘制一个元素,同时在颜色的交界处进行衰减变化的一种设计。从拟物到扁平再到渐变,人们慢慢发现它能创造出从未有过的一种色彩感觉 —— 独特、...

极光推送
11分钟前
0
0
powerdesigner name 转注释vb脚本

Option Explicit ValidationMode = True InteractiveMode = im_BatchDim mdl ' the current model' get the current active model Set mdl = ......

zhu97
16分钟前
0
0
V2Ray的安装与使用

1 1. bash <(curl -s -L https://git.io/v2ray.sh)yum update -y && yum install curl -y安装好 curl 之后就能安装脚本了输入快捷管理命令v2ray后,开始进行v2ray服务端配置...

吕湘颖
18分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部