Exemple #1
0
    def localize_detection(self, detection):
        """
            2d image detection -> 3d point in [map frame]
        """
        u = detection.x + detection.width / 2
        v = detection.y + detection.height / 2

        camera_info = None
        best_time = 100
        for ci in self.camera_infos:
            time = abs(ci.header.stamp.to_sec() -
                       detection.header.stamp.to_sec())
            if time < best_time:
                camera_info = ci
                best_time = time

        if not camera_info or best_time > 1:
            return False, None

        camera_model = PinholeCameraModel()
        camera_model.fromCameraInfo(camera_info)

        point = Point(
            ((u - camera_model.cx()) - camera_model.Tx()) / camera_model.fx(),
            ((v - camera_model.cy()) - camera_model.Ty()) / camera_model.fy(),
            1)

        localization = self.localize(detection.header, point,
                                     self.region_scope)

        if not localization:
            return False, None

        point_trans = None

        print "Face localized ", localization.pose.position.x, localization.pose.position.y
        if localization.pose.position.x == 0.0:
            print "Ignoring this one!"
            return False, None
        try:
            #(pos_trans, rot) = self.tf_listener.lookupTransform('/map', detection.header.frame_id, rospy.Time(0))
            point_trans = self.tf_listener.transformPoint(
                '/map',
                PointStamped(detection.header, localization.pose.position))
        except (tf.LookupException, tf.ConnectivityException,
                tf.ExtrapolationException):
            pass

        if point_trans == None:  # transformation failed
            return False, None

        print "Face detected at %d,%d" % (point_trans.point.x,
                                          point_trans.point.y)
        return True, point_trans.point
class coord_converter:

  def __init__(self):
    self.image_sub = rospy.Subscriber("hough_circles/circles", CircleArrayStamped, self.callback)
    self.camera_info_msg = None
    self.camera_model = PinholeCameraModel() 
    self.image_info_sub = rospy.Subscriber("camera1/camera_info", CameraInfo, self.image_info_cb, queue_size=1) 

#    if self.camera_info_msg is not None:
#	print('PinholeCameraModel parameters:\n')
#       print('cx: ' + str(self.camera_model.cx()))
#	print('cy: ' + str(self.camera_model.cy()))
#	print('fx: ' + str(self.camera_model.fx()))
#	print('fy: ' + str(self.camera_model.fy()))

  def callback(self,data):
    print('\nIMAGE COORDINATES (center):')
    for i in range (len(data.circles)):
      print(' circle' + str(i+1) + ' detected:')
      print('  x: ' + str(data.circles[i].center.x))
      print('  y: ' + str(data.circles[i].center.y))
      
    print('\nWORLD COORDINATES (center):')
    print(' camera_robot coordinates:\n  x: 1.4\n  y: 2.2')
    for i in range (len(data.circles)):
      print(' circle' + str(i+1) + ' detected:')
      # using the equations showed at the beggining of this script:
      x_world = ((data.circles[i].center.x) - self.camera_model.cx()) * 1.25 / self.camera_model.fx() #z_world = camera rod height = 1.25
      y_world = ((data.circles[i].center.y) - self.camera_model.cy()) * 1.25 / self.camera_model.fy()
      print('  x: ' + str(1.4 + x_world)) #x=0 from image = 1.4 from world
      print('  y: ' + str(2.6 - y_world)) #y=0 from image = 2.6 from world / direction of y axis from world = -y from image

  def image_info_cb(self, msg):
    if self.camera_info_msg is None:
      self.camera_model.fromCameraInfo(msg)
      self.camera_info_msg = msg
class Scanner:
    def __init__(self):
        self.pixels_per_scanline = rospy.get_param('~pixels_per_scanline')
        self.scanner_info_file_name = rospy.get_param('~scanner_info_file_name')
        self.threshold = rospy.get_param('~threshold')        

        self.mutex = threading.RLock()
        self.image_update_flag = threading.Event()
        self.bridge = CvBridge()
        rospy.Subscriber("image_stream", sensor_msgs.msg.Image, self.update_image)
        rospy.loginfo("Waiting for camera info...")
        self.camera_info = rospy.wait_for_message('camera_info', sensor_msgs.msg.CameraInfo)
        rospy.loginfo("Camera info received.")

        rospy.loginfo("Waiting for projector info service...")
        rospy.wait_for_service('get_projector_info')
        rospy.loginfo("Projector info service found.")
        get_projector_info = rospy.ServiceProxy('get_projector_info', projector.srv.GetProjectorInfo)
        self.projector_info = get_projector_info().projector_info

        self.projector_model = PinholeCameraModel()
        self.projector_model.fromCameraInfo(self.projector_info)

        self.read_scanner_info()

        self.projector_to_camera_rotation_matrix = cv.CreateMat(3, 3, cv.CV_32FC1)
        cv.Rodrigues2(self.projector_to_camera_rotation_vector, self.projector_to_camera_rotation_matrix)        

        predistortmap_x = cv.CreateMat(self.projector_info.height, self.projector_info.width, cv.CV_32FC1)
        predistortmap_y = cv.CreateMat(self.projector_info.height, self.projector_info.width, cv.CV_32FC1)
        InitPredistortMap(self.projector_model.intrinsicMatrix(), self.projector_model.distortionCoeffs(), predistortmap_x, predistortmap_y)

        minVal, maxVal, minLoc, maxLoc = cv.MinMaxLoc(predistortmap_x)
        cv.AddS(predistortmap_x, -minVal, predistortmap_x)
        uncropped_projection_width = int(math.ceil(maxVal - minVal))
        self.center_pixel = self.projector_model.cx() - minVal

        minVal, maxVal, minLoc, maxLoc = cv.MinMaxLoc(predistortmap_y)
        cv.AddS(predistortmap_y, -minVal, predistortmap_y)
        uncropped_projection_height = int(math.ceil(maxVal - minVal))

        self.number_of_scanlines = int(math.ceil(float(uncropped_projection_width)/self.pixels_per_scanline))

        rospy.loginfo("Generating projection patterns...")

        graycodes = []
        for i in range(self.number_of_scanlines):
            graycodes.append(graycodemath.generate_gray_code(i))
    
        self.number_of_projection_patterns = int(math.ceil(math.log(self.number_of_scanlines, 2)))        
        self.predistorted_positive_projections = []
        self.predistorted_negative_projections = []

        for i in range(self.number_of_projection_patterns):
            cross_section = cv.CreateMat(1, uncropped_projection_width, cv.CV_8UC1)

            #Fill in cross section with the associated bit of each gray code
            for pixel in range(uncropped_projection_width):
                scanline = pixel // self.pixels_per_scanline
                scanline_value = graycodemath.get_bit(graycodes[scanline], i) * 255
                cross_section[0, pixel] = scanline_value

            #Repeat the cross section over the entire image
            positive_projection = cv.CreateMat(uncropped_projection_height, uncropped_projection_width, cv.CV_8UC1)
            cv.Repeat(cross_section, positive_projection)

            #Predistort the projections to compensate for projector optics so that that the scanlines are approximately planar
            predistorted_positive_projection = cv.CreateMat(self.projector_info.height, self.projector_info.width, cv.CV_8UC1)
            cv.Remap(positive_projection, predistorted_positive_projection, predistortmap_x, predistortmap_y, flags=cv.CV_INTER_NN)

            #Create a negative of the pattern for thresholding
            predistorted_negative_projection = cv.CreateMat(self.projector_info.height, self.projector_info.width, cv.CV_8UC1)
            cv.Not(predistorted_positive_projection, predistorted_negative_projection)
                
            #Fade the borders of the patterns to avoid artifacts at the edges of projection
            predistorted_positive_projection_faded = fade_edges(predistorted_positive_projection, 20)
            predistorted_negative_projection_faded = fade_edges(predistorted_negative_projection, 20)
                
            self.predistorted_positive_projections.append(predistorted_positive_projection_faded)
            self.predistorted_negative_projections.append(predistorted_negative_projection_faded)

        rospy.loginfo("Waiting for projection setting service...")
        rospy.wait_for_service('set_projection')
        rospy.loginfo("Projection setting service found.")
        self.set_projection = rospy.ServiceProxy('set_projection', projector.srv.SetProjection)

        self.pixel_associations_msg = None
        self.point_cloud_msg = None

        rospy.Service("~get_point_cloud", graycode_scanner.srv.GetPointCloud, self.handle_point_cloud_srv)

        point_cloud_pub = rospy.Publisher('~point_cloud', sensor_msgs.msg.PointCloud)

        rospy.loginfo("Ready.")

        rate = rospy.Rate(1)
        while not rospy.is_shutdown():
            if self.point_cloud_msg is not None:
                point_cloud_pub.publish(self.point_cloud_msg)
            rate.sleep()

    def read_scanner_info(self):
        try:
            input_stream = file(self.scanner_info_file_name, 'r')
        except IOError:
            rospy.loginfo('Specified scanner info file at ' + self.scanner_info_file_name + ' does not exist.')
            return
        info_dict = yaml.load(input_stream)
        try:
            self.projector_to_camera_translation_vector = tuple(info_dict['projector_to_camera_translation_vector'])
            self.projector_to_camera_rotation_vector = list_to_matrix(info_dict['projector_to_camera_rotation_vector'], 3, 1, cv.CV_32FC1)
        except (TypeError, KeyError):
            rospy.loginfo('Scanner info file at ' + self.scanner_info_file_name + ' is in an unrecognized format.')
            return
        rospy.loginfo('Scanner info successfully read from ' + self.scanner_info_file_name)

    def update_image(self, imagemsg):
        with self.mutex:
            if not self.image_update_flag.is_set():
                self.latest_image = self.bridge.imgmsg_to_cv(imagemsg, "mono8")
                self.image_update_flag.set()
    
    def get_next_image(self):
        with self.mutex:
            self.image_update_flag.clear()
        self.image_update_flag.wait()
        with self.mutex:
            return self.latest_image
                            
    def get_picture_of_projection(self, projection):
        image_message = self.bridge.cv_to_imgmsg(projection, encoding="mono8")
        self.set_projection(image_message)
        return self.get_next_image()
    
    def get_projector_line_associations(self):
        rospy.loginfo("Scanning...")
        positives = []
        negatives = []
        for i in range(self.number_of_projection_patterns):
            positives.append(self.get_picture_of_projection(self.predistorted_positive_projections[i]))
            negatives.append(self.get_picture_of_projection(self.predistorted_negative_projections[i]))
        
            
        rospy.loginfo("Thresholding...")
        strike_sum = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_32SC1)
        cv.SetZero(strike_sum)
        gray_codes = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_32SC1)
        cv.SetZero(gray_codes)
        for i in range(self.number_of_projection_patterns):
            difference = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_8UC1)
            cv.Sub(positives[i], negatives[i], difference)

            absolute_difference = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_8UC1)
            cv.AbsDiff(positives[i], negatives[i], absolute_difference)

            #Mark all the pixels that were "too close to call" and add them to the running total
            strike_mask = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_8UC1)
            cv.CmpS(absolute_difference, self.threshold, strike_mask, cv.CV_CMP_LT)
            strikes = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_32SC1)
            cv.Set(strikes, 1, strike_mask)
            cv.Add(strikes, strike_sum, strike_sum)
            
            #Set the corresponding bit in the gray_code
            bit_mask = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_8UC1)
            cv.CmpS(difference, 0, bit_mask, cv.CV_CMP_GT)
            bit_values = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_32SC1)
            cv.Set(bit_values, 2 ** i, bit_mask)
            cv.Or(bit_values, gray_codes, gray_codes)

        rospy.loginfo("Decoding...")
        # Decode every gray code into binary
        projector_line_associations = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_32SC1)
        cv.Copy(gray_codes, projector_line_associations)
        for i in range(cv.CV_MAT_DEPTH(cv.GetElemType(projector_line_associations)), -1, -1):
            projector_line_associations_bitshifted_right = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_32SC1)
            #Using ConvertScale with a shift of -0.5 to do integer division for bitshifting right
            cv.ConvertScale(projector_line_associations, projector_line_associations_bitshifted_right, (2 ** -(2 ** i)), -0.5)
            cv.Xor(projector_line_associations, projector_line_associations_bitshifted_right, projector_line_associations)
        
        rospy.loginfo("Post processing...")
        
        # Remove all pixels that were "too close to call" more than once
        strikeout_mask = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_8UC1)
        cv.CmpS(strike_sum, 1, strikeout_mask, cv.CV_CMP_GT)
        cv.Set(projector_line_associations, -1, strikeout_mask)
        
        # Remove all pixels that don't decode to a valid scanline number
        invalid_scanline_mask = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_8UC1)
        cv.InRangeS(projector_line_associations, 0, self.number_of_scanlines, invalid_scanline_mask)
        cv.Not(invalid_scanline_mask, invalid_scanline_mask)
        cv.Set(projector_line_associations, -1, invalid_scanline_mask)
        
        self.display_scanline_associations(projector_line_associations)

        return projector_line_associations

    def handle_point_cloud_srv(self, req):
        response = graycode_scanner.srv.GetPointCloudResponse()
        self.get_point_cloud()
        response.point_cloud = self.point_cloud_msg
        response.success = True
        return response

    def get_point_cloud(self):

        # Scan the scene
        col_associations = self.get_projector_line_associations()

        # Project white light onto the scene to get the intensities of each pixel (for coloring our point cloud)
        illumination_projection = cv.CreateMat(self.projector_info.height, self.projector_info.width, cv.CV_8UC1)
        cv.Set(illumination_projection, 255)
        intensities_image = self.get_picture_of_projection(illumination_projection)

        # Turn projector off when done with it
        off_projection = cv.CreateMat(self.projector_info.height, self.projector_info.width, cv.CV_8UC1)
        cv.SetZero(off_projection)
        off_image_message = self.bridge.cv_to_imgmsg(off_projection, encoding="mono8")
        self.set_projection(off_image_message)

        camera_model = PinholeCameraModel()
        camera_model.fromCameraInfo(self.camera_info)
        
        valid_points_mask = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_8UC1)
        cv.CmpS(col_associations, -1, valid_points_mask, cv.CV_CMP_NE)
        
        number_of_valid_points = cv.CountNonZero(valid_points_mask)

        rectified_camera_coordinates = cv.CreateMat(1, number_of_valid_points, cv.CV_32FC2)
        scanline_associations = cv.CreateMat(1, number_of_valid_points, cv.CV_32FC1)
        intensities = cv.CreateMat(1, number_of_valid_points, cv.CV_8UC1)
        i = 0;
        for row in range(self.camera_info.height):
            for col in range(self.camera_info.width):
                if valid_points_mask[row, col] != 0:
                    rectified_camera_coordinates[0, i] = (col, row)
                    scanline_associations[0, i] = col_associations[row, col]
                    intensities[0, i] = intensities_image[row, col]
                    i += 1
       
        cv.UndistortPoints(rectified_camera_coordinates, rectified_camera_coordinates, camera_model.intrinsicMatrix(), camera_model.distortionCoeffs())

        # Convert scanline numbers to plane normal vectors
        planes = self.scanline_numbers_to_planes(scanline_associations)

        camera_rays = project_pixels_to_3d_rays(rectified_camera_coordinates, camera_model)
        
        intersection_points = ray_plane_intersections(camera_rays, planes)
        
        self.point_cloud_msg = sensor_msgs.msg.PointCloud()
        self.point_cloud_msg.header.stamp = rospy.Time.now()
        self.point_cloud_msg.header.frame_id = 'base_link'
        channels = []
        channel = sensor_msgs.msg.ChannelFloat32()
        channel.name = "intensity"
        points = []
        intensities_list = []

        for i in range(number_of_valid_points):
            point = geometry_msgs.msg.Point32()
            point.x = intersection_points[0, i][0]
            point.y = intersection_points[0, i][1]
            point.z = intersection_points[0, i][2]
            if point.z < 0:
                print scanline_associations[0, i]
                print rectified_camera_coordinates[0, i]
                
            points.append(point)
            intensity = intensities[0, i]
            intensities_list.append(intensity)
     
        channel.values = intensities_list
        channels.append(channel)
        self.point_cloud_msg.channels = channels
        self.point_cloud_msg.points = points

        return self.point_cloud_msg

    def scanline_numbers_to_planes(self, scanline_numbers):
        rows = scanline_numbers.height
        cols = scanline_numbers.width
        normal_vectors_x = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.Set(normal_vectors_x, -1)
        normal_vectors_y = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.Set(normal_vectors_y, 0)
        normal_vectors_z = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.Copy(scanline_numbers, normal_vectors_z)

        cv.ConvertScale(normal_vectors_z, normal_vectors_z, scale=self.pixels_per_scanline)
        cv.AddS(normal_vectors_z, -self.center_pixel, normal_vectors_z)
        cv.ConvertScale(normal_vectors_z, normal_vectors_z, scale=1.0/self.projector_model.fx())
        
        normal_vectors = cv.CreateMat(rows, cols, cv.CV_32FC3)
        cv.Merge(normal_vectors_x, normal_vectors_y, normal_vectors_z, None, normal_vectors)

        # Bring the normal vectors into camera coordinates
        cv.Transform(normal_vectors, normal_vectors, self.projector_to_camera_rotation_matrix)
        
        normal_vectors_split = [None]*3
        for i in range(3):
            normal_vectors_split[i] = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.Split(normal_vectors, normal_vectors_split[0], normal_vectors_split[1], normal_vectors_split[2], None)

        n_dot_p = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.SetZero(n_dot_p)
        for i in range(3):
            cv.ScaleAdd(normal_vectors_split[i], self.projector_to_camera_translation_vector[i], n_dot_p, n_dot_p)

        planes = cv.CreateMat(rows, cols, cv.CV_32FC4)
        cv.Merge(normal_vectors_split[0], normal_vectors_split[1], normal_vectors_split[2], n_dot_p, planes)
        

        return planes

    def display_scanline_associations(self, associations):
        display_image = cv.CreateMat(self.camera_info.height, self.camera_info.width, cv.CV_8UC1)
        cv.ConvertScale(associations, display_image, 255.0/self.number_of_scanlines)
        cv.NamedWindow("associations", flags=0)
        cv.ShowImage("associations", display_image)
        cv.WaitKey(800)
    def detections_callback(self, detection):
        global counter
        global maxDistance  #the maximal distance between two points required for them to be considered the same detection
        global alreadyDetected
        global n
        global lastAdded
        global detected
        #global tf
        global numFaces

        u = detection.x + detection.width / 2
        v = detection.y + detection.height / 2

        camera_info = None
        best_time = 100
        for ci in self.camera_infos:
            time = abs(ci.header.stamp.to_sec() -
                       detection.header.stamp.to_sec())
            if time < best_time:
                camera_info = ci
                best_time = time

        if not camera_info or best_time > 1:
            print("Best time is higher than 1")
            return

        camera_model = PinholeCameraModel()
        camera_model.fromCameraInfo(camera_info)

        point = Point(
            ((u - camera_model.cx()) - camera_model.Tx()) / camera_model.fx(),
            ((v - camera_model.cy()) - camera_model.Ty()) / camera_model.fy(),
            1)

        localization = self.localize(detection.header, point,
                                     self.region_scope)
        transformedPoint = point
        if not localization:
            return

        now = detection.header.stamp
        self.tf.waitForTransform("camera_rgb_optical_frame", "map", now,
                                 rospy.Duration(5.0))

        m = geometry_msgs.msg.PoseStamped()
        m.header.frame_id = "camera_rgb_optical_frame"
        m.pose = localization.pose
        m.header.stamp = detection.header.stamp
        transformedPoint = self.tf.transformPose("map", m)

        if (localization.pose.position.x != 0.0):

            #print("Localisation: ", localization)
            print("Transformation: ", transformedPoint)
            #print("Point: ", point)

            if counter == 0:
                #print("Counter is zero.")
                counter += 1
                lastAdded = transformedPoint
                #print("Adding the point to the array.")
                #alreadyDetected.append(transformedPoint)
                #print(len(alreadyDetected))
            else:
                #print("Counter: ", counter)
                dist = self.distance(transformedPoint, lastAdded)

                #print("Number of detected faces so far: ", len(detected))
                print("Distance is ", dist)

                if dist <= maxDistance:
                    #print("-----------Less then max----------------------------------")
                    if counter < 2 or counter >= 2:
                        #alreadyDetected.append(transformedPoint)
                        #print(len(alreadyDetected))
                        lastAdded = transformedPoint
                        counter += 1
                        beenDetected = False
                        for p in detected:
                            #print("Checking already detected")
                            #print("Distance: ", self.distance(p, transformedPoint))

                            if self.distance(p,
                                             transformedPoint) <= maxDistance:
                                #print("This face has already been detected")
                                #print("Distance: ", self.distance(p, transformedPoint))
                                beenDetected = True
                                break

                        if (beenDetected == False):
                            print(
                                "-----------------Good to go------------------------"
                            )
                            detected.append(lastAdded)

                            marker = Marker()
                            #print("Localisation: ", localization)
                            marker.header.stamp = detection.header.stamp
                            marker.header.frame_id = detection.header.frame_id
                            marker.pose = localization.pose
                            marker.type = Marker.CUBE
                            marker.action = Marker.ADD
                            marker.frame_locked = False
                            marker.lifetime = rospy.Duration.from_sec(1)
                            marker.id = self.marker_id_counter
                            marker.scale = Vector3(0.1, 0.1, 0.1)
                            marker.color = ColorRGBA(1, 0, 0, 1)
                            self.markers.markers.append(marker)
                            self.marker_id_counter += 1
                            self.soundhandle.say("I detected a face.",
                                                 blocking=False)
                            print("Number of detected faces: ", len(detected))
                            if len(detected) == numFaces:
                                #publish stop

                                #rospy.init_node('mapper', anonymous=True)
                                #msg = String()
                                #msg.data = "Found all faces."
                                print("Sending shutdown")
                                self.pub.publish("Found all faces.")

                else:
                    #print("-----------------------------------------More then max----")
                    lastAdded = transformedPoint

        else:
            print("Localisation: ", localization)
class Scanner:
    def __init__(self):
        self.pixels_per_scanline = rospy.get_param('~pixels_per_scanline')
        self.scanner_info_file_name = rospy.get_param(
            '~scanner_info_file_name')
        self.threshold = rospy.get_param('~threshold')

        self.mutex = threading.RLock()
        self.image_update_flag = threading.Event()
        self.bridge = CvBridge()
        rospy.Subscriber("image_stream", sensor_msgs.msg.Image,
                         self.update_image)
        rospy.loginfo("Waiting for camera info...")
        self.camera_info = rospy.wait_for_message('camera_info',
                                                  sensor_msgs.msg.CameraInfo)
        rospy.loginfo("Camera info received.")

        rospy.loginfo("Waiting for projector info service...")
        rospy.wait_for_service('get_projector_info')
        rospy.loginfo("Projector info service found.")
        get_projector_info = rospy.ServiceProxy('get_projector_info',
                                                projector.srv.GetProjectorInfo)
        self.projector_info = get_projector_info().projector_info

        self.projector_model = PinholeCameraModel()
        self.projector_model.fromCameraInfo(self.projector_info)

        self.read_scanner_info()

        self.projector_to_camera_rotation_matrix = cv.CreateMat(
            3, 3, cv.CV_32FC1)
        cv.Rodrigues2(self.projector_to_camera_rotation_vector,
                      self.projector_to_camera_rotation_matrix)

        predistortmap_x = cv.CreateMat(self.projector_info.height,
                                       self.projector_info.width, cv.CV_32FC1)
        predistortmap_y = cv.CreateMat(self.projector_info.height,
                                       self.projector_info.width, cv.CV_32FC1)
        InitPredistortMap(self.projector_model.intrinsicMatrix(),
                          self.projector_model.distortionCoeffs(),
                          predistortmap_x, predistortmap_y)

        minVal, maxVal, minLoc, maxLoc = cv.MinMaxLoc(predistortmap_x)
        cv.AddS(predistortmap_x, -minVal, predistortmap_x)
        uncropped_projection_width = int(math.ceil(maxVal - minVal))
        self.center_pixel = self.projector_model.cx() - minVal

        minVal, maxVal, minLoc, maxLoc = cv.MinMaxLoc(predistortmap_y)
        cv.AddS(predistortmap_y, -minVal, predistortmap_y)
        uncropped_projection_height = int(math.ceil(maxVal - minVal))

        self.number_of_scanlines = int(
            math.ceil(
                float(uncropped_projection_width) / self.pixels_per_scanline))

        rospy.loginfo("Generating projection patterns...")

        graycodes = []
        for i in range(self.number_of_scanlines):
            graycodes.append(graycodemath.generate_gray_code(i))

        self.number_of_projection_patterns = int(
            math.ceil(math.log(self.number_of_scanlines, 2)))
        self.predistorted_positive_projections = []
        self.predistorted_negative_projections = []

        for i in range(self.number_of_projection_patterns):
            cross_section = cv.CreateMat(1, uncropped_projection_width,
                                         cv.CV_8UC1)

            #Fill in cross section with the associated bit of each gray code
            for pixel in range(uncropped_projection_width):
                scanline = pixel // self.pixels_per_scanline
                scanline_value = graycodemath.get_bit(graycodes[scanline],
                                                      i) * 255
                cross_section[0, pixel] = scanline_value

            #Repeat the cross section over the entire image
            positive_projection = cv.CreateMat(uncropped_projection_height,
                                               uncropped_projection_width,
                                               cv.CV_8UC1)
            cv.Repeat(cross_section, positive_projection)

            #Predistort the projections to compensate for projector optics so that that the scanlines are approximately planar
            predistorted_positive_projection = cv.CreateMat(
                self.projector_info.height, self.projector_info.width,
                cv.CV_8UC1)
            cv.Remap(positive_projection,
                     predistorted_positive_projection,
                     predistortmap_x,
                     predistortmap_y,
                     flags=cv.CV_INTER_NN)

            #Create a negative of the pattern for thresholding
            predistorted_negative_projection = cv.CreateMat(
                self.projector_info.height, self.projector_info.width,
                cv.CV_8UC1)
            cv.Not(predistorted_positive_projection,
                   predistorted_negative_projection)

            #Fade the borders of the patterns to avoid artifacts at the edges of projection
            predistorted_positive_projection_faded = fade_edges(
                predistorted_positive_projection, 20)
            predistorted_negative_projection_faded = fade_edges(
                predistorted_negative_projection, 20)

            self.predistorted_positive_projections.append(
                predistorted_positive_projection_faded)
            self.predistorted_negative_projections.append(
                predistorted_negative_projection_faded)

        rospy.loginfo("Waiting for projection setting service...")
        rospy.wait_for_service('set_projection')
        rospy.loginfo("Projection setting service found.")
        self.set_projection = rospy.ServiceProxy('set_projection',
                                                 projector.srv.SetProjection)

        self.pixel_associations_msg = None
        self.point_cloud_msg = None

        rospy.Service("~get_point_cloud", graycode_scanner.srv.GetPointCloud,
                      self.handle_point_cloud_srv)

        point_cloud_pub = rospy.Publisher('~point_cloud',
                                          sensor_msgs.msg.PointCloud)

        rospy.loginfo("Ready.")

        rate = rospy.Rate(1)
        while not rospy.is_shutdown():
            if self.point_cloud_msg is not None:
                point_cloud_pub.publish(self.point_cloud_msg)
            rate.sleep()

    def read_scanner_info(self):
        try:
            input_stream = file(self.scanner_info_file_name, 'r')
        except IOError:
            rospy.loginfo('Specified scanner info file at ' +
                          self.scanner_info_file_name + ' does not exist.')
            return
        info_dict = yaml.load(input_stream)
        try:
            self.projector_to_camera_translation_vector = tuple(
                info_dict['projector_to_camera_translation_vector'])
            self.projector_to_camera_rotation_vector = list_to_matrix(
                info_dict['projector_to_camera_rotation_vector'], 3, 1,
                cv.CV_32FC1)
        except (TypeError, KeyError):
            rospy.loginfo('Scanner info file at ' +
                          self.scanner_info_file_name +
                          ' is in an unrecognized format.')
            return
        rospy.loginfo('Scanner info successfully read from ' +
                      self.scanner_info_file_name)

    def update_image(self, imagemsg):
        with self.mutex:
            if not self.image_update_flag.is_set():
                self.latest_image = self.bridge.imgmsg_to_cv(imagemsg, "mono8")
                self.image_update_flag.set()

    def get_next_image(self):
        with self.mutex:
            self.image_update_flag.clear()
        self.image_update_flag.wait()
        with self.mutex:
            return self.latest_image

    def get_picture_of_projection(self, projection):
        image_message = self.bridge.cv_to_imgmsg(projection, encoding="mono8")
        self.set_projection(image_message)
        return self.get_next_image()

    def get_projector_line_associations(self):
        rospy.loginfo("Scanning...")
        positives = []
        negatives = []
        for i in range(self.number_of_projection_patterns):
            positives.append(
                self.get_picture_of_projection(
                    self.predistorted_positive_projections[i]))
            negatives.append(
                self.get_picture_of_projection(
                    self.predistorted_negative_projections[i]))

        rospy.loginfo("Thresholding...")
        strike_sum = cv.CreateMat(self.camera_info.height,
                                  self.camera_info.width, cv.CV_32SC1)
        cv.SetZero(strike_sum)
        gray_codes = cv.CreateMat(self.camera_info.height,
                                  self.camera_info.width, cv.CV_32SC1)
        cv.SetZero(gray_codes)
        for i in range(self.number_of_projection_patterns):
            difference = cv.CreateMat(self.camera_info.height,
                                      self.camera_info.width, cv.CV_8UC1)
            cv.Sub(positives[i], negatives[i], difference)

            absolute_difference = cv.CreateMat(self.camera_info.height,
                                               self.camera_info.width,
                                               cv.CV_8UC1)
            cv.AbsDiff(positives[i], negatives[i], absolute_difference)

            #Mark all the pixels that were "too close to call" and add them to the running total
            strike_mask = cv.CreateMat(self.camera_info.height,
                                       self.camera_info.width, cv.CV_8UC1)
            cv.CmpS(absolute_difference, self.threshold, strike_mask,
                    cv.CV_CMP_LT)
            strikes = cv.CreateMat(self.camera_info.height,
                                   self.camera_info.width, cv.CV_32SC1)
            cv.Set(strikes, 1, strike_mask)
            cv.Add(strikes, strike_sum, strike_sum)

            #Set the corresponding bit in the gray_code
            bit_mask = cv.CreateMat(self.camera_info.height,
                                    self.camera_info.width, cv.CV_8UC1)
            cv.CmpS(difference, 0, bit_mask, cv.CV_CMP_GT)
            bit_values = cv.CreateMat(self.camera_info.height,
                                      self.camera_info.width, cv.CV_32SC1)
            cv.Set(bit_values, 2**i, bit_mask)
            cv.Or(bit_values, gray_codes, gray_codes)

        rospy.loginfo("Decoding...")
        # Decode every gray code into binary
        projector_line_associations = cv.CreateMat(self.camera_info.height,
                                                   self.camera_info.width,
                                                   cv.CV_32SC1)
        cv.Copy(gray_codes, projector_line_associations)
        for i in range(
                cv.CV_MAT_DEPTH(cv.GetElemType(projector_line_associations)),
                -1, -1):
            projector_line_associations_bitshifted_right = cv.CreateMat(
                self.camera_info.height, self.camera_info.width, cv.CV_32SC1)
            #Using ConvertScale with a shift of -0.5 to do integer division for bitshifting right
            cv.ConvertScale(projector_line_associations,
                            projector_line_associations_bitshifted_right,
                            (2**-(2**i)), -0.5)
            cv.Xor(projector_line_associations,
                   projector_line_associations_bitshifted_right,
                   projector_line_associations)

        rospy.loginfo("Post processing...")

        # Remove all pixels that were "too close to call" more than once
        strikeout_mask = cv.CreateMat(self.camera_info.height,
                                      self.camera_info.width, cv.CV_8UC1)
        cv.CmpS(strike_sum, 1, strikeout_mask, cv.CV_CMP_GT)
        cv.Set(projector_line_associations, -1, strikeout_mask)

        # Remove all pixels that don't decode to a valid scanline number
        invalid_scanline_mask = cv.CreateMat(self.camera_info.height,
                                             self.camera_info.width,
                                             cv.CV_8UC1)
        cv.InRangeS(projector_line_associations, 0, self.number_of_scanlines,
                    invalid_scanline_mask)
        cv.Not(invalid_scanline_mask, invalid_scanline_mask)
        cv.Set(projector_line_associations, -1, invalid_scanline_mask)

        self.display_scanline_associations(projector_line_associations)

        return projector_line_associations

    def handle_point_cloud_srv(self, req):
        response = graycode_scanner.srv.GetPointCloudResponse()
        self.get_point_cloud()
        response.point_cloud = self.point_cloud_msg
        response.success = True
        return response

    def get_point_cloud(self):

        # Scan the scene
        col_associations = self.get_projector_line_associations()

        # Project white light onto the scene to get the intensities of each pixel (for coloring our point cloud)
        illumination_projection = cv.CreateMat(self.projector_info.height,
                                               self.projector_info.width,
                                               cv.CV_8UC1)
        cv.Set(illumination_projection, 255)
        intensities_image = self.get_picture_of_projection(
            illumination_projection)

        # Turn projector off when done with it
        off_projection = cv.CreateMat(self.projector_info.height,
                                      self.projector_info.width, cv.CV_8UC1)
        cv.SetZero(off_projection)
        off_image_message = self.bridge.cv_to_imgmsg(off_projection,
                                                     encoding="mono8")
        self.set_projection(off_image_message)

        camera_model = PinholeCameraModel()
        camera_model.fromCameraInfo(self.camera_info)

        valid_points_mask = cv.CreateMat(self.camera_info.height,
                                         self.camera_info.width, cv.CV_8UC1)
        cv.CmpS(col_associations, -1, valid_points_mask, cv.CV_CMP_NE)

        number_of_valid_points = cv.CountNonZero(valid_points_mask)

        rectified_camera_coordinates = cv.CreateMat(1, number_of_valid_points,
                                                    cv.CV_32FC2)
        scanline_associations = cv.CreateMat(1, number_of_valid_points,
                                             cv.CV_32FC1)
        intensities = cv.CreateMat(1, number_of_valid_points, cv.CV_8UC1)
        i = 0
        for row in range(self.camera_info.height):
            for col in range(self.camera_info.width):
                if valid_points_mask[row, col] != 0:
                    rectified_camera_coordinates[0, i] = (col, row)
                    scanline_associations[0, i] = col_associations[row, col]
                    intensities[0, i] = intensities_image[row, col]
                    i += 1

        cv.UndistortPoints(rectified_camera_coordinates,
                           rectified_camera_coordinates,
                           camera_model.intrinsicMatrix(),
                           camera_model.distortionCoeffs())

        # Convert scanline numbers to plane normal vectors
        planes = self.scanline_numbers_to_planes(scanline_associations)

        camera_rays = project_pixels_to_3d_rays(rectified_camera_coordinates,
                                                camera_model)

        intersection_points = ray_plane_intersections(camera_rays, planes)

        self.point_cloud_msg = sensor_msgs.msg.PointCloud()
        self.point_cloud_msg.header.stamp = rospy.Time.now()
        self.point_cloud_msg.header.frame_id = 'base_link'
        channels = []
        channel = sensor_msgs.msg.ChannelFloat32()
        channel.name = "intensity"
        points = []
        intensities_list = []

        for i in range(number_of_valid_points):
            point = geometry_msgs.msg.Point32()
            point.x = intersection_points[0, i][0]
            point.y = intersection_points[0, i][1]
            point.z = intersection_points[0, i][2]
            if point.z < 0:
                print scanline_associations[0, i]
                print rectified_camera_coordinates[0, i]

            points.append(point)
            intensity = intensities[0, i]
            intensities_list.append(intensity)

        channel.values = intensities_list
        channels.append(channel)
        self.point_cloud_msg.channels = channels
        self.point_cloud_msg.points = points

        return self.point_cloud_msg

    def scanline_numbers_to_planes(self, scanline_numbers):
        rows = scanline_numbers.height
        cols = scanline_numbers.width
        normal_vectors_x = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.Set(normal_vectors_x, -1)
        normal_vectors_y = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.Set(normal_vectors_y, 0)
        normal_vectors_z = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.Copy(scanline_numbers, normal_vectors_z)

        cv.ConvertScale(normal_vectors_z,
                        normal_vectors_z,
                        scale=self.pixels_per_scanline)
        cv.AddS(normal_vectors_z, -self.center_pixel, normal_vectors_z)
        cv.ConvertScale(normal_vectors_z,
                        normal_vectors_z,
                        scale=1.0 / self.projector_model.fx())

        normal_vectors = cv.CreateMat(rows, cols, cv.CV_32FC3)
        cv.Merge(normal_vectors_x, normal_vectors_y, normal_vectors_z, None,
                 normal_vectors)

        # Bring the normal vectors into camera coordinates
        cv.Transform(normal_vectors, normal_vectors,
                     self.projector_to_camera_rotation_matrix)

        normal_vectors_split = [None] * 3
        for i in range(3):
            normal_vectors_split[i] = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.Split(normal_vectors, normal_vectors_split[0],
                 normal_vectors_split[1], normal_vectors_split[2], None)

        n_dot_p = cv.CreateMat(rows, cols, cv.CV_32FC1)
        cv.SetZero(n_dot_p)
        for i in range(3):
            cv.ScaleAdd(normal_vectors_split[i],
                        self.projector_to_camera_translation_vector[i],
                        n_dot_p, n_dot_p)

        planes = cv.CreateMat(rows, cols, cv.CV_32FC4)
        cv.Merge(normal_vectors_split[0], normal_vectors_split[1],
                 normal_vectors_split[2], n_dot_p, planes)

        return planes

    def display_scanline_associations(self, associations):
        display_image = cv.CreateMat(self.camera_info.height,
                                     self.camera_info.width, cv.CV_8UC1)
        cv.ConvertScale(associations, display_image,
                        255.0 / self.number_of_scanlines)
        cv.NamedWindow("associations", flags=0)
        cv.ShowImage("associations", display_image)
        cv.WaitKey(800)
class PixelConversion():
    def __init__(self):
        self.image_topic = "wall_camera/image_raw"
        self.image_info_topic = "wall_camera/camera_info"
        self.point_topic = "/clicked_point"
        self.frame_id = "/map"

        self.pixel_x = 350
        self.pixel_y = 215

        # What we do during shutdown
        rospy.on_shutdown(self.cleanup)

        # Create the OpenCV display window for the RGB image
        self.cv_window_name = self.image_topic
        cv.NamedWindow(self.cv_window_name, cv.CV_WINDOW_NORMAL)
        cv.MoveWindow(self.cv_window_name, 25, 75)

        # Create the cv_bridge object
        self.bridge = CvBridge()

        self.image_sub = rospy.Subscriber(self.image_topic, Image, self.image_cb, queue_size = 1)
        self.image_info_sub = rospy.Subscriber(self.image_info_topic, CameraInfo, self.image_info_cb, queue_size = 1)
        self.point_sub = rospy.Subscriber(self.point_topic, PointStamped, self.point_cb, queue_size = 4)

        self.line_pub = rospy.Publisher("line", Marker, queue_size = 10)
        self.inter_pub = rospy.Publisher("inter", Marker, queue_size = 10)
        self.plane_pub = rospy.Publisher("plane", Marker, queue_size = 10)

        self.points = []
        self.ready_for_image = False
        self.has_pic = False
        self.camera_info_msg = None

        self.tf_listener = tf.TransformListener()

        # self.display_picture()
        self.camera_model = PinholeCameraModel()
        

    def point_cb(self, point_msg):
        if len(self.points) < 4:
            self.points.append(point_msg.point)

        if len(self.points) == 1:
            self.ready_for_image = True 
            print "Point stored from click: ", point_msg.point


    def image_cb(self, img_msg):
        if self.ready_for_image:
            # Use cv_bridge() to convert the ROS image to OpenCV format
            try:
                frame = self.bridge.imgmsg_to_cv2(img_msg, "bgr8")
            except CvBridgeError, e:
                print e
            
            # Convert the image to a Numpy array since most cv2 functions
            # require Numpy arrays.
            frame = np.array(frame, dtype=np.uint8)
            print "Got array"
            
            # Process the frame using the process_image() function
            #display_image = self.process_image(frame)
                           
            # Display the image.
            self.img = frame 
            # self.has_pic = True
            

            if self.camera_info_msg is not None:
                print "cx ", self.camera_model.cx()
                print "cy ", self.camera_model.cy()
                print "fx ", self.camera_model.fx()
                print "fy ", self.camera_model.fy()

                # Get the point from the clicked message and transform it into the camera frame                
                self.tf_listener.waitForTransform(img_msg.header.frame_id, self.frame_id, rospy.Time(0), rospy.Duration(0.5))
                (trans,rot) = self.tf_listener.lookupTransform(img_msg.header.frame_id, self.frame_id, rospy.Time(0))
                self.tfros = tf.TransformerROS()
                tf_mat = self.tfros.fromTranslationRotation(trans, rot)
                point_in_camera_frame = tuple(np.dot(tf_mat, np.array([self.points[0].x, self.points[0].y, self.points[0].z, 1.0])))[:3]
                # Get the pixels related to the clicked point (the point must be in the camera frame)
                pixel_coords = self.camera_model.project3dToPixel(point_in_camera_frame)
                print "Pixel coords ", pixel_coords

                # Get the unit vector related to the pixel coords 
                unit_vector = self.camera_model.projectPixelTo3dRay((int(pixel_coords[0]), int(pixel_coords[1])))
                print "Unit vector ", unit_vector

                # TF the unit vector of the pixel to the frame of the clicked point from the map frame
                # self.tf_listener.waitForTransform(self.frame_id, img_msg.header.frame_id, rospy.Time(0), rospy.Duration(0.5))
                # (trans,rot) = self.tf_listener.lookupTransform(self.frame_id, img_msg.header.frame_id, rospy.Time(0))
                # self.tfros = tf.TransformerROS()
                # tf_mat = self.tfros.fromTranslationRotation(trans, rot)
                # xyz = tuple(np.dot(tf_mat, np.array([unit_vector[0], unit_vector[1], unit_vector[2], 1.0])))[:3]

                # print "World xyz ", xyz 

                # intersect the unit vector with the ground plane 

                red = (0,125,255)
                cv2.circle(self.img, (int(pixel_coords[0]), int(pixel_coords[1])), 30, red)
                cv2.imshow(self.image_topic, self.img)


                ''' trying better calculations for going from pixel to world '''

                # need plane of the map in camera frame points
                # (0, 0, 0), (1, 1, 0), (-1, -1, 0) = map plane in map frame coordinates
                p1 = [-94.0, -98.0, 0.0]
                p2 = [-92.0, -88.0, 0.0]
                p3 = [-84.0, -88.0, 0.0]
                # p2 = [1.0, -1.0, 0.0]
                # p3 = [-1.0, -1.0, 0.0]
                # point_marker = self.create_points_marker([p1, p2, p3], "/map")
                # self.plane_pub.publish(point_marker)

                self.tf_listener.waitForTransform(img_msg.header.frame_id, self.frame_id, rospy.Time(0), rospy.Duration(0.5))
                (trans,rot) = self.tf_listener.lookupTransform(img_msg.header.frame_id, self.frame_id,  rospy.Time(0))
                self.tfros = tf.TransformerROS()
                tf_mat = self.tfros.fromTranslationRotation(trans, rot)

                # pts in camera frame coodrds
                p1 = list(np.dot(tf_mat, np.array([p1[0], p1[1], p1[2], 1.0])))[:3]
                p2 = list(np.dot(tf_mat, np.array([p2[0], p2[1], p2[2], 1.0])))[:3]
                p3 = list(np.dot(tf_mat, np.array([p3[0], p3[1], p3[2], 1.0])))[:3]
                plane_norm = self.get_plane_normal(p1, p2, p3) ## maybe viz
                print "P1 ", p1
                print "P2 ", p2
                print "P3 ", p3
                print "Plane norm: ", plane_norm
                point_marker = self.create_points_marker([p1, p2, p3], img_msg.header.frame_id)
                self.plane_pub.publish(point_marker)

                
                # need unit vector to define ray to cast onto plane
                line_pt = list(unit_vector)
                line_norm = self.get_line_normal([0.0,0.0,0.0], np.asarray(line_pt) * 10) # just scale the unit vector for another point, maybe just use both unit vector for the point and the line

                inter = self.line_plane_intersection(line_pt, line_norm, p1, plane_norm)

                ## intersection is in the camera frame...
                ### tf this into map frame
                self.tf_listener.waitForTransform(self.frame_id, img_msg.header.frame_id, rospy.Time(0), rospy.Duration(0.5))
                (trans,rot) = self.tf_listener.lookupTransform(self.frame_id, img_msg.header.frame_id, rospy.Time(0))
                self.tfros = tf.TransformerROS()
                tf_mat = self.tfros.fromTranslationRotation(trans, rot)
                xyz = tuple(np.dot(tf_mat,np.array([inter[0], inter[1], inter[2], 1.0])))[:3]
                print "intersection pt: ", xyz
                point_marker = self.create_point_marker(xyz, "/map")
                self.inter_pub.publish(point_marker)

                line_marker = self.create_line_marker([0.0,0.0,0.0], np.asarray(unit_vector) * 30, img_msg.header.frame_id) 
                self.line_pub.publish(line_marker)



            self.ready_for_image = False
            self.points = []
    def detections_callback(self, detection):
        global counter
        global maxDistance  #the maximal distance between two points required for them to be considered the same detection
        global alreadyDetected
        global n
        global lastAdded
        global detected
        global numFaces
        global brojach
        global avgx
        global avgy
        global avgr
        global flag
        global maxHeight
        global minHeight
        global maxDistRing
        if flag == 0:
            if brojach < 10:
                avgx = avgx + detection.pose.position.x
                avgy = avgy + detection.pose.position.y
                avgr = avgr + detection.pose.position.z
                brojach = brojach + 1
                return
            if brojach == 10:
                tp = detection
                avgx = avgx / 10
                avgy = avgy / 10
                avgr = avgr / 10
                camera_info = None
                best_time = 100
                for ci in self.camera_infos:
                    time = abs(ci.header.stamp.to_sec() -
                               detection.header.stamp.to_sec())
                    if time < best_time:
                        camera_info = ci
                        best_time = time

                if not camera_info or best_time > 1:
                    print("Best time is higher than 1")
                    tp.pose.position.z = -1
                    self.pub_avg_ring.publish(tp)
                    flag = 1
                    return

                camera_model = PinholeCameraModel()
                camera_model.fromCameraInfo(camera_info)

                p = Point(
                    ((avgx - camera_model.cx()) - camera_model.Tx()) /
                    camera_model.fx(),
                    ((avgy + avgr - camera_model.cy()) - camera_model.Ty()) /
                    camera_model.fy(), 0)
                #p2 = Point(((avgx - camera_model.cx()) - camera_model.Tx()) / camera_model.fx(),((avgy -avgr - camera_model.cy()) - camera_model.Ty()) / camera_model.fy(), 0)
                avgx = avgy = avgr = 0
                lp = self.localize(detection.header, p1, self.region_scope)
                #lp2 = self.localize(detection.header, p2, self.region_scope)
                self.tf.waitForTransform(detection.header.frame_id, "map",
                                         rospy.Time.now(), rospy.Duration(5.0))
                mp = geometry_msgs.msg.PoseStamped()
                mp.header.frame_id = detection.header.frame_id
                mp.pose = lp.pose
                mp.header.stamp = detection.header.stamp
                tp = self.tf.transformPose("map", mp1)

                #mp2 = geometry_msgs.msg.PoseStamped()
                #mp2.header.frame_id = detection.header.frame_id
                #mp2.pose = lp2.pose
                #mp2.header.stamp = detection.header.stamp
                #tp2 = self.tf.transformPose("map", mp2)

                now2 = rospy.Time.now()
                self.tf2.waitForTransform("base_link", "map", now2,
                                          rospy.Duration(5.0))

                robot = geometry_msgs.msg.PoseStamped()
                robot.header.frame_id = "base_link"
                robot.pose.position.x = 0
                robot.pose.position.y = 0
                robot.header.stamp = now2
                robotmap = self.tf2.transformPose("map", robot)

                if lp1.pose.position.z != 0:
                    dp1 = self.distance(robotmap, tp)
                    if dp > maxDistRing:
                        print("Distance too big: ", dp)
                        tp.pose.position.z = -1
                    if tp.pose.position.z > maxHeight + 0.2 or tp.pose.position.z < minHeight:
                        print("Height is wrong: ", tp.pose.position.z)
                        tp.pose.position.z = -1
                    #if ((point1.y - point2.y)/2 > 0.7 or (point1.y - point2.y)/2 < 0.5):
                    #	tp.pose.position.z = -1
                    #if (point1.z > 0.5 or point1.z < 0.3):
                    #	tp.pose.position.z = -1
                    #if (point2.z > 0.5 or point2.z < 0.3): # visina
                    #	tp.pose.position.z = -1
                else:
                    print("Localizer failed")
                    tp.pose.position.z = -1
                self.pub_avg_ring.publish(tp)
                flag = 1
                return

        if flag == 1:
            u = detection.pose.position.x
            #u = avgx+avgr
            v = detection.pose.position.y + detection.pose.position.z
            #v = avgy

            w = detection.pose.position.x
            #w = avgx-avgr
            q = detection.pose.position.y - detection.pose.position.z

            g = detection.pose.position.x
            #w = avgx-avgr
            h = detection.pose.position.y + detection.pose.position.z + 3

            r = detection.pose.position.x
            #w = avgx-avgr
            t = detection.pose.position.y + detection.pose.position.z - 3
            #q = avgy

            camera_info = None
            best_time = 100
            for ci in self.camera_infos:
                time = abs(ci.header.stamp.to_sec() -
                           detection.header.stamp.to_sec())
                if time < best_time:
                    camera_info = ci
                    best_time = time

            if not camera_info or best_time > 1:
                print("Best time is higher than 1")
                return

            camera_model = PinholeCameraModel()
            camera_model.fromCameraInfo(camera_info)

            point1 = Point(((u - camera_model.cx()) - camera_model.Tx()) /
                           camera_model.fx(),
                           ((v - camera_model.cy()) - camera_model.Ty()) /
                           camera_model.fy(), 1)

            point2 = Point(((w - camera_model.cx()) - camera_model.Tx()) /
                           camera_model.fx(),
                           ((q - camera_model.cy()) - camera_model.Ty()) /
                           camera_model.fy(), 1)

            point3 = Point(((g - camera_model.cx()) - camera_model.Tx()) /
                           camera_model.fx(),
                           ((h - camera_model.cy()) - camera_model.Ty()) /
                           camera_model.fy(), 1)

            point4 = Point(((r - camera_model.cx()) - camera_model.Tx()) /
                           camera_model.fx(),
                           ((t - camera_model.cy()) - camera_model.Ty()) /
                           camera_model.fy(), 1)

            localization1 = self.localize(detection.header, point1,
                                          self.region_scope)
            localization2 = self.localize(detection.header, point2,
                                          self.region_scope)
            localization3 = self.localize(detection.header, point3,
                                          self.region_scope)
            localization4 = self.localize(detection.header, point4,
                                          self.region_scope)
            if not (localization1 or localization2 or localization3
                    or localization):
                print("Localization failed")
                return
            now = detection.header.stamp
            self.tf.waitForTransform(detection.header.frame_id, "map", now,
                                     rospy.Duration(5.0))

            m = geometry_msgs.msg.PoseStamped()
            m.header.frame_id = detection.header.frame_id
            m.pose = localization1.pose
            m.header.stamp = detection.header.stamp
            transformedPoint1 = self.tf.transformPose("map", m)

            m2 = geometry_msgs.msg.PoseStamped()
            m2.header.frame_id = detection.header.frame_id
            m2.pose = localization2.pose
            m2.header.stamp = detection.header.stamp
            transformedPoint2 = self.tf.transformPose("map", m2)

            m3 = geometry_msgs.msg.PoseStamped()
            m3.header.frame_id = detection.header.frame_id
            m3.pose = localization3.pose
            m3.header.stamp = detection.header.stamp
            transformedPoint3 = self.tf.transformPose("map", m3)

            m4 = geometry_msgs.msg.PoseStamped()
            m4.header.frame_id = detection.header.frame_id
            m4.pose = localization4.pose
            m4.header.stamp = detection.header.stamp
            transformedPoint4 = self.tf.transformPose("map", m4)

            now2 = rospy.Time.now()
            self.tf2.waitForTransform("base_link", "map", now2,
                                      rospy.Duration(5.0))

            robot = geometry_msgs.msg.PoseStamped()
            robot.header.frame_id = "base_link"
            robot.pose.position.x = 0
            robot.pose.position.y = 0
            robot.header.stamp = now2
            robotmap = self.tf2.transformPose("map", robot)

            if localization1.pose.position.z != 0:
                dist1 = self.distance(robotmap, transformedPoint1)
            else:
                dist1 = 100000
            if localization2.pose.position.z != 0:
                dist2 = self.distance(robotmap, transformedPoint2)
            else:
                dist2 = 100000
            if localization3.pose.position.z != 0:
                dist3 = self.distance(robotmap, transformedPoint3)
            else:
                dist3 = 100000
            if localization4.pose.position.z != 0:
                dist4 = self.distance(robotmap, transformedPoint4)
            else:
                dist4 = 100000
            # find smallest distance to a point.
            dist = dist1
            transformedPoint = transformedPoint1

            if dist2 < dist:
                dist = dist2
                transformedPoint = transformedPoint2
            if dist3 < dist:
                dist = dist3
                transformedPoint = transformedPoint3
            if dist4 < dist:
                dist = dist4
                transformedPoint = transformedPoint4

            print("distance: ", dist)
            if (dist < maxDistRing):
                radius = abs((transformedPoint1.pose.position.y -
                              transformedPoint2.pose.position.y) / 2)
                print("radius: ", radius)
                print("height: ", transformedPoint.pose.position.z)
                if (dist1 < maxDistRing
                        and dist2 < maxDistRing) or (dist1 > maxDistRing
                                                     and dist2 > maxDistRing):
                    print("Checking radius")
                    if (radius > 0.7 or radius < 0.3):
                        print("Wrong radius")
                        return
                else:
                    print("Cant use radius")
                if (transformedPoint.pose.position.z > maxHeight
                        or transformedPoint.pose.position.z < minHeight):
                    print("Wrong height")
                    return
                print("start checking")
                print("Detected rings: ", len(detected))
                if len(detected) == 0:
                    beenDetected = False
                else:
                    beenDetected = False
                    for p in detected:
                        if self.distance(p, transformedPoint) <= maxDistance:
                            print("Already detected ring!")
                            beenDetected = True
                            break

                if (beenDetected == False):
                    detected.append(transformedPoint)
                    print("Publishing new ring")
                    self.pub_ring.publish(transformedPoint)
                    marker = Marker()
                    marker.header.stamp = detection.header.stamp
                    marker.header.frame_id = transformedPoint.header.frame_id
                    marker.pose.position.x = transformedPoint.pose.position.x
                    marker.pose.position.y = transformedPoint.pose.position.y
                    marker.pose.position.z = transformedPoint.pose.position.z
                    marker.type = Marker.CUBE
                    marker.action = Marker.ADD
                    marker.frame_locked = False
                    marker.lifetime = rospy.Duration.from_sec(1)
                    marker.id = self.marker_id_counter
                    marker.scale = Vector3(0.1, 0.1, 0.1)
                    marker.color = ColorRGBA(1, 0, 0, 1)
                    self.markers.markers.append(marker)
                    self.marker_id_counter += 1
                    print("Number of detected rings: ", len(detected))
                    #if len(detected) == numFaces:
                    #	print("Sending shutdown")
            else:
                print("Too far away")
class GridToImageConverter():
    def __init__(self):
        self.image_topic = "wall_camera/image_raw"
        self.image_info_topic = "wall_camera/camera_info"
        self.point_topic = "/clicked_point"
        self.frame_id = "/map"
        self.occupancy 

        self.pixel_x = 350
        self.pixel_y = 215

        # What we do during shutdown
        rospy.on_shutdown(self.cleanup)

        # Create the OpenCV display window for the RGB image
        self.cv_window_name = self.image_topic
        cv.NamedWindow(self.cv_window_name, cv.CV_WINDOW_NORMAL)
        cv.MoveWindow(self.cv_window_name, 25, 75)

        # Create the cv_bridge object
        self.bridge = CvBridge()

        self.image_sub = rospy.Subscriber(self.image_topic, Image, self.image_cb, queue_size = 1)
        self.image_info_sub = rospy.Subscriber(self.image_info_topic, CameraInfo, self.image_info_cb, queue_size = 1)
        self.point_sub = rospy.Subscriber(self.point_topic, PointStamped, self.point_cb, queue_size = 4)

        self.points = []
        self.ready_for_image = False
        self.has_pic = False
        self.camera_info_msg = None

        self.tf_listener = tf.TransformListener()

        # self.display_picture()
        self.camera_model = PinholeCameraModel()
        

    def point_cb(self, point_msg):
        if len(self.points) < 4:
            self.points.append(point_msg.point)

        if len(self.points) == 1:
            self.ready_for_image = True 
            print "Point stored from click: ", point_msg.point


    def image_cb(self, img_msg):
        if self.ready_for_image:
            # Use cv_bridge() to convert the ROS image to OpenCV format
            try:
                frame = self.bridge.imgmsg_to_cv2(img_msg, "bgr8")
            except CvBridgeError, e:
                print e
            
            # Convert the image to a Numpy array since most cv2 functions
            # require Numpy arrays.
            frame = np.array(frame, dtype=np.uint8)
            print "Got array"
            
            # Process the frame using the process_image() function
            #display_image = self.process_image(frame)
                           
            # Display the image.
            self.img = frame 
            # self.has_pic = True
            

            if self.camera_info_msg is not None:
                print "cx ", self.camera_model.cx()
                print "cy ", self.camera_model.cy()
                print "fx ", self.camera_model.fx()
                print "fy ", self.camera_model.fy()

                # Get the point from the clicked message and transform it into the camera frame                
                self.tf_listener.waitForTransform(img_msg.header.frame_id, self.frame_id, rospy.Time(0), rospy.Duration(0.5))
                (trans,rot) = self.tf_listener.lookupTransform(img_msg.header.frame_id, self.frame_id, rospy.Time(0))
                self.tfros = tf.TransformerROS()
                tf_mat = self.tfros.fromTranslationRotation(trans, rot)
                point_in_camera_frame = tuple(np.dot(tf_mat, np.array([self.points[0].x, self.points[0].y, self.points[0].z, 1.0])))[:3]
                # Get the pixels related to the clicked point (the point must be in the camera frame)
                pixel_coords = self.camera_model.project3dToPixel(point_in_camera_frame)
                print "Pixel coords ", pixel_coords

                # Get the unit vector related to the pixel coords 
                unit_vector = self.camera_model.projectPixelTo3dRay((int(pixel_coords[0]), int(pixel_coords[1])))
                print "Unit vector ", unit_vector

                # TF the unit vector of the pixel to the frame of the clicked point from the map frame
                self.tf_listener.waitForTransform(self.frame_id, img_msg.header.frame_id, rospy.Time(0), rospy.Duration(0.5))
                (trans,rot) = self.tf_listener.lookupTransform(self.frame_id, img_msg.header.frame_id, rospy.Time(0))
                self.tfros = tf.TransformerROS()
                tf_mat = self.tfros.fromTranslationRotation(trans, rot)
                xyz = tuple(np.dot(tf_mat, np.array([unit_vector[0], unit_vector[1], unit_vector[2], 1.0])))[:3]

                print "World xyz ", xyz 

                red = (0,125,255)
                cv2.circle(self.img, (int(pixel_coords[0]), int(pixel_coords[1])), 30, red)
                cv2.imshow(self.image_topic, self.img)


            self.ready_for_image = False
            self.points = []
            
            # Process any keyboard commands
            self.keystroke = cv.WaitKey(5)
            if 32 <= self.keystroke and self.keystroke < 128:
                cc = chr(self.keystroke).lower()
                if cc == 'q':
                    # The user has press the q key, so exit
                    rospy.signal_shutdown("User hit q key to quit.")
Exemple #9
0
    def detections_callback(self, detection):
        global counter
        global maxDistance  #the maximal distance between two points required for them to be considered the same detection
        global alreadyDetected
        global n
        global lastAdded
        global detected
        global numFaces
        global brojach
        global avgx
        global avgy
        global avgr
        global flag
        if flag == 0:
            if brojach < 10:
                avgx = avgx + detection.pose.position.x
                avgy = avgy + detection.pose.position.y
                avgr = avgr + detection.pose.position.z
                brojach = brojach + 1
                return
            if brojach == 10:
                avgx = avgx / 10
                avgy = avgy / 10
                avgr = avgr / 10
                p = Point(((avgx - camera_model.cx()) - camera_model.Tx()) /
                          camera_model.fx(),
                          ((avgy - camera_model.cy()) - camera_model.Ty()) /
                          camera_model.fy(), avgr)
                lp = self.localize(detection.header, p, self.region_scope)
                self.tf.waitForTransform(detection.header.frame_id, "map",
                                         rospy.Time.now(), rospy.Duration(5.0))
                mp = geometry_msgs.msg.PoseStamped()
                mp.header.frame_id = detection.header.frame_id
                mp.pose = lp.pose
                mp.header.stamp = detection.header.stamp
                tp = self.tf.transformPose("map", mp)
                if lp.pose.position.x != 0:
                    dp = self.distance(robotmap, tp)
                    if dp > 1.5:
                        tp.pose.position.z = -1
                    #if ((point1.y - point2.y)/2 > 0.7 or (point1.y - point2.y)/2 < 0.5):
                    #	tp.pose.position.z = -1
                    #if (point1.z > 0.5 or point1.z < 0.3):
                    #	tp.pose.position.z = -1
                    #if (point2.z > 0.5 or point2.z < 0.3): # visina
                    #	tp.pose.position.z = -1
                else:
                    tp.pose.position.z = -1
                self.pub_avg_ring.publish(tp)
                flag = 1
                return

        if flag == 1:
            u = detection.pose.position.x
            #u = avgx+avgr
            v = detection.pose.position.y + detection.pose.position.z
            #v = avgy

            w = detection.pose.position.x
            #w = avgx-avgr
            q = detection.pose.position.y - detection.pose.position.z

            g = detection.pose.position.x
            #w = avgx-avgr
            h = detection.pose.position.y + detection.pose.position.z + 4

            r = detection.pose.position.x
            #w = avgx-avgr
            t = detection.pose.position.y + detection.pose.position.z - 4
            #q = avgy

            camera_info = None
            best_time = 100
            for ci in self.camera_infos:
                time = abs(ci.header.stamp.to_sec() -
                           detection.header.stamp.to_sec())
                if time < best_time:
                    camera_info = ci
                    best_time = time

            if not camera_info or best_time > 1:
                print("Best time is higher than 1")
                return

            camera_model = PinholeCameraModel()
            camera_model.fromCameraInfo(camera_info)

            point1 = Point(((u - camera_model.cx()) - camera_model.Tx()) /
                           camera_model.fx(),
                           ((v - camera_model.cy()) - camera_model.Ty()) /
                           camera_model.fy(), 1)

            point2 = Point(((w - camera_model.cx()) - camera_model.Tx()) /
                           camera_model.fx(),
                           ((q - camera_model.cy()) - camera_model.Ty()) /
                           camera_model.fy(), 1)

            point3 = Point(((g - camera_model.cx()) - camera_model.Tx()) /
                           camera_model.fx(),
                           ((h - camera_model.cy()) - camera_model.Ty()) /
                           camera_model.fy(), 1)

            point4 = Point(((r - camera_model.cx()) - camera_model.Tx()) /
                           camera_model.fx(),
                           ((t - camera_model.cy()) - camera_model.Ty()) /
                           camera_model.fy(), 1)

            localization1 = self.localize(detection.header, point1,
                                          self.region_scope)
            localization2 = self.localize(detection.header, point2,
                                          self.region_scope)
            localization3 = self.localize(detection.header, point3,
                                          self.region_scope)
            localization4 = self.localize(detection.header, point4,
                                          self.region_scope)
            if not localization1:
                return

            # calculate center
            center = Point(localization1.pose.position.x,
                           localization1.pose.position.y,
                           localization1.pose.position.z)
            now = detection.header.stamp
            self.tf.waitForTransform(detection.header.frame_id, "map", now,
                                     rospy.Duration(5.0))

            m = geometry_msgs.msg.PoseStamped()
            m.header.frame_id = detection.header.frame_id
            #m.pose.position.x = center.x
            #m.pose.position.y = center.y
            m.pose = localization1.pose
            m.header.stamp = detection.header.stamp
            transformedPoint1 = self.tf.transformPose("map", m)

            m2 = geometry_msgs.msg.PoseStamped()
            m2.header.frame_id = detection.header.frame_id
            m2.pose = localization2.pose
            m2.header.stamp = detection.header.stamp
            transformedPoint2 = self.tf.transformPose("map", m2)

            m3 = geometry_msgs.msg.PoseStamped()
            m3.header.frame_id = detection.header.frame_id
            m3.pose = localization3.pose
            m3.header.stamp = detection.header.stamp
            transformedPoint3 = self.tf.transformPose("map", m3)

            m4 = geometry_msgs.msg.PoseStamped()
            m4.header.frame_id = detection.header.frame_id
            m4.pose = localization4.pose
            m4.header.stamp = detection.header.stamp
            transformedPoint4 = self.tf.transformPose("map", m4)

            now2 = rospy.Time.now()
            self.tf2.waitForTransform("base_link", "map", now2,
                                      rospy.Duration(5.0))

            robot = geometry_msgs.msg.PoseStamped()
            robot.header.frame_id = "base_link"
            robot.pose.position.x = 0
            robot.pose.position.y = 0
            #robot.pose = localization1.pose
            robot.header.stamp = now2
            robotmap = self.tf2.transformPose("map", robot)

            #dist = self.distance(robotmap,transformedPoint)
            transformedPoint = transformedPoint1
            if localization1.pose.position.x != 0:
                dist1 = self.distance(robotmap, transformedPoint1)
            else:
                dist1 = 100000
            if localization2.pose.position.x != 0:
                dist2 = self.distance(robotmap, transformedPoint2)
                transformedPoint = transformedPoint2
            else:
                dist2 = 100000
            if localization3.pose.position.x != 0:
                dist3 = self.distance(robotmap, transformedPoint3)
                transformedPoint = transformedPoint3
            else:
                dist3 = 100000
            if localization4.pose.position.x != 0:
                dist4 = self.distance(robotmap, transformedPoint4)
                transformedPoint = transformedPoint4
            else:
                dist4 = 100000
            # find smallest distance to a point.
            dist = dist1
            if dist2 < dist:
                dist = dist2
            if dist3 < dist:
                dist = dist3
            if dist4 < dist:
                dist = dist4

            print("distance: ", dist)
            if (dist < 1.5):
                rad = abs((point1.y - point2.y) / 2)
                print("radius: ", rad)
                print("height p1: ", point1.z)
                print("height p2: ", point2.z)
                #if ((point1.y - point2.y)/2 > 0.7 or (point1.y - point2.y)/2 < 0.5):
                #	return
                #if (point1.z > 0.5 or point1.z < 0.3):
                #	return
                #if (point2.z > 0.5 or point2.z < 0.3): # visina
                #	return
                self.pub.publish(transformedPoint)
                print("start checking")
                print(len(detected))
                if len(detected) == 0:
                    detected.append(transformedPoint)
                    beenDetected = False
                else:
                    beenDetected = False
                    for p in detected:
                        if self.distance(p, transformedPoint) <= maxDistance:
                            print("Already detected ring!")
                            beenDetected = True
                            break

                if (beenDetected == False):
                    print("Publishing new ring")
                    self.pub_ring.publish(transformedPoint)
                    marker = Marker()
                    marker.header.stamp = detection.header.stamp
                    marker.header.frame_id = transformedPoint.header.frame_id
                    marker.pose.position.x = transformedPoint.pose.position.x
                    marker.pose.position.y = transformedPoint.pose.position.y
                    marker.pose.position.z = transformedPoint.pose.position.z
                    marker.type = Marker.CUBE
                    marker.action = Marker.ADD
                    marker.frame_locked = False
                    marker.lifetime = rospy.Duration.from_sec(1)
                    marker.id = self.marker_id_counter
                    marker.scale = Vector3(0.1, 0.1, 0.1)
                    marker.color = ColorRGBA(1, 0, 0, 1)
                    self.markers.markers.append(marker)
                    self.marker_id_counter += 1
                    print("Number of detected rings: ", len(detected))
                    if len(detected) == numFaces:
                        print("Sending shutdown")
            else:
                print("Just zeros")
class Realsense:
    """
    Class to use a Relsense camera for Hand detection
    """
    def __init__(self):
        """
        Constructor
        """
        rospy.init_node("ros_yolo", anonymous=True, disable_signals=False)

        self.bridge = CvBridge()
        self.rgb_lock = threading.Lock()
        self.depth_lock = threading.Lock()

        self.cameraModel = PinholeCameraModel()
        self.cameraInfo = CameraInfo()

        self.sub_color = rospy.Subscriber("/camera/color/image_raw",
                                          Image,
                                          self.color_callback,
                                          queue_size=1)

        self.sub_depth = rospy.Subscriber(
            "/camera/aligned_depth_to_color/image_raw",
            Image,
            self.depth_callback,
            queue_size=1)
        self.sub_camera_info = rospy.Subscriber("/camera/depth/camera_info",
                                                CameraInfo,
                                                self.camera_info_callback,
                                                queue_size=1)

        self.target_pub = rospy.Publisher("/hand_detection/target_camera",
                                          PoseStamped)

        self.color_img = np.zeros((480, 640, 3), np.uint8)
        self.depth_img = np.zeros((480, 640), np.uint8)
        self.img_width = 640
        self.img_height = 480
        self.hand_counter = 0
        self.not_hand_counter = 0
        self.hand_3D_pos = np.empty((0, 3), int)

    def _random_centered_pixels(self, box_x, box_y, box_w, box_h, radius,
                                samples):
        """
        Returns an array of pixel positions in 2D
        """
        pixels = []
        center_x = int(box_w / 2)
        center_y = int(box_h / 2)
        x = box_x + center_x - radius
        y = box_y + center_y - radius
        samples_limit = radius * radius

        if samples < samples_limit:
            random_positions = random.sample(range(0, samples_limit), samples)
            for sample in random_positions:
                pixel_x = x + (sample % radius)
                if pixel_x > (self.img_width / 2 - 1):
                    pixel_x = self.img_width / 2 - 1
                pixel_y = y + int(sample / radius)
                if pixel_y > (self.img_height / 2 - 1):
                    pixel_y = self.img_height / 2 - 1
                pixels.append([pixel_x, pixel_y])
        else:
            print("The samples number should be minor" + " than radius*radius")
        return pixels

    def _load_model(self, custom=True):
        if custom:
            model_def_path = "config/yolov3-custom-hand-arm.cfg"
            weights_path = "checkpoints-arm-hand/yolov3_ckpt_54.pth"
            class_path = "data/custom/classes.names"
        else:
            model_def_path = "config/yolov3.cfg"
            weights_path = "weights/yolov3.weights"
            class_path = "data/coco.names"

        self.img_size = 416

        # Object confidence threshold
        self.conf_thres = 0.95
        # IOU thresshold for non-maximum suppression
        self.nms_thres = 0.05

        if torch.cuda.is_available():
            print("---------GPU AVAILABLE---------")
            self.Tensor = torch.cuda.FloatTensor
        else:
            print("---------CPU AVAILABLE---------")
            self.Tensor = torch.FloatTensor

        # Create the model
        device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        self.model = Darknet(model_def_path, img_size=416).to(device)

        # Load the custom weights
        if custom:
            self.model.load_state_dict(torch.load(weights_path))
        else:
            self.model.load_darknet_weights(weights_path)

        self.model.eval()

        self.classes = load_classes(class_path)

        cmap = plt.get_cmap("tab20b")
        colors = [cmap(i) for i in np.linspace(0, 1, 10000)]
        self.bbox_colors = random.sample(colors, len(self.classes))

    def _infer(self):
        with self.rgb_lock:
            frame = self.color_img.copy()
            # frame = self.color_img
        # Display only purpose
        img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        img = ImagePIL.fromarray(frame)
        ratio = min(self.img_size / img.size[0], self.img_size / img.size[1])
        imw = round(img.size[0] * ratio)
        imh = round(img.size[1] * ratio)
        img_transforms = transforms.Compose([
            transforms.Resize((imh, imw)),
            transforms.Pad((max(int(
                (imh - imw) / 2), 0), max(int(
                    (imw - imh) / 2), 0), max(int(
                        (imh - imw) / 2), 0), max(int((imw - imh) / 2), 0)),
                           (128, 128, 128)),
            transforms.ToTensor(),
        ])

        image_tensor = img_transforms(img).float()
        image_tensor = image_tensor.unsqueeze_(0)
        input_img = Variable(image_tensor.type(self.Tensor))

        with torch.no_grad():
            detections = self.model(input_img)
            detections = non_max_suppression(detections, self.conf_thres,
                                             self.nms_thres)

        if detections[0] is not None:

            unit_scaling = 0.001
            center_x = self.cameraModel.cx()
            center_y = self.cameraModel.cy()
            constant_x = unit_scaling / self.cameraModel.fx()
            constant_y = unit_scaling / self.cameraModel.fy()

            # Rescale boxes to original image
            detections = rescale_boxes(detections[0], self.img_size,
                                       frame.shape[:2])

            unique_labels = detections[:, -1].cpu().unique()

            for x1, y1, x2, y2, conf, cls_conf, cls_pred in detections:
                box_w = x2 - x1
                box_h = y2 - y1
                w_proportion = box_w / img.size[0]
                h_proportion = box_h / img.size[1]
                if ((self.classes[int(cls_pred)] == 'Human hand'
                     or self.classes[int(cls_pred)] == 'Human arm')
                        and w_proportion >= 0.1 and w_proportion <= 0.90
                        and h_proportion >= 0.1 and h_proportion <= 1.0
                        and box_w > 10 and box_h > 10):

                    color = self.bbox_colors[int(
                        np.where(unique_labels == int(cls_pred))[0])]

                    frame = cv2.rectangle(
                        frame, (x1, y1), (x2, y2),
                        (color[0] * 255, color[1] * 255, color[2] * 255), 2)

                    cv2.putText(frame, self.classes[int(cls_pred)], (x1, y1),
                                cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255),
                                2, cv2.LINE_AA)

                    radius = 5
                    samples = 10
                    pixels = self._random_centered_pixels(
                        float(x1), float(y1), box_w, box_h, radius, samples)
                    depthPoint = []
                    arrayPoints = np.empty((0, 3), int)

                    for i in range(0, samples - 1):
                        x = int(pixels[i][0])
                        y = int(pixels[i][1])
                        depthPoint = np.array([
                            (x - center_x / 2) *
                            self.depth_img[y, x] * constant_x,
                            (y - center_y / 2) * self.depth_img[y, x] *
                            constant_y, self.depth_img[y, x] * unit_scaling
                        ])
                        if depthPoint.sum() > 0:
                            arrayPoints = np.append(arrayPoints, [depthPoint],
                                                    axis=0)

                    if len(arrayPoints) > 0:
                        mean_x = np.mean(arrayPoints[:, 0], axis=0)
                        mean_y = np.mean(arrayPoints[:, 1], axis=0)
                        mean_z = np.mean(arrayPoints[:, 2], axis=0)

                        pos_3D = np.array([mean_x, mean_y, mean_z])
                        if self.hand_counter == 0:
                            self.hand_3D_pos = pos_3D
                            self.hand_counter = 1
                        elif mean_z > 0.25 and mean_z < 1.20:
                            dist = np.linalg.norm(self.hand_3D_pos - pos_3D)
                            if ((dist < 0.10)
                                    or (pos_3D[2] < self.hand_3D_pos[2])):
                                self.hand_3D_pos = pos_3D
                                self.hand_counter = self.hand_counter + 1

                                if self.hand_counter > 2:
                                    # if self.hand_counter == 3:
                                    #    cv2.imwrite('hand.jpg', frame)

                                    header = std_msgs.msg.Header()
                                    header.stamp = rospy.Time.now()
                                    header.frame_id = 'RealSense_optical_frame'
                                    # publish
                                    p = PoseStamped()
                                    p.header.frame_id = 'target_camera'
                                    p.header.stamp = rospy.Time.now()

                                    p.pose.position.x = mean_x
                                    p.pose.position.y = mean_y
                                    p.pose.position.z = mean_z
                                    self.target_pub.publish(p)
                                    break
                            else:
                                self.not_hand_counter = self.not_hand_counter + 1

            if self.not_hand_counter > 20:
                self.hand_counter = 0
                self.not_hand_counter = 0

        cv2.imshow('frame', frame)
        cv2.waitKey(1)

    def color_callback(self, data):
        """
        Callback function for color image subscriber
        """
        try:
            with self.rgb_lock:
                cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
                self.color_img = cv_image
        except CvBridgeError as e:
            print(e)

    def depth_callback(self, data):
        """
        Callback function for depth image subscriber
        """
        try:
            with self.depth_lock:
                cv_image = self.bridge.imgmsg_to_cv2(data, "passthrough")
                self.depth_img = np.array(cv_image, dtype=np.float32)
        except CvBridgeError as e:
            print(e)

    def camera_info_callback(self, data):
        """
        Callback function for camera info subscriber
        """
        try:
            self.cameraModel.fromCameraInfo(data)
            self.cameraInfo = data
        except Error as e:
            print(e)
Exemple #11
0
    def detections_callback(self, detection):
        global counter
        global maxDistance  #the maximal distance between two points required for them to be considered the same detection
        global alreadyDetected
        global n
        global lastAdded
        global detected
        global numFaces

        u = detection.x + detection.width / 2
        v = detection.y + detection.height / 2

        camera_info = None
        best_time = 100
        for ci in self.camera_infos:
            time = abs(ci.header.stamp.to_sec() -
                       detection.header.stamp.to_sec())
            if time < best_time:
                camera_info = ci
                best_time = time

        if not camera_info or best_time > 1:
            print("Best time is higher than 1")
            return

        camera_model = PinholeCameraModel()
        camera_model.fromCameraInfo(camera_info)

        point = Point(
            ((u - camera_model.cx()) - camera_model.Tx()) / camera_model.fx(),
            ((v - camera_model.cy()) - camera_model.Ty()) / camera_model.fy(),
            1)

        localization = self.localize(detection.header, point,
                                     self.region_scope)
        transformedPoint = point
        if not localization:
            return

        now = detection.header.stamp
        self.tf.waitForTransform("camera_rgb_optical_frame", "map", now,
                                 rospy.Duration(5.0))

        m = geometry_msgs.msg.PoseStamped()
        m.header.frame_id = "camera_rgb_optical_frame"
        m.pose = localization.pose
        m.header.stamp = detection.header.stamp
        transformedPoint = self.tf.transformPose("map", m)

        if (localization.pose.position.x != 0.0):

            #print("Transformation: ", transformedPoint)
            beenDetected = False
            if counter == 0:
                lastAdded = transformedPoint
            else:
                lastAdded = transformedPoint
                for p in detected:

                    if self.distance(p, transformedPoint) <= maxDistance:
                        beenDetected = True
                        break

            if (beenDetected == False):
                counter += 1
                print("-----------------Good to go------------------------")
                detected.append(lastAdded)
                self.pub_face.publish(transformedPoint)
                marker = Marker()
                marker.header.stamp = detection.header.stamp
                marker.header.frame_id = detection.header.frame_id
                marker.pose = localization.pose
                marker.type = Marker.CUBE
                marker.action = Marker.ADD
                marker.frame_locked = False
                marker.lifetime = rospy.Duration.from_sec(1)
                marker.id = self.marker_id_counter
                marker.scale = Vector3(0.1, 0.1, 0.1)
                marker.color = ColorRGBA(1, 0, 0, 1)
                self.markers.markers.append(marker)
                self.marker_id_counter += 1
                #self.soundhandle.say("I detected a face.", blocking = False)
                print("Number of detected faces: ", len(detected))
                lastAdded = transformedPoint