выбор изображения в свободной форме (желательно на с ++) - PullRequest
5 голосов
/ 19 ноября 2011

Я новичок в манипулировании изображениями.Я заметил, что вы можете указать прямоугольную область интереса и другие, такие как круги и т. Д. В библиотеках для работы с изображениями, таких как opencv.Основные программы рисования, такие как ms-paint, включают в себя выбор произвольной формы, но я не могу найти функцию или руководство о том, как сделать выбор изображения в произвольной форме в opencv или других библиотеках обработки изображений.Есть идеи как этого добиться?PS: мой любимый язык - с / с ++.enter image description here

Ответы [ 2 ]

3 голосов
/ 19 ноября 2011

Одна вещь, которую вы можете попробовать:

Если выделение может быть представлено как последовательность 2d-векторов, вы можете думать о нем как о многоугольнике. Выделите новое 1-канальное изображение, которое будет вашей маской, и заполните его 0. Затем используйте

void cvFillPoly(CvArr* img, CvPoint** pts, int* npts, int contours, CvScalar color, int lineType=8, int shift=0)

задокументировано

http://opencv.willowgarage.com/documentation/drawing_functions.html

для рисования ненулевой области на изображении маски для представления выбранной части изображения.

1 голос
/ 19 ноября 2011

Я написал демо для отображения изображения и рисования маленьких зеленых точек, пока ваша мышь двигается , см. Ниже.

Вы должны знать, что OpenCV не был разработан для этого типа взаимодействия , поэтому производительность является проблемой (и это плохо)! Вы поймете, что я имею в виду.

#include <stdio.h>    
#include <cv.h>
#include <highgui.h>

// mouse callback    
void on_mouse(int event, int x, int y, int flags, void* param)
{
    // Remove comment below to paint only when left mouse button is pressed
    //if (event == CV_EVENT_LBUTTONDOWN)
    {
        //fprintf(stderr, "Painting at %dx%d\n", x, y);
        IplImage* img = (IplImage*)param;

        cvCircle(img, cvPoint(x,y), 1, CV_RGB(0, 255, 0), -1, CV_AA, 0);
            cvShowImage("cvPaint", img);
    }
}


int main(int argc, char* argv[])
{
    if (argc < 2)
    {
        fprintf( stderr, "Usage: %s <img>\n", argv[0]);
        return -1;
    }

    IplImage* frame = NULL; 
    frame = cvLoadImage(argv[1], CV_LOAD_IMAGE_UNCHANGED);
    if (!frame)
    {
        fprintf( stderr, "Failed: Couldn't load file %s\n", argv[1]);
        return -1;
    }

    cvNamedWindow("cvPaint", CV_WINDOW_AUTOSIZE);
    cvShowImage("cvPaint", frame);

    cvSetMouseCallback("cvPaint", &on_mouse, frame);
    while (1)
    {
        // Keep looping to prevent the app from exiting, 
        // so the mouse callback can be called by OpenCV and do some painting

        char key = cvWaitKey(10);
        if (key  == 113 || key == 27) // q was pressed on the keyboard
            break;
    }

    cvReleaseImage(&frame);
    cvDestroyWindow("cvPaint");

    return 0;
}

Я предлагаю, чтобы вы использовали какую-либо другую оконную систему для этого типа задачи , где производительность выше. Взгляните, например, на Qt . Но вы также можете использовать собственные платформы, такие как win32 или X , если хотите.

Что касается другой части вопроса, как обрезать по выбору пользователя, я предлагаю вам взглянуть на код, доступный по адресу: Изменение размера OpenCV и обрезка изображения в соответствии со значением пикселя

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

CvScalar s;        
for (x=0; x<width-1; x++)
{
    for(y=0; y<height-1; y++)
    {
        s = cvGet2D(binImage, y, x);
        if (s.val[0] == 1)
        {
            minX = min(minX, x);
            minY = min(minY, y);
            maxX = max(maxX, x);
            maxY = max(maxY, y);
        }   
    }
}

cvSetImageROI(binImage, cvRect(minX, minY, maxX-minX, maxY-minY));

В этом конкретном случае вместо итерации по изображению в поисках конкретных пикселей, как это сделал пользователь в этом вопросе, вы будете перебирать массив координат, записанных во время движения мыши.

...