Jump to content

Need help transforming colors in a bitmap with GDI+


Go to solution Solved by MeteorTheLizard,

Recommended Posts

Recently I've started to work with Tesseract OCR. It is working great so far, however I wanted to improve the results even further by optimizing the colors of the image.

Right now I'm capturing a screenshot and then convert it into a bitmap which is then cloned with 8 bit colors. The cloned bitmap is then inverted and then up-scaled and then saved.

The results are sub-optimal as the text I want to extract has different colors while the background is always gray/black. Ideally, I want everything that isn't the background to be black while the background is always white in the final product. That way, all text is black and the background is white which provides perfect conditions for Tesseract.

 

The problem I have is that I have no idea how I would transform all colors that aren't gray/black to black and all colors that are gray/black to white.

Any help is greatly appreciated.

 

This is the code I'm using:

Local $hIA = _GDIPlus_ImageAttributesCreate() ;- Create matrix attributes and apply negative colors
    Local $tColorMatrix = _GDIPlus_ColorMatrixCreateNegative()
        _GDIPlus_ImageAttributesSetColorMatrix($hIA,0,True,$tColorMatrix)


    Local $hHBmp = _ScreenCapture_CaptureWnd($sEmpty,$WinHandle,$PosX + 4,$PosY + ($TitleBarHeight/2) + 101,$PosX + $I_SystemBoxX - 20,$PosY + $I_SystemBoxY + ($TitleBarHeight/2) - 15)
        Local $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp) ;- Capture the image and transform it into a GDI+ bitmap
            Local $hBitmap_Size = _GDIPlus_ImageGetDimension($hBitmap)


    Local $hClone = _GDIPlus_BitmapCloneArea($hBitmap,0,0,$hBitmap_Size[0],$hBitmap_Size[1],$GDIP_PXF08INDEXED) ;- Grayscale
        _WinAPI_DeleteObject($hHBmp) ;- Convert the colors to 8 Bit
        _GDIPlus_BitmapDispose($hBitmap)


    Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hClone)
        _GDIPlus_GraphicsDrawImageRectRect($hGraphics,$hClone,0,0,$hBitmap_Size[0],$hBitmap_Size[1],0,0,$hBitmap_Size[0],$hBitmap_Size[1],$hIA)
            _GDIPlus_ImageAttributesDispose($hIA) ;- Create inverted image


    Local $hBitmap_Scaled = _GDIPlus_ImageScale($hClone,$UpscaleRate,$UpscaleRate,$GDIP_INTERPOLATIONMODE_NEARESTNEIGHBOR)
        _GDIPlus_ImageDispose($hClone) ;- Up-scale the image


    _GDIPlus_ImageSaveToFile($hBitmap_Scaled,$TempScreenshotPath)
        _GDIPlus_BitmapDispose($hBitmap_Scaled) ;- Save the image
        _GDIPlus_GraphicsDispose($hGraphics)

 

Link to post
Share on other sites
  • Solution

After some more fiddling, I managed to solve this problem using _GDIPlus_ImageAttributesSetRemapTable and simply replacing the colors. This is the most effective method for my use case and works perfectly. The OCR can read any text I throw at it now with perfect accuracy. (Which is pretty impressive ngl)

Link to post
Share on other sites
Link to post
Share on other sites
2 hours ago, Nine said:

Mind sharing your final script.  I am sure someone will benefit from the example in the future...

;-----------------------------------------
;- THIS IS PSEUDO CODE AND WILL NOT FUNCTION BY ITSELF.

Global $sEmpty = ""

;-----------------------------------------

Global $RemapTable[2][2] ;- (Replace specific colors)
    $RemapTable[0][0] = 1 ;- Number of replacement colors

    ;- Example Color
    $RemapTable[1][0] = 0xFFB2BEFF ;- Old color
    $RemapTable[1][1] = 0xFFFFFFFF ;- Replacement
    
;-----------------------------------------

Local $hIA = _GDIPlus_ImageAttributesCreate()
    _GDIPlus_ImageAttributesSetRemapTable($hIA,$RemapTable) ;- Replace specific colors


Local $tColorMatrix = _GDIPlus_ColorMatrixCreateNegative() ;- Invert colors
    _GDIPlus_ImageAttributesSetColorMatrix($hIA,0,True,$tColorMatrix)


Local $hHBmp = _ScreenCapture_CaptureWnd($sEmpty,$WinHandle,$PosX + 4,$PosY + ($TitleBarHeight/2) + 101,$PosX + $I_SystemBoxX - 20,$PosY + $I_SystemBoxY + ($TitleBarHeight/2) - 15)
    Local $hBitmap = _GDIPlus_BitmapCreateFromHBITMAP($hHBmp) ;- Capture the image and transform it into a GDI+ bitmap
        Local $hBitmap_Size = _GDIPlus_ImageGetDimension($hBitmap)
            _WinAPI_DeleteObject($hHBmp)



Local $hGraphics = _GDIPlus_ImageGetGraphicsContext($hBitmap)
    _GDIPlus_GraphicsDrawImageRectRect($hGraphics,$hBitmap,0,0,$hBitmap_Size[0],$hBitmap_Size[1],0,0,$hBitmap_Size[0],$hBitmap_Size[1],$hIA)
    _GDIPlus_ImageAttributesDispose($hIA) ;- Apply our image filters


    Global $tPalette = _GDIPlus_PaletteInitialize(256,$GDIP_PaletteTypeOptimal,2,False,$hBitmap)
        $tPalette.ARGB((1)) = 0xFF000000
        $tPalette.ARGB((2)) = 0xFFFFFFFF ;- Convert it to black and white (Removes dithering)

    _GDIPlus_BitmapConvertFormat($hBitmap, $GDIP_PXF04INDEXED, $GDIP_DitherTypeSolid, $GDIP_PaletteTypeOptimal, $tPalette)
        DllCall($__g_hGDIPDll, "int", "GdipSetImagePalette", "handle", $hBitmap, "struct*", $tPalette) ;- Apply it


Local $hBitmap_Scaled = _GDIPlus_ImageScale($hBitmap,$UpscaleRate,$UpscaleRate,$GDIP_INTERPOLATIONMODE_NEARESTNEIGHBOR)
    _GDIPlus_ImageDispose($hBitmap) ;- Up-scale the image


_GDIPlus_ImageSaveToFile($hBitmap_Scaled,$TempScreenshotPath)
    _GDIPlus_BitmapDispose($hBitmap_Scaled) ;- Save the image
    _GDIPlus_GraphicsDispose($hGraphics)

 

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...