OTSU算法对图像二值化

来源:互联网 发布:js动态流程图 编辑:程序博客网 时间:2024/05/17 23:45


    

OTSU算法对图像二值化

  1. OTSU算法原理简介
       对于一幅图像,设当前景与背景的分割阈值为t时,前景点占图像比例为w0,均值为u0,背景点占图像比例为w1,均值为u1。则整个图像的均值为u = w0*u0+w1*u1。建立目标函数g(t)=w0*(u0-u)^2+w1*(u1-u)^2,g(t)就是当分割阈值为t时的类间方差表达式。OTSU算法使得g(t)取得全局最大值,当g(t)为最大时所对应的t称为最佳阈值。OTSU算法又称为最大类间方差法。
       2.OTSU算法例程
下面是OSTU算法的C语言代码及其测试,代码基于opencv。
#include <cv.h>
#include <highgui.h>
int otsu(IplImage *image)
{
 assert(NULL != image);
 int width = image->width;
 int height = image->height;
 int x=0,y=0;
 int pixelCount[256];
 float pixelPro[256];
 int i, j, pixelSum = width * height, threshold = 0;
 uchar* data = (uchar*)image->imageData;
 //初始化
 for(i = 0; i < 256; i++)
 {
  pixelCount[i] = 0;
  pixelPro[i] = 0;
 }
 //统计灰度级中每个像素在整幅图像中的个数
 for(i = y; i < height; i++)
 {
  for(j = x;j <width;j++)
  {
   pixelCount[data[i * image->widthStep + j]]++;
  }
 }

 //计算每个像素在整幅图像中的比例
 for(i = 0; i < 256; i++)
 {
  pixelPro[i] = (float)(pixelCount[i]) / (float)(pixelSum);
 }


 //经典ostu算法,得到前景和背景的分割
 //遍历灰度级[0,255],计算出方差最大的灰度值,为最佳阈值
 float w0, w1, u0tmp, u1tmp, u0, u1, u,deltaTmp, deltaMax = 0;
 for(i = 0; i < 256; i++)
 {
  w0 = w1 = u0tmp = u1tmp = u0 = u1 = u = deltaTmp = 0;

  for(j = 0; j < 256; j++)
  {
   if(j <= i) //背景部分
   {
    //以i为阈值分类,第一类总的概率
    w0 += pixelPro[j];  
    u0tmp += j * pixelPro[j];
   }
   else       //前景部分
   {
    //以i为阈值分类,第二类总的概率
    w1 += pixelPro[j];  
    u1tmp += j * pixelPro[j];
   }
  }

  u0 = u0tmp / w0;  //第一类的平均灰度
  u1 = u1tmp / w1;  //第二类的平均灰度
  u = u0tmp + u1tmp;  //整幅图像的平均灰度
  //计算类间方差
  deltaTmp = w0 * (u0 - u)*(u0 - u) + w1 * (u1 - u)*(u1 - u);
  //找出最大类间方差以及对应的阈值
  if(deltaTmp > deltaMax)
  { 
   deltaMax = deltaTmp;
   threshold = i;
  }
 }
 //返回最佳阈值;
 return threshold;
}

int main(int argc, char* argv[])
{
 IplImage* srcImage = cvLoadImage("D:\\technology\\CV\\Database\\image\\rice.png",0);
 assert(NULL != srcImage);

 cvNamedWindow("src");
 cvShowImage("src",srcImage);

 IplImage* biImage = cvCreateImage(cvGetSize(srcImage),8,1);

 //计算最佳阈值
 int threshold = otsu(srcImage);
 //对图像二值化
 cvThreshold(srcImage,biImage,threshold,255,CV_THRESH_BINARY);

 cvNamedWindow("binary");
 cvShowImage("binary",biImage);
 
 cvWaitKey(0);

 cvReleaseImage(&srcImage);
 cvReleaseImage(&biImage);
 cvDestroyWindow("src");
 cvDestroyWindow("binary");

 return 0;
}


使用openCV读取视频或摄像头
使用openCV读取摄像头或者视频非常方便,废话不多说,下面直接把源代码贴出来。

#include <stdio.h>
#include <highgui.h>
#include <cv.h>
int main(int argc, char * argv[])
{
 IplImage* frame = NULL;
 cvNamedWindow("vedio");
 //CvCapture* capture = cvCreateFileCapture("E:\\Videos\\shouji\\MOV0061A.avi");
 CvCapture* capture = cvCreateCameraCapture(1);
 assert(NULL!=capture);
 while(1)
 {
  frame = cvQueryFrame(capture);
  if(!frame)
  {
   break;
  }
  
  cvShowImage("vedio",frame);
  if(27==cvWaitKey(33))
  {
   break;
  }
 }
 cvReleaseCapture(&capture);
 cvDestroyWindow("vedio");
 return 0;
 
}

0 0
原创粉丝点击