OpenCV,从图像围绕对象绘制一个框 [英] Opencv, drawing a box around an object from an image

查看:85
本文介绍了OpenCV,从图像围绕对象绘制一个框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在做一个有趣的项目,以了解有关OpenCV的更多信息.此刻,我想画一个给定图像的盒子.我有一个可以完成这项工作的功能,但是在将mouse_control函数传递给OpenCV的setMouseCallback函数时遇到了一些问题.

I am doing a project for fun to learn more about OpenCV. At the moment I want to draw a box given an image. I have a working function that achieves the job but I am having some problem regarding passing the mouse_control function into the setMouseCallback function from OpenCV.

我收到的错误是这样的:

The error I am receiving is this:

 error C3867:  'Box::mouse_control': non-standard syntax; use '&' to create a pointer to member

当我尝试放置建议的参考文献时,出现此错误:

When I try to place the suggested reference I get this error:

error C2276:  '&': illegal operation on bound member function expression

我是OpenCV的新手,所以我不确定如何调试和修复我的代码.

I am brand new to OpenCV so I am not sure exactly how to debug and fix the code I have.

这是我正在处理的类的头文件:

Here is the header file to the class I am working on:

#pragma once
#include "Image.h"

class Box : public Image
{
public:
    Box() = default;


    Mat draw_box(Mat& img, Rect box);
    void mouse_control(int event, int x, int y, int flag, void* param);

private:
    Rect g_rectangle;
    bool g_drawbox;


};

这是与头文件关联的.cpp文件:

Here is the .cpp file associated to the header file:

#include "Box.h"
#define WINDOW_NAME "Drawing Rectangle"


void Box::mouse_control(int event, int x, int y, int flag, void* param)
{
    Mat& image = *(cv::Mat*) param;

    switch (event) 
    {
    case EVENT_MOUSEMOVE: 
    {    // When mouse moves, get the current rectangle's width and height
        if (g_drawbox) 
        {
            g_rectangle.width = x - g_rectangle.x;
            g_rectangle.height = y - g_rectangle.y;
        }
    }
    break;

    case EVENT_LBUTTONDOWN: 
    {  // when the left mouse button is pressed down,
       // get the starting corner's coordinates of the rectangle
        g_drawbox = true;
        g_rectangle = Rect(x, y, 0, 0);
    }
    break;

    case EVENT_LBUTTONUP: 
    {   // when the left mouse button is released,
        // draw the rectangle
        g_drawbox = false;
        if (g_rectangle.width < 0) 
        {
            g_rectangle.x += g_rectangle.width;
            g_rectangle.width *= -1;
        }

        if (g_rectangle.height < 0) 
        {
            g_rectangle.y += g_rectangle.height;
            g_rectangle.height *= -1;
        }
        draw_box(image, g_rectangle);
    }
    break;
    }
}

Mat Box::draw_box(Mat& img, Rect box)
{
    // Get input from user to draw box around object of interest
    rectangle(img, box.tl(), box.br(), Scalar(0, 255, 255), FILLED, LINE_8);
    Mat tempImage;
    //Mat srcImage(600, 800, CV_8UC3);
    //srcImage = Scalar::all(0);
    namedWindow(WINDOW_NAME);
    setMouseCallback(WINDOW_NAME, mouse_control, (void*)& img);
    while (1) {
        img.copyTo(tempImage);
        if (g_drawbox)
            draw_box(tempImage, g_rectangle);
        imshow(WINDOW_NAME, tempImage);
        if (waitKey(10) == 27)  // stop drawing rectanglge if the key is 'ESC'
            break;
    }
    return img;
}

错误发生在这里:

setMouseCallback(WINDOW_NAME, mouse_control, (void*)& img);

这里是主文件,另一个标头和cpp文件需要复制错误:

Here is the main file and the other header and cpp file needed to duplicate the error:

#include <iostream>
#include "Box.h"
#include "Image.h"


int main()
{

    // Declare image object and the name of the image (store image in project file)
    Image img_obj;
    std::string image_name = "hawaii.png";

    // Read and display image
    auto img1 = img_obj.get_image(image_name);
    img_obj.display(img1);

    Rect g_rectangle;
    Box b;
    auto new_img = b.draw_box(img1, g_rectangle);
    b.display(new_img);


    std::cin.get();
}

#pragma once
#include <opencv2/opencv.hpp>

using namespace cv;


class Image
{
public:
    Image() = default;


    // Member functions
    const Mat get_image(std::string& image_name);
    void display(Mat& img);
};

#include "Image.h"


const Mat Image::get_image(std::string& image_name)
{
    Mat img = imread(image_name);
    return img;
}

void Image::display(Mat& img)
{
    namedWindow("image", WINDOW_NORMAL);
    imshow("image", img);
    waitKey(0);
}

推荐答案

成员函数和 normal 函数是两个不同的东西.

Member function and normal function are two different things.

setMouseCallback函数采用签名为:

handleMouse(int event, int x, int y, int flag, void* param)

您尝试通过mouse_control作为回调来调用setMouseCallback,但由于mouse_controlBox类的成员函数,因此无法正常工作.您调用特定对象的成员函数,就不能将其称为独立"-没有对象.这就是为什么您的代码无法编译的原因.

you try to call setMouseCallback passing mouse_control as callback, it cannot work because mouse_control is member function of Box class. You call member function for particular object, you cannot call it "standalone" - without object. That is why your code doesn't compile.

解决方案?

回调的最后一个参数是void*.现在,您正在将指针传递给Image,但是您可以将指针传递给Box,不是吗?因此,您可以将mouse_control设置为Box类的静态函数:

The last param of callback is void*. Now, you are passing pointer to Image, but you can pass pointer to Box, isn't it? So, you can make mouse_control as static function of Box class:

class Box : public Image {
public:
    Box() = default;
    Mat draw_box(Mat& img, Rect box);
    static void mouse_control(int event, int x, int y, int flag, void* param); // static added

(静态函数不需要具有要调用的对象). 您可以通过调用以下内容来指向该指针:

(static function doesn't need to have an object to be called). Pointer to this you pass by calling:

setMouseCallback(WINDOW_NAME, mouse_control, this);

和内部:

void Box::mouse_control(int event, int x, int y, int flag, void* param) {
    Box* box = (Box*)param;

    // you can access member variable of Box by 
    box->g_rectangle
    box->draw_box

还需要找出如何存储img的方法,也许是作为Box的数据成员吗?或者,您可以制作一些包装器

also you need to find out how to store img, maybe as data member of Box?. Or you can make some wrapper like

struct Foo {
    Box* box;
    Image img;
};

,并将指向此结构的指针作为回调的最后一个参数.

and pass pointer to this struct as the last parameter of your callback.

这篇关于OpenCV,从图像围绕对象绘制一个框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆