日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

otsu自适应阈值分割的算法描述和opencv实现,及其在肤色检测中的应用

發(fā)布時間:2025/7/25 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 otsu自适应阈值分割的算法描述和opencv实现,及其在肤色检测中的应用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

from:http://blog.csdn.net/onezeros/article/details/6136770

?otsu算法選擇使類間方差最大的灰度值為閾值,具有很好的效果
算法具體描述見otsu論文,或?qū)_雷斯著名的數(shù)字圖像處理那本書
這里給出程序流程:
1、計算直方圖并歸一化histogram
2、計算圖像灰度均值avgValue.
3、計算直方圖的零階w[i]和一級矩u[i]
4、計算并找到最大的類間方差(between-class variance)
variance[i]=(avgValue*w[i]-u[i])*(avgValue*w[i]-u[i])/(w[i]*(1-w[i]))
對應(yīng)此最大方差的灰度值即為要找的閾值
5、用找到的閾值二值化圖像

我在代碼中做了一些優(yōu)化,所以算法描述的某些地方跟程序并不一致

?

otsu代碼,先找閾值,繼而二值化

[cpp]?view plaincopy
  • //?implementation?of?otsu?algorithm??
  • //?author:?onezeros(@yahoo.cn)??
  • //?reference:?Rafael?C.?Gonzalez.?Digital?Image?Processing?Using?MATLAB??
  • void?cvThresholdOtsu(IplImage*?src,?IplImage*?dst)??
  • {??
  • ????int?height=src->height;??
  • ????int?width=src->width;??????
  • ??????
  • ????//histogram??
  • ????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++]++;??
  • ????????}??
  • ????}??
  • ????//normalize?histogram??
  • ????int?size=height*width;??
  • ????for(int?i=0;i<256;i++)?{??
  • ????????histogram[i]=histogram[i]/size;??
  • ????}??
  • ??????
  • ????//average?pixel?value??
  • ????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;??
  • ????????}??
  • ????}??
  • ??
  • ????cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY);??
  • }??
  • ?

    更多情況下我們并不需要對每一幀都是用otsu尋找閾值,于是可以先找到閾值,然后用找到的閾值處理后面的圖像。下面這個函數(shù)重載了上面的,返回值就是閾值。只做了一點改變

    [cpp]?view plaincopy
  • //?implementation?of?otsu?algorithm??
  • //?author:?onezeros(@yahoo.cn)??
  • //?reference:?Rafael?C.?Gonzalez.?Digital?Image?Processing?Using?MATLAB??
  • int?cvThresholdOtsu(IplImage*?src)??
  • {??
  • ????int?height=src->height;??
  • ????int?width=src->width;??????
  • ??
  • ????//histogram??
  • ????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++]++;??
  • ????????}??
  • ????}??
  • ????//normalize?histogram??
  • ????int?size=height*width;??
  • ????for(int?i=0;i<256;i++)?{??
  • ????????histogram[i]=histogram[i]/size;??
  • ????}??
  • ??
  • ????//average?pixel?value??
  • ????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;??
  • }??
  • ?

    我在手的自動檢測中使用這個方法,效果很好。

    下面是使用上述兩個函數(shù)的簡單的主程序,可以試運行一下,如果處理視頻,要保證第一幀時,手要在圖像中。

    ?

    [cpp]?view plaincopy
  • #include?<cv.h>??
  • #include?<cxcore.h>??
  • #include?<highgui.h>??
  • #pragma?comment(lib,"cv210d.lib")??
  • #pragma?comment(lib,"cxcore210d.lib")??
  • #pragma?comment(lib,"highgui210d.lib")??
  • ??
  • #include?<iostream>??
  • using?namespace?std;??
  • ??
  • int?main(int?argc,?char**?argv)??
  • {?????
  • #ifdef?VIDEO?//video?process??
  • ????CvCapture*?capture=cvCreateCameraCapture(-1);??
  • ????if?(!capture){??
  • ????????cout<<"failed?to?open?camera"<<endl;??
  • ????????exit(0);??
  • ????}??
  • ??
  • ????int?threshold=-1;??
  • ????IplImage*?img;????
  • ????while?(img=cvQueryFrame(capture)){??
  • ????????cvShowImage("video",img);??
  • ????????cvCvtColor(img,img,CV_RGB2YCrCb);??
  • ??
  • ????????IplImage*?imgCb=cvCreateImage(cvGetSize(img),8,1);??
  • ????????cvSplit(img,NULL,NULL,imgCb,NULL);??
  • ????????if?(threshold<0){??
  • ????????????threshold=cvThresholdOtsu(imgCb);??
  • ????????}??
  • ????????//cvThresholdOtsu(imgCb,imgCb);??
  • ????????cvThreshold(imgCb,imgCb,threshold,255,CV_THRESH_BINARY);??
  • ????????cvErode(imgCb,imgCb);??
  • ????????cvDilate(imgCb,imgCb);??
  • ??????????
  • ????????cvShowImage("object",imgCb);??
  • ????????cvReleaseImage(&imgCb);??
  • ??
  • ????????if?(cvWaitKey(3)==27){//esc??
  • ????????????break;??
  • ????????}??
  • ????}?????
  • ??
  • ????cvReleaseCapture(&capture);??
  • ??????
  • #else?//single?image?process??
  • ????const?char*?filename=(argc>=2?argv[1]:"cr.jpg");??
  • ????IplImage*?img=cvLoadImage(filename,CV_LOAD_IMAGE_GRAYSCALE);??
  • ??
  • ????cvThresholdOtsu(img,img);??
  • ????cvShowImage(?"src",?img?);??
  • ????char?buf[256];??
  • ????sprintf_s(buf,256,"%s.otsu.jpg",filename);??
  • ????cvSaveImage(buf,img);??
  • ??
  • ????cvErode(img,img);??
  • ????cvDilate(img,img);??
  • ????cvShowImage(?"dst",?img?);??
  • ????sprintf_s(buf,256,"%s.otsu.processed.jpg",filename);??
  • ????cvSaveImage(buf,img);??
  • ??
  • ????cvWaitKey(0);??
  • #endif??
  • ??????
  • ????return?0;??
  • }??
  • ?

    ?

    效果圖:

    1、膚色cb分量

    ?

    2、otsu自適應(yīng)閾值分割效果

    ?

    3、開運算后效果

    總結(jié)

    以上是生活随笔為你收集整理的otsu自适应阈值分割的算法描述和opencv实现,及其在肤色检测中的应用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。