-
Notifications
You must be signed in to change notification settings - Fork 157
/
Copy pathMorphoFeatures.scala
140 lines (111 loc) · 3.15 KB
/
MorphoFeatures.scala
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
/*
* Copyright (c) 2011-2019 Jarek Sacha. All Rights Reserved.
*
* Author's e-mail: jpsacha at gmail.com
*/
package opencv_cookbook.chapter05
import java.awt.geom.Ellipse2D
import java.awt.{Color, Graphics2D, Image}
import opencv_cookbook.OpenCVUtils._
import org.bytedeco.javacpp.BytePointer
import org.bytedeco.opencv.global.opencv_core._
import org.bytedeco.opencv.global.opencv_imgproc._
import org.bytedeco.opencv.opencv_core._
/**
* Equivalent of C++ class MorphoFeatures presented in section "Detecting edges and filters using
* morphological filters". Contains methods for morphological corner detection.
*/
class MorphoFeatures {
// Threshold to produce binary image
var thresholdValue: Int = -1
// Structural elements used in corner detection
private val cross = new Mat(5, 5, CV_8U,
new BytePointer(
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
1, 1, 1, 1, 1,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0
)
)
private val diamond = new Mat(5, 5, CV_8U,
new BytePointer(
0, 0, 1, 0, 0,
0, 1, 1, 1, 0,
1, 1, 1, 1, 1,
0, 1, 1, 1, 0,
0, 0, 1, 0, 0
)
)
private val square = new Mat(5, 5, CV_8U,
new BytePointer(
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1,
1, 1, 1, 1, 1
)
)
private val x = new Mat(5, 5, CV_8U,
new BytePointer(
1, 0, 0, 0, 1,
0, 1, 0, 1, 0,
0, 0, 1, 0, 0,
0, 1, 0, 1, 0,
1, 0, 0, 0, 1
)
)
def getEdges(image: Mat): Mat = {
// Get gradient image
val result = new Mat()
morphologyEx(image, result, MORPH_GRADIENT, new Mat())
// Apply threshold to obtain a binary image
applyThreshold(result)
result
}
def getCorners(image: Mat): Mat = {
val result = new Mat()
// Dilate with a cross
dilate(image, result, cross)
// Erode with a diamond
erode(result, result, diamond)
val result2 = new Mat()
// Dilate with X
dilate(image, result2, x)
// Erode with a square
erode(result2, result2, square)
// Corners are obtained by differentiating the two closed images
absdiff(result2, result, result)
// Apply threshold to get binary image
applyThreshold(result)
result
}
private def applyThreshold(image: Mat): Unit = {
if (thresholdValue > 0) {
threshold(image, image, thresholdValue, 255, THRESH_BINARY_INV)
}
}
/**
* Draw circles at feature point locations on an image it assumes that images are of the same size.
*/
def drawOnImage(binary: Mat, image: Mat): Image = {
// OpenCV drawing seems to crash a lot, so use Java2D
val binaryRaster = toBufferedImage(binary).getData
val radius = 6
val diameter = radius * 2
val imageBI = toBufferedImage(image)
val width = imageBI.getWidth
val height = imageBI.getHeight
val g2d = imageBI.getGraphics.asInstanceOf[Graphics2D]
g2d.setColor(Color.WHITE)
for (y <- 0 until height) {
for (x <- 0 until width) {
val v = binaryRaster.getSample(x, y, 0)
if (v == 0) {
g2d.draw(new Ellipse2D.Double(x - radius, y - radius, diameter, diameter))
}
}
}
imageBI
}
}