OTSU算法及其改进算法学习

简介:    这篇文章还是来自斯坦福课后作业hw2_3,主要是结合一个例子介绍otsu算法【亦称为大律算法,小日本】及其改进算法。    本文将先介绍老外的题目、解题思路及maltab解答,然后分析otsu算法步骤,末了给出opencv实现。

   这篇文章还是来自斯坦福课后作业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.

写博客,贴公式太烦,见谅。

睡觉!

目录
相关文章
|
1月前
|
存储 算法
数据结构与算法学习二二:图的学习、图的概念、图的深度和广度优先遍历
这篇文章详细介绍了图的概念、表示方式以及深度优先遍历和广度优先遍历的算法实现。
52 1
数据结构与算法学习二二:图的学习、图的概念、图的深度和广度优先遍历
|
20天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
数据结构与算法系列学习之串的定义和基本操作、串的储存结构、基本操作的实现、朴素模式匹配算法、KMP算法等代码举例及图解说明;【含常见的报错问题及其对应的解决方法】你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
2024重生之回溯数据结构与算法系列学习之串(12)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丟脸好嘛?】
|
1月前
|
缓存 算法 Java
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
这篇文章详细介绍了Java虚拟机(JVM)中的垃圾回收机制,包括垃圾的定义、垃圾回收算法、堆内存的逻辑分区、对象的内存分配和回收过程,以及不同垃圾回收器的工作原理和参数设置。
65 4
JVM知识体系学习六:JVM垃圾是什么、GC常用垃圾清除算法、堆内存逻辑分区、栈上分配、对象何时进入老年代、有关老年代新生代的两个问题、常见的垃圾回收器、CMS
|
1月前
|
算法
动态规划算法学习三:0-1背包问题
这篇文章是关于0-1背包问题的动态规划算法详解,包括问题描述、解决步骤、最优子结构性质、状态表示和递推方程、算法设计与分析、计算最优值、算法实现以及对算法缺点的思考。
67 2
动态规划算法学习三:0-1背包问题
|
16天前
|
机器学习/深度学习 人工智能 自然语言处理
【EMNLP2024】基于多轮课程学习的大语言模型蒸馏算法 TAPIR
阿里云人工智能平台 PAI 与复旦大学王鹏教授团队合作,在自然语言处理顶级会议 EMNLP 2024 上发表论文《Distilling Instruction-following Abilities of Large Language Models with Task-aware Curriculum Planning》。
|
20天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习(8)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
20天前
|
存储 算法 安全
2024重生之回溯数据结构与算法系列学习之顺序表【无论是王道考研人还真爱粉都能包会的;不然别给我家鸽鸽丢脸好嘛?】
顺序表的定义和基本操作之插入;删除;按值查找;按位查找等具体详解步骤以及举例说明
|
20天前
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
20天前
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
20天前
|
算法 安全 NoSQL
2024重生之回溯数据结构与算法系列学习之栈和队列精题汇总(10)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第3章之IKUN和I原达人之数据结构与算法系列学习栈与队列精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!