OTSU算法及其改进算法学习
来源:互联网 发布:淘宝直播ipad可以看吗 编辑:程序博客网 时间:2024/04/28 01:38
这篇文章转自http://blog.csdn.net/jinshengtao/article/details/19506005点击打开链接
这篇文章还是来自斯坦福课后作业hw2_3,主要是结合一个例子介绍otsu算法【亦称为大律算法,小日本】及其改进算法。
本文将先介绍老外的题目、解题思路及maltab解答,然后分析otsu算法步骤,末了给出opencv实现。
老外的题目:Binarization of Scanned Book Pages
题目大意:
网上图书服务,比如百度文库需要将大量藏书数字化。首先,书的每一页将被扫描。然后,这些扫描图片将被二值化,并通过字符识别引擎OCR处理,即图片转字符。对于传统书籍【由于装订原因,如果在不破坏书的情况下】,书的每一页被扫描时,由于纸张被弯曲导致扫描结果的光照不均匀。如下图所示:现在要求:
1. 对每一幅图像使用otsu算法执行全局二值化处理,计算原始图像的直方图,并在该直方图上标注OTSU阈值
2. 对每一幅图像执行局部自适应阈值,根据局部变化区分对待均匀和非均匀区域。
解题思路:
第一题,直接使用matlab的graythresh函数,通过最大类间方差法【OTSU】找到图片的一个合适的阈值(threshold)。末了,用imhist求取直方图便是。
第二题,使用一个水平滑窗,大小为21列宽*图像原始高度,从左往右逐像素滑动。对于窗口内的像素,计算局部变化【方差或平均值,代码用的是方差】。若窗口内方差大于阈值,使用otsu算法计算窗口内局部阈值,并二值化该窗口内像素;若方差小于阈值,则是书页上的空白区域,将该窗口内所有像素设为白色。如下图所示:
【题外话,本题的意思就是在对图书使用OCR进行字符识别前,优化二值化结果,使得OCR结果更精确。】
matlab代码:
- clc; clear all;
- imageFiles = {'hw2_book_page_1.jpg', 'hw2_book_page_2.jpg'};
- for nImage = 1:length(imageFiles)
- % Load image
- img = im2double(imread(imageFiles{nImage}));
- figure(1); clf;
- imshow(img);
- [height, width] = size(img);
- % [pathStr, name, ext] = fileparts(imageFiles{nImage});
- % Global thresholding
- globalThresh = graythresh(img);
- imgBinGlobal = im2bw(img, globalThresh);%Convert image to binary image, based on threshold
- figure(2); clf;
- imshow(imgBinGlobal);
- figure(3); clf; set(gcf, 'Color', 'w');
- imhist(img); hold on;
- histCounts = imhist(img);
- h = plot(globalThresh*ones(1,100), linspace(0,max(histCounts)), 'r-');
- set(h, 'LineWidth', 2);
- set(gca, 'FontSize', 26);
- h = text(globalThresh+0.01, max(histCounts)/4, ...
- sprintf('T = %.2f', globalThresh));
- set(h, 'FontSize', 26);
- ylabel('Frequency');
- % imwrite(imgBinGlobal, ['Global_' name '.jpg']);
- % Locally adaptive thresholding
- imgBinLocal = imgBinGlobal;
- winHalfWidth = 10;
- localVarThresh = 0.002;
- for col = 1:width
- inCols = max(1,col-winHalfWidth) : min(width,col+winHalfWidth);
- inRows = 1:height;
- inTile = img(inRows, inCols);
- localThresh = graythresh(inTile);
- %localMean = mean2(inTile);
- localVar = std(inTile(:))^2; %方差
- if localVar > localVarThresh
- imgBinLocal(:,col) = im2bw(img(:,col), localThresh);
- else
- imgBinLocal(:,col) = 1;
- end
- end % col
- figure(4); clf;
- imshow(imgBinLocal);
- % imwrite(imgBinLocal, ['Local_' name '.jpg']);
- if nImage == 1
- pause
- end
- end % nImage
实验结果:
hw2_book_page_1.jpg 原始图像:
全局阈值化处理结果,即全局otsu结果:
全局OTSU结果在灰度直方图中的位置【注意这里所有的灰度都被缩放到0-1之间,包括阈值才0.65,我后面自己实现的要167】:
局部OTSU效果:
可以明显发现大片黑色木有了,得,另一副图片的结果,大家自己去斯坦福下载学习吧。
下面着重介绍OTSU算法原理及实现:
内容参考原文《A Threshold Selection Method from Gray-Level Histograms》
最大类间方差是由日本学者大津(Nobuyuki Otsu)于1979年提出,是一种自适应的阈值确定方法。算法假设图像像素能够根据阈值,被分成背景[background]和目标[objects]两部分。然后,计算该最佳阈值来区分这两类像素,使得两类像素区分度最大【用方差表达,具体公式见后】。OTSU的扩展算法,可进行多级阈值处理,称为“Multi Otsu method”【题外话】
设原始灰度级为M,灰度级为i的像素点个数为ni,对灰度直方图进行归一化:
opencv实现代码:
- // m_otsu.cpp : 定义控制台应用程序的入口点。
- //
- #include "stdafx.h"
- #include "cv.h"
- #include "highgui.h"
- int _tmain(int argc, _TCHAR* argv[])
- {
- int i,j,nThresh;
- int nHistogram[256] = {0};
- double fStdHistogram[256] = {0.0};
- double fGrayAccu[256] = {0.0};
- double fGrayAve[256] = {0.0};
- double fAverage = 0;
- double fTemp = 0;
- double fMax = 0;
- IplImage *src,*dst;
- src = cvLoadImage("test.jpg",CV_LOAD_IMAGE_GRAYSCALE);
- dst = cvCreateImage(cvSize(src->width,src->height),IPL_DEPTH_8U,1);
- //统计直方图
- // 每行
- for(i = 0; i < src->height; i++)
- {
- // 每列
- for(j = 0; j < src->width; j++)
- {
- nHistogram[(unsigned char)src->imageData[i*src->width+j]] ++;
- }
- }
- //归一化直方图
- for(i = 0; i <= 255;i++)
- {
- fStdHistogram[i] = nHistogram[i]/(double)(src->width * src->height); //Pi
- //printf("%f\n",fStdHistogram[i]);
- }
- for(i=0;i<=255;i++)
- {
- for(j=0;j<=i;j++)
- {
- fGrayAccu[i] += fStdHistogram[j]; //所有灰度级,关于w0的数组
- fGrayAve[i] += j*fStdHistogram[j]; //所有灰度级,关于u(t)的数组
- }
- fAverage += i*fStdHistogram[i]; //uT
- //printf("%f\n",fAverage);
- }
- //计算OSTU
- for(i=0;i<=255;i++)
- {
- fTemp=(fAverage*fGrayAccu[i]-fGrayAve[i])*(fAverage*fGrayAccu[i]-fGrayAve[i])/(fGrayAccu[i]*(1-fGrayAccu[i]));
- if(fTemp>fMax)
- {
- fMax=fTemp;
- nThresh=i;
- }
- }
- //计算二值图像
- for (i=0;i<src->height;i++)
- {
- for (j=0;j<src->width;j++)
- {
- if ((unsigned char)src->imageData[i*src->width+j]<nThresh)
- {
- dst->imageData[i*src->width+j] = 0;
- }else{
- dst->imageData[i*src->width+j] = 255;
- }
- }
- }
- printf("%d",nThresh);
- cvNamedWindow("otsu",0);
- cvShowImage("otsu",dst);
- cvSaveImage("otsu_result.jpg",dst);
- cvWaitKey(0);
- return 0;
- }
实验结果:【全局OTSU】
阈值为167.
- OTSU算法及其改进算法学习
- OTSU算法及其改进算法学习
- OTSU算法学习 OTSU公式证明
- OTSU算法学习 人工智能导论
- otsu算法---matlab实现,和一种改进算法
- KMP及其改进算法
- KMP及其改进算法
- 冒泡算法及其改进
- OTSU算法
- Otsu算法
- otsu算法
- otsu算法
- Otsu算法
- otsu算法
- OTSU算法
- otsu算法
- Otsu算法
- 遗传算法及其改进算法
- Eclipse下查看jdk源代码
- 小心StringBuilder.toString
- 假广告
- ArcGIS教程:栅格计算器的工作原理
- 融入了最新的Java应用技术的洞察
- OTSU算法及其改进算法学习
- SQLite清空表并将自增列归零
- 触摸G4全球定位系统的Wi-Fi的中国手机
- C# 代码编写规范
- Apache CXF Rest与Spring 3.0 mvc 的异常处理框架总结
- c++中的Heap算法
- Integer Inquiry(高精度)
- 有关信息特别案例
- FreeMarker学习记录