Opencv, рисование рамки вокруг объекта из изображения - PullRequest
0 голосов
/ 07 октября 2019

Я делаю проект для развлечения, чтобы узнать больше об OpenCV. На данный момент я хочу нарисовать коробку с заданным изображением. У меня есть рабочая функция, которая выполняет эту работу, но у меня возникла проблема с передачей функции mouse_control в функцию setMouseCallback из OpenCV.

Я получаю следующую ошибку:

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

Когда я пытаюсь разместить предложенную ссылку, я получаю эту ошибку:

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

Я новичок вOpenCV, поэтому я не уверен, как именно отладить и исправить код, который у меня есть.

Вот файл заголовка для класса, над которым я работаю:

#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файл, связанный с файлом заголовка:

#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, необходимые для дублирования ошибки:

#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);
}

Ответы [ 2 ]

1 голос
/ 07 октября 2019

Функция-член и нормальная функция - это две разные вещи.

setMouseCallback функция принимает в качестве функции обратного вызова обычную функцию, подпись которой:

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

, которую вы пытаетесьвызов setMouseCallback с передачей mouse_control в качестве обратного вызова, он не может работать, потому что mouse_control является функцией-членом класса Box. Вы вызываете функцию-член для определенного объекта, вы не можете назвать ее «автономной» - без объекта. Вот почему ваш код не компилируется.

Решение?

Последний параметр обратного вызова - void*. Теперь вы передаете указатель на Image, но вы можете передать указатель на Box, не так ли? Таким образом, вы можете сделать mouse_control статической функцией класса Box:

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

(статическая функция не должна иметь объект для вызова). Указатель на это вы передаете по телефону:

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?. Или вы можете создать какую-нибудь оболочку, например

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

и передать указатель на эту структуру в качестве последнего параметра вашего обратного вызова.

1 голос
/ 07 октября 2019

Функция-член C ++ имеет внутреннюю сигнатуру, отличную от сигнатуры обычной функции. Он будет неявно включать указатель на сигнатуру функции. В противном случае, как функция может узнать, какие данные объекта необходимо изменить, если функция должна изменить некоторые из них?

Таким образом, подпись вашей функции-члена MouseControl() будет выглядеть так:

void mouse_control(Box *object, int event, int x, int y, int flag, void* param);

Очевидно, что это не принимается библиотекой OpenCV (несовпадающий тип указателя на функцию, т. Е. Дополнительный Box * object приводит к сбою.).

Чтобы исправить это, попробуйте один из двух ниже:

  1. Используйте обычную функцию вместо функции-члена класса.

  2. Используйте статическую функцию класса (статическая функция класса непривязан к объекту и поэтому не имеет «дополнительного аргумента в подписи», т. е. Box *object).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...