Skip to content

Commit e15078a

Browse files
committed
renamed
1 parent 1d3b949 commit e15078a

File tree

1 file changed

+366
-0
lines changed

1 file changed

+366
-0
lines changed

BlimpDetect.py

Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
#!/usr/bin/python
2+
3+
# import system modules
4+
import cv2.cv as cv
5+
import urllib
6+
import numpy as np
7+
from numpy import linalg as LA
8+
9+
import socket
10+
import time
11+
import os
12+
13+
global imghsv
14+
15+
# purpose: using HSV thresholds, detects blue, yellow and purple objects in a video stream in three new windows
16+
# 1) a black/white stream showing objects matching threshold values (window "threshold")
17+
# 2) a black/color stream tracking the locations of the objects in their respective colors (window "final")
18+
# 3) a full-color stream showing the original video and the bounding boxes of detected objects (window "real")
19+
20+
# things that would make this script more useful for future tests:
21+
# 1) GUI HSV threshold and minimum pixel size sliders like Kevin has added to the Canny Edge Detection program
22+
# 2) Limit the number of blue/yellow/purple objects that can be detected at one time to one
23+
24+
# source from:
25+
# http://stackoverflow.com/questions/8152504/tracking-two-different-colors-using-opencv-2-3-and-python
26+
27+
# definitely works with Mac OSX, Python 2.7, and OpenCV library
28+
29+
# to modify color thresholds, change the cv.Scalar values in the InRange method in the gettresholdedimg function below
30+
31+
def connect(ip,port):
32+
#make a client socket
33+
34+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
35+
s.settimeout(1)
36+
#keep trying to connect to the server until success
37+
print("connecting to control server...")
38+
print("")
39+
connected = False
40+
#while not connected:
41+
try:
42+
s.connect((ip, port))
43+
connected = True
44+
except Exception as err:
45+
pass
46+
#print("connected")
47+
return s
48+
49+
#---------------------------------------------------------
50+
#The following function takes coordinates from the images and convertes them to 3D spatial positions
51+
#The calibration constants are in R1, T1, R2, and T2 for cameras 1 (west) and 2 (east)
52+
#These constants are produced by matlab code that is available here:
53+
#http://www.vision.caltech.edu/bouguetj/calib_doc/
54+
def triang_3D(col_1, row_1, col_2, row_2) :
55+
56+
#Corrected camera matrix for west side
57+
P1 = np.array([[408.4918, -1607.7562, 3814.1879, 490234.8756], [-1793.2995, -707.4668, -45.8775, 646489.5760], [0.1810, -0.9505, -0.2524, 1285.5524]])
58+
59+
#Corrected camera matrix for east side
60+
P2 = np.array([[-49.3179, -518.1547, -4126.6037, 847220.0489], [-1776.8193, 738.4249, -127.1965, 963513.3797], [0.2075, 0.9387, -0.2753, 1589.9759]])
61+
62+
#blimp position from camera 1
63+
#col_1 = 396
64+
#row_1 = 424
65+
#m1 = np.array([
66+
#blimp position from camera 2
67+
#col_2 = 518
68+
#row_2 = 538
69+
70+
71+
#translated from matlab:
72+
73+
#Camera 1
74+
invR1 = LA.inv(P1[0:3,0:3])
75+
m1T1 = -1*P1[:,3]
76+
C1 = np.dot(invR1, m1T1)
77+
x0 = C1[0]
78+
y0 = C1[1]
79+
z0 = C1[2]
80+
m1 = np.array([[col_1], [row_1], [1]]);
81+
M1 = np.dot(LA.pinv(P1), m1)
82+
x = M1[0]/M1[3]
83+
y = M1[1]/M1[3]
84+
z = M1[2]/M1[3]
85+
v1L = np.array([x0, y0, z0])
86+
v2L = np.array([x, y, z])
87+
a = x-x0
88+
b = y-y0
89+
c = z-z0
90+
91+
#Camera 2
92+
invR2 = LA.inv(P2[0:3,0:3])
93+
m1T2 = -1*P2[:,3]
94+
C2 = np.dot(invR2, m1T2)
95+
x1 = C2[0]
96+
y1 = C2[1]
97+
z1 = C2[2]
98+
m2 = np.array([[col_2], [row_2], [1]]);
99+
M2 = np.dot(LA.pinv(P2), m2)
100+
x = M2[0]/M2[3]
101+
y = M2[1]/M2[3]
102+
z = M2[2]/M2[3]
103+
v1R = np.array([x1, y1, z1])
104+
v2R = np.array([x, y, z])
105+
d = x-x1
106+
e = y-y1
107+
f = z-z1
108+
109+
A11 = (a*a + b*b + c*c)
110+
A12 = -1*(a*d + e*b + f*c)
111+
A21 = -1*(a*d + e*b + f*c)
112+
A22 = d*d + e*e + f*f
113+
A = np.array([[A11, A12], [A21, A22]])
114+
A = np.squeeze(A) #get rid of 3rd dimension
115+
v = np.array([[(x1-x0)*a + (y1-y0)*b + (z1-z0)*c], [(x0-x1)*d + (y0-y1)*e + (z0-z1)*f]])
116+
v = np.squeeze(v) #get rid of 3rd dimension
117+
invA = LA.inv(A)
118+
r = np.dot(invA,v)
119+
x_coord = x0+a*r[0]
120+
y_coord = y0+b*r[0]
121+
z_coord = z0+c*r[0]
122+
M = np.array([x_coord, y_coord, z_coord])
123+
124+
#compute distance to each ray from the estimated 3D location
125+
v1L = v1L.transpose()
126+
v2L = v2L.transpose()
127+
v1R = v1R.transpose()
128+
v2R = v2R.transpose()
129+
130+
d1 = LA.norm(np.cross(np.subtract(v1L, v2L),np.subtract(M.transpose(),v2L)))/LA.norm(np.subtract(v1L,v2L))
131+
d2 = LA.norm(np.cross(np.subtract(v1R, v2R),np.subtract(M.transpose(),v2R)))/LA.norm(np.subtract(v1R,v2R))
132+
err1 = d1 + d2;
133+
134+
#project the estimated 3D position onto image, then find distance from original position
135+
m1rn = np.dot(P1,np.vstack((M,[1])))
136+
m2rn = np.dot(P2,np.vstack((M,[1])))
137+
m1r = m1rn/m1rn[2]
138+
m2r = m2rn/m2rn[2]
139+
err2 = np.sqrt(np.sum(np.square(m1r[0:2]-m1[0:2]))) + np.sqrt(np.sum(np.square(m2r[0:2]-m2[0:2])))
140+
141+
142+
return (x_coord[0], y_coord[0], z_coord[0], err1, err2)
143+
144+
#---------------------------------------------------------
145+
def getthresholdedimg(im):
146+
147+
# this function take RGB image.Then convert it into HSV for easy colour detection
148+
# and threshold it with yellow and blue part as white and all other regions as black.Then return that image
149+
150+
global imghsv
151+
imghsv = cv.CreateImage(cv.GetSize(im),8,3)
152+
153+
# Convert image from RGB to HSV
154+
cv.CvtColor(im,imghsv,cv.CV_BGR2HSV)
155+
156+
# creates images for blue
157+
imgblue = cv.CreateImage(cv.GetSize(im),8,1)
158+
159+
# creates blank image to which color images are added
160+
imgthreshold = cv.CreateImage(cv.GetSize(im),8,1)
161+
162+
# determine HSV color thresholds for yellow, blue, and green
163+
# cv.InRange(src, lowerbound, upperbound, dst)
164+
# for imgblue, lowerbound is 95, and upperbound is 115
165+
cv.InRangeS(imghsv, cv.Scalar(55,110,110), cv.Scalar(155,255,255), imgblue )
166+
167+
# add color thresholds to blank 'threshold' image
168+
cv.Add(imgthreshold, imgblue, imgthreshold)
169+
170+
#return imgthreshold
171+
return imgblue
172+
#---------------------------------------------------------
173+
#img is an image (passed in by reference)
174+
#sideName is for output printing purposes
175+
#this returns an x and y coordinate of the blimp (x = col, y = row)
176+
def procImg(img,sideName,dispFlag):
177+
178+
#creates empty images of the same size
179+
imdraw = cv.CreateImage(cv.GetSize(img), 8, 3)
180+
#put the smoothed image here
181+
imgSmooth = cv.CreateImage(cv.GetSize(img), 8, 3)
182+
#put thresholded image here
183+
imgMask = cv.CreateImage(cv.GetSize(img), 8, 1)
184+
185+
cv.SetZero(imdraw)
186+
cv.Smooth(img, imgSmooth, cv.CV_GAUSSIAN, 3, 0) #Gaussian filter the image
187+
imgbluethresh = getthresholdedimg(img) #Get a color thresholed binary image
188+
imgMask = imgbluethresh
189+
cv.Erode(imgbluethresh, imgbluethresh, None, 3)
190+
cv.Dilate(imgbluethresh, imgbluethresh, None, 10)
191+
#img2 = cv.CloneImage(imgbluethresh)
192+
storage = cv.CreateMemStorage(0)
193+
contour = cv.FindContours(imgbluethresh, storage, cv.CV_RETR_CCOMP, cv.CV_CHAIN_APPROX_SIMPLE)
194+
195+
centroidx = 0
196+
centroidy = 0
197+
prevArea = 0
198+
pt1 = (0, 0)
199+
pt2 = (0, 0)
200+
201+
while contour:
202+
#find the area of each collection of contiguous points (contour)
203+
bound_rect = cv.BoundingRect(list(contour))
204+
contour = contour.h_next()
205+
206+
#get the largest contour
207+
area = bound_rect[2]*bound_rect[3];
208+
209+
#if dispFlag:
210+
# print("Area= " + str(area))
211+
212+
if (area > prevArea and area > 3000):
213+
pt1 = (bound_rect[0], bound_rect[1])
214+
pt2 = (bound_rect[0] + bound_rect[2], bound_rect[1] + bound_rect[3])
215+
216+
# Draw bounding rectangle
217+
cv.Rectangle(img, pt1, pt2, cv.CV_RGB(255,0,0), 3)
218+
219+
# calculating centroid
220+
centroidx = cv.Round((pt1[0]+pt2[0])/2)
221+
centroidy = cv.Round((pt1[1]+pt2[1])/2)
222+
223+
if (centroidx == 0 or centroidy == 0):
224+
print ("no blimp detected from " + sideName)
225+
else:
226+
print(sideName + " centroid x:" + str(centroidx))
227+
print(sideName + " centroid y:" + str(centroidy))
228+
229+
print("")
230+
231+
if dispFlag:
232+
small_thresh = cv.CreateImage((int(dispScale1*cv.GetSize(imgbluethresh)[0]), int(dispScale1*cv.GetSize(imgbluethresh)[1])), 8, 1)
233+
cv.Resize(imgMask, small_thresh)
234+
cv.Threshold(small_thresh, small_thresh, 0, 255, cv.CV_THRESH_BINARY)
235+
cv.ShowImage(sideName + "_threshold", small_thresh)
236+
cv.WaitKey(100)
237+
238+
small_hsv = cv.CreateImage((int(0.25*cv.GetSize(imghsv)[0]), int(0.25*cv.GetSize(imghsv)[1])), 8, 3)
239+
cv.Resize(imghsv, small_hsv)
240+
241+
small_hsv_h = cv.CreateImage((int(0.25*cv.GetSize(imghsv)[0]), int(0.25*cv.GetSize(imghsv)[1])), 8, 1)
242+
small_hsv_s = cv.CreateImage((int(0.25*cv.GetSize(imghsv)[0]), int(0.25*cv.GetSize(imghsv)[1])), 8, 1)
243+
small_hsv_v = cv.CreateImage((int(0.25*cv.GetSize(imghsv)[0]), int(0.25*cv.GetSize(imghsv)[1])), 8, 1)
244+
small_hsv_x = cv.CreateImage((int(0.25*cv.GetSize(imghsv)[0]), int(0.25*cv.GetSize(imghsv)[1])), 8, 1)
245+
246+
cv.Split(small_hsv, small_hsv_h, small_hsv_s, small_hsv_v, None)
247+
cv.ShowImage(sideName + "_hsv", small_hsv)
248+
cv.WaitKey(100)
249+
250+
return (centroidx, centroidy)
251+
252+
253+
254+
#---------------------------------------------------------
255+
#!!Need to be on the local WID network to be able to grab images from the cameras
256+
#grab a frame from the east camera, store it to disk
257+
fname_east = './/east.jpg'
258+
url_east = 'http://10.129.20.11/snapshot/view0.jpg'
259+
260+
#grab a frame from the west camera, store it to disk
261+
fname_west = './/west.jpg'
262+
url_west = 'http://10.129.20.12/snapshot/view0.jpg'
263+
264+
# three windows that will open upon execution
265+
cv.NamedWindow("west",cv.CV_WINDOW_AUTOSIZE)
266+
cv.NamedWindow("east",cv.CV_WINDOW_AUTOSIZE)
267+
268+
# extra images to show intermediate tracking results
269+
dispMore = 1
270+
if dispMore:
271+
cv.NamedWindow("west_threshold",cv.CV_WINDOW_AUTOSIZE)
272+
cv.NamedWindow("east_threshold",cv.CV_WINDOW_AUTOSIZE)
273+
cv.NamedWindow("west_hsv",cv.CV_WINDOW_AUTOSIZE)
274+
cv.NamedWindow("east_hsv",cv.CV_WINDOW_AUTOSIZE)
275+
276+
#Live images from the IP cameras
277+
#(if not live, then this file needs to be in folder with a bunch of images)
278+
#(if live, then need to be local at WID)
279+
liveIP = 0
280+
if liveIP == 0:
281+
#need to be in directory with a bunch of images
282+
dirList = os.listdir(os.getcwd())
283+
num_base = 0
284+
both_offset = 10
285+
num_imgs = 145 - both_offset
286+
east_offset = 0 + both_offset
287+
west_offset = 147 + both_offset
288+
289+
290+
#address of the control server
291+
ip = "md-red5.discovery.wisc.edu"
292+
port = 7779
293+
size = 1024
294+
295+
#first get a connection to the server
296+
#s = connect(ip,port)
297+
298+
dispScale1 = 0.35
299+
dispScale2 = 0.25
300+
301+
302+
while(1):
303+
if liveIP:
304+
#capture images from cameras, store images to file
305+
urllib.urlretrieve(url_west,fname_west)
306+
urllib.urlretrieve(url_east,fname_east)
307+
else:
308+
num_base = (num_base + 1)%(num_imgs)
309+
west_num = west_offset + num_base
310+
east_num = east_offset + num_base
311+
fname_west = dirList[west_num]
312+
fname_east = dirList[east_num]
313+
cv.WaitKey(2000) #wait for 2 seconds so I can see the output
314+
315+
#open the images from file
316+
frame_west = cv.LoadImage(fname_west,cv.CV_LOAD_IMAGE_COLOR);
317+
frame_east = cv.LoadImage(fname_east,cv.CV_LOAD_IMAGE_COLOR);
318+
319+
#find the blimp with one camera, frame is passed in by reference
320+
centroids = procImg(frame_west,"west",dispMore)
321+
centx_west = centroids[0]
322+
centy_west = centroids[1]
323+
324+
#find the blimp with one camera, frame is passed in by reference
325+
centroids = procImg(frame_east,"east",dispMore)
326+
centx_east = centroids[0]
327+
centy_east = centroids[1]
328+
329+
#decimate the resulting images
330+
small_west = cv.CreateImage((int(dispScale1*cv.GetSize(frame_west)[0]), int(dispScale1*cv.GetSize(frame_west)[1])), 8, 3)
331+
small_east = cv.CreateImage((int(dispScale1*cv.GetSize(frame_east)[0]), int(dispScale1*cv.GetSize(frame_east)[1])), 8, 3)
332+
cv.Resize(frame_west, small_west)
333+
cv.Resize(frame_east, small_east)
334+
335+
336+
#display the images with the blimp outlined
337+
cv.ShowImage("west", small_west)
338+
cv.WaitKey(100)
339+
cv.ShowImage("east", small_east)
340+
cv.WaitKey(100)
341+
342+
if (centx_west != 0 and centy_west != 0 and centx_east != 0 and centy_east != 0):
343+
#get the 3D location of the blimp
344+
coord3D = triang_3D(centx_west, centy_west, centx_east, centy_east)
345+
346+
print("x_3d: " + str(coord3D[0]))
347+
print("y_3d: " + str(coord3D[1]))
348+
print("z_3d: " + str(coord3D[2]))
349+
print("err1: " + str(coord3D[3]))
350+
print("err2: " + str(coord3D[4]))
351+
352+
353+
## #send the 3D location to the control server
354+
## try:
355+
## #x,y,z = getPosition()
356+
## msg = "" + str(coord3D[0]) + "," + str(coord3D[1]) + "," + str(coord3D[2]) + "\n"
357+
## s.send(msg)
358+
## #time.sleep(1)
359+
## except Exception as err:
360+
## print("disconnected")
361+
## #we got disconnected somehow, reconnect
362+
## s = connect(ip,port)
363+
print("-----------------------------------")
364+
365+
366+
######################################################

0 commit comments

Comments
 (0)