生活随笔
收集整理的這篇文章主要介紹了
OTSU算法(也称最大类间差法,有时也称之为大津算法)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
在圖像處理應(yīng)用中二值化操作是一個(gè)很常用的處理方式,例如零器件圖片的處理、文本圖片和驗(yàn)證碼圖片中字符的提取、車牌識(shí)別中的字符分割,以及視頻圖像中的運(yùn)動(dòng)目標(biāo)檢測(cè)中的前景分割,等等。
? ?較為常用的圖像二值化方法有:1)全局固定閾值;2)局部自適應(yīng)閾值;3)OTSU等。此篇講述的是OTSU算法。
OTSU算法也稱最大類間差法,有時(shí)也稱之為大津算法,由大津于1979年提出,被認(rèn)為是圖像分割中閾值選取的最佳算法,計(jì)算簡(jiǎn)單,不受圖像亮度和對(duì)比度的影響,因此在數(shù)字圖像處理上得到了廣泛的應(yīng)用。它是按圖像的灰度特性,將圖像分成背景和前景兩部分。因方差是灰度分布均勻性的一種度量,背景和前景之間的類間方差越大,說明構(gòu)成圖像的兩部分的差別越大,當(dāng)部分前景錯(cuò)分為背景或部分背景錯(cuò)分為前景都會(huì)導(dǎo)致兩部分差別變小。因此,使類間方差最大的分割意味著錯(cuò)分概率最小。
? otsu使用的是聚類的思想,把圖像的灰度數(shù)按灰度級(jí)分成2個(gè)部分,使得兩個(gè)部分之間的灰度值差異最大,每個(gè)部分之間的灰度差異最小,通過方差的計(jì)算來(lái)尋找一個(gè)合適的灰度級(jí)別 來(lái)劃分。 ?所以 可以在二值化的時(shí)候 采用otsu算法來(lái)自動(dòng)選取閾值進(jìn)行二值化。otsu算法被認(rèn)為是圖像分割中閾值選取的最佳算法,計(jì)算簡(jiǎn)單,不受圖像亮度和對(duì)比度的影響。因此,使類間方差最大的分割意味著錯(cuò)分概率最小。
使用otsu大津法實(shí)現(xiàn)直方圖的單閾值分割,可用于圖像的分割。大津是用最大類間方差來(lái)判讀閾值的,也可以用最小類內(nèi)方差判讀,最大類間方差+最小類內(nèi)方差=總方差
OPENCV的二值化操作中,有一種“大津閾值處理”的方法,使用函數(shù)cvThreshold(image,image2,0,255,CV_THRESH_OTSU)?實(shí)現(xiàn),該函數(shù)就會(huì)使用大律法OTSU得到的全局自適應(yīng)閾值來(lái)進(jìn)行二值化圖片,而參數(shù)中的threshold不再起作用。
設(shè)t為設(shè)定的閾值。
wo: 分開后 ?前景像素點(diǎn)數(shù)占圖像的比例
uo:??分開后 ?前景像素點(diǎn)的平均灰度
w1:分開后 ?被景像素點(diǎn)數(shù)占圖像的比例
u1:??分開后 ?被景像素點(diǎn)的平均灰度
u=w0*u0 + w1*u1 :圖像總平均灰度
從L個(gè)灰度級(jí)遍歷t,使得t為某個(gè)值的時(shí)候,前景和背景的方差最大, 則 這個(gè) t ?值便是我們要求得的閾值。
其中,方差的計(jì)算公式如下:
g=wo * (uo - u) * (uo - u) + w1 * (u1 - u) * (u1 - u)
[ ? ? ? ? ? ? 此公式計(jì)算量較大,可以采用: ? ? ?g = wo * w1 * (uo - u1) * (uo - u1) ? ? ? ? ? ? ? ?]
由于otsu算法是對(duì)圖像的灰度級(jí)進(jìn)行聚類,so ?在執(zhí)行otsu算法之前,需要計(jì)算該圖像的灰度直方圖。
【第一套代碼】
#include?"stdafx.h"?? #include?"stdio.h"?? #include?"cv.h"?? #include?"highgui.h"?? #include?"Math.h"?? ?? int?Otsu(IplImage*?src);?? ?? int?_tmain(int?argc,?_TCHAR*?argv[])?? {?? ????IplImage*?img?=?cvLoadImage("c:\\aSa.jpg",0);?? ????IplImage*?dst?=?cvCreateImage(cvGetSize(img),?8,?1);?? ????int?threshold?=?Otsu(img);?? ?? ????cvThreshold(img,?dst,?threshold,?255,?CV_THRESH_BINARY);?? ?? ?? ????cvNamedWindow(?"img",?1?);?? ????cvShowImage("img",?dst);?? ?? ?? ????cvWaitKey(-1);?? ?? ????cvReleaseImage(&img);?? ????cvReleaseImage(&dst);?? ?? ????cvDestroyWindow(?"dst"?);?? ????return?0;?? }?? ?? int?Otsu(IplImage*?src)???? {???? ????int?height=src->height;???? ????int?width=src->width;???????? ????long?size?=?height?*?width;??? ?? ?????? ????float?histogram[256]?=?{0};???? ????for(int?m=0;?m?<?height;?m++)?? ????{???? ????????unsigned?char*?p=(unsigned?char*)src->imageData?+?src->widthStep?*?m;???? ????????for(int?n?=?0;?n?<?width;?n++)??? ????????{???? ????????????histogram[int(*p++)]++;???? ????????}???? ????}???? ?? ????int?threshold;?????? ????long?sum0?=?0,?sum1?=?0;??? ????long?cnt0?=?0,?cnt1?=?0;??? ????double?w0?=?0,?w1?=?0;??? ????double?u0?=?0,?u1?=?0;???? ????double?variance?=?0;??? ????int?i,?j;?? ????double?u?=?0;?? ????double?maxVariance?=?0;?? ????for(i?=?1;?i?<?256;?i++)??? ????{???? ????????sum0?=?0;?? ????????sum1?=?0;??? ????????cnt0?=?0;?? ????????cnt1?=?0;?? ????????w0?=?0;?? ????????w1?=?0;?? ????????for(j?=?0;?j?<?i;?j++)?? ????????{?? ????????????cnt0?+=?histogram[j];?? ????????????sum0?+=?j?*?histogram[j];?? ????????}?? ?? ????????u0?=?(double)sum0?/??cnt0;??? ????????w0?=?(double)cnt0?/?size;?? ?? ????????for(j?=?i?;?j?<=?255;?j++)?? ????????{?? ????????????cnt1?+=?histogram[j];?? ????????????sum1?+=?j?*?histogram[j];?? ????????}?? ?? ????????u1?=?(double)sum1?/?cnt1;?? ????????w1?=?1?-?w0;??? ?? ????????u?=?u0?*?w0?+?u1?*?w1;??? ????????printf("u?=?%f\n",?u);?? ?????????? ????????variance?=??w0?*?w1?*??(u0?-?u1)?*?(u0?-?u1);?? ????????if(variance?>?maxVariance)??? ????????{???? ????????????maxVariance?=?variance;???? ????????????threshold?=?i;???? ????????}??? ????}???? ?? ????printf("threshold?=?%d\n",?threshold);?? ????return?threshold;???? } ? ?
【第二套代碼】
#include?"stdafx.h"?? #include?"stdio.h"?? #include?"cv.h"?? #include?"highgui.h"?? #include?"Math.h"?? ?? int?Otsu(IplImage*?src);?? ?? int?_tmain(int?argc,?_TCHAR*?argv[])?? {?? ????IplImage*?img?=?cvLoadImage("c:\\aSa.jpg",0);?? ????IplImage*?dst?=?cvCreateImage(cvGetSize(img),?8,?1);?? ????int?threshold?=?Otsu(img);?? ????printf("threshold?=?%d\n",?threshold);?? ????cvThreshold(img,?dst,?threshold,?255,?CV_THRESH_BINARY);?? ?? ????cvNamedWindow(?"img",?1?);?? ????cvShowImage("img",?dst);?? ?? ?? ????cvWaitKey(-1);?? ?? ????cvReleaseImage(&img);?? ????cvReleaseImage(&dst);?? ?????? ????cvDestroyWindow(?"dst"?);?? ????return?0;?? }?? ?? int?Otsu(IplImage*?src)???? {???? ????int?height=src->height;???? ????int?width=src->width;???????? ?? ?????? ????float?histogram[256]?=?{0};???? ????for(int?i=0;?i?<?height;?i++)?? ????{???? ????????unsigned?char*?p=(unsigned?char*)src->imageData?+?src->widthStep?*?i;???? ????????for(int?j?=?0;?j?<?width;?j++)??? ????????{???? ????????????histogram[*p++]++;???? ????????}???? ????}???? ?????? ????int?size?=?height?*?width;???? ????for(int?i?=?0;?i?<?256;?i++)?? ????{???? ????????histogram[i]?=?histogram[i]?/?size;???? ????}???? ?? ?????? ????float?avgValue=0;???? ????for(int?i=0;?i?<?256;?i++)?? ????{???? ????????avgValue?+=?i?*?histogram[i];???? ????}????? ?? ????int?threshold;?????? ????float?maxVariance=0;???? ????float?w?=?0,?u?=?0;???? ????for(int?i?=?0;?i?<?256;?i++)??? ????{???? ????????w?+=?histogram[i];???? ????????u?+=?i?*?histogram[i];???? ?? ????????float?t?=?avgValue?*?w?-?u;???? ????????float?variance?=?t?*?t?/?(w?*?(1?-?w)?);???? ????????if(variance?>?maxVariance)??? ????????{???? ????????????maxVariance?=?variance;???? ????????????threshold?=?i;???? ????????}???? ????}???? ?? ????return?threshold;???? } ??
總結(jié)
以上是生活随笔為你收集整理的OTSU算法(也称最大类间差法,有时也称之为大津算法)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。