2013-10-27 60 views
1

目前正在使用VC++打開/讀取圖像。使用openCV VC++讀取文件I/O

我在互聯網上遇到的一些例子使用Windows.h I/O例程,如ReadFile ...但似乎有聲明中的不一致。 (不是說我對Windows有挑戰性......可能是因爲我的理解太少)

這就是我所得到的。

//So i have this function to load file 
BYTE* LoadFile (int* width, int* height, long* size, LPCWSTR bmpfile) 
{ 
    BITMAPFILEHEADER bmpheader; 
    BITMAPINFOHEADER bmpinfo; 
    DWORD bytesread = 0; 
     HANDLE file = CreateFile (bmpfile , GENERIC_READ, FILE_SHARE_READ,NULL, 
           OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 
    if (NULL == file) 
    return NULL; 

    if (ReadFile (file, &bmpheader, sizeof (BITMAPFILEHEADER),&bytesread, 
         NULL) == false) 
    { 
    CloseHandle (file); 
    return NULL; 
    } 
. 
. 
. 
return appropriate value; 
} 

現在ReadFile的API函數聲明爲在WINBASE.H

WINBASEAPI BOOL WINAPI ReadFile(
    _In_   HANDLE hFile, 
    _Out_  LPVOID lpBuffer, 
    _In_   DWORD nNumberOfBytesToRead, 
    _Out_opt_ LPDWORD lpNumberOfBytesRead, 
    _Inout_opt_ LPOVERLAPPED lpOverlapped 
); 

而且在MSDN的例子如下... 他們這樣調用這個函數。

ReadFile(hFile, chBuffer, BUFSIZE, &dwBytesRead, NULL) 

哪一個需要「bytesRead」是某種輸出參數。所以它給了我讀取的字節數。

但在我的代碼..它給錯誤信息。 'ReadFile':無法將參數4從'LPDWORD *'轉換爲'LPDWORD'

所以我只是初始化bytesRead爲0並通過值傳遞(這是錯誤的,但只是爲了檢查它是否工作)。

則給出了這樣的例外

Unhandled exception at 0x774406ae in ImProc.exe: 0xC0000005: Access violation 
writing location 0x00000000. 

請建議。

請告訴我是否錯過了任何代碼......包括在形成問題本身時。

謝謝。

+1

你確定你已經正確地複製了'bytesread'的聲明嗎?當你在引用的代碼中是DWORD(這是正確的)時,錯誤使它看起來像是實際聲明爲'LPDWORD'('DWORD *')。此外,'NULL'不是'CreateFile'在失敗時返回的內容。你爲什麼在這裏使用Windows API? ''和''都使用起來更簡單並且便於攜帶。 –

+0

嗨,詹姆斯,呀宣言是錯誤的...它應該是LPDWORD bytesRead = 0; 錯字 上述錯誤顯示正確的聲明。 我會嘗試iostream功能以及...我想你是指fread()和其他功能....但仍然可以檢查我使用的Windows API中的任何故障。 – Haswell

回答

0

LPDWORD bytesread = 0更改爲DWORD bytesread = 0

我使用跑代碼:

#include <windows.h> 
#include <cstdio> 

BYTE* LoadFile(int* width, int* height, long* size, LPCWSTR bmpfile) 
{ 
    DWORD bytesread = 0; 
    BITMAPFILEHEADER bmpheader; 
    BITMAPINFOHEADER bmpinfo; 

    HANDLE file = CreateFile(bmpfile , GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); 
    if (file == NULL) 
     return NULL; 

    if (ReadFile(file, &bmpheader, sizeof(BITMAPFILEHEADER), &bytesread, NULL) == FALSE) 
    { 
     CloseHandle(file); 
     return NULL; 
    } 

    printf("Bytes Read: %d", bytesread); 
    CloseHandle(file); 
    return NULL; 
} 

int main() 
{ 
    int width = 0; 
    int height = 0; 
    long size = 0; 

    LoadFile(&width, &height, &size, L"C:/Users/Brandon/Desktop/Foo.bmp"); 
} 

打印14

但是,如果你想要一個更便攜的解決方案那麼下面可以爲你工作呢?

Bitmap.h:

#ifndef BITMAP_H_INCLUDED 
#define BITMAP_H_INCLUDED 

#include <iostream> 
#include <fstream> 
#include <vector> 
#include <stdexcept> 

class Bitmap 
{ 
    private: 
     std::vector<std::uint8_t> Pixels; 
     std::uint32_t width, height; 
     std::uint16_t BitsPerPixel; 

    public: 
     Bitmap(const char* FilePath); 
     void Save(const char* FilePath); 
}; 
#endif // BITMAP_H_INCLUDED 

Bitmap.cpp:

Bitmap::Bitmap(const char* FilePath) : Pixels(0), width(0), height(0), BitsPerPixel(0) 
{ 
    std::fstream hFile(FilePath, std::ios::in | std::ios::binary); 
    if (!hFile.is_open()) throw std::invalid_argument("Error: File Not Found."); 

    hFile.seekg(0, std::ios::end); 
    int Length = hFile.tellg(); 
    hFile.seekg(0, std::ios::beg); 
    std::vector<std::uint8_t> FileInfo(Length); 
    hFile.read(reinterpret_cast<char*>(FileInfo.data()), 54); 

    if(FileInfo[0] != 'B' && FileInfo[1] != 'M') 
    { 
     hFile.close(); 
     throw std::invalid_argument("Error: Invalid File Format. Bitmap Required."); 
    } 

    if (FileInfo[28] != 24 || FileInfo[28] != 32) 
    { 
     hFile.close(); 
     throw std::invalid_argument("Error: Invalid File Format. 24 or 32 bit Image Required."); 
    } 

    BitsPerPixel = FileInfo[28]; 
    width = FileInfo[18] + (FileInfo[19] << 8); 
    height = FileInfo[22] + (FileInfo[23] << 8); 
    std::uint32_t PixelsOffset = FileInfo[10] + (FileInfo[11] << 8); 
    std::uint32_t size = ((width * BitsPerPixel + 31)/32) * 4 * height; 
    Pixels.resize(size); 

    hFile.seekg (PixelsOffset, std::ios::beg); 
    hFile.read(reinterpret_cast<char*>(Pixels.data()), size); 
    hFile.close(); 
} 

void Bitmap::Save(const char* FilePath) 
{ 
    std::fstream hFile(FilePath, std::ios::out | std::ios::binary); 
    if (!hFile.is_open()) throw std::invalid_argument("Error: File not found."); 

    std::uint32_t Trash = 0; 
    std::uint16_t Planes = 1; 
    std::uint32_t biSize = 40; 
    std::uint16_t Type = 0x4D42; 
    std::uint32_t compression = 0; 
    std::uint32_t PixelsOffsetBits = 54; 
    std::uint32_t size = ((width * BitsPerPixel + 31)/32) * 4 * height; 
    std::uint32_t bfSize = 54 + size; 

    hFile.write(reinterpret_cast<char*>(&Type), sizeof(Type)); 
    hFile.write(reinterpret_cast<char*>(&bfSize), sizeof(bfSize)); 
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(std::uint32_t)); 
    hFile.write(reinterpret_cast<char*>(&PixelsOffsetBits), sizeof(PixelsOffsetBits)); 
    hFile.write(reinterpret_cast<char*>(&biSize), sizeof(biSize)); 
    hFile.write(reinterpret_cast<char*>(&width), sizeof(width)); 
    hFile.write(reinterpret_cast<char*>(&height), sizeof(height)); 
    hFile.write(reinterpret_cast<char*>(&Planes), sizeof(Planes)); 
    hFile.write(reinterpret_cast<char*>(&BitsPerPixel), sizeof(BitsPerPixel)); 
    hFile.write(reinterpret_cast<char*>(&compression), sizeof(compression)); 
    hFile.write(reinterpret_cast<char*>(&size), sizeof(size)); 
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(std::uint32_t)); 
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(std::uint32_t)); 
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(std::uint32_t)); 
    hFile.write(reinterpret_cast<char*>(&Trash), sizeof(std::uint32_t)); 
    hFile.write(reinterpret_cast<char*>(Pixels.data()), size); 
    hFile.close(); 
} 
+0

嗨CCU,我只包含windows.h(與其他庫),但它會引發這些錯誤... 我提到了winbase.h的ReadFile函數的聲明..我得到了這個頭,當我按下ReadLine上的F12 )。 – Haswell

+0

你好eyanand,我添加了你寫的代碼的一個工作樣本。你可以運行它並查看它的工作原理。我不確定您的編譯器是否有問題,但上面的代碼應該打印14或至少爲您打印某些內容。你的代碼有'LPDWORD bytesread'而不是'DWORD bytesread'。 – Brandon

+0

嗨CCU,是啊,它正在與數據類型的變化..我檢查了數據類型LPDWORD ...這是一個長指針DWORD..hence接受DWORD&bytesRead的地址...我的壞...感謝您花時間在這。 – Haswell

0

的問題是你如何申報bytesread。

它應該是:

DWORD bytesread = 0; 

不:

LPDWORD bytesread = 0; 

讀取爲 「(長)指針DWORD」,相當於:

DWORD *bytesread = 0; 

當通過它通過價值,你傳遞了一個NULL指針,導致你的崩潰。

+0

嗨,好吧thnks它的工作...現在我想我應該看看LPDWORD和DWORD的那些定義...我對readline參數感到困惑,因爲它接受LPDWORD ?? ??這種情況? – Haswell

+0

TLDR:您想要將雙字的地址傳遞給ReadFile。在這種情況下,「現有DWORD的地址與LPDWORD相同」。你在做什麼是:'LPDWORD bytesRead = NULL'。在這種情況下,你說'DWORD * bytesread = null;'。這是一個指向沒有指向哪裏的dword的指針。但是,該函數需要一個指向現有雙字的指針,以便它可以存儲該值。因此你需要傳遞一些現有雙字的地址。 – Brandon