OTSU算法及其改进算法学习

article/2025/8/18 23:08:34

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

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

睡觉!


http://chatgpt.dhexx.cn/article/AmBrN1F8.shtml

相关文章

Otsu Thresholding

1. Otsu Thresholding Explained Otsu对image中的所有像素都假定为阈值&#xff0c;然后根据此值将image分为前景物体和背景&#xff1b;遍历所有像素值 计算类内方差&#xff0c;最小的类内方差对应的threshold即为最优阈值&#xff1b; 以6阶灰度图像为例 A 6-level greys…

Otsu算法原理及实现

在图像处理中Otsu方法&#xff0c;是以 Nobuyuki otsu 的名字命名的&#xff08;日本人&#xff0c;大津展之&#xff09;&#xff0c;常用于基于图像分割的聚类。该算法的理论依据是&#xff1a;假定图像包含两类像素&#xff08;前景像素和背景像素&#xff09;&#xff0c;直…

10 Otsu 算法

文章目录 前言一、Otsu 是什么&#xff1f;二、算法实验1.使用第三方库2.不使用第三方库 前言 Otsu 是一种利用图像的灰度特征自动计算二值化阈值的方法&#xff0c;常被称为 Otsu 自动阈值法。 使用 Otsu 方法可以避免主观性和繁琐性的阈值选取操作&#xff0c;并能够在一定…

OTSU(最大类间方差法、大津算法)

OTSU是阈值分割中一种常用的算法&#xff0c;它可以根据图像自动生成最佳分割阈值。OTSU的核心思想是类间方差最大化。 import cv2 import numpy as np from matplotlib import pyplot as pltimage cv2.imread("2.bmp") gray cv2.cvtColor(image, cv2.COLOR_BGR2G…

Bootstrap模态框里 再弹模态框

Bootstrap模态框里 再弹模态框 后端代码点击编辑 按钮 将参数赋值隐藏 input 中 , 便于修改 获取对应id修改模态框详情模态框 后端代码 /*** 财务审核使用详情** param request* param id* return*/RequestMapping(params "getUseDatil")ResponseBodypublic JSONAr…

新增模态框

平时我们在VS中也常常会用到模态框&#xff0c;今天我们就来聊聊模态框&#xff0c;但是我要说的是新增模态框&#xff0c;而不是修改模态框喔。在书写模态框代码时&#xff0c;我们还要引用一个插件: 然后就可以进行对代码进行书写了。 我们先说说模态框插件的用法&#xff0c…

html模态框常见问题,模态框无法弹出的问题

问题起因&#xff1a; 昨晚写到了一个模态框&#xff0c;用到了bootstrap和jquery&#xff0c;依赖的js已经复制到项目中&#xff0c;并在Jsp页面上进行了引用&#xff0c;最初的引用如下&#xff1a; 问题描述&#xff1a; 模态框无法正常弹出&#xff0c;使用浏览器查看资源看…

Vue模态框的封装

一、模态框 1、模态框&#xff1a;若对话框不关闭&#xff0c;不能操作其父窗口 2、非模态框&#xff1a;对话框不关闭&#xff0c;可以操作其窗口 二、Vue组件实现模态框的功能 1、模态框是一个子组件 2、显示和隐藏由父组件决定 3、对话框的标题也是由父组件传递的 4、对话框…

Bootstrap之模态框

前言 模态框&#xff08;Modal&#xff09;是覆盖在父窗体上的子窗体。通常&#xff0c;目的是显示来自一个单独的源的内容&#xff0c;可以在不离开父窗体的情况下有一些互动。子窗体可提供信息、交互等。 用法 您可以切换模态框&#xff08;Modal&#xff09;插件的隐藏内…

php什么是模态框,bootstrap模态框有什么用

Bootstrap Modals(模态框)是使用定制的Jquery 插件创建的。 它可以用来创建模态窗口丰富用户体验&#xff0c;或者为用户添加实用功能。您可以在 Modals(模态框)中使用 Popover(弹出框)和 Tooltip(工具提示插件)。(推荐学习&#xff1a;Bootstrap视频教程) 将通过一些实例和解释…

弹出模态框

想必大家都知道弹出层的重要性&#xff0c;在很多的地方都能用到这个方法&#xff0c;所以说这种是非常的普遍的实用性&#xff0c;在大家编写过程中也是很常见的模态框以及弹出层&#xff0c;基本也是一个概念。 插件不可缺少 1.多窗口模式 层叠置顶 Esc 关闭 为什么是说多窗…

模态框动态赋值

模态框动态赋值&#xff0c;可以有多种方式&#xff1a;1、每次一个个填充&#xff1b;2、直接针对模态框中的ID赋值。。。 今天说下同事犯的错误&#xff0c;大家引以为鉴&#xff1a; 首先如图&#xff1a; 他在点击详情链接时&#xff0c;是能拿到相关参数的&#xff0c;进…

html 自定义模态框,自定义对话框、模态框

致敬iphoneX的小刘海....自定义模态框 body{ text-align: center; } #modalBg{ position: absolute; left: 0; top: 0; background-color: rgba(0,0,0,0.2); width: 100%; height: 100%; margin: auto; display: none; } #modal{ min-width: 30%; background-color: white; bor…

html怎么自动弹出模态框,纯CSS实现带点击模态框外部自动关闭的模态框

在网页中我们经常会用到模态框,一般会用于显示表单或者是提示信息。由于模态框涉及到页面上比较多的交互效果,最简单的交互就是打开以及关闭两个操作,而关闭又会涉及是否需要在打开状态下点击模态框外部能够关闭这样的功能,因为这些交互问题,所以一般都会首先考虑到使用Ja…

模态框拖拽

1、点击弹出层&#xff0c;回弹出模态框&#xff0c;并且显示半透明的遮挡层 2、点击关闭按钮&#xff0c;可以关闭模态框&#xff0c;并且同时关闭灰色半透明遮挡层 3、鼠标放到模态框最上面一行&#xff0c;可以按住鼠标拖拽模态框在页面中移动 4、鼠标松开&#xff0c;可…

模态框案例

模态框 模态框在很多网站是很常见的&#xff0c;比如网易云音乐登录&#xff0c;百度登录等网站。 网易云音乐如图&#xff1a; 让我们来看看代码吧&#xff01;&#xff01;注意&#xff1a;这里为了更好的演示效果&#xff0c;增加了遮挡层。 HTML部分&#xff1a; <!-- …

零基础Bootstrap入门教程(16)--模态框

点此查看 所有教程、项目、源码导航 本文目录 1. 概述2. 模态框样式3. 按钮直接关联模态框4. 通过JS方法打开/关闭模态框5. 调整大小6. 动画效果7. 小结 1. 概述 模态框这个名字有点高雅了&#xff0c;其实就是对话框&#xff0c;用来弹出一个新的界面。 模态框的使用非常的场…

模态框

模态对话框&#xff08;Modal Dialogue Box&#xff0c;又叫做模式对话框&#xff09;&#xff0c;是指在用户想要对对话框以外的应用程序进行操作时&#xff0c;必须首先对该对话框进行响应 摘自百度百科 先放上效果图&#xff1a; 基本功能为点击窗口中间的发光按钮&#xff…

HTML+CSS+JavaScript实现模态框(可拖拽)

前言 模态框是指覆盖在父窗口上的子窗口&#xff0c;但在HTML网页中&#xff0c;并没有父窗口和子窗口的概念。这里是通过可隐藏的遮罩层和一个可隐藏的盒子来实现模态框的效果。 效果演示&#xff1a; 下面开始详细介绍如何实现一个可拖拽的模态框。只对 JS 部分详解&#x…

Bootstrap系列之模态框(Modal)

文章の目录 1、工作原理2、示例2.1、Modal组件2.2、在线演示2.3、静态背景2.4、滚动内容2.5、垂直居中2.6、提示和弹窗2.7、使用网格2.8、不同模态框的内容2.9、改变动画2.10、移除动画2.11、动态高度2.12、Accessibility2.13、嵌入YouTube视频 3、Optional sizes4、用法4.1、通…