生活随笔
收集整理的這篇文章主要介紹了
肤色检测合集
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1 HSV 顏色空間
from:?http://blog.csdn.net/onezeros/article/details/5930520
把rgb轉換到hsv空間,用h分量 進行識別,像素值在7~29之間 是膚色的幾乎全部范圍
識別會受到光照的影響。但是整體上準確度是較高的。
在白天 正常的明亮的光照下,效果非常好。
這是我在晚上拍攝的一張圖像的處理
對于不同的環境(主要是光照條件),閾值應相應 變動以提高精確度
程序源碼下載?http://download.csdn.net/source/2744062
2 YCrCb
源碼下下載?http://download.csdn.net/source/2873223
效果圖
3 3種模型
今天是地球日,就選了張相關主題的圖像做測試
?
第一種:RGB color space
第二種:RG color space
第三種:Ycrcb之cr分量+otsu閾值化
?
還有別的一些模型,效果不太好就不貼了
?
1.rgb model
[cpp]?view plain
?copy ?? void?SkinRGB(IplImage*?rgb,IplImage*?_dst)?? {?? ????assert(rgb->nChannels==3&&?_dst->nChannels==3);?? ?? ????static?const?int?R=2;?? ????static?const?int?G=1;?? ????static?const?int?B=0;?? ?? ????IplImage*?dst=cvCreateImage(cvGetSize(_dst),8,3);?? ????cvZero(dst);?? ?? ????for?(int?h=0;h<rgb->height;h++)?{?? ????????unsigned?char*?prgb=(unsigned?char*)rgb->imageData+h*rgb->widthStep;?? ????????unsigned?char*?pdst=(unsigned?char*)dst->imageData+h*dst->widthStep;?? ????????for?(int?w=0;w<rgb->width;w++)?{?? ????????????if?((prgb[R]>95?&&?prgb[G]>40?&&?prgb[B]>20?&&?? ????????????????prgb[R]-prgb[B]>15?&&?prgb[R]-prgb[G]>15? )||?? ????????????????(prgb[R]>200?&&?prgb[G]>210?&&?prgb[B]>170?&&?? ????????????????abs(prgb[R]-prgb[B])<=15?&&?prgb[R]>prgb[B]&&?prgb[G]>prgb[B])?? ????????????????)?{?? ????????????????????memcpy(pdst,prgb,3);?? ????????????}????????????? ????????????prgb+=3;?? ????????????pdst+=3;?? ????????}?? ????}?? ????cvCopyImage(dst,_dst);?? ????cvReleaseImage(&dst);?? }?? ?
2.rg model
[cpp]?view plain
?copy ?? void?cvSkinRG(IplImage*?rgb,IplImage*?gray)?? {?? ????assert(rgb->nChannels==3&&gray->nChannels==1);?? ?????? ????const?int?R=2;?? ????const?int?G=1;?? ????const?int?B=0;?? ?? ????double?Aup=-1.8423;?? ????double?Bup=1.5294;?? ????double?Cup=0.0422;?? ????double?Adown=-0.7279;?? ????double?Bdown=0.6066;?? ????double?Cdown=0.1766;?? ????for?(int?h=0;h<rgb->height;h++)?{?? ????????unsigned?char*?pGray=(unsigned?char*)gray->imageData+h*gray->widthStep;?? ????????unsigned?char*?pRGB=(unsigned?char*?)rgb->imageData+h*rgb->widthStep;?? ????????for?(int?w=0;w<rgb->width;w++)?{?? ????????????int?s=pRGB[R]+pRGB[G]+pRGB[B];?? ????????????double?r=(double)pRGB[R]/s;?? ????????????double?g=(double)pRGB[G]/s;?? ????????????double?Gup=Aup*r*r+Bup*r+Cup;?? ????????????double?Gdown=Adown*r*r+Bdown*r+Cdown;?? ????????????double?Wr=(r-0.33)*(r-0.33)+(g-0.33)*(g-0.33);?? ????????????if?(g<Gup?&&?g>Gdown?&&?Wr>0.004){?? ????????????????*pGray=255;?? ????????????}else{??? ????????????????*pGray=0;?? ????????????}?? ????????????pGray++;?? ????????????pRGB+=3;?? ????????}?? ????}?? ?? }?? ?
3.cr+otsu
[c-sharp]?view plain
?copy ?? ?? ?? void?cvThresholdOtsu(IplImage*?src,?IplImage*?dst)?? {?? ????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;?? ????????}?? ????}?? ?? ????cvThreshold(src,dst,threshold,255,CV_THRESH_BINARY);?? }?? ?? void?cvSkinOtsu(IplImage*?src,?IplImage*?dst)?? {?? ????assert(dst->nChannels==1&&?src->nChannels==3);?? ?? ????IplImage*?ycrcb=cvCreateImage(cvGetSize(src),8,3);?? ????IplImage*?cr=cvCreateImage(cvGetSize(src),8,1);?? ????cvCvtColor(src,ycrcb,CV_BGR2YCrCb);?? ????cvSplit(ycrcb,0,cr,0,0);?? ?? ????cvThresholdOtsu(cr,cr);?? ????cvCopyImage(cr,dst);?? ????cvReleaseImage(&cr);?? ????cvReleaseImage(&ycrcb);?? }?? ?
原圖像
?
rgb model
?
rg model
?
otsu+cr
4 RGB YCrCb
本文涉及的很多算法,在網絡上也有不少同類型的文章,但是肯定的一點就是,很多都是不配代碼的,或者所附帶的代碼都是象征性的,速度慢,不優雅,不具有實用價值,本文努力解決這些問題。
????? 文中各算法出現的順序并不代表算法的優越性,僅僅是作者隨機排布的而已。
????? 2、基于RGB顏色空間的簡單閾值膚色識別
???????在human skin color clustering for face detection一文中提出如下簡單的判別算式:
R>95 And G>40 And B>20 And R>G And R>B And Max(R,G,B)-Min(R,G,B)>15 And Abs(R-G)>15?
? 算法非常之簡單,同樣主要把復雜的判斷條件放到后面去判斷,能有效的降低程序的執行時間,參考代碼:
?
for (Y =
0; Y < Height; Y++
)
{Pointer = Scan0 + Y *
Stride;SkinP = SkinScan0 + Y *
SkinStride;for (X =
0; X < Width; X++
){Blue = *Pointer; Green = *(Pointer +
1); Red = *(Pointer +
2);if (Red >
95 && Green >
40 && Blue >
20 && Red > Blue && Red > Green && Math.Abs(Red - Green) >
15){if (Blue >=
Green) {Max =
Blue;Min =
Green;}else{Max =
Green;Min =
Blue;}if (Red >
Max)Max =
Red;else if (Red <
Min)Min =
Red;if (Max - Min >
15) *SkinP =
255;}Pointer +=
3;SkinP++
;} ??算法效果:
???????????????
原圖 ?????? ?識別結果圖???????????????????????????????????????????????????原圖 ??? 識別結果圖
???? 由上述結果似乎該算法得到了過多的皮膚區域,然后就是算法更喜歡美女一些(^_^)。
?????3、基于YCbCr顏色空間的簡單閾值膚色識別
該算法則更為簡單,將圖像轉換到YCbCr顏色空間,然后按下述計算式判斷是否屬于皮膚區域:
(Cb > 77 And Cb < 127)??And (Cr > 133?And Cr < 173)
????? 關于RGB和YCbCr顏色空間的轉換的優化算法,可參考本博客相關文章。
????? 由于當初寫這方面的時候沒有注明該算法的出處,現在也沒從提起了。
????? 代碼參考:
for (Y = 0; Y < Height; Y++)
{Pointer = Scan0 + Y * Stride;SkinP = SkinScan0 + Y * SkinStride;for (X = 0; X < Width; X++){Blue = *Pointer; Green = *(Pointer + 1); Red = *(Pointer + 2);Cb = (-176933 * Red - 347355 * Green + 524288 * Blue + 134217728) >> 20;if (Cb > 77 && Cb < 127){Cr = (524288 * Red - 439026 * Green - 85262 * Blue + 134217728) >> 20;if (Cr > 133 && Cr < 173) *SkinP = 255;}Pointer += 3;SkinP++;}
}
?
??????
?
??????? ????????
????????????? 原圖 ?????? ???? 識別結果圖???????????????????????????????????????????????????原圖 ??? 識別結果圖
?????誤判的區域還是很大的。
?????還有一種是基于YUV顏色空間進行的膚色識別,似乎也不太準確,可參考http://www.doc88.com/p-97381067005.html。
總結
以上是生活随笔為你收集整理的肤色检测合集的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。