diff --git a/src/add_qr.py b/src/add_qr.py index 095a8a3e1ae1db770956f3dd37a5d98857745619..86beb0741286e4f945704495500f81ddfa6f5d54 100755 --- a/src/add_qr.py +++ b/src/add_qr.py @@ -56,10 +56,10 @@ def json_to_transform(jobj): res.translation.x = jobj["tra"]["x"] res.translation.y = jobj["tra"]["y"] res.translation.z = jobj["tra"]["z"] - res.rotation.x = jobj["rot"]["x"] - res.rotation.y = jobj["rot"]["y"] - res.rotation.z = jobj["rot"]["z"] - res.rotation.w = jobj["rot"]["w"] + res.rotation.x = jobj["rot"]["x"] + res.rotation.y = jobj["rot"]["y"] + res.rotation.z = jobj["rot"]["z"] + res.rotation.w = jobj["rot"]["w"] return res def header_to_json(data): @@ -82,7 +82,7 @@ def image_callback(data): global fifo, remembered_points, have_points try: # print("image_callback_main") - if options.compressed: + if options.compressed: img = bridge.compressed_imgmsg_to_cv2(data, desired_encoding='bgr8') else: img = bridge.imgmsg_to_cv2(data, desired_encoding='bgr8') @@ -94,7 +94,7 @@ def image_callback(data): look_up_time = rospy.Time(0) # look_up_time = data.header.stamp - + # print("TRANS-ROT:", trans, rot) if options.qr_transform: @@ -117,14 +117,14 @@ def image_callback(data): jobj = transform_to_json(transform) # print("DUMPS:", json.dumps(jobj)) - + scaledimg = cv2.resize(img, (1024, 600)) if options.qr_transform or options.qr_header or options.qr_time: # print("SCALEDIMG:", scaledimg.shape, scaledimg.dtype) frame_pil = PilImage.fromarray(scaledimg) - + qr = qrcode.QRCode(box_size=2) if options.qr_time: timestamp = time.time() @@ -136,48 +136,50 @@ def image_callback(data): pos = (frame_pil.size[0] - img_qr.size[0] - 1, 1) #better result when 1 pixel in, thus -1 and +1 # print("POS QR:", pos) - + frame_pil.paste(img_qr, pos) final_image = np.asarray(frame_pil) else: final_image = scaledimg # print("FINALIMAGE:", final_image.shape, final_image.dtype) - + #gray = numpy.array(img_qr).astype(numpy.float32) #print("GRAY:", gray.shape, gray.dtype) #cv_img_qr = cv2.cvtColor(gray, cv2.COLOR_GRAY2RGB) - #print("CV_IMG_QR:", cv_img_qr.shape, cv_img_qr.dtype) + #print("CV_IMG_QR:", cv_img_qr.shape, cv_img_qr.dtype) # gray = cv2. cvtColor(image, cv2. COLOR_BGR2GRAY) # x_offset=y_offset=50 # scaledimg[y_offset:y_offset+cv_img_qr.shape[0], x_offset:x_offset+cv_img_qr.shape[1]] = cv_img_qr - - + if options.test: cv2.imshow("image", final_image) cv2.waitKey(1) - if options.compressed: + if options.compressed: msg = bridge.cv2_to_compressed_imgmsg(final_image) + msg.header = data.header image_pub.publish(msg) else: msg = bridge.cv2_to_imgmsg(final_image) + msg.header = data.header image_pub.publish(msg) - + if options.decode: retval, points = detector.detect(final_image) - # print(retval, points) + print(retval, points) if retval: remembered_points = points have_points = True else: print("FAILED TO FIND CODE, trying to use saved points") + if have_points: decoded_data, _ = detector.decode(final_image, remembered_points) if decoded_data: print("DECODED DATA:", decoded_data) if options.qr_transform: - jobj = json.loads(decoded_data) - transform = json_to_transform(jobj) + #jobj = json.loads(decoded_data) + #transform = json_to_transform(jobj) print("ROS TRANSFORM:", transform) else: print("DECODING FAILED!!!!!!!!!") @@ -186,13 +188,13 @@ def image_callback(data): #print("DETECT:", retval, points) #qr_timestamp, _ , _ = detector.detectAndDecode(final_image) #print("QR_TIMESTAMP:", qr_timestamp) - + except Exception as exc: print("image_callback exception:", exc) #fifo.close() #fifo = open(options.fifo, 'wb') #print(f'FIFO RE-OPENED: {options.fifo}') - + if __name__ == "__main__": rospy.init_node ("add_qr") @@ -206,7 +208,7 @@ if __name__ == "__main__": # os.mkfifo(options.fifo) #except Exception as exc: # print(f'{options.fifo} exist:', exc) - + #if not options.test: # fifo = open(options.fifo, 'wb') # print(f'FIFO OPENED: {options.fifo}') @@ -229,9 +231,9 @@ if __name__ == "__main__": image_pub = rospy.Publisher(out_topic, CompressedImage, queue_size=10) else: image_sub = rospy.Subscriber(in_topic, Image, image_callback) - image_pub = rospy.Publisher(out_topic, Image, queue_size=10) + image_pub = rospy.Publisher(out_topic, Image, queue_size=10) + + rospy.spin() - rospy.spin() - diff --git a/src/decode_qr_inference.py b/src/decode_qr_inference.py new file mode 100755 index 0000000000000000000000000000000000000000..a7eb1290004efc82a26b5b6b91a77bbfd605ce01 --- /dev/null +++ b/src/decode_qr_inference.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 + +import rospy + +import json +import time +import os +import qrcode +import numpy +from PIL import Image as PilImage + +from optparse import OptionParser + +from lrs_msgs_common.msg import InferenceVisionDetection + +import cv2 +from sensor_msgs.msg import Image, CompressedImage +from cv_bridge import CvBridge, CvBridgeError +import numpy as np +import tf + +from camera_info_manager import CameraInfoManager, CameraInfoError, CameraInfoMissingError, resolveURL, parseURL, \ + loadCalibrationFile, getPackageFileName, URL_empty, URL_file, URL_package + +remembered_points = None +have_points = False +camera_info = None + +parser = OptionParser() +parser.add_option("", "--image-topic", action="store", type="string", dest="image_topic", + help="Topic to take image from", default="/dji21/camera0/image_raw_orig") +parser.add_option("", "--camera-info-file", action="store", type="string", dest="camera_info_file", + help="Full path of the camera calibration YAML file", default="camera_gazebo.yml") +parser.add_option("", "--camera-name", action="store", type="string", dest="camera_name", + help="Camera name", default="camera_gazebo") +parser.add_option("", "--topic-out", action="store", type="string", dest="topic_out", + help="Info decoded from the image + camera info", default="inference_image_info") +parser.add_option("", "--compressed", action="store_true", dest="compressed", help="If true image in is compressed.") +parser.add_option("", "--test", action="store_true", dest="test", help="Test mode.") +parser.add_option("", "--debug", action="store_true", dest="debug", help="Extra debug print") +(options, args) = parser.parse_args() + +from geometry_msgs.msg import TransformStamped, Transform + + +def json_to_transform(jobj): + res = Transform() + res.translation.x = jobj["tra"]["x"] + res.translation.y = jobj["tra"]["y"] + res.translation.z = jobj["tra"]["z"] + res.rotation.x = jobj["rot"]["x"] + res.rotation.y = jobj["rot"]["y"] + res.rotation.z = jobj["rot"]["z"] + res.rotation.w = jobj["rot"]["w"] + return res + + +def image_callback(data): + global fifo, remembered_points, have_points, camera_info + try: + # print("image_callback_main") + if options.compressed: + img = bridge.compressed_imgmsg_to_cv2(data, desired_encoding='bgr8') + else: + #img = bridge.imgmsg_to_cv2(data, desired_encoding='bgr8') + # FIXME - encoding gives an error + img = bridge.imgmsg_to_cv2(data) + + scaledimg = cv2.resize(img, (1024, 600)) + + final_image = scaledimg + + retval, points = detector.detect(final_image) + # print(retval, points) + if retval: + remembered_points = points + have_points = True + else: + print("FAILED TO FIND CODE, trying to use saved points") + + if have_points: + decoded_data, _ = detector.decode(final_image, remembered_points) + if decoded_data: + print("DECODED DATA:", decoded_data) + + jobj = json.loads(decoded_data) + c2w_transform = json_to_transform(jobj) + if options.debug: + print("ROS TRANSFORM:", c2w_transform) + else: + print("DECODING FAILED!!!!!!!!!") + + # make and publish the message + # + msg = InferenceVisionDetection() + msg.header = data.header + msg.camera_info = camera_info + msg.c2w_transform = c2w_transform + data_pub.publish(msg) + if options.debug: + print(msg) + + except Exception as exc: + print("image_callback exception:", exc) + + +if __name__ == "__main__": + + rospy.init_node("decode_qr_inference") + + print("OpenCV version: ", cv2.__version__) + + listener = tf.TransformListener() + detector = cv2.QRCodeDetector() + + print("Create cv bridge") + bridge = CvBridge() + + _camera_name = options.camera_name + _camera_info_file = options.camera_info_file + + resolved_url = resolveURL(_camera_info_file, _camera_name) + print("Camera info URL: ", resolved_url) + + # the exception is not working - wrong version? + try: + camera_info = loadCalibrationFile(_camera_info_file, _camera_name) + except IOError as exc: + print("Camera info load exception: ", exc) + exit() + + # extra check because the above exception is not working + if camera_info.height != 0 and camera_info.width != 0: + print("Loaded camera info: ", camera_info) + else: + print("Loaded camera info width and height are zeros. Calibration camera info URL correct?") + exit() + + if options.compressed: + in_topic = f'{options.image_topic}/compressed' + else: + in_topic = f'{options.image_topic}' + + print("in_topic:", in_topic) + print("out_topic:", options.topic_out) + + if options.compressed: + image_sub = rospy.Subscriber(in_topic, CompressedImage, image_callback) + else: + image_sub = rospy.Subscriber(in_topic, Image, image_callback) + + data_pub = rospy.Publisher(options.topic_out, InferenceVisionDetection, queue_size=10) + + rospy.spin()