手工局部二值化,MFC, BMP

拿知乎上的一张图练练手,光照是斜对角,全局二值化阈值20,一个角太白;改为全局80,另一个角太黑。

就把图分成4x4,16个小方块,用一个阈值矩阵手工搞,虽说是滥竽充数,好歹也弄出来了。

 

 

 

程序段:

void CXDTS1View::OnTestTest1()
{
    // TODO: Add your command handler code here
    CXDTDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    unsigned char* pData;
    int            DataLen;

    
    //pData = (unsigned char*)pDoc->m_Data;
    DataLen = pDoc->m_DataLen;
    if (DataLen == 0) return;

    pData = new unsigned char[DataLen];
    
    memcpy(pData, (void*)pDoc->m_Data, DataLen);


    //if (DataLen > 10000) DataLen = 10000;

    BITMAPFILEHEADER hdr;
    LPBITMAPINFOHEADER lpbi;
    BITMAPINFOHEADER  bmpInfo;//信息头  

    memcpy(&hdr, pData, 14);
    memcpy(&bmpInfo, pData + 14, 40);


    unsigned char* p = NULL;
    unsigned char* pBmpdata = NULL;
    unsigned char* pBmpdata2 = NULL;
    p = (unsigned char*)pData + 14;
    pBmpdata = (unsigned char*)(pData + hdr.bfOffBits);
    pBmpdata2 = (unsigned char*)(pData + hdr.bfOffBits);
    lpbi = (LPBITMAPINFOHEADER)(p);
    /*PRINT("%d-%d-%d", hdr.bfType, hdr.bfSize, hdr.bfOffBits);
    PRINT("%d-%d-%d", lpbi->biSize, lpbi->biWidth, lpbi->biHeight);
    PRINT("%d-%d-%d", bmpInfo.biSize, bmpInfo.biWidth, bmpInfo.biHeight);*/

    int bfWidth, bfHeight;
    int biBitCount;
    int bytesPerLine;
    int skip;
    int imageSize;

    //DBI 数据信息
    bfWidth = lpbi->biWidth;
    bfHeight = lpbi->biHeight;
    biBitCount = lpbi->biBitCount;

    
    //内存数据映射
    bytesPerLine = ((bfWidth * biBitCount + 31) >> 5) << 2;//bfWidth *3+skip
    skip = 4 - ((bfWidth * biBitCount) >> 3) & 3;
    imageSize = bytesPerLine * bfHeight;

    PRINT("BMP W:%d-H:%d-b:%d  MEM: BpL:%d-Skip:%d-Size:%d", 
        bfWidth, bfHeight, biBitCount,
        bytesPerLine, skip, imageSize);


    CMainFrame* pMainFrame = (CMainFrame*)((CXDTApp*)AfxGetApp())->m_pMainWnd;
    CPropertiesWnd* pwndProperties = &(pMainFrame->m_wndProperties);

    CString str = pwndProperties->m_pSize->GetSubItem(0)->FormatProperty();
    int  door;
    door = atoi(str.GetBuffer());
    

    int R, G, B, Gray;
    
    //door = 80;
    
    int tdoor[4][4] =
    {
        50, 60, 70, 80,
        40, 50, 60, 70,
        30, 40, 50, 60,
        20, 30, 40, 50 
    };
    
    //处理内存数据
    for (int i = 0; i < bfHeight; i++) //高度是反的
    {
        for (int j = 0; j < bytesPerLine; j+=3)  //宽度 转换为 行(列数) 
        {
                
            B=pBmpdata[i * bytesPerLine + j] ;
            G=pBmpdata[i * bytesPerLine + j+1];
            R=pBmpdata[i * bytesPerLine + j+2];

            Gray = (R * 19595 + G * 38469 + B * 7472) >> 16;

            door = tdoor[i * 4 / bfHeight][j * 4 / bytesPerLine];

            if (Gray > door) Gray = 255;
            else  Gray = 0;

            pBmpdata[i * bytesPerLine + j] = Gray;
            pBmpdata[i * bytesPerLine + j+1] = Gray;
            pBmpdata[i * bytesPerLine + j+2] = Gray;
            
        }
    }
    
    
    //pDoc->UpdateAllViews(NULL);
    ShowBMP(pData, DataLen);
    
    delete pData;

}

 

2022-07-27

忍不住又把程序改进了一下,做成了滑窗小区域的局部二值化,效果如下:滑窗中的阈值若是取均值的加权,对连续灰度会造成影响,导致空心化。

对于灰度变化的区域,实际上是边缘强化了,滑窗越小,突变越大,越难控制。

 

 

 

程序段如下:

void CXDTS1View::OnTestTest1()
{
    // TODO: Add your command handler code here
    CXDTDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc)
        return;

    unsigned char* pData;
    unsigned char* pData2;
    int            DataLen;

    
    //pData = (unsigned char*)pDoc->m_Data;
    DataLen = pDoc->m_DataLen;
    if (DataLen == 0) return;

    pData = new unsigned char[DataLen];
    pData2 = new unsigned char[DataLen];
    
    memcpy(pData, (void*)pDoc->m_Data, DataLen);
    memcpy(pData2, (void*)pDoc->m_Data, DataLen);

    

    //if (DataLen > 10000) DataLen = 10000;

    BITMAPFILEHEADER hdr;
    LPBITMAPINFOHEADER lpbi;
    BITMAPINFOHEADER  bmpInfo;//信息头  

    memcpy(&hdr, pData, 14);
    memcpy(&bmpInfo, pData + 14, 40);


    unsigned char* p = NULL;
    unsigned char* pBmpdata = NULL;
    unsigned char* pBmpdata2 = NULL;
    p = (unsigned char*)pData + 14;
    pBmpdata = (unsigned char*)(pData + hdr.bfOffBits);
    pBmpdata2 = (unsigned char*)(pData2 + hdr.bfOffBits);
    
    lpbi = (LPBITMAPINFOHEADER)(p);
    /*PRINT("%d-%d-%d", hdr.bfType, hdr.bfSize, hdr.bfOffBits);
    PRINT("%d-%d-%d", lpbi->biSize, lpbi->biWidth, lpbi->biHeight);
    PRINT("%d-%d-%d", bmpInfo.biSize, bmpInfo.biWidth, bmpInfo.biHeight);*/

    int bfWidth, bfHeight;
    int biBitCount;
    int bytesPerLine;
    int skip;
    int imageSize;

    //DBI 数据信息
    bfWidth = lpbi->biWidth;
    bfHeight = lpbi->biHeight;
    biBitCount = lpbi->biBitCount;

    
    //内存数据映射
    bytesPerLine = ((bfWidth * biBitCount + 31) >> 5) << 2;//bfWidth *3+skip
    skip = 4 - ((bfWidth * biBitCount) >> 3) & 3;
    imageSize = bytesPerLine * bfHeight;

    PRINT("BMP W:%d-H:%d-b:%d  MEM: BpL:%d-Skip:%d-Size:%d", 
        bfWidth, bfHeight, biBitCount,
        bytesPerLine, skip, imageSize);


    CMainFrame* pMainFrame = (CMainFrame*)((CXDTApp*)AfxGetApp())->m_pMainWnd;
    CPropertiesWnd* pwndProperties = &(pMainFrame->m_wndProperties);

    CString str = pwndProperties->m_pSize->GetSubItem(0)->FormatProperty();
    int  door;
    door = atoi(str.GetBuffer());
    

    int R, G, B, Gray;
    
    //door = 80;
    
    int tdoor[4][4] =
    {
        50, 60, 70, 80,
        40, 50, 60, 70,
        30, 40, 50, 60,
        20, 30, 40, 50 
    };
    
    //处理内存数据
    for (int i = 0; i < bfHeight; i++) //高度是反的
    {
        for (int j = 0; j < bytesPerLine; j+=3)  //宽度 转换为 行(列数) 
        {
                
            B=pBmpdata[i * bytesPerLine + j] ;
            G=pBmpdata[i * bytesPerLine + j+1];
            R=pBmpdata[i * bytesPerLine + j+2];

            Gray = (R * 19595 + G * 38469 + B * 7472) >> 16;

            door = tdoor[i * 4 / bfHeight][j * 4 / bytesPerLine];

            //if (Gray > door) Gray = 255;
            //else  Gray = 0;

            pBmpdata[i * bytesPerLine + j] = Gray;
            pBmpdata[i * bytesPerLine + j+1] = Gray;
            pBmpdata[i * bytesPerLine + j+2] = Gray;
            
        }
    }
    
    
    
    //处理内存数据
    int sum = 0;

    for (int i = 4; i < bfHeight-4; i++) //高度是反的
    {
        for (int j = 12; j < bytesPerLine-12; j += 3)  //宽度 转换为 行(列数) 
        {
            B = pBmpdata2[i * bytesPerLine + j];
            G = pBmpdata2[i * bytesPerLine + j + 1];
            R = pBmpdata2[i * bytesPerLine + j + 2];

            Gray = (R * 19595 + G * 38469 + B * 7472) >> 16;


            sum = 0;
            for (int m = i-4; m < i+4; m++)
            {
                for (int n = j - 4; n < j + 4; n++)   //2022-7-28 这里有个错误,X轴是3个字节,所以是+-12,步长3, 改正后效果会好一些
                {                                        
                    sum += pBmpdata[m * bytesPerLine + n];
                }
            }
            door = (int)(sum *1.23/ 81);

            if (Gray > door) Gray = 255;
            else  Gray = 0;

            pBmpdata2[i * bytesPerLine + j] = Gray;
            pBmpdata2[i * bytesPerLine + j + 1] = Gray;
            pBmpdata2[i * bytesPerLine + j + 2] = Gray;

        }
    }

    

    
    //pDoc->UpdateAllViews(NULL);
    ShowBMP(pData2, DataLen);
    
    delete pData;

}

 

posted @ 2022-07-26 18:49  XGZ21  阅读(65)  评论(0编辑  收藏  举报