Interactive Tools Recommendation System integrating QT/ROS /Pytorch

2 篇文章 0 订阅

项目背景

任务为交互工具的推荐。需要实现的目标为:机器人进入场景中自动识别工具以及被操作物体,通过对任务进行分析,自动推荐出操作该物体的合适工具。最终将整个流程通过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

成果展示

在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值