-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathsaliency.go
195 lines (159 loc) · 5.41 KB
/
saliency.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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
package saliency
/*
* Computes the saliency mean factor based on Radhakrishna Achanta and and S. Suesstrunk
* salient detection algorithm published in "Saliency Detection using Maximum Symmetric Surround",
* Proceedings of IEEE International Conference on Image Processing (ICIP), 2010.
*
* This code is a simple scripted go implementation of the C++ code, published at
* http://ivrl.epfl.ch/page-75168-en.html
*
* Original code (c) 2010 Radhakrishna Achanta [EPFL]. All rights reserved.
* Go code (c) 2017 Sascha Kohlmann
*/
import (
lab "github.com/skohlmann/go-lab"
)
type SaliencyMap []float64
func gaussianSmooth(srcImg []float64, width int, height int, kernel []float64, ch chan<- []float64) {
smoothImg := make([]float64, len(srcImg))
tmpImg := make([]float64, len(srcImg))
center := len(kernel) / 2
rows := height
cols := width
// Blur in the x direction.
idx := 0
for r := 0; r < rows; r++ {
for c := 0; c < cols; c++ {
var kernelsum float64
var sum float64
for cc := (-center); cc <= center; cc++ {
if ((c + cc) >= 0) && ((c + cc) < cols) {
sum += srcImg[r * cols + (c + cc)] * kernel[center + cc]
kernelsum += kernel[center + cc]
}
}
tmpImg[idx] = sum / kernelsum
idx++
}
}
// Blur in the y direction.
idx = 0
for r := 0; r < rows; r++ {
for c := 0; c < cols; c++ {
var kernelsum float64
var sum float64
for rr := (-center); rr <= center; rr++ {
if ((r + rr) >= 0) && ((r + rr) < rows) {
sum += tmpImg[(r + rr) * cols + c] * kernel[center + rr]
kernelsum += kernel[center + rr]
}
}
smoothImg[idx] = sum / kernelsum;
idx++;
}
}
ch <- smoothImg
}
func createIntegralImage(srcImg []float64, width int, height int, ch chan<- [][]float64) {
intImg := make([][]float64, height)
for i := range intImg {
intImg[i] = make([]float64, width)
}
idx := 0
for j := 0; j < height; j++ {
var sumRow float64
for k := 0; k < width; k++ {
sumRow += srcImg[idx]
idx++
if 0 == j {
intImg[j][k] = sumRow
} else {
intImg[j][k] = intImg[j - 1][k] + sumRow
}
}
}
ch <- intImg
}
func getIntegralSum(intImg [][]float64, x1, y1, x2, y2 int) float64 {
var sum float64
if x1 - 1 < 0 && y1 - 1 < 0 {
sum = intImg[y2][x2]
} else if x1 - 1 < 0 {
sum = intImg[y2][x2] - intImg[y1 - 1][x2]
} else if y1 - 1 < 0 {
sum = intImg[y2][x2] - intImg[y2][x1 - 1]
} else {
sum = intImg[y2][x2] + intImg[y1 - 1][x1 - 1] - intImg[y1 - 1][x2] - intImg[y2][x1 - 1]
}
return sum
}
func normalize(salMap SaliencyMap) {
maxValue := 0.0
minValue := float64(1 << 30)
size := len(salMap)
for i := 0; i < size; i++ {
if maxValue < salMap[i] {
maxValue = salMap[i]
}
if minValue > salMap[i] {
minValue = salMap[i]
}
}
_range := maxValue - minValue
if _range <= 0 {panic("Range lower 0")}
for i := 0; i < size; i++ {
salMap[i] = ((255.0 * (salMap[i] - minValue)) / _range)
}
}
func max(a, b int) int {
if a <= b {
return b
}
return a
}
func min(a, b int) int {
if a <= b {
return a
}
return b
}
func MaximumSymmetricSurroundSaliency(source lab.LAB) SaliencyMap {
width := source.Stride()
height := len(source.L) / width
size := width * height
saliencyMap := make(SaliencyMap, size)
kernel := []float64{1.0, 2.0, 1.0}
chLs, chAs, chBs := make(chan []float64), make(chan []float64), make(chan []float64)
chLint, chAint, chBint := make(chan [][]float64), make(chan [][]float64), make(chan [][]float64)
go gaussianSmooth(source.L, width, height, kernel, chLs)
go gaussianSmooth(source.A, width, height, kernel, chAs)
go gaussianSmooth(source.B, width, height, kernel, chBs)
go createIntegralImage(source.L, width, height, chLint)
go createIntegralImage(source.A, width, height, chAint)
go createIntegralImage(source.B, width, height, chBint)
ls := <- chLs
as := <- chAs
bs := <- chBs
lint := <-chLint
aint := <-chAint
bint := <-chBint
index := 0
for j := 0; j < height; j++ {
yoff := min(j, height - j)
y1 := max(j - yoff, 0)
y2 := min(j + yoff, height - 1)
for k := 0; k < width; k++ {
xoff := min(k, width - k)
x1 := max(k - xoff, 0)
x2 := min(k + xoff, width - 1)
area := (x2 - x1 + 1) * (y2 - y1 + 1);
lval := getIntegralSum(lint, x1, y1, x2, y2) / float64(area)
aval := getIntegralSum(aint, x1, y1, x2, y2) / float64(area)
bval := getIntegralSum(bint, x1, y1, x2, y2) / float64(area)
saliencyMap[index] = (lval - ls[index]) * (lval - ls[index]) + (aval - as[index]) * (aval - as[index]) + (bval - bs[index]) * (bval - bs[index]); //square of the euclidean distance
index++
}
}
normalize(saliencyMap)
return saliencyMap
}