region.go (2850B)
1 package nude 2 3 import ( 4 "math" 5 ) 6 7 type Pixel struct { 8 id int 9 isSkin bool 10 region int 11 X int 12 Y int 13 chekced bool 14 V float64 // intesitiy(Value) of HSV 15 } 16 17 // TODO: cache caluculated leftMost, rightMost, upperMost, lowerMost. 18 type Region []*Pixel 19 20 // TODO: optimize 21 //func (r Region) isSkin(x, y int) bool { 22 // for _, pixel := range r { 23 // if pixel.isSkin && pixel.X == x && pixel.Y == y { 24 // return true 25 // } 26 // } 27 // return false 28 //} 29 30 func (r Region) leftMost() *Pixel { 31 minX := math.MaxInt32 32 index := 0 33 for i, pixel := range r { 34 if pixel.X < minX { 35 minX = pixel.X 36 index = i 37 } 38 } 39 return r[index] 40 } 41 42 func (r Region) rightMost() *Pixel { 43 maxX := math.MinInt32 44 index := 0 45 for i, pixel := range r { 46 if pixel.X > maxX { 47 maxX = pixel.X 48 index = i 49 } 50 } 51 return r[index] 52 } 53 54 func (r Region) upperMost() *Pixel { 55 minY := math.MaxInt32 56 index := 0 57 for i, pixel := range r { 58 if pixel.Y < minY { 59 minY = pixel.Y 60 index = i 61 } 62 } 63 return r[index] 64 } 65 66 func (r Region) lowerMost() *Pixel { 67 maxY := math.MinInt32 68 index := 0 69 for i, pixel := range r { 70 if pixel.Y > maxY { 71 maxY = pixel.Y 72 index = i 73 } 74 } 75 return r[index] 76 } 77 78 func (r Region) skinRateInBoundingPolygon() float64 { 79 // build the bounding polygon by the regions edge values: 80 // Identify the leftmost, the uppermost, the rightmost, and the lowermost skin pixels of the three largest skin regions. 81 // Use these points as the corner points of a bounding polygon. 82 left := r.leftMost() 83 right := r.rightMost() 84 upper := r.upperMost() 85 lower := r.lowerMost() 86 vertices := []*Pixel{left, upper, right, lower, left} 87 total := 0 88 skin := 0 89 90 // via http://katsura-kotonoha.sakura.ne.jp/prog/c/tip0002f.shtml 91 for _, p1 := range r { 92 inPolygon := true 93 for i := 0; i < len(vertices)-1; i++ { 94 p2 := vertices[i] 95 p3 := vertices[i+1] 96 n := p1.X*(p2.Y-p3.Y) + p2.X*(p3.Y-p1.Y) + p3.X*(p1.Y-p2.Y) 97 if n < 0 { 98 inPolygon = false 99 break 100 } 101 } 102 if inPolygon && p1.isSkin { 103 skin = skin + 1 104 } 105 total = total + 1 106 } 107 return float64(skin) / float64(total) 108 } 109 110 func (r Region) averageIntensity() float64 { 111 var totalIntensity float64 112 for _, pixel := range r { 113 totalIntensity = totalIntensity + pixel.V 114 } 115 return totalIntensity / float64(len(r)) 116 } 117 118 type Regions []Region 119 120 func (r Regions) totalPixels() int { 121 var totalSkin int 122 for _, pixels := range r { 123 totalSkin += len(pixels) 124 } 125 return totalSkin 126 } 127 128 func (r Regions) averageIntensity() float64 { 129 var totalIntensity float64 130 for _, region := range r { 131 totalIntensity = totalIntensity + region.averageIntensity() 132 } 133 return totalIntensity / float64(len(r)) 134 } 135 136 // 137 // sort interface 138 // 139 140 func (r Regions) Len() int { 141 return len(r) 142 } 143 144 func (r Regions) Swap(i, j int) { 145 r[i], r[j] = r[j], r[i] 146 } 147 148 func (r Regions) Less(i, j int) bool { 149 return len(r[i]) < len(r[j]) 150 }