数字图像处理——大津法实现图像二值化
来源:互联网 发布:2016淘宝直通车 编辑:程序博客网 时间:2024/05/17 06:46
图像二值化
二值图像,图像中只有两种颜色的信息,通常是黑色和白色,是将普通图像二值化后得到的图像 。图像二值化的作用是为了方便提取图像中的信息。二值图像在进行计算机识别时可以增加识别效率。比如 需要计算水面悬浮物的数量 就可以将一定面积的水拍成图片后二值化:黑色为水 白色为悬浮物然后通过计算机进行图像扫描 如果是黑色 0 就继续扫描如果是白色 1就改变变量 通过连续算法 得出一个悬浮物二值化就是就是将一幅图像的所有像素点按照256灰阶分类,每个像素点表示一个灰阶,然后我们将高于某一灰阶像素(阈值)全部显示成白色,低于某一灰阶(阈值)的像素点显示成黑色。这样就完成了对一幅图像二值化处理。 根据阈值选取的不同,二值化的算法分为固定阈值和自适应阈值。 比较常用的二值化方法则有:双峰法、P参数法、迭代法和OTSU法等。
OTSU法(大津法)
对于图像I(x,y),前景(即目标)和背景的分割阈值记作T,属于前景的像素点数占整幅图像的比例记为ω0,其平均灰度μ0;背景像素点数占整幅图像的比例为ω1,其平均灰度为μ1。图像的总平均灰度记为μ,类间方差记假设图像的背景较暗,并且图像的大小为M×N,图像中像素的灰度值小于阈值T的像素个数记作N0,像素灰度大于阈值T的像素个数记作N1,则有: ω0=N0/ M×N (1) ω1=N1/ M×N (2) N0+N1=M×N (3) ω0+ω1=1 (4) μ=ω0*μ0+ω1*μ1 (5) g=ω0(μ0-μ)^2+ω1(μ1-μ)^2 (6)将式(5)代入式(6),得到等价公式: g=ω0ω1(μ0-μ1)^2 (7) 这就是类间方差采用遍历的方法得到使类间方差g最大的阈值T,即为所求。(遍历灰度级(0-255),得到是的g取最大值的灰度级就是阈值T。)
大津法求阈值代码:
//大津法求阈值int otsu(const IplImage *src_image) { double sum = 0.0; double w0 = 0.0; double w1 = 0.0; double u0_temp = 0.0; double u1_temp = 0.0; double u0 = 0.0; double u1 = 0.0; double delta_temp = 0.0; double delta_max = 0.0; //src_image灰度级 int pixel_count[256] = { 0 }; float pixel_pro[256] = { 0 }; int threshold = 0; uchar* data = (uchar*)src_image->imageData;//src->imageData是指向一片数据区的地址 //统计每个灰度级中像素的个数 for (int i = 0; i < src_image->height; i++) { for (int j = 0; j < src_image->width; j++) { pixel_count[(int)data[i * src_image->width + j]]++;//每个灰度级的像素数目 sum += (int)data[i * src_image->width + j];//灰度之和 } } cout << "平均灰度:" << sum / (src_image->height * src_image->width) << endl; //计算每个灰度级的像素数目占整幅图像的比例 for (int i = 0; i < 256; i++) { pixel_pro[i] = (float)pixel_count[i] / (src_image->height * src_image->width); } //遍历灰度级[0,255],寻找合适的threshold for (int i = 0; i < 256; i++) { w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0; for (int j = 0; j < 256; j++) { if (j <= i) //背景部分 { w0 += pixel_pro[j];//背景像素比例 u0_temp += j * pixel_pro[j]; } else //前景部分 { w1 += pixel_pro[j];//前景像素比例 u1_temp += j * pixel_pro[j]; } } u0 = u0_temp / w0;//背景像素点的平均灰度 u1 = u1_temp / w1;//前景像素点的平均灰度 //http://blog.163.com/yuyang_tech/blog/static/216050083201302113341762/ delta_temp = (float)(w0 *w1* pow((u0 - u1), 2));//类间方差 g=w0*w1*(u0-u1)^2 //当类间方差delta_temp最大时,对应的i就是阈值T if (delta_temp > delta_max) { delta_max = delta_temp; threshold = i; } } return threshold;}
全部代码:
//图像的二值化 #include <opencv2/opencv.hpp> using namespace std;//大津法求阈值int otsu(const IplImage *src_image) { double sum = 0.0; double w0 = 0.0; double w1 = 0.0; double u0_temp = 0.0; double u1_temp = 0.0; double u0 = 0.0; double u1 = 0.0; double delta_temp = 0.0; double delta_max = 0.0; //src_image灰度级 int pixel_count[256] = { 0 }; float pixel_pro[256] = { 0 }; int threshold = 0; uchar* data = (uchar*)src_image->imageData;//src->imageData是指向一片数据区的地址 //统计每个灰度级中像素的个数 for (int i = 0; i < src_image->height; i++) { for (int j = 0; j < src_image->width; j++) { pixel_count[(int)data[i * src_image->width + j]]++;//每个灰度级的像素数目 sum += (int)data[i * src_image->width + j];//灰度之和 } } cout << "平均灰度:" << sum / (src_image->height * src_image->width) << endl; //计算每个灰度级的像素数目占整幅图像的比例 for (int i = 0; i < 256; i++) { pixel_pro[i] = (float)pixel_count[i] / (src_image->height * src_image->width); } //遍历灰度级[0,255],寻找合适的threshold for (int i = 0; i < 256; i++) { w0 = w1 = u0_temp = u1_temp = u0 = u1 = delta_temp = 0; for (int j = 0; j < 256; j++) { if (j <= i) //背景部分 { w0 += pixel_pro[j];//背景像素比例 u0_temp += j * pixel_pro[j]; } else //前景部分 { w1 += pixel_pro[j];//前景像素比例 u1_temp += j * pixel_pro[j]; } } u0 = u0_temp / w0;//背景像素点的平均灰度 u1 = u1_temp / w1;//前景像素点的平均灰度 //http://blog.163.com/yuyang_tech/blog/static/216050083201302113341762/ delta_temp = (float)(w0 *w1* pow((u0 - u1), 2));//类间方差 g=w0*w1*(u0-u1)^2 //当类间方差delta_temp最大时,对应的i就是阈值T if (delta_temp > delta_max) { delta_max = delta_temp; threshold = i; } } return threshold;}int main(int argc, char** argv){ const char *pstrWindowsBinaryTitle = "二值图"; const char *pstrWindowsSrcTitle = "原图"; IplImage *g_pGrayImage = NULL;//灰度图 IplImage *g_pBinaryImage = NULL;//二值图片 // 从文件中加载原图 IplImage *pSrcImage = cvLoadImage("qrcode.jpg", CV_LOAD_IMAGE_UNCHANGED); if (pSrcImage ==NULL) { cout << "Can not load images" << endl; return -1; } // 转为灰度图 g_pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); cvCvtColor(pSrcImage, g_pGrayImage, CV_BGR2GRAY); // 创建二值图 g_pBinaryImage = cvCreateImage(cvGetSize(g_pGrayImage), IPL_DEPTH_8U, 1); //大律法求的阈值 int pos = otsu(g_pGrayImage); // 转为二值图 cvThreshold(g_pGrayImage, g_pBinaryImage, pos, 255, CV_THRESH_BINARY);//pos 是阈值 // 显示原图 cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE); cvShowImage(pstrWindowsSrcTitle, pSrcImage); // 创建二值图窗口 cvNamedWindow(pstrWindowsBinaryTitle, CV_WINDOW_AUTOSIZE); // 显示二值图 cvShowImage(pstrWindowsBinaryTitle, g_pBinaryImage); cout << "阈值是:"<<pos << endl; cvWaitKey(0); cvDestroyWindow(pstrWindowsSrcTitle); cvDestroyWindow(pstrWindowsBinaryTitle); cvReleaseImage(&pSrcImage); cvReleaseImage(&g_pGrayImage); cvReleaseImage(&g_pBinaryImage); return 0;}
运行结果:
原图:
二值图:
0 0
- 数字图像处理——大津法实现图像二值化
- 《数字图像处理》——图像滤波之实现均值滤波
- 《数字图像处理》——形态学图像处理
- 数字图像处理—图像分割—分类
- 《数字图像处理》——图像滤波
- 《数字图像处理》——图像分割概述
- 使用 matlab 数字图像处理(三)—— 实现图像的旋转(不使用 imrotate)
- 数字图像处理—图像恢复和重建—退化模型
- 数字图像处理—图像分割—串行边界(图)
- 《数字图像处理》——图像的二阶微分
- 《数字图像处理》——图像变换与增强
- 《数字图像处理》——图像退化与压缩编码
- 《数字图像处理》——图像分割与表示描述
- 冈萨雷斯数字图像处理——彩色图像增强3实例
- 数字图像处理——图像平滑(均值滤波)
- 数字图像处理——图像平滑(中值滤波)
- 数字图像处理——用Java对图像做镜像变换
- 数字图像处理—图像高斯模糊运算直观解释
- 使用Visual Studio 2017作为Linux C++开发工具
- 基础篇:让线程停止运行的几种方式(七)
- 树莓派中文输入法
- 关于C/C++中静态本地变量的使用与数据类型修饰符const
- 在android studio里修改jar包
- 数字图像处理——大津法实现图像二值化
- POJ3494
- 543. Diameter of Binary Tree
- Linux格式化U盘
- javaSE_08Java中static、继承、重写
- Ubuntu 14.10 apt-get update 404错误
- 使用浏览器
- Ajax学习和JSON
- nginx源码解析-ngx_show_version_info()