通过RGB、YCbCr、HSV三种不同的方法判断像素是否属于皮肤肤色。
package main import ( "image" "image/color" "image/jpeg" "math" "os" "golang.org/x/image/draw" ) // RGBColor RBG Color Type type RGBColor struct { Red uint8 Green uint8 Blue uint8 } // HSVColor HSV Color Type type HSVColor struct { Hue float64 Saturation float64 Value float64 } type YCbCrColor struct { Y uint8 Cb uint8 Cr uint8 } func main() { i, err := getImage("/Users/bing/Downloads/11.jpeg") if err != nil { return } width := i.Bounds().Dx() height := i.Bounds().Dy() for y := 0; y < height; y++ { for x := 0; x < width; x++ { tmp := i.RGBAAt(x, y) c := RGBColor{ Red: tmp.R, Green: tmp.G, Blue: tmp.B, } // 使用hsv判断皮肤 hc := rgbToHSV(c) if hc.Hue > 0 && hc.Hue < 35 && hc.Saturation > 0.23 && hc.Saturation < 0.68 { nc := color.RGBA{0, 0, 255, 255} i.SetRGBA(x, y, nc) } // 使用YCbCr判断皮肤 yc := rgbToYCbCr(c) // if (97.5 <= float64(yc.Cb) && float64(yc.Cb) <= 142.5) && // (134 <= float64(yc.Cr) && float64(yc.Cr) <= 176) { // nc := color.RGBA{0, 0, 255, 255} // i.SetRGBA(x, y, nc) // } if yc.Cb > 77 && yc.Cb < 127 && yc.Cr > 133 && yc.Cr < 173 { nc := color.RGBA{0, 0, 255, 255} i.SetRGBA(x, y, nc) } // 使用rgb判断皮肤 if c.Red > 95 && c.Green > 40 && c.Green < 100 && c.Blue > 20 && max(c)-min(c) > 15 && math.Abs(float64(c.Red-c.Green)) > 15 && c.Red > c.Green && c.Red > c.Blue { nc := color.RGBA{0, 0, 255, 255} i.SetRGBA(x, y, nc) } } } writeImageToJpeg(i, "/Users/bing/Downloads/ot.jpg") } func writeImageToJpeg(img image.Image, name string) error { fso, err := os.Create(name) if err != nil { return err } defer fso.Close() return jpeg.Encode(fso, img, &jpeg.Options{Quality: 100}) } func getImage(input string) (*image.RGBA, error) { file, err := os.Open(input) if err != nil { return nil, err } defer file.Close() src, _, err := image.Decode(file) if err != nil { return nil, err } img := toRGBA(src) return img, nil } func max(c RGBColor) float64 { max := math.Max(float64(c.Red), float64(c.Green)) max = math.Max(max, float64(c.Blue)) return max } func min(c RGBColor) float64 { min := math.Min(float64(c.Red), float64(c.Green)) min = math.Min(min, float64(c.Blue)) return min } // toRGBA converts an image.Image to an image.RGBA func toRGBA(img image.Image) *image.RGBA { switch img.(type) { case *image.RGBA: return img.(*image.RGBA) } out := image.NewRGBA(img.Bounds()) draw.Copy(out, image.Pt(0, 0), img, img.Bounds(), draw.Src, nil) return out } func rgbToHSV(c RGBColor) HSVColor { r := float64(c.Red) / 255 g := float64(c.Green) / 255 b := float64(c.Blue) / 255 max := math.Max(r, g) max = math.Max(max, b) min := math.Min(r, g) min = math.Min(min, b) var h float64 if r == max { h = (g - b) / (max - min) } if g == max { h = 2 + (b-r)/(max-min) } if b == max { h = 4 + (r-g)/(max-min) } h *= 60 if h < 0 { h += 360 } return HSVColor{h, (max - min) / max, max} } func rgbToYCbCr(c RGBColor) YCbCrColor { y, cb, cr := color.RGBToYCbCr(c.Red, c.Green, c.Blue) return YCbCrColor{y, cb, cr} }
三种方式都测试过了,在背景色和肤色相近的情况下,使用HSV的方式相对来说处理的好些。其他情况下相差不大。
如果这篇文章对你有所帮助,可以通过下边的“打赏”功能进行小额的打赏。
本网站部分内容来源于互联网,如有侵犯版权请来信告知,我们将立即处理。