-
Notifications
You must be signed in to change notification settings - Fork 43
/
image.go
157 lines (142 loc) · 4.18 KB
/
image.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package Answer
import (
"fmt"
"image"
"image/draw"
"sync"
"github.com/henson/Answer/util"
"github.com/ngaut/log"
)
func saveImage(png image.Image, cfg *util.Config, c1 chan<- string, c2 chan<- string) error {
/* go func() {
screenshotPath := fmt.Sprintf("%sscreenshot.png", util.ImagePath)
err := util.SavePNG(screenshotPath, png)
if err != nil {
log.Errorf("保存截图失败,%v", err)
}
log.Debugf("保存完整截图成功,%s", screenshotPath)
}() */
//裁剪图片
questionImg, answerImg, err := splitImage(png, cfg)
if err != nil {
return fmt.Errorf("截图失败,%v", err)
}
var wg sync.WaitGroup
wg.Add(2)
go func() {
defer wg.Done()
pic := thresholdingImage(questionImg)
err = util.SavePNG(util.QuestionImage, pic)
if err != nil {
log.Errorf("保存question截图失败,%v", err)
}
c1 <- util.QuestionImage
log.Debugf("保存question截图成功")
}()
go func() {
defer wg.Done()
pic := thresholdingImage(answerImg)
err = util.SavePNG(util.AnswerImage, pic)
if err != nil {
log.Errorf("保存answer截图失败,%v", err)
}
c2 <- util.AnswerImage
log.Debugf("保存answer截图成功")
}()
wg.Wait()
return nil
}
//裁剪图片
func splitImage(src image.Image, cfg *util.Config) (questionImg image.Image, answerImg image.Image, err error) {
var qX, qY, qW, qH, aX, aY, aW, aH int
switch cfg.APP {
case "xigua":
qX, qY, qW, qH = cfg.XgQx, cfg.XgQy, cfg.XgQw, cfg.XgQh
aX, aY, aW, aH = cfg.XgAx, cfg.XgAy, cfg.XgAw, cfg.XgAh
case "cddh":
qX, qY, qW, qH = cfg.CdQx, cfg.CdQy, cfg.CdQw, cfg.CdQh
aX, aY, aW, aH = cfg.CdAx, cfg.CdAy, cfg.CdAw, cfg.CdAh
case "huajiao":
qX, qY, qW, qH = cfg.HjQx, cfg.HjQy, cfg.HjQw, cfg.HjQh
aX, aY, aW, aH = cfg.HjAx, cfg.HjAy, cfg.HjAw, cfg.HjAh
case "zscr":
qX, qY, qW, qH = cfg.ZsQx, cfg.ZsQy, cfg.ZsQw, cfg.ZsQh
aX, aY, aW, aH = cfg.ZsAx, cfg.ZsAy, cfg.ZsAw, cfg.ZsAh
}
questionImg, err = util.CutImage(src, qX, qY, qW, qH)
if err != nil {
return
}
answerImg, err = util.CutImage(src, aX, aY, aW, aH)
if err != nil {
return
}
return
}
//二值化图片
func thresholdingImage(img image.Image) image.Image {
size := img.Bounds()
pic := image.NewGray(size)
draw.Draw(pic, size, img, size.Min, draw.Src)
width := size.Dx()
height := size.Dy()
zft := make([]int, 256) //用于保存每个像素的数量,注意这里用了int类型,在某些图像上可能会溢出。
var idx int
for i := 0; i < width; i++ {
for j := 0; j < height; j++ {
idx = i*height + j
zft[pic.Pix[idx]]++ //image对像有一个Pix属性,它是一个slice,里面保存的是所有像素的数据。
}
}
fz := getOSTUThreshold(zft)
for i := 0; i < len(pic.Pix); i++ {
if int(pic.Pix[i]) > fz {
pic.Pix[i] = 255
} else {
pic.Pix[i] = 0
}
}
return pic
}
//getOSTUThreshold OSTU大律法 计算阀值
func getOSTUThreshold(HistGram []int) int {
var Y, Amount int
var PixelBack, PixelFore, PixelIntegralBack, PixelIntegralFore, PixelIntegral int
var OmegaBack, OmegaFore, MicroBack, MicroFore, SigmaB, Sigma float64 // 类间方差;
var MinValue, MaxValue int
var Threshold int
for MinValue = 0; MinValue < 256 && HistGram[MinValue] == 0; MinValue++ {
}
for MaxValue = 255; MaxValue > MinValue && HistGram[MinValue] == 0; MaxValue-- {
}
if MaxValue == MinValue {
return MaxValue // 图像中只有一个颜色
}
if MinValue+1 == MaxValue {
return MinValue // 图像中只有二个颜色
}
for Y = MinValue; Y <= MaxValue; Y++ {
Amount += HistGram[Y] // 像素总数
}
PixelIntegral = 0
for Y = MinValue; Y <= MaxValue; Y++ {
PixelIntegral += HistGram[Y] * Y
}
SigmaB = -1
for Y = MinValue; Y < MaxValue; Y++ {
PixelBack = PixelBack + HistGram[Y]
PixelFore = Amount - PixelBack
OmegaBack = float64(PixelBack) / float64(Amount)
OmegaFore = float64(PixelFore) / float64(Amount)
PixelIntegralBack += HistGram[Y] * Y
PixelIntegralFore = PixelIntegral - PixelIntegralBack
MicroBack = float64(PixelIntegralBack) / float64(PixelBack)
MicroFore = float64(PixelIntegralFore) / float64(PixelFore)
Sigma = OmegaBack * OmegaFore * (MicroBack - MicroFore) * (MicroBack - MicroFore)
if Sigma > SigmaB {
SigmaB = Sigma
Threshold = Y
}
}
return Threshold
}