Spaces:
No application file
No application file
Upload folder using huggingface_hub
Browse files- .gitattributes +1 -0
- morph/README.md +35 -0
- morph/citedsources.txt +13 -0
- morph/faceMorph.py +120 -0
- morph/points.py +44 -0
- morph/shape_predictor_68_face_landmarks.dat +3 -0
- morph/tri.txt +149 -0
- morph/triangles.py +126 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
morph/shape_predictor_68_face_landmarks.dat filter=lfs diff=lfs merge=lfs -text
|
morph/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Project Name: Morph It
|
2 |
+
|
3 |
+
Name of team members: Sovreign-Ariel McCarthy, Santiago Bruno, Yazmin Hernandez
|
4 |
+
Class: CST-205
|
5 |
+
Date: 3/15/2017
|
6 |
+
Link to GitHub repo: https://github.com/CSUMB-SP17-CST205/project2-Team25
|
7 |
+
Link to C9: https://ide.c9.io/yazminrh/yazminruby
|
8 |
+
Your TA: Samuel
|
9 |
+
|
10 |
+
Explanation of your project: A user can input two images in order to morph them together as one image.
|
11 |
+
|
12 |
+
What did you plan to accomplish? We hoped the program would be similar to what it currently does, but a bit more user friendly,
|
13 |
+
in that they wouldn't need to change the name of their image.
|
14 |
+
|
15 |
+
Where could you envision this project going? If you had more time, what would you have done?
|
16 |
+
In the future we would like to implement a website that anyone could access and find by simply typing in "morph" as a keyword.
|
17 |
+
|
18 |
+
Description of how to use the application:
|
19 |
+
|
20 |
+
Use images within a similar size to 600x800
|
21 |
+
|
22 |
+
Step 1:
|
23 |
+
Import image into the morph folder
|
24 |
+
|
25 |
+
Step 2:
|
26 |
+
Go to the file named "points.py" go to line 37 and enter the name of the desired image.
|
27 |
+
Do this for both images.
|
28 |
+
|
29 |
+
Step 3:
|
30 |
+
Go to the file named "faceMorph.py", go to line 73 and 74. Change those image names
|
31 |
+
|
32 |
+
|
33 |
+
|
34 |
+
Step 4
|
35 |
+
Go to faceMorph.py on line, 73 & 74, change the image names to your image name of the two pictures you are using. Run it.
|
morph/citedsources.txt
ADDED
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
facemorph.py - Satya Mallick
|
2 |
+
http://www.learnopencv.com/face-morph-using-opencv-cpp-python/
|
3 |
+
|
4 |
+
triangles.py - Satya Mallick
|
5 |
+
https://github.com/spmallick/learnopencv/blob/master/Delaunay/delaunay.py
|
6 |
+
|
7 |
+
Landmark detectin / points.py
|
8 |
+
http://stackoverflow.com/questions/39793680/how-to-get-points-coordinate-position-in-the-face-landmark-detection-program-of
|
9 |
+
|
10 |
+
used dlib - c++ library
|
11 |
+
|
12 |
+
used skimage
|
13 |
+
|
morph/faceMorph.py
ADDED
@@ -0,0 +1,120 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/env python
|
2 |
+
import numpy as np
|
3 |
+
import cv2
|
4 |
+
import sys
|
5 |
+
|
6 |
+
# Read points from text file
|
7 |
+
def readPoints(path) :
|
8 |
+
# Create an array of points.
|
9 |
+
points = [];
|
10 |
+
# Read points
|
11 |
+
with open(path) as file :
|
12 |
+
for line in file :
|
13 |
+
x, y = line.split()
|
14 |
+
points.append((int(x), int(y)))
|
15 |
+
|
16 |
+
return points
|
17 |
+
|
18 |
+
# Apply affine transform calculated using srcTri and dstTri to src and
|
19 |
+
# output an image of size.
|
20 |
+
def applyAffineTransform(src, srcTri, dstTri, size) :
|
21 |
+
|
22 |
+
# Given a pair of triangles, find the affine transform.
|
23 |
+
warpMat = cv2.getAffineTransform( np.float32(srcTri), np.float32(dstTri) )
|
24 |
+
|
25 |
+
# Apply the Affine Transform just found to the src image
|
26 |
+
dst = cv2.warpAffine( src, warpMat, (size[0], size[1]), None, flags=cv2.INTER_LINEAR, borderMode=cv2.BORDER_REFLECT_101 )
|
27 |
+
|
28 |
+
return dst
|
29 |
+
|
30 |
+
|
31 |
+
# Warps and alpha blends triangular regions from img1 and img2 to img
|
32 |
+
def morphTriangle(img1, img2, img, t1, t2, t, alpha) :
|
33 |
+
|
34 |
+
# Find bounding rectangle for each triangle
|
35 |
+
r1 = cv2.boundingRect(np.float32([t1]))
|
36 |
+
r2 = cv2.boundingRect(np.float32([t2]))
|
37 |
+
r = cv2.boundingRect(np.float32([t]))
|
38 |
+
|
39 |
+
|
40 |
+
# Offset points by left top corner of the respective rectangles
|
41 |
+
t1Rect = []
|
42 |
+
t2Rect = []
|
43 |
+
tRect = []
|
44 |
+
|
45 |
+
|
46 |
+
for i in xrange(0, 3):
|
47 |
+
tRect.append(((t[i][0] - r[0]),(t[i][1] - r[1])))
|
48 |
+
t1Rect.append(((t1[i][0] - r1[0]),(t1[i][1] - r1[1])))
|
49 |
+
t2Rect.append(((t2[i][0] - r2[0]),(t2[i][1] - r2[1])))
|
50 |
+
|
51 |
+
|
52 |
+
# Get mask by filling triangle
|
53 |
+
mask = np.zeros((r[3], r[2], 3), dtype = np.float32)
|
54 |
+
cv2.fillConvexPoly(mask, np.int32(tRect), (1.0, 1.0, 1.0), 16, 0);
|
55 |
+
|
56 |
+
# Apply warpImage to small rectangular patches
|
57 |
+
img1Rect = img1[r1[1]:r1[1] + r1[3], r1[0]:r1[0] + r1[2]]
|
58 |
+
img2Rect = img2[r2[1]:r2[1] + r2[3], r2[0]:r2[0] + r2[2]]
|
59 |
+
|
60 |
+
size = (r[2], r[3])
|
61 |
+
warpImage1 = applyAffineTransform(img1Rect, t1Rect, tRect, size)
|
62 |
+
warpImage2 = applyAffineTransform(img2Rect, t2Rect, tRect, size)
|
63 |
+
|
64 |
+
# Alpha blend rectangular patches
|
65 |
+
imgRect = (1.0 - alpha) * warpImage1 + alpha * warpImage2
|
66 |
+
|
67 |
+
# Copy triangular region of the rectangular patch to the output image
|
68 |
+
img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] = img[r[1]:r[1]+r[3], r[0]:r[0]+r[2]] * ( 1 - mask ) + imgRect * mask
|
69 |
+
|
70 |
+
|
71 |
+
if __name__ == '__main__' :
|
72 |
+
|
73 |
+
filename1 = 'hillary_clinton.jpg'
|
74 |
+
filename2 = 'ted_cruz.jpg'
|
75 |
+
alpha = 0.5
|
76 |
+
|
77 |
+
# Read images
|
78 |
+
img1 = cv2.imread(filename1);
|
79 |
+
img2 = cv2.imread(filename2);
|
80 |
+
|
81 |
+
# Convert Mat to float data type
|
82 |
+
img1 = np.float32(img1)
|
83 |
+
img2 = np.float32(img2)
|
84 |
+
|
85 |
+
# Read array of corresponding points
|
86 |
+
points1 = readPoints('coordinates1.txt')
|
87 |
+
points2 = readPoints('coordinates2.txt')
|
88 |
+
points = [];
|
89 |
+
|
90 |
+
# Compute weighted average point coordinates
|
91 |
+
for i in xrange(0, len(points1)):
|
92 |
+
x = ( 1 - alpha ) * points1[i][0] + alpha * points2[i][0]
|
93 |
+
y = ( 1 - alpha ) * points1[i][1] + alpha * points2[i][1]
|
94 |
+
points.append((x,y))
|
95 |
+
|
96 |
+
|
97 |
+
# Allocate space for final output
|
98 |
+
imgMorph = np.zeros(img1.shape, dtype = img1.dtype)
|
99 |
+
|
100 |
+
# Read triangles from tri.txt
|
101 |
+
with open("tri.txt") as file :
|
102 |
+
for line in file :
|
103 |
+
x,y,z = line.split()
|
104 |
+
|
105 |
+
x = int(x)
|
106 |
+
y = int(y)
|
107 |
+
z = int(z)
|
108 |
+
|
109 |
+
t1 = [points1[x], points1[y], points1[z]]
|
110 |
+
t2 = [points2[x], points2[y], points2[z]]
|
111 |
+
t = [points[x], points[y], points[z]]
|
112 |
+
|
113 |
+
# Morph one triangle at a time.
|
114 |
+
morphTriangle(img1, img2, imgMorph, t1, t2, t, alpha)
|
115 |
+
|
116 |
+
|
117 |
+
# Display Result
|
118 |
+
#cv2.imshow("Morphed Face", np.uint8(imgMorph))
|
119 |
+
cv2.imwrite('Morphed.jpg',imgMorph)
|
120 |
+
cv2.waitKey(0)
|
morph/points.py
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import dlib
|
2 |
+
import numpy as np
|
3 |
+
from skimage import io
|
4 |
+
import random as r #imported to make the file name randomized
|
5 |
+
|
6 |
+
|
7 |
+
class GetPoints: #class container so that code can be reused easily, and is modular
|
8 |
+
def __init__(self, image):
|
9 |
+
self.predictor_path = "shape_predictor_68_face_landmarks.dat"
|
10 |
+
|
11 |
+
self.detector = dlib.get_frontal_face_detector()
|
12 |
+
self.predictor = dlib.shape_predictor(self.predictor_path)
|
13 |
+
|
14 |
+
self.img = io.imread(image)
|
15 |
+
|
16 |
+
self.dets = self.detector(self.img)
|
17 |
+
|
18 |
+
def get_coors(self):
|
19 |
+
save_coordinates = open(str(r.randint(0,100)) + 'coordinates.txt', 'a') #randint changes the name of the text file
|
20 |
+
|
21 |
+
for k, d in enumerate(self.dets):
|
22 |
+
shape = self.predictor(self.img, d)
|
23 |
+
|
24 |
+
vec = np.empty([68, 2], dtype = int)
|
25 |
+
|
26 |
+
for b in range(68): #gets the coordinates of the picture passed in
|
27 |
+
vec[b][0] = shape.part(b).x
|
28 |
+
vec[b][1] = shape.part(b).y
|
29 |
+
save_coordinates.write(str(vec[b][0]) + " "+ str(vec[b][1]) + "\n") #adds them to the randomized text file
|
30 |
+
|
31 |
+
extra_points = ['514 360', '294 676', '0 680', '599 588', '0 0', '0 400', '0 799', '300 799',
|
32 |
+
'599 799', '599 400', '599 0' , '300 0']
|
33 |
+
|
34 |
+
for i in range(len(extra_points)): #this accesses the array of extra points and writes them into the text file
|
35 |
+
save_coordinates.write(extra_points[i] + "\n")
|
36 |
+
|
37 |
+
save_coordinates.close() #this closes the picture
|
38 |
+
|
39 |
+
name = "ted_cruz" #this will have to be gotten from the user instead of hardcoding
|
40 |
+
image = name + ".jpg"
|
41 |
+
|
42 |
+
x = GetPoints(image) #pass the file name into the class to be converted into a text file
|
43 |
+
x.get_coors() #this calls the object so that files can be used appropriately
|
44 |
+
|
morph/shape_predictor_68_face_landmarks.dat
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:fbdc2cb80eb9aa7a758672cbfdda32ba6300efe9b6e6c7a299ff7e736b11b92f
|
3 |
+
size 99693937
|
morph/tri.txt
ADDED
@@ -0,0 +1,149 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
38 40 37
|
2 |
+
35 30 29
|
3 |
+
38 37 20
|
4 |
+
18 37 36
|
5 |
+
33 32 30
|
6 |
+
54 64 53
|
7 |
+
30 32 31
|
8 |
+
59 48 60
|
9 |
+
19 79 20
|
10 |
+
40 31 41
|
11 |
+
36 37 41
|
12 |
+
21 39 38
|
13 |
+
35 34 30
|
14 |
+
51 33 52
|
15 |
+
40 29 31
|
16 |
+
57 58 66
|
17 |
+
36 17 18
|
18 |
+
35 52 34
|
19 |
+
2 73 1
|
20 |
+
65 66 62
|
21 |
+
58 67 66
|
22 |
+
53 63 52
|
23 |
+
61 67 49
|
24 |
+
53 65 63
|
25 |
+
56 66 65
|
26 |
+
55 10 9
|
27 |
+
4 73 3
|
28 |
+
64 54 55
|
29 |
+
69 74 70
|
30 |
+
25 79 78
|
31 |
+
18 17 72
|
32 |
+
43 42 22
|
33 |
+
23 79 24
|
34 |
+
46 54 35
|
35 |
+
14 68 13
|
36 |
+
16 26 78
|
37 |
+
0 73 17
|
38 |
+
1 0 36
|
39 |
+
73 72 17
|
40 |
+
79 19 72
|
41 |
+
19 37 18
|
42 |
+
1 36 41
|
43 |
+
0 17 36
|
44 |
+
37 19 20
|
45 |
+
18 72 19
|
46 |
+
21 38 20
|
47 |
+
39 40 38
|
48 |
+
79 23 20
|
49 |
+
28 29 39
|
50 |
+
41 31 2
|
51 |
+
59 67 58
|
52 |
+
29 30 31
|
53 |
+
34 33 30
|
54 |
+
21 27 39
|
55 |
+
28 42 29
|
56 |
+
52 33 34
|
57 |
+
62 66 67
|
58 |
+
3 73 2
|
59 |
+
48 4 3
|
60 |
+
73 0 1
|
61 |
+
41 2 1
|
62 |
+
31 3 2
|
63 |
+
37 40 41
|
64 |
+
39 29 40
|
65 |
+
57 7 58
|
66 |
+
31 48 3
|
67 |
+
5 4 48
|
68 |
+
70 73 4
|
69 |
+
32 49 31
|
70 |
+
60 49 59
|
71 |
+
7 69 6
|
72 |
+
10 75 9
|
73 |
+
59 5 48
|
74 |
+
70 4 5
|
75 |
+
7 6 58
|
76 |
+
70 5 6
|
77 |
+
31 49 48
|
78 |
+
49 67 59
|
79 |
+
6 59 58
|
80 |
+
6 5 59
|
81 |
+
8 7 57
|
82 |
+
69 70 6
|
83 |
+
12 71 11
|
84 |
+
75 74 69
|
85 |
+
48 49 60
|
86 |
+
32 33 50
|
87 |
+
49 50 61
|
88 |
+
49 32 50
|
89 |
+
51 61 50
|
90 |
+
62 67 61
|
91 |
+
33 51 50
|
92 |
+
63 65 62
|
93 |
+
51 62 61
|
94 |
+
51 52 63
|
95 |
+
51 63 62
|
96 |
+
52 35 53
|
97 |
+
47 46 35
|
98 |
+
54 10 55
|
99 |
+
56 57 66
|
100 |
+
56 8 57
|
101 |
+
69 8 9
|
102 |
+
69 7 8
|
103 |
+
53 55 65
|
104 |
+
9 8 56
|
105 |
+
9 75 69
|
106 |
+
56 55 9
|
107 |
+
11 71 10
|
108 |
+
77 71 13
|
109 |
+
13 71 12
|
110 |
+
10 76 75
|
111 |
+
10 71 76
|
112 |
+
65 55 56
|
113 |
+
10 54 11
|
114 |
+
53 64 55
|
115 |
+
53 35 54
|
116 |
+
12 54 13
|
117 |
+
12 11 54
|
118 |
+
54 14 13
|
119 |
+
68 77 13
|
120 |
+
35 42 47
|
121 |
+
16 77 68
|
122 |
+
45 16 15
|
123 |
+
26 25 78
|
124 |
+
15 68 14
|
125 |
+
15 16 68
|
126 |
+
22 42 27
|
127 |
+
42 35 29
|
128 |
+
27 42 28
|
129 |
+
44 25 45
|
130 |
+
44 47 43
|
131 |
+
46 14 54
|
132 |
+
45 46 44
|
133 |
+
45 14 46
|
134 |
+
39 27 28
|
135 |
+
22 23 43
|
136 |
+
21 22 27
|
137 |
+
21 20 23
|
138 |
+
43 23 24
|
139 |
+
22 21 23
|
140 |
+
44 43 24
|
141 |
+
47 42 43
|
142 |
+
25 44 24
|
143 |
+
46 47 44
|
144 |
+
16 45 26
|
145 |
+
15 14 45
|
146 |
+
45 25 26
|
147 |
+
24 79 25
|
148 |
+
77 78 71
|
149 |
+
77 16 78
|
morph/triangles.py
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#!/usr/bin/python
|
2 |
+
|
3 |
+
import cv2
|
4 |
+
import numpy as np
|
5 |
+
import random
|
6 |
+
|
7 |
+
# Check if a point is inside a rectangle
|
8 |
+
def rect_contains(rect, point) :
|
9 |
+
if point[0] < rect[0] :
|
10 |
+
return False
|
11 |
+
elif point[1] < rect[1] :
|
12 |
+
return False
|
13 |
+
elif point[0] > rect[2] :
|
14 |
+
return False
|
15 |
+
elif point[1] > rect[3] :
|
16 |
+
return False
|
17 |
+
return True
|
18 |
+
|
19 |
+
# Draw a point
|
20 |
+
def draw_point(img, p, color ) :
|
21 |
+
cv2.circle( img, p, 2, color, cv2.cv.CV_FILLED, cv2.CV_AA, 0 )
|
22 |
+
|
23 |
+
|
24 |
+
# Draw delaunay triangles
|
25 |
+
def draw_delaunay(img, subdiv, delaunay_color ) :
|
26 |
+
|
27 |
+
triangleList = subdiv.getTriangleList();
|
28 |
+
size = img.shape
|
29 |
+
r = (0, 0, size[1], size[0])
|
30 |
+
|
31 |
+
for t in triangleList :
|
32 |
+
|
33 |
+
pt1 = (t[0], t[1])
|
34 |
+
pt2 = (t[2], t[3])
|
35 |
+
pt3 = (t[4], t[5])
|
36 |
+
|
37 |
+
if rect_contains(r, pt1) and rect_contains(r, pt2) and rect_contains(r, pt3) :
|
38 |
+
|
39 |
+
cv2.line(img, pt1, pt2, delaunay_color, 1, cv2.CV_AA, 0)
|
40 |
+
cv2.line(img, pt2, pt3, delaunay_color, 1, cv2.CV_AA, 0)
|
41 |
+
cv2.line(img, pt3, pt1, delaunay_color, 1, cv2.CV_AA, 0)
|
42 |
+
|
43 |
+
|
44 |
+
# Draw voronoi diagram
|
45 |
+
def draw_voronoi(img, subdiv) :
|
46 |
+
|
47 |
+
( facets, centers) = subdiv.getVoronoiFacetList([])
|
48 |
+
|
49 |
+
for i in xrange(0,len(facets)) :
|
50 |
+
ifacet_arr = []
|
51 |
+
for f in facets[i] :
|
52 |
+
ifacet_arr.append(f)
|
53 |
+
|
54 |
+
ifacet = np.array(ifacet_arr, np.int)
|
55 |
+
color = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
|
56 |
+
|
57 |
+
cv2.fillConvexPoly(img, ifacet, color, cv2.CV_AA, 0);
|
58 |
+
ifacets = np.array([ifacet])
|
59 |
+
cv2.polylines(img, ifacets, True, (0, 0, 0), 1, cv2.CV_AA, 0)
|
60 |
+
cv2.circle(img, (centers[i][0], centers[i][1]), 3, (0, 0, 0), cv2.cv.CV_FILLED, cv2.CV_AA, 0)
|
61 |
+
|
62 |
+
|
63 |
+
if __name__ == '__main__':
|
64 |
+
|
65 |
+
# Define window names
|
66 |
+
win_delaunay = "Delaunay Triangulation"
|
67 |
+
win_voronoi = "Voronoi Diagram"
|
68 |
+
|
69 |
+
# Turn on animation while drawing triangles
|
70 |
+
animate = True
|
71 |
+
|
72 |
+
# Define colors for drawing.
|
73 |
+
delaunay_color = (255,255,255)
|
74 |
+
points_color = (0, 0, 255)
|
75 |
+
|
76 |
+
# Read in the image.
|
77 |
+
img = cv2.imread("d.jpg");
|
78 |
+
|
79 |
+
# Keep a copy around
|
80 |
+
img_orig = img.copy();
|
81 |
+
|
82 |
+
# Rectangle to be used with Subdiv2D
|
83 |
+
size = img.shape
|
84 |
+
rect = (0, 0, size[1], size[0])
|
85 |
+
|
86 |
+
# Create an instance of Subdiv2D
|
87 |
+
subdiv = cv2.Subdiv2D(rect);
|
88 |
+
|
89 |
+
# Create an array of points.
|
90 |
+
points = [];
|
91 |
+
|
92 |
+
# Read in the points from a text file
|
93 |
+
with open("d.jpg.txt") as file :
|
94 |
+
for line in file :
|
95 |
+
x, y = line.split()
|
96 |
+
points.append((int(x), int(y)))
|
97 |
+
|
98 |
+
# Insert points into subdiv
|
99 |
+
for p in points :
|
100 |
+
subdiv.insert(p)
|
101 |
+
|
102 |
+
# Show animation
|
103 |
+
if animate :
|
104 |
+
img_copy = img_orig.copy()
|
105 |
+
# Draw delaunay triangles
|
106 |
+
draw_delaunay( img_copy, subdiv, (255, 255, 255) );
|
107 |
+
cv2.imwrite("win_delaunay1.jpg", img_copy)
|
108 |
+
cv2.waitKey(100)
|
109 |
+
|
110 |
+
# Draw delaunay triangles
|
111 |
+
draw_delaunay( img, subdiv, (255, 255, 255) );
|
112 |
+
|
113 |
+
# Draw points
|
114 |
+
for p in points :
|
115 |
+
draw_point(img, p, (0,0,255))
|
116 |
+
|
117 |
+
# Allocate space for Voronoi Diagram
|
118 |
+
img_voronoi = np.zeros(img.shape, dtype = img.dtype)
|
119 |
+
|
120 |
+
# Draw Voronoi diagram
|
121 |
+
draw_voronoi(img_voronoi,subdiv)
|
122 |
+
|
123 |
+
# Show results
|
124 |
+
cv2.imwrite("win_delaunay.jpg",img)
|
125 |
+
cv2.imwrite("win_voronoi.jpg",img_voronoi)
|
126 |
+
cv2.waitKey(0)
|