test_camera.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # Software License Agreement (BSD License)
3 #
4 # Copyright (c) 2008, Willow Garage, Inc.
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 #
11 # * Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 # * Redistributions in binary form must reproduce the above
14 # copyright notice, this list of conditions and the following
15 # disclaimer in the documentation and/or other materials provided
16 # with the distribution.
17 # * Neither the name of the Willow Garage nor the names of its
18 # contributors may be used to endorse or promote products derived
19 # from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 #
34 
35 
36 
37 PKG = 'pr2_gazebo'
38 NAME = 'test_camera'
39 
40 import math
41 import roslib
42 roslib.load_manifest(PKG)
43 roslib.load_manifest('rostest')
44 roslib.load_manifest('actionlib')
45 roslib.load_manifest('pr2_controllers_msgs')
46 
47 import sys, unittest
48 import os, os.path, threading, time
49 import rospy, rostest, string
50 from std_msgs.msg import Int32
51 from sensor_msgs.msg import Image as image_msg
52 from sensor_msgs.msg import CameraInfo as camerainfo_msg
53 from PIL import Image as pili
54 from PIL import ImageChops as pilic
55 from geometry_msgs.msg import PointStamped, Point, Vector3
56 from pr2_controllers_msgs.msg import PointHeadGoal, PointHeadAction
58 
59 #FRAME_TARGET = "cam_sen-0050.ppm"
60 FRAME_TARGET = "test_camera.valid.ppm"
61 FRAME_DIR = "test_camera_frames"
62 TOTAL_ERROR_TOL = 5
63 TEST_DURATION = 70
64 
65 class PollCameraThread(threading.Thread):
66  def __init__(self, target, dir):
67  super(PollCameraThread, self).__init__()
68  self.target = target
69  self.dir = dir
70 
71  def run(self):
72  while 1:
73  time.sleep(0.01)
74  if (os.path.isdir(self.dir)):
75  ls = os.listdir(self.dir)
76  #print "Dir: " + str(ls)
77  for file in ls:
78  if (file == FRAME_TARGET):
79  self.target.onTargetFrame()
80  return
81 
82 class TestCameras(unittest.TestCase):
83  def __init__(self, *args):
84  super(TestCameras, self).__init__(*args)
85  self.success = False
86  self.got_camerainfo = False
89 
90  def onTargetFrame(self):
91  time.sleep(0.5) #Safety, to make sure the image is really done being written.
92  ps = "diff -q " + FRAME_DIR + "/" + FRAME_TARGET + " test/test_camera.valid.ppm"
93  #print "CMD: " + ps + "\n"
94  result = os.system(ps)
95  if (result == 0):
96  self.success = True
97  #print "Success\n"
98  else:
99  self.success = False
100  #print "Failure\n"
101  rospy.signal_shutdown('test done')
102 
103  def images_are_the_same(self,i0,i1):
104  print("comparing images... ")
105  error_count = 0
106  error_total = 0
107  pixel_tol = 0
108 
109  # thumbnail-ize images
110  size = 100,100
111  i0.thumbnail(size,pili.ANTIALIAS)
112  i1.thumbnail(size,pili.ANTIALIAS)
113  ic = pilic.difference(i0,i1)
114  i0.save("t_0.ppm")
115  i1.save("t_1.ppm")
116  ic.save("t_d.ppm")
117 
118  # get raw data for comparison
119  i0d = i0.getdata()
120  i1d = i1.getdata()
121 
122  # assert len(i0)==len(i1)
123  if len(i0d) != len(i1d):
124  print("lengths not equal ",len(i0d), len(i1d))
125  return False
126  print("thumbnail lengths ",len(i0d), len(i1d))
127 
128  #compare pixel by pixel for thumbnails
129  for i in range(len(i0d)):
130  (p0) = i0d[i]
131  (p1) = i1d[i]
132  if abs(p0-p1) > pixel_tol:
133  error_count = error_count + 1
134  error_total = error_total + abs(p0-p1)
135  error_avg = float(error_total)/float(len(i0d))
136  print("total error count:",error_count)
137  print("average error: ",error_avg)
138  if error_avg > TOTAL_ERROR_TOL:
139  return False
140  else:
141  return True
142 
143  def camerainfoInput(self,camerainfo):
144  self.got_camerainfo = True
145  self.camerainfo_width = camerainfo.width
146  self.camerainfo_height = camerainfo.height
147  print(" got cam info (",camerainfo.width,"X",camerainfo.height,")")
148 
149  def imageInput(self,image):
150 
151  if (self.got_camerainfo):
152  print(" got image and camerainfo from ROS, begin comparing images.")
153  else:
154  print(" got image but no camerainfo.")
155  return
156 
157  print(" - load validation image from file test_camera.valid.ppm ")
158  fname = roslib.packages.get_pkg_dir('pr2_gazebo') + '/test/sensors/test_camera.valid.ppm'
159  if os.path.isfile(fname):
160  im0 = pili.open(fname)
161  else:
162  print("cannot find validation file: test_camera.valid.ppm")
163  self.success = False
164  return
165 
166  print(" - load image from ROS ")
167  size = self.camerainfo_width,self.camerainfo_height
168  im1 = pili.new("L",size)
169  if os.environ['ROS_DISTRO'] == 'noetic':
170  im1 = pili.frombuffer("L",size,image.data, "raw", "L", 0, 1);
171  else:
172  im1 = pili.frombuffer("L",size,str(image.data));
173  im1 = im1.transpose(pili.FLIP_LEFT_RIGHT).rotate(180);
174  imc = pilic.difference(im0,im1)
175 
176 
177  print(" - comparing images ")
178  im1.save("test_1.ppm") # uncomment this line to capture a new valid frame when things change
179  im0.save("test_0.ppm")
180  imc.save("test_d.ppm")
181  #im1.show()
182  #im0.show()
183  #imc.show()
184  comp_result = self.images_are_the_same(im0,im1)
185  print("test comparison ", comp_result)
186  #print "proofcomparison ", self.images_are_the_same(im1.getdata(),im1.getdata())
187  if (self.success == False): # test if we have not succeeded
188  if (comp_result == True):
189  print(" - images are the Same ")
190  self.success = True
191  else:
192  print(" - images differ ")
193  self.success = False
194 
195 
196  def test_camera(self):
197  rospy.init_node(NAME, anonymous=True)
198  head_action_client = actionlib.action_client.ActionClient('/head_traj_controller/point_head_action',PointHeadAction)
199  def send_head_goal(g):
200  g.target.header.stamp = rospy.get_rostime()
201  return head_action_client.send_goal(g)
202  head_goal = PointHeadGoal()
203  head_goal.target.header.frame_id = 'base_link'
204  head_goal.target.point = Point(10,0,0.55)
205 
206  projector_pub = rospy.Publisher("/projector_wg6802418_controller/projector", Int32, latch=True);
207  projector_pub.publish(Int32(0));
208 
209  print(" subscribe stereo left image from ROS ")
210  rospy.Subscriber("/narrow_stereo/left/image_raw", image_msg, self.imageInput) # this is a camera mounted on PR2 head (left stereo camera)
211  rospy.Subscriber("/narrow_stereo/left/camera_info", camerainfo_msg, self.camerainfoInput) # this is a camera mounted on PR2 head (left stereo camera)
212  timeout_t = time.time() + TEST_DURATION
213  while not rospy.is_shutdown() and not self.success and time.time() < timeout_t:
214  head_goal_status = send_head_goal(head_goal)
215  time.sleep(1.0)
216  self.assert_(self.success)
217 
218 
219 
220 
221 if __name__ == '__main__':
222  #while (os.path.isfile(FRAME_DIR + "/" + FRAME_TARGET)):
223  # print "Old test case still alive."
224  # time.sleep(1)
225 
226  print(" starting test ")
227  rostest.run(PKG, sys.argv[0], TestCameras, sys.argv)
228 
229 
msg
test_camera.PollCameraThread.target
target
Definition: test_camera.py:68
test_camera.TestCameras.imageInput
def imageInput(self, image)
Definition: test_camera.py:149
test_camera.PollCameraThread
Definition: test_camera.py:65
actionlib::action_client
test_camera.TestCameras.got_camerainfo
got_camerainfo
Definition: test_camera.py:86
test_camera.TestCameras.images_are_the_same
def images_are_the_same(self, i0, i1)
Definition: test_camera.py:103
test_camera.TestCameras
Definition: test_camera.py:82
test_camera.TestCameras.success
success
Definition: test_camera.py:85
test_camera.PollCameraThread.dir
dir
Definition: test_camera.py:69
test_camera.TestCameras.test_camera
def test_camera(self)
Definition: test_camera.py:196
test_camera.TestCameras.camerainfoInput
def camerainfoInput(self, camerainfo)
Definition: test_camera.py:143
test_camera.TestCameras.camerainfo_width
camerainfo_width
Definition: test_camera.py:88
test_camera.PollCameraThread.__init__
def __init__(self, target, dir)
Definition: test_camera.py:66
test_camera.PollCameraThread.run
def run(self)
Definition: test_camera.py:71
test_camera.TestCameras.camerainfo_height
camerainfo_height
Definition: test_camera.py:87
actionlib::action_client::ActionClient
test_camera.TestCameras.onTargetFrame
def onTargetFrame(self)
Definition: test_camera.py:90
test_camera.TestCameras.__init__
def __init__(self, *args)
Definition: test_camera.py:83


pr2_gazebo
Author(s): John Hsu
autogenerated on Sun Apr 17 2022 02:26:38