00001
00002 import roslib
00003 roslib.load_manifest('pr2_playpen')
00004 import rospy
00005 from pr2_playpen.srv import *
00006 import sys
00007 import cv
00008 import numpy as np
00009 import cPickle
00010 import glob
00011 from collections import deque
00012 from std_msgs.msg import String
00013 from sensor_msgs.msg import Image
00014 from cv_bridge import CvBridge, CvBridgeError
00015
00016 class HistAnalyzer:
00017
00018 def __init__(self, background_noise, mask, topic=None):
00019 rospy.init_node('playpen_color_results')
00020 if topic != None:
00021 rospy.Subscriber(topic, Image, self.get_img)
00022 self.check = rospy.Service("playpen_check_success_hist", Check, self.serv_success)
00023 self.train_empty = rospy.Service("playpen_train_hist", Train, self.serv_train)
00024 self.background_noise = background_noise
00025 self.h_bins = 30
00026 self.s_bins = 32
00027 self.h_ranges = [0, 180]
00028 self.s_ranges = [0, 255]
00029 self.ranges = [self.h_ranges, self.s_ranges]
00030 self.hist = None
00031 self.mask = mask
00032 self.avg_noise = None
00033 self.online_img = None
00034 self.bridge = CvBridge()
00035 size = cv.GetSize(background_noise[0])
00036 self.IavgF = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00037 self.IdiffF = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00038 self.IprevF = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00039 self.IhiF = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00040 self.IlowF = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00041 self.Ilow1 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00042 self.Ilow2 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00043 self.Ilow3 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00044 self.Ihi1 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00045 self.Ihi2 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00046 self.Ihi3 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00047 cv.Zero(self.IavgF)
00048 cv.Zero(self.IdiffF)
00049 cv.Zero(self.IprevF)
00050 cv.Zero(self.IhiF)
00051 cv.Zero(self.IlowF)
00052 self.Icount = 0.00001
00053 self.Iscratch = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00054 self.Iscratch2 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00055 self.Igray1 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00056 self.Igray2 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00057 self.Igray3 = cv.CreateImage(size, cv.IPL_DEPTH_32F, 1)
00058 self.Imaskt = cv.CreateImage(size, cv.IPL_DEPTH_8U, 1)
00059 cv.Zero(self.Iscratch)
00060 cv.Zero(self.Iscratch2)
00061 self.first = 1
00062
00063 def accumulateBackground(self, img):
00064 cv.CvtScale(img, self.Iscratch, 1, 0)
00065 if (not self.first):
00066 cv.Acc(self.Iscratch, self.IavgF)
00067 cv.AbsDiff(self.Iscratch, self.IprevF, self.Iscratch2)
00068 cv.Acc(self.Iscratch2, self.IdiffF)
00069 self.Icount += 1.0
00070 self.first = 0
00071 cv.Copy(self.Iscratch, self.IprevF)
00072
00073 def setHighThresh(self, thresh):
00074 cv.ConvertScale(self.IdiffF, self.Iscratch, thresh)
00075 cv.Add(self.Iscratch, self.IavgF, self.IhiF)
00076
00077
00078 def setLowThresh(self, thresh):
00079 cv.ConvertScale(self.IdiffF, self.Iscratch, thresh)
00080 cv.Sub(self.IavgF, self.Iscratch, self.IlowF)
00081
00082
00083
00084 def createModelsfromStats(self):
00085 cv.ConvertScale(self.IavgF, self.IavgF, float(1.0/self.Icount))
00086 cv.ConvertScale(self.IdiffF, self.IdiffF, float(1.0/self.Icount))
00087
00088 cv.AddS(self.IdiffF, cv.Scalar(1.0, 1.0, 1.0), self.IdiffF)
00089 self.setHighThresh(200.0)
00090 self.setLowThresh(200.0)
00091
00092 def backgroundDiff(self, img, Imask):
00093
00094 cv.Zero(Imask)
00095 cv.CvtScale(img, self.Iscratch, 1, 0)
00096 cv.InRange(self.Iscratch, self.IlowF, self.IhiF, Imask)
00097 cv.SubRS(Imask, 255, Imask)
00098 cv.MorphologyEx(Imask, Imask, None, None, cv.CV_MOP_OPEN, 1)
00099 cv.MorphologyEx(Imask, Imask, None, None, cv.CV_MOP_CLOSE, 2)
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116 return Imask
00117
00118
00119 def get_img(self, msg):
00120 try:
00121 self.online_img = self.bridge.imgmsg_to_cv(msg, "bgr8")
00122 except CvBridgeError, e:
00123 print e
00124
00125 def serv_train(self, req):
00126 if req.expected== 'table':
00127 print 'great'
00128 num_samples = 0
00129 return TrainResponse(num_samples)
00130
00131
00132 def serv_success(self, req):
00133 result = "none"
00134 return CheckResponse(result)
00135
00136
00137 def calc_hist(self):
00138 self.hist = cv.CreateHist([self.h_bins, self.s_bins], cv.CV_HIST_ARRAY, self.ranges, 1)
00139 hsv = cv.CreateImage(cv.GetSize(self.background_noise[0]), 8, 3)
00140 h_plane = cv.CreateMat(self.background_noise[0].height, self.background_noise[0].width, cv.CV_8UC1)
00141 s_plane = cv.CreateMat(self.background_noise[0].height, self.background_noise[0].width, cv.CV_8UC1)
00142 for i in xrange(len(self.background_noise)):
00143 cv.CvtColor(self.background_noise[i], hsv, cv.CV_BGR2HSV)
00144 cv.Split(hsv, h_plane, s_plane, None, None)
00145 planes = [h_plane, s_plane]
00146 cv.CalcHist([cv.GetImage(i) for i in planes], self.hist, True, self.mask)
00147
00148
00149 def check_for_hist(self):
00150 if self.hist == None:
00151 print "YOU CAN'T CALCULATE NOISE WITHOUT HIST MODEL OF TABLETOP"
00152 exit
00153
00154 def calc_stats(self):
00155 self.check_for_hist()
00156 for i in xrange(len(self.background_noise)):
00157 back_proj_img1, hist1 = self.back_project_hs(self.background_noise[i])
00158
00159 self.accumulateBackground(back_proj_img1)
00160
00161
00162
00163 self.createModelsfromStats()
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 def compare_imgs(self, img1, img2):
00175 back_proj_img, hist1 = self.back_project_hs(img1)
00176 back_proj_img2, hist2 = self.back_project_hs(img2)
00177
00178 scratch = cv.CreateImage(cv.GetSize(back_proj_img2), 8, 1)
00179 scratch2 = cv.CreateImage(cv.GetSize(back_proj_img2), 8, 1)
00180 cv.Zero(scratch)
00181 cv.Zero(scratch2)
00182
00183
00184 cv.Sub(back_proj_img2, back_proj_img, scratch2)
00185 cv.Sub(scratch2, ha.avg_noise, scratch)
00186
00187 return scratch
00188
00189
00190 def back_project_hs(self, img):
00191 self.check_for_hist()
00192 hsv = cv.CreateImage(cv.GetSize(img), 8, 3)
00193 scratch = cv.CreateImage(cv.GetSize(img), 8, 1)
00194 back_proj_img = cv.CreateImage(cv.GetSize(img), 8, 1)
00195 cv.CvtColor(img, hsv, cv.CV_BGR2HSV)
00196 h_plane_img = cv.CreateImage(cv.GetSize(img), 8, 1)
00197 s_plane_img = cv.CreateImage(cv.GetSize(img), 8, 1)
00198 cv.Split(hsv, h_plane_img, s_plane_img, None, None)
00199 cv.CalcBackProject([h_plane_img, s_plane_img], back_proj_img, self.hist)
00200
00201
00202
00203 return back_proj_img, self.hist
00204
00205
00206 if __name__ == '__main__':
00207
00208 import optparse
00209 p = optparse.OptionParser()
00210
00211 p.add_option('--batch', action='store', dest='batch_folder', type="string",
00212 default=None, help='check for success or failure in batch mode with already stored data')
00213 p.add_option('--online', action='store', dest='topic', type="string",
00214 default=None, help='tries to run success or failure detection online using histograms and backprojection')
00215 p.add_option('--label_manually', action='store_true', dest='manual',
00216 default=False, help='allows user to manually label data for validation purposes')
00217
00218
00219
00220 opt, args = p.parse_args()
00221
00222
00223 if opt.batch_folder != None:
00224 folder = opt.batch_folder+'/background_noise/'
00225 background_noise = deque()
00226
00227 cv.NamedWindow("Source", cv.CV_WINDOW_AUTOSIZE)
00228
00229
00230 for i in xrange(30):
00231 try:
00232 background_noise.append(cv.LoadImage(folder+'file'+str(i).zfill(3)+'.png'))
00233 except:
00234 print "no file # ", i
00235 mask = cv.LoadImage(folder+'mask.png', 0)
00236
00237 ha = HistAnalyzer(background_noise, mask)
00238 ha.calc_hist()
00239 ha.calc_stats()
00240
00241 print "should see avg noise"
00242
00243
00244
00245
00246
00247 back_sum_ls = deque()
00248 Imask = cv.CreateImage(cv.GetSize(ha.background_noise[0]), cv.IPL_DEPTH_8U, 1)
00249
00250 for i in xrange(130):
00251 try:
00252 img = cv.LoadImage(folder+'file'+str(i).zfill(3)+'.png')
00253 back_img, hist = ha.back_project_hs(img)
00254 result = ha.backgroundDiff(back_img, Imask)
00255 back_sum_ls.append(float(cv.Sum(result)[0]))
00256 except:
00257 print "no training file # ", i
00258
00259 avg = np.mean(back_sum_ls)
00260 std = np.std(back_sum_ls)
00261
00262 print "here's the back_sum_ls : \n", back_sum_ls
00263
00264 print "avg and std are :", avg, std
00265
00266 n = 0
00267 sum_val = 0
00268
00269 if opt.manual:
00270 manual_classification_list = []
00271
00272 for i in xrange(9):
00273
00274
00275 file_list = glob.glob(opt.batch_folder+'/object'+str(i).zfill(3)+'*after*.png')
00276 file_list.sort()
00277 length = int(file_list[-1][-17:-14])
00278
00279 res_dict = {'frames':[], 'success': [None]*length}
00280
00281
00282
00283 for j in xrange(length):
00284 try:
00285
00286 img = cv.LoadImageM(opt.batch_folder+'/object'+str(i).zfill(3)+'_try'+str(j).zfill(3)+'_before_pr2.png')
00287 back_img, hist = ha.back_project_hs(img)
00288 result = ha.backgroundDiff(back_img, Imask)
00289
00290 is_object = False
00291 loc_sum = float(cv.Sum(result)[0])
00292 if loc_sum < avg+5*std:
00293 res_dict['success'][j] = None
00294 print "no object to start with!?"
00295 else:
00296 is_object = True
00297 print "there's an object let's check for success ..."
00298
00299
00300 if is_object == True:
00301 try:
00302 img = cv.LoadImageM(opt.batch_folder+'/object'+str(i).zfill(3)+'_try'+str(j).zfill(3)+'_after_pr2.png')
00303
00304 if opt.manual:
00305 cv.ShowImage("Source", img)
00306 cv.WaitKey(100)
00307 user_inp = raw_input('success:1, failure:0, not sure:-1 \n')
00308 if user_inp == 'q':
00309 file_manual = open('/home/mkillpack/Desktop/manual_classification_.pkl', 'w')
00310 cPickle.dump(manual_classification_list, file_manual)
00311 file_manual.close()
00312 else:
00313 manual_classification_list.append(int(user_inp))
00314 print "length of manual list is: ", len(manual_classification_list)
00315 print "number of real samples is :",
00316 print len(np.where(np.array(manual_classification_list) == 1)[0]) + len(np.where(np.array(manual_classification_list) == 0)[0])
00317 print '\n'
00318
00319 else:
00320 back_img, hist = ha.back_project_hs(img)
00321 result2 = ha.backgroundDiff(back_img, Imask)
00322 n = n+1
00323 sum_val = sum_val + float(cv.Sum(result2)[0])
00324
00325
00326 loc_sum2 = float(cv.Sum(result2)[0])
00327 if loc_sum2 < loc_sum/2.0:
00328 res_dict['success'][j] = True
00329 print "success ! \t:", loc_sum2, "\t compared to \t", loc_sum/2.0
00330
00331
00332 else:
00333 res_dict['success'][j] = False
00334 print "epic fail ! \t:", loc_sum2, "\t compared to \t", loc_sum/2.0
00335
00336 cv.ShowImage("Source", img)
00337 cv.ShowImage("final", result2)
00338 cv.WaitKey(33)
00339
00340 except:
00341 print "no image to test named : "
00342 print opt.batch_folder+'/object'+str(i).zfill(3)+'_try'+str(j).zfill(3)+'_after_pr2.png'
00343 res_dict['success'][j] = None
00344
00345 except:
00346 res_dict['success'][j] = None
00347 print "problem in try statement"
00348
00349 try:
00350 os.system('rm '+opt.batch_folder+'/object'+str(i).zfill(3)+'.pkl')
00351 except:
00352 print "PROBLEM DELETING OLD FILE..., it didn't exist"
00353 exit
00354 file_h2 = open(opt.batch_folder+'/object'+str(i).zfill(3)+'.pkl', 'w')
00355 cPickle.dump(res_dict, file_h2)
00356 file_h2.close()
00357 print "moving to next object..."
00358
00359
00360 print "done!"
00361
00362 if opt.manual:
00363 file_manual = open('/home/mkillpack/Desktop/manual_classification_.pkl', 'w')
00364 cPickle.dump(manual_classification_list, file_manual)
00365 file_manual.close()
00366 else:
00367 print "average error for objects present :", sum_val/n
00368
00369 elif opt.topic != None:
00370 rospy.logerr("online evaluation is not yet implemented, but all the necessary tools should be present to do it ...")
00371 assert(False)