OpenCv из взаимодействия C # зависает на cvSaveImage, если нет отладчика! - PullRequest
2 голосов
/ 23 декабря 2010

каждый - у меня есть Heisenbug, здесь (только обнаруживается с отключенным отладчиком!). Кажется, в C # для неуправляемого взаимодействия - если я делаю OpenCv cvSaveImage в каталог% TEMP%, это нормально, но в других каталогах, которые я пробовал, он выбрасывает AccVio или зависает. Запуск от имени администратора, поэтому не является проблемой безопасности. Работает под отладчиком C # Visual Studio 2010, он работает нормально для любого каталога. Отладчик отключен (Ctrl F5) ... сбой или зависание! Accch.

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

Должен быть установлен OpenCv2.2 [бесплатная обработка изображений и компьютерное зрение (cv)] (версия от декабря 2010 г.) с использованием значений по умолчанию, от sourceforge.net/projects/opencvlibrary/

Тогда возьмите мой проект Visual Studio 2010 из http://dl.dropbox.com/u/1997638/OpenCv2.2Test.zip

Имеется оболочка (спасибо Heiko Kießling, iib-chemnitz.de за оригинал!) И программа TEST с комментариями, которые приведут вас к повторяющейся ошибке.

еще раз, я был бы очень признателен за любые советы или подсказки!

РЕДАКТИРОВАТЬ: @Aliostad: Вот вся программа (за исключением оболочки, которая находится в проекте VS, который я связал)

        static void Main(string[] args)
    {
        CvLib.CvNamedWindow("TestWindow2", CvLib.CV_WINDOW_AUTOSIZE);

        var img = CvLib.CvCreateImage(
            CvLib.CvSize(256, 256),
            depth: 8,
            channels: 3);

        var pts = new[] {
            CvLib.CvPoint(0, 0),
            CvLib.CvPoint(0, 255),
            CvLib.CvPoint(255,255),
            CvLib.CvPoint(255, 0)
        };

        CvLib.CvFillConvexPoly(
            img: ref img,
            pts: ref pts[0],
            npts: 4,
            color: CvLib.CV_RGB(0, 0, 255),
            line_type: 8,
            shift: 0);

        CvLib.CvCircle(
            img: ref img,
            center: CvLib.CvPoint(128, 128),
            radius: 20,
            color: CvLib.CV_RGB(255, 255, 0),
            thickness: 5,
            line_type: 8,
            shift: 0);

        CvLib.CvShowImage(
            name: "TestWindow2",
            image: ref img);

        var tempDirectory = Environment.GetEnvironmentVariable("TEMP");
        var path = tempDirectory + @"\test.png";

        CvLib.CvSaveImage(
            path: path,
            img: ref img);

        MessageBox.Show("Click OK to exit");
        CvLib.CvDestroyAllWindows();
    }

Изменение «пути» к чему-либо еще вызывает сбой или зависание, когда отладчик НЕ подключен.

РЕДАКТИРОВАТЬ: @Aliostad - вот код взаимодействия для cvSaveImage. Я уверен, что не понимаю атрибут MarshalAs, и я предполагаю, что это источник проблемы

        public static void CvSaveImage(string path, ref IplImage img)
    {
        cvSaveImage(path, img.ptr);
    }
    [DllImport(HIGHGUI_LIBRARY, CallingConvention = CallingConvention.Cdecl)]
    private static extern void cvSaveImage([MarshalAs(UnmanagedType.LPStr)] String filename, IntPtr img);

1 Ответ

3 голосов
/ 24 декабря 2010

Это объявление встроенной функции cvSaveImage (), полученной из highgui.h:

CVAPI(int) cvSaveImage( const char* filename, const CvArr* image,
                        const int* params CV_DEFAULT(0) );

Это объявление pinvoke для него, полученное из оболочки HighGui.cs:

    [DllImport(HIGHGUI_LIBRARY, CallingConvention = CallingConvention.Cdecl)]
    private static extern void cvSaveImage([MarshalAs(UnmanagedType.LPStr)] String filename, IntPtr img);

Обратите внимание, что у нативного объявления есть три аргумента, у объявления pinvoke есть только два. Можно вызвать встроенную функцию из программы на C ++ и передать только два аргумента, компилятор автоматически применяет значение по умолчанию для третьего аргумента. Но это не работает таким образом с маршаллером пинвока, он не имеет ни малейшего понятия, что третий аргумент даже существует.

В результате встроенная функция получает произвольное значение для параметра params . Это работает, когда это случайно 0. Но есть 4 миллиарда других способов для функции получить ненулевой аргумент и выполнить пикирование при нарушении доступа, когда она разыменовывает указатель. Отказ будет случайным.

Исправьте проблему, отредактировав объявление pinvoke и добавив IntPtr в качестве 3-го параметра. Передайте IntPtr.Zero в коде C #.

Это довольно основная ошибка, ожидайте больше проблем с этой оболочкой.

...