GetOpenFileName 对话框和 opencv 的奇怪行为

Strange behaviour with GetOpenFileName dialog and opencv

我正在尝试使用打开文件对话框来允许我的程序的用户select一个图像,然后使用 opencv 对其进行处理。

我有一个功能可以打开对话框并尝试加载图像:

Mat load_image()
{

OPENFILENAME ofn;       // common dialog box structure
TCHAR szFile[260];       // buffer for file name
HWND hwnd;              // owner window
HANDLE hf;              // file handle

// Initialize OPENFILENAME
ZeroMemory(&ofn, sizeof(ofn));
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hwnd;
ofn.lpstrFile = szFile;
// Set lpstrFile[0] to '[=10=]' so that GetOpenFileName does not 
// use the contents of szFile to initialize itself.
ofn.lpstrFile[0] = '[=10=]';
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"All[=10=]*.*[=10=]Text[=10=]*.TXT[=10=]";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

// Display the Open dialog box. 
if (GetOpenFileName(&ofn)==TRUE) 
    hf = CreateFile(ofn.lpstrFile, 
                    GENERIC_READ,
                    0,
                    (LPSECURITY_ATTRIBUTES) NULL,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL,
                    (HANDLE) NULL);
char filepath[260];
wcstombs(filepath, ofn.lpstrFile, 260);
cout << filepath << endl;
Mat src = imread(filepath);
//imshow("src", src);
return src;
}

您在此处看到的代码有效,打开对话框并允许用户选择文件。然后将文件路径转换为字符串(传递到 imread)。当我尝试与图像 src 交互时出现问题。

例如,如果我取消注释 'imshow' 行,GetOpenFileName 将 return 0 并且对话框甚至不会打开。这种情况经常发生,我实际上无法访问图像,因为我尝试的一切都会导致这种情况发生。

为了使函数正常工作,它被这样调用:

load_image();

但是如果我尝试分配图像即:

img = load_image(); 

出现同样的问题。帮助!可能是什么原因造成的?

这些只是我在您的代码中注意到的事情...所以我不希望它起作用,但也许它会有所帮助。

imread 可能失败了。您使用 CreateFile 打开文件并在打开后将其锁定(无共享属性。有关详细信息,请参阅 CreateFile)。 imread 无论如何都会尝试打开文件,因此您无需创建自己的句柄!只需使用收到的文件路径并调用 imread 而不是使用 CreateFile.

Mat src;
if (GetOpenFileName(&ofn)==TRUE)
{
    // Succeeded in choosing a file
    char filepath[260];
    wcstombs(filepath, ofn.lpstrFile, 260);
    cout << filepath << endl;
    src = imread(filepath);
}

此外,如果您没有 hwnd,那么您应该设置 ofn.hwndOwner=NULL 而不是任意设置。

如果您选择使用 CreateFile(也许您希望在 OpenCV 之外出于您自己的目的打开它进行手动读取访问),那么请确保在打开文件句柄之前调用 CloseHandle( HANDLE h )再次归档。

正如前面评论中提到的,CreateFile 方法锁定了图像文件,因此 cv::imread() 无法 access/read 它的内容。

尽量避免使用 CreateFile,我认为没有理由在您的代码中使用它,以下代码运行良好:

cv::Mat load_image()
{
    cv::Mat outMat;
    OPENFILENAME ofn;       // common dialog box structure
    TCHAR szFile[260];      // buffer for file name

    // Initialize OPENFILENAME
    ZeroMemory(&ofn, sizeof(ofn));
    ofn.lStructSize = sizeof(ofn);
    ofn.hwndOwner = NULL;
    ofn.lpstrFile = szFile;
    ofn.lpstrFile[0] = '[=10=]';
    ofn.nMaxFile = sizeof(szFile);
    ofn.lpstrFilter = L"All[=10=]*.*[=10=]Text[=10=]*.TXT[=10=]";
    ofn.nFilterIndex = 1;
    ofn.lpstrFileTitle = NULL;
    ofn.nMaxFileTitle = 0;
    ofn.lpstrInitialDir = NULL;
    ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

    // Display the Open dialog box. 
    if (GetOpenFileName(&ofn) == TRUE)
    {
        char filepath[260];

        wcstombs(filepath, ofn.lpstrFile, 260);
        cout << filepath << endl;

        outMat = cv::imread(filepath);
    }

    return outMat;
}

int main()
{
    cv::Mat image = load_image();

    cv::imshow("image", image);
    cv::waitKey(-1);

    return 0;
}