Jump to content

Change background color on bitmap


Recommended Posts

I am using a OCR to capture text and numbers (tesseract). Well since the background disturb a good result I would like to change

the background in the picture.

I took a look around and found that script interesting for me: http://www.autoitscript.com/forum/index.ph...ap+color+change.

I modificated a bit but somehow the background keeps only black or white, whatever I do, I cant create a "blue" background for example.

The idea is that the font has always the same color, so I change all pixel that not accords to the font color in black or white or blue, w.e.. so I get a very nice background color for the OCR programm.

I had some success with white fonts, but with a kind of red font failed total.

CODE

#include-once

#Include <Array.au3>

#Include <File.au3>

#include <GDIPlus.au3>

#include <ScreenCapture.au3>

#include <WinAPI.au3>

#include <ScrollBarConstants.au3>

#include <WindowsConstants.au3>

#Include <GuiComboBox.au3>

#Include <GuiListBox.au3>

#include <GuiConstants.au3>

#EndRegion Header

#Region Global Variables and Constants

Global $last_capture

Global $tesseract_temp_path = "C:\"

#EndRegion Global Variables and Constants

#Region Core functions

; #FUNCTION# ;===============================================================================

;

; Name...........: _TesseractTempPathSet()

; Description ...: Sets the location where Tesseract functions temporary store their files.

; You must have read and write access to this location.

; The default location is "C:\".

; Syntax.........: _TesseractTempPathSet($temp_path)

; Parameters ....: $temp_path - The path to use for temporary file storage.

; This path must not contain any spaces (see "Remarks" below).

; Return values .: On Success - Returns 1.

; On Failure - Returns 0.

; Author ........: seangriffin

; Modified.......:

; Remarks .......: The current version of Tesseract doesn't support paths with spaces.

; Related .......:

; Link ..........:

; Example .......: No

;

; ;==========================================================================================

func _TesseractTempPathSet($temp_path)

$tesseract_temp_path = $temp_path

Return 1

EndFunc

; #FUNCTION# ;===============================================================================

;

; Name...........: _TesseractScreenCapture()

; Description ...: Captures text from the screen.

; Syntax.........: _TesseractScreenCapture($get_last_capture = 0, $delimiter = "", $cleanup = 1, $scale = 2, $left_indent = 0, $top_indent = 0, $right_indent = 0, $bottom_indent = 0, $show_capture = 0)

; Parameters ....: $get_last_capture - Retrieve the text of the last capture, rather than

; performing another capture. Useful if the text in

; the window or control hasn't changed since the last capture.

; 0 = do not retrieve the last capture (default)

; 1 = retrieve the last capture

; $delimiter - Optional: The string that delimits elements in the text.

; A string of text will be returned if this isn't provided.

; An array of delimited text will be returned if this is provided.

; Eg. Use @CRLF to return the items of a listbox as an array.

; $cleanup - Optional: Remove invalid text recognised

; 0 = do not remove invalid text

; 1 = remove invalid text (default)

; $scale - Optional: The scaling factor of the screenshot prior to text recognition.

; Increase this number to improve accuracy.

; The default is 2.

; $iLeft - x-Left coordinate

; $iTop - y-Top coordinate

; $iRight - x-Right coordinate

; $iBottom - y-Bottom coordinate

; $show_capture - Display screenshot and text captures

; (for debugging purposes).

; 0 = do not display the screenshot taken (default)

; 1 = display the screenshot taken and exit

; Return values .: On Success - Returns an array of text that was captured.

; On Failure - Returns an empty array.

; Author ........: seangriffin

; Modified.......:

; Remarks .......: Use the default values for first time use. If the text recognition accuracy is low,

; I suggest setting $show_capture to 1 and rerunning. If the screenshot of the

; window or control includes borders or erroneous pixels that may interfere with

; the text recognition process, then use $left_indent, $top_indent, $right_indent and

; $bottom_indent to adjust the portion of the screen being captured, to

; exclude these non-textural elements.

; If text accuracy is still low, increase the $scale parameter. In general, the higher

; the scale the clearer the font and the more accurate the text recognition.

; Related .......:

; Link ..........:

; Example .......: No

;

; ;==========================================================================================

func _TesseractScreenCapture($get_last_capture = 0, $delimiter = "", $cleanup = 1, $scale = 2, $iLeft = 0, $iTop = 0, $iRight = 1, $iBottom = 1, $show_capture = 0, $BackgroundColor = "", $fontColor = "" )

Local $tInfo

dim $aArray, $final_ocr[1], $xyPos_old = -1, $capture_scale = 3

Local $tSCROLLINFO = DllStructCreate($tagSCROLLINFO)

DllStructSetData($tSCROLLINFO, "cbSize", DllStructGetSize($tSCROLLINFO))

DllStructSetData($tSCROLLINFO, "fMask", $SIF_ALL)

if $last_capture = "" Then

$last_capture = ObjCreate("Scripting.Dictionary")

EndIf

; if last capture is requested, and one exists.

if $get_last_capture = 1 and $last_capture.item(0) <> "" Then

return $last_capture.item(0)

EndIf

$capture_filename = _TempFile($tesseract_temp_path, "~", ".tif")

$ocr_filename = StringLeft($capture_filename, StringLen($capture_filename) - 4)

$ocr_filename_and_ext = $ocr_filename & ".txt"

CaptureToTIFF("", "", "", $capture_filename, $scale, $iLeft , $iTop , $iRight , $iBottom, $BackgroundColor, $fontColor)

ShellExecuteWait(@ProgramFilesDir & "\tesseract\tesseract.exe", $capture_filename & " " & $ocr_filename)

; If no delimter specified, then return a string

if StringCompare($delimiter, "") = 0 Then

$final_ocr = FileRead($ocr_filename_and_ext)

Else

_FileReadToArray($ocr_filename_and_ext, $aArray)

_ArrayDelete($aArray, 0)

; Append the recognised text to a final array

_ArrayConcatenate($final_ocr, $aArray)

EndIf

; If the captures are to be displayed

if $show_capture = 1 Then

GUICreate("Tesseract Screen Capture. Note: image displayed is not to scale", 640, 480, 0, 0, $WS_SIZEBOX + $WS_SYSMENU) ; will create a dialog box that when displayed is centered

GUISetBkColor(0xE0FFFF)

$Obj1 = ObjCreate("Preview.Preview.1")

$Obj1_ctrl = GUICtrlCreateObj($Obj1, 0, 0, 640, 480)

$Obj1.ShowFile ($capture_filename, 1)

GUISetState()

if IsArray($final_ocr) Then

_ArrayDisplay($aArray, "Tesseract Text Capture")

Else

MsgBox(0, "Tesseract Text Capture", $final_ocr)

EndIf

GUIDelete()

EndIf

FileDelete($ocr_filename & ".*")

; Cleanup

if IsArray($final_ocr) And $cleanup = 1 Then

; Cleanup the items

for $final_ocr_num = 1 to (UBound($final_ocr)-1)

; Remove erroneous characters

$final_ocr[$final_ocr_num] = StringReplace($final_ocr[$final_ocr_num], ".", "")

$final_ocr[$final_ocr_num] = StringReplace($final_ocr[$final_ocr_num], "'", "")

$final_ocr[$final_ocr_num] = StringReplace($final_ocr[$final_ocr_num], ",", "")

$final_ocr[$final_ocr_num] = StringStripWS($final_ocr[$final_ocr_num], 3)

Next

; Remove duplicate and blank items

for $each in $final_ocr

$found_item = _ArrayFindAll($final_ocr, $each)

; Remove blank items

if IsArray($found_item) Then

if StringCompare($final_ocr[$found_item[0]], "") = 0 Then

_ArrayDelete($final_ocr, $found_item[0])

EndIf

EndIf

; Remove duplicate items

for $found_item_num = 2 to UBound($found_item)

_ArrayDelete($final_ocr, $found_item[$found_item_num-1])

Next

Next

EndIf

; Store a copy of the capture

if $last_capture.item(0) = "" Then

$last_capture.item(0) = $final_ocr

EndIf

Return $final_ocr

EndFunc

; #FUNCTION# ;===============================================================================

;

; Name...........: CaptureToTIFF()

; Description ...: Captures an image of the screen, a window or a control, and saves it to a TIFF file.

; Syntax.........: CaptureToTIFF($win_title = "", $win_text = "", $ctrl_id = "", $sOutImage = "", $scale = 1, $left_indent = 0, $top_indent = 0, $right_indent = 0, $bottom_indent = 0)

; Parameters ....: $win_title - The title of the window to capture an image of.

; $win_text - Optional: The text of the window to capture an image of.

; $ctrl_id - Optional: The ID of the control to capture an image of.

; An image of the window will be returned if one isn't provided.

; $sOutImage - The filename to store the image in.

; $scale - Optional: The scaling factor of the capture.

; $iLeft - x-Left coordinate

; $iTop - y-Top coordinate

; $iRight - x-Right coordinate

; $iBottom - y-Bottom coordinate

; $bottom_indent - A number of pixels to indent the screen capture from the

; bottom of the window or control.

; Return values .: None

; Author ........: seangriffin

; Modified.......:

; Remarks .......:

; Related .......:

; Link ..........:

; Example .......: No

;

; ;==========================================================================================

Func CaptureToTIFF($win_title = "", $win_text = "", $ctrl_id = "", $sOutImage = "", $scale = 1, $iLeft = 0, $iTop = 0, $iRight = 1, $iBottom = 1, $BackgroundColor = "", $fontColor = "" )

Local $hWnd, $hwnd2, $hDC, $hBMP, $hImage1, $hGraphic, $CLSID, $tParams, $pParams, $tData, $i = 0, $hImage2, $pos[4]

Local $Ext = StringUpper(StringMid($sOutImage, StringInStr($sOutImage, ".", 0, -1) + 1))

Local $giTIFColorDepth = 24

Local $giTIFCompression = $GDIP_EVTCOMPRESSIONNONE

; If capturing a control

if StringCompare($ctrl_id, "") <> 0 Then

$hwnd2 = ControlGetHandle($win_title, $win_text, $ctrl_id)

$pos[0] = 0

$pos[1] = 0

$pos[2] = $iRight - $iLeft

$pos[3] = $iBottom - $iTop

Else

; If capturing a window

if StringCompare($win_title, "") <> 0 Then

$hwnd2 = WinGetHandle($win_title, $win_text)

$pos[0] = 0

$pos[1] = 0

$pos[2] = $iRight - $iLeft

$pos[3] = $iBottom - $iTop

Else

; If capturing the desktop

$hwnd2 = ""

$pos[0] = 0

$pos[1] = 0

$pos[2] = $iRight - $iLeft

$pos[3] = $iBottom - $iTop

EndIf

EndIf

; Capture an image of the window / control

if IsHWnd($hwnd2) Then

WinActivate($win_title, $win_text)

$hBitmap2 = _ScreenCapture_CaptureWnd("", $hwnd2, $iLeft, $iTop, $iRight, $iBottom, False)

Else

$hBitmap2 = _ScreenCapture_Capture("", $iLeft, $iTop, $iRight, $iBottom, False)

EndIf

_GDIPlus_Startup ()

; Convert the image to a bitmap

$hImage2 = _GDIPlus_BitmapCreateFromHBITMAP ($hBitmap2)

if StringCompare($BackgroundColor, "") <> 0 And StringCompare($fontColor, "") <> 0 Then

$hImage2 = ChangeColors($hImage2, 0, 0, $iRight - $iLeft, $iBottom - $iTop, $BackgroundColor, $fontColor)

EndIf

$hWnd = _WinAPI_GetDesktopWindow()

$hDC = _WinAPI_GetDC($hWnd)

$hBMP = _WinAPI_CreateCompatibleBitmap($hDC, $pos[2] * $scale , $pos[3] * $scale)

_WinAPI_ReleaseDC($hWnd, $hDC)

$hImage1 = _GDIPlus_BitmapCreateFromHBITMAP ($hBMP)

$hGraphic = _GDIPlus_ImageGetGraphicsContext($hImage1)

_GDIPLus_GraphicsDrawImageRect($hGraphic, $hImage2, 0 , 0 , $pos[2] * $scale, $pos[3] * $scale)

$CLSID = _GDIPlus_EncodersGetCLSID($Ext)

; Set TIFF parameters

$tParams = _GDIPlus_ParamInit(2)

$tData = DllStructCreate("int ColorDepth;int Compression")

DllStructSetData($tData, "ColorDepth", $giTIFColorDepth)

DllStructSetData($tData, "Compression", $giTIFCompression)

_GDIPlus_ParamAdd($tParams, $GDIP_EPGCOLORDEPTH, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "ColorDepth"))

_GDIPlus_ParamAdd($tParams, $GDIP_EPGCOMPRESSION, 1, $GDIP_EPTLONG, DllStructGetPtr($tData, "Compression"))

If IsDllStruct($tParams) Then $pParams = DllStructGetPtr($tParams)

; Save TIFF and cleanup

_GDIPlus_ImageSaveToFileEx($hImage1, $sOutImage, $CLSID, $pParams)

_GDIPlus_ImageDispose($hImage1)

_GDIPlus_ImageDispose($hImage2)

_GDIPlus_GraphicsDispose ($hGraphic)

_WinAPI_DeleteObject($hBMP)

_GDIPlus_Shutdown()

EndFunc

;--- Change Background Color

Func ChangeColors($hImage2, $iStartPosX = 0, $iStartPosY = 0, $GuiSizeX = Default, $GuiSizeY = Default, $iColor1 = Default, $iColor2 = Default)

Local $hBitmap1, $Reslt, $width, $height, $stride, $format, $Scan0, $v_Buffer, $v_Value, $iIW, $iIH

$iIW = _GDIPlus_ImageGetWidth($hImage2)

$iIH = _GDIPlus_ImageGetHeight($hImage2)

If $GuiSizeX = Default Or $GuiSizeX > $iIW - $iStartPosX Then $GuiSizeX = $iIW - $iStartPosX

If $GuiSizeY = Default Or $GuiSizeY > $iIH - $iStartPosY Then $GuiSizeY = $iIH - $iStartPosY

$hBitmap1 = _GDIPlus_BitmapCloneArea($hImage2, $iStartPosX, $iStartPosY, $GuiSizeX, $GuiSizeY, $GDIP_PXF32ARGB)

ProgressOn("Making a color Transparent", "The image is being processed.", "0 percent", -1, -1, 16)

$Reslt = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $GuiSizeX, $GuiSizeY, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)

;Get the returned values of _GDIPlus_BitmapLockBits ()

$width = DllStructGetData($Reslt, "width")

$height = DllStructGetData($Reslt, "height")

$stride = DllStructGetData($Reslt, "stride")

$format = DllStructGetData($Reslt, "format")

$Scan0 = DllStructGetData($Reslt, "Scan0")

For $i = 0 To $GuiSizeX - 1

For $j = 0 To $GuiSizeY - 1

$v_Buffer = DllStructCreate("dword", $Scan0 + ($j * $stride) + ($i * 4))

$v_Value = DllStructGetData($v_Buffer, 1)

If (Hex($v_Value, 6) = Hex($iColor2, 6)) Then ; font color

Else

DllStructSetData($v_Buffer, 1, Hex($iColor1, 6)) ; Sets to $BackgroundColor

EndIf

Next

ProgressSet(Int(100 * $i / ($GuiSizeX)), Int(100 * $i / ($GuiSizeX)) & " percent")

Next

_GDIPlus_BitmapUnlockBits($hBitmap1, $Reslt)

ProgressOff()

Return $hBitmap1

EndFunc ;==>OtherColorsToWhite

The Function ChangeColors is my modificated function from the link above (OtherColorsToWhite, it works fine on original script).

The only time that the function ChangeColors is used is on the function CaptureToTIFF

if StringCompare($BackgroundColor, "") <> 0 And StringCompare($fontColor, "") <> 0 Then

$hImage2 = ChangeColors($hImage2, 0, 0, $iRight - $iLeft, $iBottom - $iTop, $BackgroundColor, $fontColor)

EndIf

My goal is to change the background color to any color I want with any font color (red/yellow/blue,etc..)

like:

#include <SimpleTesseract.au3>

$test = _TesseractScreenCapture(0,"",1,2,322,593,420,616,1,16751103,13434828);pink background, font is light green

MsgBox(1, "Test:", $test)

The first blue picture is before editing with script. Tesseract couldnt scan the numbers very well, so I need to change background

post-33507-1241277486_thumb.jpg

post-33507-1241277520_thumb.jpg

SimpleTesseract.au3

Edited by hendrikhe
Link to comment
Share on other sites

  • Moderators

hendrikhe,

I have been playing with Malkey's code and have developed a function to change a .bmp into black and white. The function looks at each pixel and then sets it to black or white depending on the luminosity - this is determined by factoring the RGB components: Luminosity = (Red * 0.3) + (Green * 0.59) + (Blue * 0.11) (the constants are industry standard values according to Google!). The default setting is 127, but this will not work if the background is light (as in your blue/white "150"). So you can alter the luminosity value if the default result is not good enough - I found a value of 185 gave pretty good results on your image.

Have a look and see what you think:

#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <GuiConstantsEx.au3>
#include <WindowsConstants.au3>
#Include <Color.au3>

_GDIPlus_Startup()
$hImage = _GDIPlus_ImageLoadFromFile(@ScriptDir & "\150.bmp");<-- Enter Image file here

If @error Then
    MsgBox(0,"","File not loaded")
    Exit
EndIf

Global $GuiSizeX = _GDIPlus_ImageGetWidth($hImage)
Global $GuiSizeY = _GDIPlus_ImageGetHeight($hImage)

$hGui = GUICreate("Change Colours", $GuiSizeX, $GuiSizeY, 100, 100)
GUISetState()

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
$hGraphicGUI = _GDIPlus_GraphicsCreateFromHWND($hGui)
$hBMPBuff = _GDIPlus_BitmapCreateFromGraphics($GuiSizeX, $GuiSizeY, $hGraphicGUI)
$hGraphic = _GDIPlus_ImageGetGraphicsContext($hBMPBuff)
;End Double Buffer add-in 1 of 3

_GDIPlus_GraphicsDrawImageRect($hGraphic, $hImage, 0, 0, $GuiSizeX, $GuiSizeY)

; Create Double Buffer, so the doesn't need to be repainted on PAINT-Event
GUIRegisterMsg(0xF, "MY_PAINT"); Register PAINT-Event 0x000F = $WM_PAINT (WindowsConstants.au3)
GUIRegisterMsg(0x85, "MY_PAINT"); $WM_NCPAINT = 0x0085 (WindowsConstants.au3)Restore after Minimize.
_GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
;End Double Buffer add-in 2 of 3

Local $hBitmap = Image_BandW($hBMPBuff, 0, 0, $GuiSizeX, $GuiSizeY, 185) ; <<<<<<<<<<<<<<<<<<< The luminosity value is set here - default is 127

If _GDIPlus_ImageSaveToFile($hBitmap, @ScriptDir & "\TestWrite1.bmp") =  True Then; Transparency file
    ShellExecute(@ScriptDir & "\TestWrite1.bmp")
Else
    MsgBox(0,"","File not created")
EndIf

WinActivate($hGui)

While 1
    $msg = GUIGetMsg()
    Switch $msg
        Case $GUI_EVENT_CLOSE
            close()
    EndSwitch
WEnd

;Func to redraw on PAINT MSG
Func MY_PAINT($hWnd, $msg, $wParam, $lParam)
    ; Check, if the GUI with the Graphic should be repainted
    ; The sequencial order of these two commands is important.
    _GDIPlus_GraphicsDrawImage($hGraphicGUI, $hBMPBuff, 0, 0)
    _WinAPI_RedrawWindow($hGui, "", "", BitOR($RDW_INVALIDATE, $RDW_UPDATENOW, $RDW_FRAME)); , $RDW_ALLCHILDREN
    Return $GUI_RUNDEFMSG
EndFunc  ;==>MY_PAINT

Func close()
    _GDIPlus_GraphicsDispose($hGraphic)
    _GDIPlus_Shutdown()
    Exit
EndFunc  ;==>close


Func Image_BandW($hImage2, $iStartPosX = 0, $iStartPosY = 0, $GuiSizeX = Default, $GuiSizeY = Default, $iLumin = 127)
    Local $hBitmap1, $Reslt, $width, $height, $stride, $format, $Scan0, $v_Buffer, $v_Value, $iIW, $iIH
    $iIW = _GDIPlus_ImageGetWidth($hImage2)
    $iIH = _GDIPlus_ImageGetHeight($hImage2)
    If $GuiSizeX = Default Or $GuiSizeX > $iIW - $iStartPosX Then $GuiSizeX = $iIW - $iStartPosX
    If $GuiSizeY = Default Or $GuiSizeY > $iIH - $iStartPosY Then $GuiSizeY = $iIH - $iStartPosY
    $hBitmap1 = _GDIPlus_BitmapCloneArea($hImage2, $iStartPosX, $iStartPosY, $GuiSizeX, $GuiSizeY, $GDIP_PXF32ARGB)
    
    ProgressOn("Making a color Transparent", "The image is being processed.", "0 percent", -1, -1, 16)

    $Reslt = _GDIPlus_BitmapLockBits($hBitmap1, 0, 0, $GuiSizeX, $GuiSizeY, BitOR($GDIP_ILMREAD, $GDIP_ILMWRITE), $GDIP_PXF32ARGB)
    
    ;Get the returned values of _GDIPlus_BitmapLockBits ()
    $width = DllStructGetData($Reslt, "width")
    $height = DllStructGetData($Reslt, "height")
    $stride = DllStructGetData($Reslt, "stride")
    $format = DllStructGetData($Reslt, "format")
    $Scan0 = DllStructGetData($Reslt, "Scan0")
    For $i = 0 To $GuiSizeX - 1
        For $j = 0 To $GuiSizeY - 1
            $v_Buffer = DllStructCreate("dword", $Scan0 + ($j * $stride) + ($i * 4))
            $v_Value = DllStructGetData($v_Buffer, 1)
            
            Local $nLumin = (_ColorGetRed($v_Value) * 0.3) + (_ColorGetGreen($v_Value) * 0.59) + (_ColorGetBlue($v_Value) * 0.11)
            If $nLumin > $iLumin Then
                DllStructSetData($v_Buffer, 1, 0xFFFFFFFF); Sets to white
            Else
                DllStructSetData($v_Buffer, 1, 0xFF000000); Sets to black
            EndIf
            
        Next
        ProgressSet(Int(100 * $i / ($GuiSizeX)), Int(100 * $i / ($GuiSizeX)) & " percent")
        Next
    _GDIPlus_BitmapUnlockBits($hBitmap1, $Reslt)
    ProgressOff()
    Return $hBitmap1
EndFunc  ;==>Image_BandW

The file I used (150.bmp) was your uploaded blue/white .jpg changed to a 24-bit .bmp in Paint.

M23

Public_Domain.png.2d871819fcb9957cf44f4514551a2935.png Any of my own code posted anywhere on the forum is available for use by others without any restriction of any kind

Open spoiler to see my UDFs:

Spoiler

ArrayMultiColSort ---- Sort arrays on multiple columns
ChooseFileFolder ---- Single and multiple selections from specified path treeview listing
Date_Time_Convert -- Easily convert date/time formats, including the language used
ExtMsgBox --------- A highly customisable replacement for MsgBox
GUIExtender -------- Extend and retract multiple sections within a GUI
GUIFrame ---------- Subdivide GUIs into many adjustable frames
GUIListViewEx ------- Insert, delete, move, drag, sort, edit and colour ListView items
GUITreeViewEx ------ Check/clear parent and child checkboxes in a TreeView
Marquee ----------- Scrolling tickertape GUIs
NoFocusLines ------- Remove the dotted focus lines from buttons, sliders, radios and checkboxes
Notify ------------- Small notifications on the edge of the display
Scrollbars ----------Automatically sized scrollbars with a single command
StringSize ---------- Automatically size controls to fit text
Toast -------------- Small GUIs which pop out of the notification area

 

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...