为什么我必须将原始图像数据的宽度除以 3?
Why do I have to divide the width of my raw image data by 3?
所以我感觉快到终点线了。我正在做一个我工作需要的指纹 reader 项目。需要在 1 月中旬之前完成,所以我需要这个工作:)
我一直在互联网上四处寻找已经从我的 reader 中获取图像的图书馆,我被推荐给了 Griaule。长话短说,在经历了很多挫折之后,我得出的结论是 Griaule 已经过时了,对于它应该做的事情来说太复杂了,太昂贵了,而且总体上太难正常工作了。
所以我决定采用另一种方法,我使用 Microsoft 提供的示例,然后使用另一个库,我在获得图像后负责处理。
我现在可以扫描指纹,然后制作 BMP 文件。但是文件的宽高比很奇怪。尽管(如果没记错的话)扫描仪应该有更高的分辨率,但它看起来非常高而且挤在一起。
控制台显示图像应该是 256 x 360
但我必须将该宽度除以 3 才能使图像正常工作。所以结果显示为 85x360
,看起来不太正确。
所以这是将图像保存为 BMP 的函数:
bool SaveBMP(BYTE* buffer, int width, int height, long paddedsize, LPCTSTR bmpfile) {
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER info;
memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));
memset(&info, 0, sizeof(BITMAPINFOHEADER));
bmfh.bfType = 0x4d42; // Don't question it. Magic Word (B and M). It's necessary. Seriously.
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bmfh.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+paddedsize;
bmfh.bfOffBits = 0x36;
info.biSize = sizeof(BITMAPINFOHEADER);
info.biWidth = width;
info.biHeight = height;
info.biPlanes = 1;
info.biBitCount = 24;
info.biCompression = BI_RGB;
info.biSizeImage = 0;
info.biXPelsPerMeter = 0x0ec4;
info.biYPelsPerMeter = 0x0ec4;
info.biClrUsed = 0;
info.biClrImportant = 0;
HANDLE file = CreateFile(bmpfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
unsigned long bwritten;
if (WriteFile(file, &bmfh, sizeof(BITMAPFILEHEADER), &bwritten, NULL) == false) {
CloseHandle(file);
return false;
}
if (WriteFile(file, &info, sizeof(BITMAPINFOHEADER), &bwritten, NULL) == false) {
CloseHandle(file);
return false;
}
if (WriteFile(file, buffer, paddedsize, &bwritten, NULL) == false) {
CloseHandle(file);
return false;
}
CloseHandle(file);
return true;
}
用于采集指纹的代码:
HRESULT CaptureSample()
{
HRESULT hr = S_OK;
WINBIO_SESSION_HANDLE sessionHandle = NULL;
WINBIO_UNIT_ID unitId = 0;
WINBIO_REJECT_DETAIL rejectDetail = 0;
PWINBIO_BIR sample = NULL;
SIZE_T sampleSize = 0;
// Connect to the system pool.
hr = WinBioOpenSession(
WINBIO_TYPE_FINGERPRINT, // Service provider
WINBIO_POOL_SYSTEM, // Pool type
WINBIO_FLAG_RAW, // Access: Capture raw data
NULL, // Array of biometric unit IDs
0, // Count of biometric unit IDs
WINBIO_DB_DEFAULT, // Default database
&sessionHandle // [out] Session handle
);
if (FAILED(hr))
{
wprintf_s(L"\n WinBioOpenSession failed. hr = 0x%x\n", hr);
goto e_Exit;
}
// Capture a biometric sample.
wprintf_s(L"\n Calling WinBioCaptureSample - Swipe sensor...\n");
hr = WinBioCaptureSample(
sessionHandle,
WINBIO_NO_PURPOSE_AVAILABLE,
WINBIO_DATA_FLAG_RAW,
&unitId,
&sample,
&sampleSize,
&rejectDetail
);
if (FAILED(hr))
{
if (hr == WINBIO_E_BAD_CAPTURE)
{
wprintf_s(L"\n Bad capture; reason: %d\n", rejectDetail);
}
else
{
wprintf_s(L"\n WinBioCaptureSample failed. hr = 0x%x\n", hr);
}
goto e_Exit;
}
wprintf_s(L"\n Swipe processed - Unit ID: %d\n", unitId);
wprintf_s(L"\n Captured %d bytes.\n", sampleSize);
// Art "Messiah" Baker at Microsoft
PWINBIO_BIR_HEADER BirHeader = (PWINBIO_BIR_HEADER)(((PBYTE)sample) + sample->HeaderBlock.Offset);
PWINBIO_BDB_ANSI_381_HEADER AnsiBdbHeader = (PWINBIO_BDB_ANSI_381_HEADER)(((PBYTE)sample) + sample->StandardDataBlock.Offset);
PWINBIO_BDB_ANSI_381_RECORD AnsiBdbRecord = (PWINBIO_BDB_ANSI_381_RECORD)(((PBYTE)AnsiBdbHeader) + sizeof(WINBIO_BDB_ANSI_381_HEADER));
PBYTE firstPixel = (PBYTE)((PBYTE)AnsiBdbRecord) + sizeof(WINBIO_BDB_ANSI_381_RECORD);
int width = AnsiBdbRecord->HorizontalLineLength;
int height = AnsiBdbRecord->VerticalLineLength;
wprintf_s(L"\n ID: %d\n", AnsiBdbHeader->ProductId.Owner);
wprintf_s(L"\n Width: %d\n", AnsiBdbRecord->HorizontalLineLength);
wprintf_s(L"\n Height: %d\n", AnsiBdbRecord->VerticalLineLength);
wprintf_s(L"\n Horizontal Img. Res.: %d\n", AnsiBdbHeader->HorizontalImageResolution);
wprintf_s(L"\n Horizontal Scan Img. Res.: %d\n", AnsiBdbHeader->HorizontalScanResolution);
wprintf_s(L"\n Vertical Img. Res.: %d\n", AnsiBdbHeader->VerticalImageResolution);
wprintf_s(L"\n Vertical Scan Img. Res.: %d\n", AnsiBdbHeader->VerticalScanResolution);
wprintf_s(L"\n First Pixel: %d\n", firstPixel);
wprintf_s(L"\n Element Count: %d\n", AnsiBdbHeader->ElementCount);
bool b = SaveBMP(firstPixel, width, height, 0, L"C:\Users\smf\Desktop\fingerprint.bmp");
wprintf_s(L"\n Success: %d\n", b);
e_Exit:
if (sample != NULL)
{
WinBioFree(sample);
sample = NULL;
}
if (sessionHandle != NULL)
{
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
wprintf_s(L"\n Press any key to exit...");
_getch();
return hr;
}
我不太明白(因为我一般是 C++ 的新手,但精通高级语言)是为了让这个函数工作,我必须将传递给函数的任何宽度除以3. 如果我不这样做,图像将无法正常工作。
这背后的原因是什么,如果可能的话,我怎样才能让图片保持原来的宽度?
据我所知,WinBioCaptureSample 返回的图像是灰度位图,即每个像素使用 8 位。
您的 SaveBitmap 实现写入一个 24 位 RGB 位图。所以它需要的字节数是原始指纹位图的 3 倍(或者 - 正如您已经发现的那样 - 它会将图像缩小 3 倍)。
所以,为了解决这个问题,你需要在某个时候将每个字节增加三倍。在 SaveBitmap 中或在将数据传递给它之前。
所以我感觉快到终点线了。我正在做一个我工作需要的指纹 reader 项目。需要在 1 月中旬之前完成,所以我需要这个工作:)
我一直在互联网上四处寻找已经从我的 reader 中获取图像的图书馆,我被推荐给了 Griaule。长话短说,在经历了很多挫折之后,我得出的结论是 Griaule 已经过时了,对于它应该做的事情来说太复杂了,太昂贵了,而且总体上太难正常工作了。
所以我决定采用另一种方法,我使用 Microsoft 提供的示例,然后使用另一个库,我在获得图像后负责处理。
我现在可以扫描指纹,然后制作 BMP 文件。但是文件的宽高比很奇怪。尽管(如果没记错的话)扫描仪应该有更高的分辨率,但它看起来非常高而且挤在一起。
控制台显示图像应该是 256 x 360
但我必须将该宽度除以 3 才能使图像正常工作。所以结果显示为 85x360
,看起来不太正确。
所以这是将图像保存为 BMP 的函数:
bool SaveBMP(BYTE* buffer, int width, int height, long paddedsize, LPCTSTR bmpfile) {
BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER info;
memset(&bmfh, 0, sizeof(BITMAPFILEHEADER));
memset(&info, 0, sizeof(BITMAPINFOHEADER));
bmfh.bfType = 0x4d42; // Don't question it. Magic Word (B and M). It's necessary. Seriously.
bmfh.bfReserved1 = 0;
bmfh.bfReserved2 = 0;
bmfh.bfSize = sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+paddedsize;
bmfh.bfOffBits = 0x36;
info.biSize = sizeof(BITMAPINFOHEADER);
info.biWidth = width;
info.biHeight = height;
info.biPlanes = 1;
info.biBitCount = 24;
info.biCompression = BI_RGB;
info.biSizeImage = 0;
info.biXPelsPerMeter = 0x0ec4;
info.biYPelsPerMeter = 0x0ec4;
info.biClrUsed = 0;
info.biClrImportant = 0;
HANDLE file = CreateFile(bmpfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
unsigned long bwritten;
if (WriteFile(file, &bmfh, sizeof(BITMAPFILEHEADER), &bwritten, NULL) == false) {
CloseHandle(file);
return false;
}
if (WriteFile(file, &info, sizeof(BITMAPINFOHEADER), &bwritten, NULL) == false) {
CloseHandle(file);
return false;
}
if (WriteFile(file, buffer, paddedsize, &bwritten, NULL) == false) {
CloseHandle(file);
return false;
}
CloseHandle(file);
return true;
}
用于采集指纹的代码:
HRESULT CaptureSample()
{
HRESULT hr = S_OK;
WINBIO_SESSION_HANDLE sessionHandle = NULL;
WINBIO_UNIT_ID unitId = 0;
WINBIO_REJECT_DETAIL rejectDetail = 0;
PWINBIO_BIR sample = NULL;
SIZE_T sampleSize = 0;
// Connect to the system pool.
hr = WinBioOpenSession(
WINBIO_TYPE_FINGERPRINT, // Service provider
WINBIO_POOL_SYSTEM, // Pool type
WINBIO_FLAG_RAW, // Access: Capture raw data
NULL, // Array of biometric unit IDs
0, // Count of biometric unit IDs
WINBIO_DB_DEFAULT, // Default database
&sessionHandle // [out] Session handle
);
if (FAILED(hr))
{
wprintf_s(L"\n WinBioOpenSession failed. hr = 0x%x\n", hr);
goto e_Exit;
}
// Capture a biometric sample.
wprintf_s(L"\n Calling WinBioCaptureSample - Swipe sensor...\n");
hr = WinBioCaptureSample(
sessionHandle,
WINBIO_NO_PURPOSE_AVAILABLE,
WINBIO_DATA_FLAG_RAW,
&unitId,
&sample,
&sampleSize,
&rejectDetail
);
if (FAILED(hr))
{
if (hr == WINBIO_E_BAD_CAPTURE)
{
wprintf_s(L"\n Bad capture; reason: %d\n", rejectDetail);
}
else
{
wprintf_s(L"\n WinBioCaptureSample failed. hr = 0x%x\n", hr);
}
goto e_Exit;
}
wprintf_s(L"\n Swipe processed - Unit ID: %d\n", unitId);
wprintf_s(L"\n Captured %d bytes.\n", sampleSize);
// Art "Messiah" Baker at Microsoft
PWINBIO_BIR_HEADER BirHeader = (PWINBIO_BIR_HEADER)(((PBYTE)sample) + sample->HeaderBlock.Offset);
PWINBIO_BDB_ANSI_381_HEADER AnsiBdbHeader = (PWINBIO_BDB_ANSI_381_HEADER)(((PBYTE)sample) + sample->StandardDataBlock.Offset);
PWINBIO_BDB_ANSI_381_RECORD AnsiBdbRecord = (PWINBIO_BDB_ANSI_381_RECORD)(((PBYTE)AnsiBdbHeader) + sizeof(WINBIO_BDB_ANSI_381_HEADER));
PBYTE firstPixel = (PBYTE)((PBYTE)AnsiBdbRecord) + sizeof(WINBIO_BDB_ANSI_381_RECORD);
int width = AnsiBdbRecord->HorizontalLineLength;
int height = AnsiBdbRecord->VerticalLineLength;
wprintf_s(L"\n ID: %d\n", AnsiBdbHeader->ProductId.Owner);
wprintf_s(L"\n Width: %d\n", AnsiBdbRecord->HorizontalLineLength);
wprintf_s(L"\n Height: %d\n", AnsiBdbRecord->VerticalLineLength);
wprintf_s(L"\n Horizontal Img. Res.: %d\n", AnsiBdbHeader->HorizontalImageResolution);
wprintf_s(L"\n Horizontal Scan Img. Res.: %d\n", AnsiBdbHeader->HorizontalScanResolution);
wprintf_s(L"\n Vertical Img. Res.: %d\n", AnsiBdbHeader->VerticalImageResolution);
wprintf_s(L"\n Vertical Scan Img. Res.: %d\n", AnsiBdbHeader->VerticalScanResolution);
wprintf_s(L"\n First Pixel: %d\n", firstPixel);
wprintf_s(L"\n Element Count: %d\n", AnsiBdbHeader->ElementCount);
bool b = SaveBMP(firstPixel, width, height, 0, L"C:\Users\smf\Desktop\fingerprint.bmp");
wprintf_s(L"\n Success: %d\n", b);
e_Exit:
if (sample != NULL)
{
WinBioFree(sample);
sample = NULL;
}
if (sessionHandle != NULL)
{
WinBioCloseSession(sessionHandle);
sessionHandle = NULL;
}
wprintf_s(L"\n Press any key to exit...");
_getch();
return hr;
}
我不太明白(因为我一般是 C++ 的新手,但精通高级语言)是为了让这个函数工作,我必须将传递给函数的任何宽度除以3. 如果我不这样做,图像将无法正常工作。
这背后的原因是什么,如果可能的话,我怎样才能让图片保持原来的宽度?
据我所知,WinBioCaptureSample 返回的图像是灰度位图,即每个像素使用 8 位。 您的 SaveBitmap 实现写入一个 24 位 RGB 位图。所以它需要的字节数是原始指纹位图的 3 倍(或者 - 正如您已经发现的那样 - 它会将图像缩小 3 倍)。
所以,为了解决这个问题,你需要在某个时候将每个字节增加三倍。在 SaveBitmap 中或在将数据传递给它之前。