0
$\begingroup$

Rosanswers logo

I'm using a library called 'tpofinder' to recognize textured objects,but it can only work using opencv's videocapture() function,and it's very slow,about 1 fps or less. I'm using CMake to build it,in the same project,the one using videocapture can process image,but the other one using cv_bridge can't process,it just return the origin image.

####The one using videocapture#### //Include headers for OpenCV Image processing #include <opencv2/imgproc/imgproc.hpp> //Include headers for OpenCV GUI handling #include <opencv2/highgui/highgui.hpp>

#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <iostream>

#include "tpofinder/configure.h"
#include "tpofinder/detect.h"
#include "tpofinder/visualize.h"

using namespace cv;
using namespace tpofinder;
using namespace std;
VideoCapture *capture = NULL;
bool verbose = true;

Mat image;
Detector detector;

void openCamera() {
    capture = new VideoCapture(0);
    if (!capture->isOpened()) {
        cerr << "Could not open default camera." << endl;
        exit(-1);
    }
}

void loadModel(Modelbase& modelbase, const string& path) {
    if (verbose) {
        cout << boost::format("Loading object %-20s ... ") % path;
    }
    modelbase.add(path);
    if (verbose) {
        cout << "[DONE]" << endl;
    }
}

void processImage(Detector& detector) {
    if (!image.empty()) {
        cout << "Detecting objects on image          ... ";
        Scene scene = detector.describe(image);
        vector<Detection> detections = detector.detect(scene);
        cout << "[DONE]" << endl;

        BOOST_FOREACH(Detection d, detections) {
        cout << "Drawing                             ..."; 
            drawDetection(image, d);
        cout << "[Done]" << endl;
        }
    }
}

void nextImage() 
{
    if (verbose) {
        cout << "Reading from webcam                 ... ";
    }
    *capture >> image;
    if (verbose) {
        cout << "[DONE]" << endl;
    }
}
 
 
/**
* This tutorial demonstrates simple image conversion between ROS image message and OpenCV formats and image processing
*/
int main(int argc, char **argv)
{

    // TODO: adapt to OpenCV 2.4.
    // TODO: remove duplication
    // TODO: support SIFT
    Ptr<FeatureDetector> fd = new OrbFeatureDetector(1000, 1.2, 8);
    Ptr<FeatureDetector> trainFd = new OrbFeatureDetector(250, 1.2, 8);
    Ptr<DescriptorExtractor> de = new OrbDescriptorExtractor(1000, 1.2, 8);
    Ptr<flann::IndexParams> indexParams = new flann::LshIndexParams(15, 12, 2);
    Ptr<DescriptorMatcher> dm = new FlannBasedMatcher(indexParams);

    Feature trainFeature(trainFd, de, dm);

    Modelbase modelbase(trainFeature);

    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/adapter");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/blokus");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/book1");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/book2");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/book3");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/coffee");

    Feature feature(fd, de, dm);

    Ptr<DetectionFilter> filter = new AndFilter(
            Ptr<DetectionFilter> (new EigenvalueFilter(-1, 4.0)),
            Ptr<DetectionFilter> (new InliersRatioFilter(0.30)));

    Detector detector(modelbase, feature, filter);


    openCamera();

    while (true) {
        nextImage();
        processImage(detector);
    //Display the image using OpenCV
     cv::imshow("image processed", image);
    //Add some delay in miliseconds. The function only works if there is at least one HighGUI window created and the window is active. If there are several HighGUI windows, any of them can be active.
     cv::waitKey(3);
    }


    //OpenCV HighGUI call to destroy a display window on shut-down.
    cv::destroyWindow("image processed");
    
 
}

####The one using cv_bridge#### //Includes all the headers necessary to use the most common public pieces of the ROS system. #include <ros/ros.h> //Use image_transport for publishing and subscribing to images in ROS #include <image_transport/image_transport.h> //Use cv_bridge to convert between ROS and OpenCV Image formats #include <cv_bridge/cv_bridge.h> //Include some useful constants for image encoding. Refer to: http://www.ros.org/doc/api/sensor_msgs/html/namespacesensor__msgs_1_1image__encodings.html for more info. #include <sensor_msgs/image_encodings.h> //Include headers for OpenCV Image processing #include <opencv2/imgproc/imgproc.hpp> //Include headers for OpenCV GUI handling #include <opencv2/highgui/highgui.hpp>

#include <boost/foreach.hpp>
#include <boost/format.hpp>
#include <iostream>

#include "tpofinder/configure.h"
#include "tpofinder/detect.h"
#include "tpofinder/visualize.h"

using namespace cv;
using namespace tpofinder;
using namespace std;
bool verbose = true;
 
//Store all constants for image encodings in the enc namespace to be used later.
namespace enc = sensor_msgs::image_encodings;
 
//Declare a string with the name of the window that we will create using OpenCV where processed images will be displayed.
static const char WINDOW[] = "Image Processed";
 
//Use method of ImageTransport to create image publisher
image_transport::Publisher pub;
cv_bridge::CvImagePtr cv_ptr;
Detector detector;

void loadModel(Modelbase& modelbase, const string& path) {
    if (verbose) {
        cout << boost::format("Loading object %-20s ... ") % path;
    }
    modelbase.add(path);
    if (verbose) {
        cout << "[DONE]" << endl;
    }
}

void processImage(Detector& detector) {
    if (!cv_ptr->image.empty()) {
        cout << "Detecting objects on image          ... ";
        Scene scene = detector.describe(cv_ptr->image);
        vector<Detection> detections = detector.detect(scene);
        cout << "[DONE]" << endl;
        BOOST_FOREACH(Detection d, detections) {
        cout << "Drawing                            ..."; 
            drawDetection(cv_ptr->image, d);
        cout << "[Done]" << endl;
        }
    }
}
 
//This function is called everytime a new image is published
void imageCallback(const sensor_msgs::ImageConstPtr& original_image)
{
    //Convert from the ROS image message to a CvImage suitable for working with OpenCV for processing
    
    try
    {
        //Always copy, returning a mutable CvImage
        //OpenCV expects color images to use BGR channel order.
        cv_ptr = cv_bridge::toCvCopy(original_image, enc::BGR8);
    }
    catch (cv_bridge::Exception& e)
    {
        //if there is an error during conversion, display it
        ROS_ERROR("tutorialROSOpenCV::main.cpp::cv_bridge exception: %s", e.what());
        return;
    }
 
    processImage(detector);
     
 
    //Display the image using OpenCV
     cv::imshow(WINDOW, cv_ptr->image);
    //Add some delay in miliseconds. The function only works if there is at least one HighGUI window created and the window is active. If there are several HighGUI windows, any of them can be active.
    cv::waitKey(3);
    imwrite("2.jpg",cv_ptr->image);
    /**
    * The publish() function is how you send messages. The parameter
    * is the message object. The type of this object must agree with the type
    * given as a template parameter to the advertise<>() call, as was done
    * in the constructor in main().
    */
    //Convert the CvImage to a ROS image message and publish it on the "camera/image_processed" topic.
        pub.publish(cv_ptr->toImageMsg());
}
 
/**
* This tutorial demonstrates simple image conversion between ROS image message and OpenCV formats and image processing
*/
int main(int argc, char **argv)
{
    /**
    * The ros::init() function needs to see argc and argv so that it can perform
    * any ROS arguments and name remapping that were provided at the command line. For programmatic
    * remappings you can use a different version of init() which takes remappings
    * directly, but for most command-line programs, passing argc and argv is the easiest
    * way to do it.  The third argument to init() is the name of the node. Node names must be unique in a running system.
    * The name used here must be a base name, ie. it cannot have a / in it.
    * You must call one of the versions of ros::init() before using any other
    * part of the ROS system.
    */
        ros::init(argc, argv, "image_processor");
    /**
    * NodeHandle is the main access point to communications with the ROS system.
    * The first NodeHandle constructed will fully initialize this node, and the last
    * NodeHandle destructed will close down the node.
    */
        ros::NodeHandle nh;
    //Create an ImageTransport instance, initializing it with our NodeHandle.
        image_transport::ImageTransport it(nh);
    //OpenCV HighGUI call to create a display window on start-up.
    cv::namedWindow(WINDOW, CV_WINDOW_AUTOSIZE);

    // TODO: adapt to OpenCV 2.4.
    // TODO: remove duplication
    // TODO: support SIFT
    Ptr<FeatureDetector> fd = new OrbFeatureDetector(1000, 1.2, 8);
    Ptr<FeatureDetector> trainFd = new OrbFeatureDetector(250, 1.2, 8);
    Ptr<DescriptorExtractor> de = new OrbDescriptorExtractor(1000, 1.2, 8);
    Ptr<flann::IndexParams> indexParams = new flann::LshIndexParams(15, 12, 2);
    Ptr<DescriptorMatcher> dm = new FlannBasedMatcher(indexParams);

    Feature trainFeature(trainFd, de, dm);

    Modelbase modelbase(trainFeature);

    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/adapter");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/blokus");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/book1");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/book2");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/book3");
    loadModel(modelbase, PROJECT_BINARY_DIR + "/data/coffee");
    Feature feature(fd, de, dm);

    Ptr<DetectionFilter> filter = new AndFilter(
            Ptr<DetectionFilter> (new EigenvalueFilter(-1, 4.0)),
            Ptr<DetectionFilter> (new InliersRatioFilter(0.30)));

    Detector detector(modelbase, feature, filter);

    /**
    * Subscribe to the "camera/image_raw" base topic. The actual ROS topic subscribed to depends on which transport is used. 
    * In the default case, "raw" transport, the topic is in fact "camera/image_raw" with type sensor_msgs/Image. ROS will call 
    * the "imageCallback" function whenever a new image arrives. The 2nd argument is the queue size.
    * subscribe() returns an image_transport::Subscriber object, that you must hold on to until you want to unsubscribe. 
    * When the Subscriber object is destructed, it will automatically unsubscribe from the "camera/image_raw" base topic.
    */
        image_transport::Subscriber sub = it.subscribe("camera/image_raw", 1, imageCallback);
    //OpenCV HighGUI call to destroy a display window on shut-down.
    cv::destroyWindow(WINDOW);
    /**
    * The advertise() function is how you tell ROS that you want to
    * publish on a given topic name. This invokes a call to the ROS
    * master node, which keeps a registry of who is publishing and who
    * is subscribing. After this advertise() call is made, the master
    * node will notify anyone who is trying to subscribe to this topic name,
    * and they will in turn negotiate a peer-to-peer connection with this
    * node.  advertise() returns a Publisher object which allows you to
    * publish messages on that topic through a call to publish().  Once
    * all copies of the returned Publisher object are destroyed, the topic
    * will be automatically unadvertised.
    *
    * The second parameter to advertise() is the size of the message queue
    * used for publishing messages.  If messages are published more quickly
    * than we can send them, the number here specifies how many messages to
    * buffer up before throwing some away.
    */
        pub = it.advertise("camera/image_processed", 1);
    /**
    * In this application all user callbacks will be called from within the ros::spin() call. 
    * ros::spin() will not return until the node has been shutdown, either through a call 
    * to ros::shutdown() or a Ctrl-C.
    */
        ros::spin();
    //ROS_INFO is the replacement for printf/cout.
    ROS_INFO("tutorialROSOpenCV::main.cpp::No error.");
 
}

I found the main problem is that the vector "detections" in vector<Detection> detections = detector.detect(scene); is empty,but can't find the reason.

I tried drawing a circle using opencv,it can show normally in the cv_bridge one.

Then I tested other cameras,but only using opencv's videocapture() can work(recognized the objects and draw something on the image),they are in the same project,so i'm confused,what's the difference between cv_ptr->image and cv::mat image?That's really strange...

You can find tpofinder's other source in here: tpofinder source

If necessary, i can provide the full source code...


Originally posted by Starsky Wong on ROS Answers with karma: 13 on 2013-05-06

Post score: 0

$\endgroup$

1 Answer 1

0
$\begingroup$

Rosanswers logo

You "use" Rosbridge, but you show the images different than what I normally do:

std_msgs::Header h;
h.stamp = ros::Time::now();
.....
cv_bridge::CvImage cv_ptr(h, sensor_msgs::image_encodings::BGR8, img);
cv::imshow(OPENCV_WINDOW_IMAGE,cv_ptr.image);//cv::imshow(WINDOW,cv_ptr.image); for you

Sorry, but your solution takes too much time to be solved in an easy way (too many lines of code), I hope someone else will do ;-)


Originally posted by pablocesar with karma: 252 on 2016-06-17

This answer was ACCEPTED on the original site

Post score: 0

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.