为什么我必须将原始图像数据的宽度除以3?

时间:2015-12-01 09:10:22

标签: c++ biometrics

所以我几乎在终点线上感觉到了。我正在研究工作所需的指纹识别器项目。需要在1月中旬完成所以我需要这个工作:)

我一直在互联网上跳来寻找已经从我的读者那里获取图像的图书馆,我被提到了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.如果我不这样做,图像将无效。

这背后的原因是什么,如果可能的话,我如何让图片保留其原始宽度?

1 个答案:

答案 0 :(得分:2)

AFAIK,WinBioCaptureSample返回的图像是灰度位图,即每像素使用8位。 SaveBitmap的实现会写入一个24位RGB位图。因此它需要3倍于原始指纹位图的字节数(或 - 正如您已经发现的那样 - 它会将图像缩小3倍)。

因此,为了解决这个问题,你需要在某个时刻将每个字节加倍。在SaveBitmap中或在将数据传递给它之前。