当前位置: 首页 > news >正文

Interactive Tools Recommendation System integrating QT/ROS /Pytorch

Interactive Tools Recommendation System

  • 项目背景
  • 环境搭建
    • 创建ROS工作空间
    • 将ROS和QT集成起来
    • 编译整个工作空间,生成qt_gui的ROS节点文件
      • 适用于本机的CMakeList.txt文件
      • 适用于本机的packge.xml文件
    • 打开QT Creator
  • 技术实现
  • 成果展示

项目背景

任务为交互工具的推荐。需要实现的目标为:机器人进入场景中自动识别工具以及被操作物体,通过对任务进行分析,自动推荐出操作该物体的合适工具。最终将整个流程通过QT交互界面实现与机器人,深度模型的通信。

环境搭建

这里的环境搭建主要是针对ROS和QT的配置,有些细节可以在之前发的一片博客里找到:QT接收ROS视频信息,并将其显示在界面上。

创建ROS工作空间

  • 创建ROS的工作空间xinjianjia_qt(此时与Qt还没有关系,只是单纯的ROS空间)
mkdir -p ~/xinjianjia_qt/src
  • 进入src文件夹:
cd ~/xinjianjia_qt/src
  • 初始化ROS工作空间:
catkin_init_workspace

这样就在src文件中创建了一个 CMakeLists.txt 的文件,目的是告诉系统,这个是ROS的工作空间。(qt_gui)是下一步生成了,这里是后截图,所以才存在的。

在这里插入图片描述

将ROS和QT集成起来

  • 创建完ROS的工作空间后,就能通过catkin_create_qt_pkg命令创建qt_gui包了,在src目录下创建包,本例程将ros_gui包命名为qt_gui:
    (此时与Qt与ROS已经有关系了)
 1. cd ~/xinjianjia_qt/src
 2.  catkin_create_qt_pkg qt_gui

这时,qt_gui就出现了

在这里插入图片描述

进入qt_gui里,可以看到主要的文件是inclide,src,ui。

在这里插入图片描述

其中,src里存储cpp文件

  • main.cpp是主函数文件
  • main_window.cpp是Qt的ui管理文件
  • qnode.cpp是ROS管理节点的文件

在这里插入图片描述

其中,include里存储hpp文件,用于存放声明

在这里插入图片描述

其中,ui里存储ui文件,也就是QT的设计文件

在这里插入图片描述

编译整个工作空间,生成qt_gui的ROS节点文件

进入工作空间xinjianjia_qt编译

catkin_make

编译的目的是生成可执行的ROS节点文件(后续QT Creator需要导入该节点)

在这里插入图片描述

但,在编译之前需要配置该功能包的CMakeList.txt和packge.xml文件,导入需要的包(主要就是Opencv的导入)

在这里插入图片描述

适用于本机的CMakeList.txt文件

##############################################################################
# CMake
##############################################################################

cmake_minimum_required(VERSION 2.8.0)
project(qt_gui)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

##############################################################################
# Catkin
##############################################################################

# qt_build provides the qt cmake glue, roscpp the comms for a default talker
set(OpenCV_DIR /usr/share/OpenCV/)
find_package(catkin REQUIRED COMPONENTS 
	OpenCV 
	sensor_msgs 
	image_transport 
	std_msgs 
	cv_bridge
)
	
find_package(Qt5 REQUIRED Core Widgets)
set(QT_LIBRARIES Qt5::Widgets)
include_directories(${catkin_INCLUDE_DIRS})
# Use this to define what the package will export (e.g. libs, headers).
# Since the default here is to produce only a binary, we don't worry about
# exporting anything. 
catkin_package()

##############################################################################
# Qt Environment
##############################################################################

# this comes from qt_build's qt-ros.cmake which is automatically 
# included via the dependency call in package.xml
#rosbuild_prepare_qt4(QtCore QtGui) # Add the appropriate components to the component list here

##############################################################################
# Sections
##############################################################################

file(GLOB QT_FORMS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ui/*.ui)
file(GLOB QT_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} resources/*.qrc)
file(GLOB_RECURSE QT_MOC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS include/qt_gui/*.hpp *.h)

QT5_ADD_RESOURCES(QT_RESOURCES_CPP ${QT_RESOURCES})
QT5_WRAP_UI(QT_FORMS_HPP ${QT_FORMS})
QT5_WRAP_CPP(QT_MOC_HPP ${QT_MOC})

##############################################################################
# Sources
##############################################################################

file(GLOB_RECURSE QT_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS src/*.cpp)

##############################################################################
# Binaries
##############################################################################
add_executable(qt_gui ${QT_SOURCES} ${QT_RESOURCES_CPP} ${QT_FORMS_HPP} ${QT_MOC_HPP})
target_link_libraries(qt_gui ${QT_LIBRARIES} ${catkin_LIBRARIES} )
install(TARGETS qt_gui RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

target_link_libraries(qt_gui 
    /usr/lib/x86_64-linux-gnu/libtiff.so.5
    /usr/lib/x86_64-linux-gnu/libgdal.so.20
    /usr/lib/x86_64-linux-gnu/libsqlite3.so.0
)


message(STATUS "OpenCV_INCLUDE_DIRS ?" : ${OpenCV_INCLUDE_DIRS})
message(STATUS "OpenCV_VERSION ?" : ${OpenCV_VERSION})
message(STATUS "OpenCV_LIB ?" : ${OpenCV_LIBS})
message(STATUS "OpenCV_CONGIG_PATH ?" : ${OpenCV_CONFIG_PATH})

适用于本机的packge.xml文件

注意:如果配置了CMakeList.txt,系统就会首先默认找CMakeList.txt里的配置选项,因此packge.xml无需更改。这里我使用的也是默认生成的。

<?xml version="1.0"?>
<package>
  <name>qt_gui</name>
  <version>0.1.0</version>
  <description>

     qt_gui

  </description>
  <maintainer email="robot@gmail.com">robot</maintainer>
  <author>robot</author>
  <license>BSD</license>
  <!-- <url type="bugtracker">https://github.com/stonier/qt_ros/issues</url> -->
  <!-- <url type="repository">https://github.com/stonier/qt_ros</url> -->

  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>qt_build</build_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>libqt4-dev</build_depend>
  <run_depend>qt_build</run_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>libqt4-dev</run_depend>

</package>

打开QT Creator

建项目的过程:QT接收ROS视频信息,并将其显示在界面上,这里也有。

项目建完之后,比较重要的一步就是要配置刚才的ROS节点,只有配置了这里的ROS节点,ROS和QT Creator才可以正常通信

项目->RUN->运行,配置运行配置为Custom Executable,可执行文件Executable选择编译好的节点,工作,目录Working directory就选择节点的上一级目录即可

在这里插入图片描述

整个QT的项目如下:

在这里插入图片描述

技术实现

先预览一下最终的交互界面

在这里插入图片描述

左侧为图像/视频显示区域,右侧为按键控制区。

显示区域:

  • Camera View需要实时显示相机的画面,因此需要放在单独的子线程里
  • Capture Tools Frame只需要显示相机画面中工具集的关键帧,这个操作由按钮Capture Tools KeyFrame控制
  • Capture Object Frame只需要显示相机画面中物体的关键帧,这个操作由按钮Capture Object KeyFrame控制
  • Tools Recommendation Result只需要显示最终的推荐结果,这个操作由按钮Tools Recommendation控制

按键控制区:

  • ----- Task Selection ------是一个QComboBox类,用来选择任务类型,是一个下拉菜单(双击即可编辑内容)
    在这里插入图片描述
    任务种类如下:
task_list = ['cutting cucumber', 'cutting banana', 'cutting bread', 'cutting cake', 'cutting pizza',
             'containing tea', 'containing redwine',  'containing coffee',
             'cropping paper', 'cropping tape', 'cropping cottonmaterial ',  'cropping rope ',
             'hitting iron nail', 'hitting raw meat',
             'storing cloth',  'storing book']

main_window.hpp
槽函数的声明,接受的const QString &类型,因为我们要得到具体任务的信息,也就是具体字符信息

public Q_SLOTS:
    /******************************************
    ** Task Selection/Analysis
    *******************************************/
    void on_comboBox_currentStringChanged(const QString &);

main_window.cpp

信号和槽的绑定:currentIndexChanged(QString)是固定的信号,不可以更改,传入的是QString,也就是我们在下拉菜单中选择的具体字符。

槽函数实现:通过方法currentText()得到具体的字符str,供后续使用

/******************************************
** Task Selection/Analysis
*******************************************/
QObject::connect(ui.Task_Selection_comboBox,
                 SIGNAL(currentIndexChanged(QString)),
                 this,
                 SLOT(on_comboBox_currentStringChanged(QString)));


void MainWindow::on_comboBox_currentStringChanged(const QString &arg1)
{
    QString str = ui.Task_Selection_comboBox->currentText();
    qDebug()<<"Task is :"<<str;

  • Analysis Task为任务解析按钮,需要对任务进行解析,调用的是Python文件

main_window.hpp

public Q_SLOTS:
    /******************************************
    ** Task Selection/Analysis
    *******************************************/
    void Call_Task_Analysis_Python();

main_window.cpp

调研python文件就采用如下的格式,但这种类型命令只能调用普通python文件,不可以调用那些需要激活虚拟环境再执行的python文件。后续会给出如何先激活虚拟环境,然后再调用python文件

QObject::connect(ui.Analysis_Task_Button, //先调python
                 SIGNAL(clicked()),
                 this,
                 SLOT(Call_Task_Analysis_Python()));
                 
void MainWindow::Call_Task_Analysis_Python()
{
    qDebug()<<"void MainWindow::Call_Task_Analysis_Python()";
    system("gnome-terminal --tab -- python '/home/robot/catkin_ws/devel/Task_Analysis.py'&");
}
  • Open Camera View是开启子线程的按钮,目前不需要,开启相机画面只需要connect ROS话题即可就可以

main_window.hpp

public Q_SLOTS:
    void display_camera_view(cv::Mat image);

main_window.cpp

// 信号和槽的绑定
QObject::connect(&qnode,
                 SIGNAL(Camera_ViewSingal(cv::Mat)),
                 this,
                 SLOT(display_camera_view(cv::Mat)),
                 Qt::BlockingQueuedConnection);
// 槽函数的实现
void MainWindow::display_camera_view(cv::Mat image)
{
    qDebug()<<"void MainWindow::display_camera_view(cv::Mat image)";
    cv::imwrite("/home/robot/xinjianjia_qt/capture.jpg",image);//一直保存
    cv::imwrite("/home/robot/xinjianjia_qt/Tail.jpg",image);//一直保存
    cv::Mat rgb;
    QImage img;

    if(image.channels() == 3) //如果是三通道需要先转为RGB才转为QImage
    {
      cv::cvtColor(image,rgb,cv::COLOR_BGR2RGB);//Mat类型的BGR转为QImage类型的RGB
      img = QImage((const unsigned char*)(rgb.data),
                   rgb.cols,
                   rgb.rows,
                   rgb.cols*rgb.channels(),
                   QImage::Format_RGB888);
      qDebug()<<"Mat BGR convert QImage RGB successful";
    }
    else  //如果是单通道可以直接转QImage了
    {
      img = QImage((const unsigned char*)(image.data),
                   image.cols,
                   image.rows,
                   image.cols*image.channels(),
                   QImage::Format_RGB888);
      qDebug()<<"Mat BGR convert QImage RGB successful";
    }

    ui.Camera_View_label->setPixmap(QPixmap::fromImage(img));
    ui.Camera_View_label->setScaledContents(true);
}

qnode.hpp

public:
    /******************************************
    ** Camera View
    *******************************************/
    void Camera_Callback_img(const sensor_msgs::ImageConstPtr& msg);//回调函数
    cv::Mat Camera_View_img;
    
Q_SIGNALS:
	/******************************************
	** Camera View
	*******************************************/
	void Camera_ViewSingal(cv::Mat); //信号
	
private:
    /******************************************
    ** Camera View
    *******************************************/
    image_transport::Subscriber camera_view_sub; //声明订阅者,订阅相机节点的话题

qnode.cpp

需要在QNode::init() 的两个重载函数中,都初始化订阅者camera_view_sub。QNode::run()中的ros::spin()是必须加的,因为我要持续读取相机画面,需要spin接着。

bool QNode::init() {
	ros::init(init_argc,init_argv,"qt_gui");
	if ( ! ros::master::check() ) {
		return false;
	}
	ros::start(); // explicitly needed since our nodehandle is going out of scope.
	ros::NodeHandle n;
	// Add your ros communications here.
	chatter_publisher = n.advertise<std_msgs::String>("chatter", 1000);

    /******************************************
    ** Camera View node init
    *******************************************/
    image_transport::ImageTransport it(n);
    camera_view_sub = it.subscribe("/camera/color/image_raw",1,&QNode::Camera_Callback_img,this);

	start();
	return true;

}

bool QNode::init(const std::string &master_url, const std::string &host_url) {
	std::map<std::string,std::string> remappings;
	remappings["__master"] = master_url;
	remappings["__hostname"] = host_url;
	ros::init(remappings,"qt_gui");
	if ( ! ros::master::check() ) {
		return false;
	}
	ros::start(); // explicitly needed since our nodehandle is going out of scope.
	ros::NodeHandle n;
	// Add your ros communications here.
	chatter_publisher = n.advertise<std_msgs::String>("chatter", 1000);

    /******************************************
    ** Camera View node init
    *******************************************/
    image_transport::ImageTransport it(n);
    camera_view_sub = it.subscribe("/camera/color/image_raw",1,&QNode::Camera_Callback_img,this);


	start();
	return true;
}

void QNode::run() {

    /******************************************
    ** Camera View node init
    *******************************************/
    ros::NodeHandle n;
    image_transport::ImageTransport it(n);
    camera_view_sub = it.subscribe("/camera/color/image_raw",1,&QNode::Camera_Callback_img,this);

    ros::spin();

	std::cout << "Ros shutdown, proceeding to close the gui." << std::endl;
	Q_EMIT rosShutdown(); // used to signal the gui for a shutdown (useful to roslaunch)
}

// 回调函数的编写
void QNode::Camera_Callback_img(const sensor_msgs::ImageConstPtr &msg)
{
    cv_bridge::CvImagePtr cv_ptr;
    try
    {
       cv_ptr = cv_bridge::toCvCopy(msg,sensor_msgs::image_encodings::BGR8);
       Camera_View_img = cv_ptr->image;
       if(Camera_View_img.empty()){
           qDebug()<<"Camera img is empty";
       }
       Q_EMIT Camera_ViewSingal(Camera_View_img); //信号发出,由SLOT(display_camera_view(cv::Mat))接着
    }
    catch (cv_bridge::Exception &e) {
        ROS_ERROR("Could not convert from '%s' to 'bgr8",msg->encoding.c_str());
    }
}
  • Capture Tools KeyFrame为捕获当前相机拍摄工具的关键帧,捕获到之后,需要调研seg.py文件进行工具检测

main_window.hpp
槽函数的声明

public Q_SLOTS:
    void display_Capture_KeyFrame_Tools();
    void Call_Detection_Python();

main_window.cpp
信号和槽的绑定

QObject::connect(ui.Capture_KeyFrame_Button_Tools,
                 SIGNAL(clicked()),
                 this,
                 SLOT(display_Capture_KeyFrame_Tools()));

QObject::connect(ui.Capture_KeyFrame_Button_Tools, //先调20220827_seg.py
                 SIGNAL(clicked()),
                 this,
                 SLOT(Call_Detection_Python()));

main_window.cpp
槽函数的实现

void MainWindow::display_Capture_KeyFrame_Tools()
{
    qDebug()<<"void MainWindow::display_Capture_KeyFrame()";
    cv::Mat rgb;
    QImage img;
    cv::Mat image = cv::imread("/home/robot/xinjianjia_qt/capture.jpg");
    if(image.empty()){
        qDebug()<<"KeyFrame not be Captured";
    }else {
        qDebug()<<"KeyFrame Capture Successfully";
        cv::imwrite("/home/robot/xinjianjia_qt/code_v2/xitong_seg/rgb/capture.jpg",image);//读取之后,立马保存该image到指定路径
    }

    if(image.channels() == 3) //如果是三通道需要先转为RGB才转为QImage
    {
      cv::cvtColor(image,rgb,cv::COLOR_BGR2RGB);//Mat类型的BGR转为QImage类型的RGB
      img = QImage((const unsigned char*)(rgb.data),
                   rgb.cols,
                   rgb.rows,
                   rgb.cols*rgb.channels(),
                   QImage::Format_RGB888);
      qDebug()<<"Mat BGR convert QImage RGB successful";
    }
    else  //如果是单通道可以直接转QImage了
    {
      img = QImage((const unsigned char*)(image.data),
                   image.cols,
                   image.rows,
                   image.cols*image.channels(),
                   QImage::Format_RGB888);
      qDebug()<<"Mat BGR convert QImage RGB successful";
    }


    ui.Capture_Frame_label->setPixmap(QPixmap::fromImage(img));
    ui.Capture_Frame_label->setScaledContents(true);

}

void MainWindow::Call_Detection_Python()
{
    qDebug()<<"void MainWindow::Call_Detection_Python()";
    system("gnome-terminal --tab  -- bash -c '/home/robot/tool_seg.sh'&"); //调用shell脚本
}

这里注意一个非常重要的点,那就是调用shell脚本,命令格式就是这样,需要额外写-- bash -c。让我们看看shell脚本里写了什么:

#!/bin/bash

source  /home/robot/anaconda3/envs/grasp/bin/activate grasp

python /home/robot/xinjianjia_qt/code_v2/xitong_seg/20220827xitong_seg.py

exit 0
  • 首先是激活虚拟环境grasp,这里采用的是该教程:在shell文件中启动anaconda的虚拟环境。
  • /home/robot/anaconda3/envs/grasp/bin/activate就是该虚拟环境下bin目录下的activate文件
  • 启动虚拟环境之后,直接执行python文件即可
  • 最后exit 0

20220827xitong_seg.py的内容如下:

# coding:utf-8

import torchvision
from Mask_model import maskrcnn as maskrcnn
import torch
import numpy as np
import cv2 as cv
from torchvision import transforms
import warnings
import os
import argparse
import json

warnings.filterwarnings('ignore')

# 加载权重
mask_rcnn = maskrcnn(ckpt_path='/home/robot/xinjianjia_qt/code_v2/xitong_seg/maskrcnn.pth')

mask_rcnn.eval()
transform_mask = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])

train_on_gpu = torch.cuda.is_available()

if train_on_gpu:
    mask_rcnn.cuda()


def get_one_hot(labels, num_classes):
    one_hot = np.zeros((1, num_classes), dtype=np.float32)
    one_hot[np.arange(1), labels] = 1
    return one_hot

def seg_mask(img_path, img_save_path):
    frame = cv.imread(img_path)
    blob = transform_mask(frame)
    c, h, w = blob.shape
    input_x = blob.view(1, c, h, w).cuda()
    output = mask_rcnn(input_x)[0]
    boxes = output['boxes'].cpu().detach().numpy()
    scores = output['scores'].cpu().detach().numpy()
    labels = output['labels'].cpu().detach().numpy()
    masks = output['masks'].cpu().detach().numpy()
    print('boxes', boxes)
    print('scores', scores)
    print('labels', labels)
    index = 0
    instances_dict = {}
    boxes_list = []
    instances_list=[]
    for x1, y1, x2, y2 in boxes:
        if scores[index] > 0.1:
            # predict_id = int(coco_class[label_txt])
            print('boxes', x1, y1, x2, y2)
            print('scores', scores[index])
            print('labels', labels[index])
            boxes_list.append([int(x1),int(y1),int(x2),int(y2)])
            # print('boxes center: ', (x1+x2)/2, (y1+y2)/2)
            frame_idx = frame[int(y1):int(y2), int(x1):int(x2)]
            cv.imwrite(img_save_path + '{}.jpg'.format(index), frame_idx)
            index = index+1
    for j in range(len(boxes_list)):
        # instances_list.append("/home/data3/xinjianjia/xitong_recommend/Head/{}.jpg+{}".format(j, boxes_list[j]))
        instances_list.append(["/home/robot/xinjianjia_qt/code_v2/xitong_recommend/Head/{}.jpg".format(j), boxes_list[j]])

    instances_dict["/home/robot/xinjianjia_qt/code_v2/xitong_recommend/Tail/Tail.jpg"] = instances_list
    with open("/home/robot/xinjianjia_qt/code_v2/xitong_recommend/test_realscene.json","w") as dump_f:
        json.dump([instances_dict], dump_f)

if __name__ == "__main__":
    path = '/home/robot/xinjianjia_qt/code_v2/xitong_seg/rgb/'
    save_path = '/home/robot/xinjianjia_qt/code_v2/xitong_recommend/Head/'
    file = open("/home/robot/xinjianjia_qt/code_v2/xitong_seg/rgb/test.txt",'w')
    if not os.path.exists(path):
        os.mkdir(path)
    if not os.path.exists(save_path):
        os.mkdir(save_path)
    path_dir = []
    img_name = []
    for dirpath, dirnames, filenames in os.walk(path):
        for filename in filenames:
            path_dir.append(os.path.join(dirpath, filename))
            img_name.append(filename)
    for img_path, img_name in zip(path_dir, img_name):
        # folder = os.path.exists(save_path + img_name)
        # if not folder:
        #     os.makedirs(save_path + img_name)
        seg_mask(img_path, save_path)

至此,按钮按下,显示图像,然后调用shell脚步的过程就完成了。

  • Capture Object KeyFrame为捕获当前相机拍摄物体的关键帧,捕获到之后,显示+保存图像即可

main_window.hpp
槽函数的声明

public Q_SLOTS:
    void display_Capture_KeyFrame_Object();

main_window.cpp
信号和槽的绑定+槽函数的实现

QObject::connect(ui.Capture_KeyFrame_Button_Object, //先将tail.jpg显示、保存
                 SIGNAL(clicked()),
                 this,
                 SLOT(display_Capture_KeyFrame_Object()));

void MainWindow::display_Capture_KeyFrame_Object()
{
    qDebug()<<"void MainWindow::display_Object_Detection_result()";
    cv::Mat rgb;
    QImage img;
    cv::Mat image = cv::imread("/home/robot/xinjianjia_qt/Tail.jpg");//读取面包的捕获结果

    if(image.empty()){
        qDebug()<<"Detection_result not be Complete";
    }else {
        qDebug()<<"Detection_result Successfully";
        cv::imwrite("/home/robot/xinjianjia_qt/code_v2/xitong_recommend/Tail/Tail.jpg",image);//保存该image到指定路径
    }

    if(image.channels() == 3) //如果是三通道需要先转为RGB才转为QImage
    {
      cv::cvtColor(image,rgb,cv::COLOR_BGR2RGB);//Mat类型的BGR转为QImage类型的RGB
      img = QImage((const unsigned char*)(rgb.data),
                   rgb.cols,
                   rgb.rows,
                   rgb.cols*rgb.channels(),
                   QImage::Format_RGB888);
      qDebug()<<"Mat BGR convert QImage RGB successful";
    }
    else  //如果是单通道可以直接转QImage了
    {
      img = QImage((const unsigned char*)(image.data),
                   image.cols,
                   image.rows,
                   image.cols*image.channels(),
                   QImage::Format_RGB888);
      qDebug()<<"Mat BGR convert QImage RGB successful";
    }

    ui.Detection_Result_label->setPixmap(QPixmap::fromImage(img));
    ui.Detection_Result_label->setScaledContents(true);
}
  • Tools Recommendation为工具推荐按钮,功能是:调用recommendation.py进行工具推荐,然后将推荐结果显示在页面上

main_window.hpp
槽函数的声明

public Q_SLOTS:
    /******************************************
    ** Tools Recommendation
    *******************************************/
    void Call_Recommendation_Python();
    void display_Tools_Recommendation_result();

main_window.cpp
信号和槽的绑定+槽函数的实现

/******************************************
** Tools Recommendation
*******************************************/
QObject::connect(ui.Tools_Recommendation_Button, //先调python
	               SIGNAL(clicked()),
	               this,
	               SLOT(Call_Recommendation_Python()));

QObject::connect(ui.Tools_Recommendation_Button, //然后再显示
	               SIGNAL(clicked()),
	               this,
	               SLOT(display_Tools_Recommendation_result()));

/******************************************
** Tools Recommendation
*******************************************/
void MainWindow::Call_Recommendation_Python()
{
    qDebug()<<"void MainWindow::Call_Recommendation_Python()";
    system("gnome-terminal --tab  -- bash -c '/home/robot/tool_recommend.sh'&");
}

void MainWindow::display_Tools_Recommendation_result()
{
    qDebug()<<"void MainWindow::display_Tools_Recommendation_result()";
    cv::Mat rgb;
    QImage img;
    cv::Mat image = cv::imread("/home/robot/xinjianjia_qt/code_v2/xitong_recommend/recommend_result.jpg");//读取推荐的结果

    if(image.empty()){
        qDebug()<<"Tools_Recommendation_result not be Complete";
    }else {
        qDebug()<<"Tools_Recommendation_result Successfully";
    }

    if(image.channels() == 3) //如果是三通道需要先转为RGB才转为QImage
    {
      cv::cvtColor(image,rgb,cv::COLOR_BGR2RGB);//Mat类型的BGR转为QImage类型的RGB
      img = QImage((const unsigned char*)(rgb.data),
                   rgb.cols,
                   rgb.rows,
                   rgb.cols*rgb.channels(),
                   QImage::Format_RGB888);
      qDebug()<<"Mat BGR convert QImage RGB successful";
    }
    else  //如果是单通道可以直接转QImage了
    {
      img = QImage((const unsigned char*)(image.data),
                   image.cols,
                   image.rows,
                   image.cols*image.channels(),
                   QImage::Format_RGB888);
      qDebug()<<"Mat BGR convert QImage RGB successful";
    }

    ui.Tools_Recommendation_label->setPixmap(QPixmap::fromImage(img));
    ui.Tools_Recommendation_label->setScaledContents(true);
}

/home/robot/tool_recommend.sh文件如下,原理跟上一个类似。

#!/bin/bash

source  /home/robot/anaconda3/envs/grasp/bin/activate grasp

python /home/robot/xinjianjia_qt/code_v2/xitong_recommend/recommend_tools.py

exit 0

recommend_tools.py内容如下:

# -*- coding:utf-8 -*-

import argparse
import os
import torch
import torch.nn as nn
import torch.optim as optim
import json
import numpy as np
from PIL import Image, ImageDraw
from torchvision import transforms


f_dim = 2048
num_class = 37

BASE = '/home/robot/xinjianjia_qt/code_v2/xitong_recommend/'

TRAINED_MODEL = BASE + 'epoch_8.pth'#  test_sep_pos_neg_dis.py  dis mse,只有pos和neg,没有mid,用的随机方法产生的
val_file = BASE + 'test_realscene.json'

mean, std = [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]
INPUT_SIZE = 224

#os.environ["CUDA_VISIBLE_DEVICES"] = '1'#
def load_checkpoint(filepath):
    checkpoint = torch.load(filepath)
    model = checkpoint['model']  # 提取网络结构
    model.load_state_dict(checkpoint['model_state_dict'])  # 加载网络权重参数
    for parameter in model.parameters():
        parameter.requires_grad = False
    model.eval()
    return model

def get_test_transform(mean=mean, std=std, size=0):
    return transforms.Compose([
        Resize((int(size * (256 / 224)), int(size * (256 / 224)))),
        transforms.CenterCrop(size),
        transforms.ToTensor(),
        transforms.Normalize(mean=mean, std=std),
    ])
class Resize(object):
    def __init__(self, size, interpolation=Image.BILINEAR):
        self.size = size
        self.interpolation = interpolation

    def __call__(self, img):
        # padding
        ratio = self.size[0] / self.size[1]
        w, h = img.size
        if w / h < ratio:
            t = int(h * ratio)
            w_padding = (t - w) // 2
            img = img.crop((-w_padding, 0, w+w_padding, h))
        else:
            t = int(w / ratio)
            h_padding = (t - h) // 2
            img = img.crop((0, -h_padding, w, h+h_padding))

        img = img.resize(self.size, self.interpolation)

        return img


def valData(val_file):
    with open(val_file, encoding='utf-8-sig', errors='ignore') as f:
        data = json.load(f, strict=False)
    data_keys = []
    for i in range(len(data)):
        data_keys.append(list(data[i].keys()))
    return data, data_keys


network = load_checkpoint(TRAINED_MODEL)
def valItem(data, data_keys,i,num_classes):
    '''返回一个键对应的的所有三元组,就是一个batch;适用于计算头结点和尾节点的特征距离(cos距离和MSE距离)的方法的测试
    '''
    [tail] = data_keys[i]
    [head] = list(data[i].values())
    [img_h_list, c_h_list, img_t_list, c_t_list, c_r_list, c_h_idx_list, c_t_idx_list, c_r_idx_list] = [[],[],[],[],[],[],[],[]]
    for j in range(len(head)):
        # print(head[j])
        img_head_path = head[j][0]
        img_tail_path = tail
        img_h = Image.open(img_head_path).convert('RGB')
        img_t = Image.open(img_tail_path).convert('RGB')
        img_h = get_test_transform(size=INPUT_SIZE)(img_h).unsqueeze(0)
        img_t = get_test_transform(size=INPUT_SIZE)(img_t).unsqueeze(0)
        #######
        img_h_list.append(img_h)
        img_t_list.append(img_t)
    return img_h_list, c_h_list, img_t_list, c_t_list, c_h_idx_list, c_t_idx_list, c_r_list, c_r_idx_list

if torch.cuda.is_available():
    network.cuda()
##########################################


data, data_keys = valData(val_file)

def sep_task():
    dict_idx = 0
    img_h_list, c_h_list, img_t_list, c_t_list, c_h_idx_list, c_t_idx_list, c_r_list, c_r_idx_list \
        = valItem(data, data_keys, dict_idx, num_class)
    score_batch = []
    for i in range(len(img_h_list)):  # 一个batch
        head = img_h_list[i].cuda()
        tail = img_t_list[i].cuda()
        score, logits_h, logits_t = network.test(head, tail)
        # print("score:",score)
        score_batch.append(score)
    s_i = torch.topk(torch.tensor(score_batch).detach(), 1, largest=False)[1].tolist()
    print(s_i, )#[9]
    recommned_tool_box = list(data[0].values())[0][s_i[0]]
    # print("recommned_tool_box", recommned_tool_box)
    recommned_box =  recommned_tool_box[1]
    img = Image.open("/home/robot/xinjianjia_qt/code_v2/xitong_seg/rgb/capture.jpg").convert('RGB')
    a = ImageDraw.ImageDraw(img)  # 用a来表示右侧这段#
    # print(int(float(recommned_box[0])), int(float(recommned_box[1])), int(float(recommned_box[2])), int(float(recommned_box[3])))
    # print(recommned_box)
    a.rectangle((recommned_box[0],recommned_box[1],recommned_box[2],recommned_box[3]), outline='red', width=10)  # 在100,150起点画长800宽200的图形,填充白色,边框黑色,边框像素为1
    img.save("/home/robot/xinjianjia_qt/code_v2/xitong_recommend/recommend_result.jpg")
    file = open("/home/robot/xinjianjia_qt/code_v2/xitong_seg/rgb/test1.txt",'w')


sep_task()#@hits N

成果展示

在这里插入图片描述

相关文章:

  • 嵌入式属于人工智能吗?
  • Linux操作系统——进程控制【一】
  • 鸡葡萄菌感染怎么防治 预防鸡感染球菌病吃啥药
  • 技术分享 | App测试时常用的adb命令你都掌握了哪些呢?
  • 鸡得关节炎有哪些症状 鸡喂什么药预防球菌病
  • Dockerfile的使用-利用docker构建包含jdk ,vim centos
  • LeetCode-946-验证栈序列
  • vnc服务
  • Js各种时间转换问题(YYYY-MM-DD 时间戳 中国标准时间)
  • 李迟2022年8月工作生活总结
  • 百度 T4 幕后揭秘!这份 Java 面试全栈手册竟让面试官节节败退
  • 干货分享:有什么软件可以让照片动起来?
  • 鸡防治球菌病的措施 鸡防球菌病抗菌的药
  • 电子产品有害物质测试项目有哪些?
  • 鸡得葡萄球菌病的危害 鸡什么药防治鸡球菌病
  • JavaScript-如何实现克隆(clone)函数
  • 【108天】Java——《Head First Java》笔记(第1-4章)
  • 03Go 类型总结
  • CSS进阶篇--用CSS开启硬件加速来提高网站性能
  • ES2017异步函数现已正式可用
  • GitUp, 你不可错过的秀外慧中的git工具
  • IP路由与转发
  • Linux链接文件
  • React16时代,该用什么姿势写 React ?
  • tab.js分享及浏览器兼容性问题汇总
  • 前端自动化解决方案
  • 如何胜任知名企业的商业数据分析师?
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 译米田引理
  • - 语言经验 - 《c++的高性能内存管理库tcmalloc和jemalloc》
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • 《码出高效》学习笔记与书中错误记录
  • 通过调用文摘列表API获取文摘
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • #在 README.md 中生成项目目录结构
  • $L^p$ 调和函数恒为零
  • (1)(1.19) TeraRanger One/EVO测距仪
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (三)c52学习之旅-点亮LED灯
  • (一)VirtualBox安装增强功能
  • (译)2019年前端性能优化清单 — 下篇
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (转)scrum常见工具列表
  • **PHP二维数组遍历时同时赋值
  • *setTimeout实现text输入在用户停顿时才调用事件!*
  • .“空心村”成因分析及解决对策122344
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .NET Compact Framework 3.5 支持 WCF 的子集
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .net mvc 获取url中controller和action
  • .NET/C# 获取一个正在运行的进程的命令行参数
  • .NET应用架构设计:原则、模式与实践 目录预览
  • @在php中起什么作用?