ToGrayscale() : Converts GDI bitmap to Greyscale

Post your working scripts, libraries and tools
User avatar
SKAN
Posts: 807
Joined: 29 Sep 2013, 16:58

ToGrayscale() : Converts GDI bitmap to Greyscale

18 Sep 2020, 16:50

  • Screen shot of demo
    ToGrayscale.PNG
    ToGrayscale.PNG (74.63 KiB) Viewed 409 times
     

    The function: Along with a demo

    Code: Select all

    ToGrayscale(sBM) {                            ; By SKAN on CR7J/D39L @ tiny.cc/tograyscale
      Local  ; Original ver. GDI_GrayscaleBitmap() @ https://autohotkey.com/board/topic/82794-
    
      P8:=(A_PtrSize=8),  VarSetCapacity(BM,P8? 32:24, 0)
      DllCall("GetObject", "Ptr",sBM, "Int",P8? 32:24, "Ptr",&BM)
      W := NumGet(BM,4,"Int"), H := NumGet(BM,8,"Int")
      sDC := DllCall( "CreateCompatibleDC", "Ptr",0, "Ptr")
    
      DllCall("DeleteObject", "Ptr",DllCall("SelectObject", "Ptr",sDC, "Ptr",sBM, "Ptr"))
    
      tBM := DllCall( "CopyImage", "Ptr"
           , DllCall( "CreateBitmap", "Int",1, "Int",1, "Int",0x1, "Int",8, "Ptr",0, "Ptr")
           , "Int",0, "Int",W, "Int",H, "Int",0x2008, "Ptr")
    
      tDC := DllCall("CreateCompatibleDC", "Ptr",0, "Ptr")
      DllCall("DeleteObject", "Ptr",DllCall("SelectObject", "Ptr",tDC, "Ptr",tBM, "Ptr"))
    
      Loop % (255, n:=0x000000, VarSetCapacity(RGBQUAD256,256*4,0))
            Numput(n+=0x010101, RGBQUAD256, A_Index*4, "Int")
      DllCall("SetDIBColorTable", "Ptr",tDC, "Int",0, "Int",256, "Ptr",&RGBQUAD256)
    
      DllCall("BitBlt",   "Ptr",tDC, "Int",0, "Int",0, "Int",W, "Int",H
                        , "Ptr",sDC, "Int",0, "Int",0, "Int",0x00CC0020)
    
    Return % (tBM, DllCall("DeleteDC", "Ptr",sDC), DllCall("DeleteDC", "Ptr",tDC))
    }
    ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
    ; Demo follows
    
    #NoEnv
    #SingleInstance, Force
    SetWorkingDir, %A_ScriptDir%
    
    If !FileExist("bluebottlefly.jpg")
       URLDownloadToFile, https://www.autohotkey.com/boards/download/file.php?id=10624
                        , bluebottlefly.jpg
    
    hBM1 := LoadPicture("bluebottlefly.jpg")
    hBM2 := ToGrayscale(hBM1)
    Gui, Margin, 24, 24
    Gui, Add, Picture,,    HBITMAP:%hBM1%
    Gui, Add, Picture,x+m, HBITMAP:%hBM2%
    Gui, Show,, ToGrayscale()
    Return
    
 
 
FsGrayscale()
 
 
iseahound
Posts: 612
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

19 Sep 2020, 08:23

Wow. Are the calculations from RGB to Greyscale done by windows itself? I know that RGB channels have different color weights, but I'm not seeing how that is accounted for in the code. (Although your sample looks very good.)

Code: Select all

      ; Returns a value between 0-255 when given an RGB value. 
      grayscale(sRGB) {
         static rY := 0.212655
         static gY := 0.715158
         static bY := 0.072187

         c1 := 255 & ( sRGB >> 16 )
         c2 := 255 & ( sRGB >> 8 )
         c3 := 255 & ( sRGB )

         loop 3 {
            c%A_Index% := c%A_Index% / 255
            c%A_Index% := (c%A_Index% <= 0.04045) ? c%A_Index%/12.92 : ((c%A_Index%+0.055)/(1.055))**2.4
         }

         v := rY*c1 + gY*c2 + bY*c3
         v := (v <= 0.0031308) ? v * 12.92 : 1.055*(v**(1.0/2.4))-0.055
         return Round(v*255)
      }
User avatar
SKAN
Posts: 807
Joined: 29 Sep 2013, 16:58

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

19 Sep 2020, 08:58

iseahound wrote:Wow. Are the calculations from RGB to Greyscale done by windows itself?
Yes. Windows uses Nearest match method.
The magic is here:
 

Code: Select all

  Loop % (255, n:=0x000000, VarSetCapacity(RGBQUAD256,256*4,0))
        Numput(n+=0x010101, RGBQUAD256, A_Index*4, "Int")
  DllCall("SetDIBColorTable", "Ptr",tDC, "Int",0, "Int",256, "Ptr",&RGBQUAD256)
 
I create a 256 color table with 256 shades of gray and windows matches nearest color in the table,
probably based on luminosity.
 
Try replacing n+=0x010101 with n+=0x000101 and you will see a Cyan-scaled image instead of GrayScale.
I conceived/devised this method. :)

:thumbup:
User avatar
SKAN
Posts: 807
Joined: 29 Sep 2013, 16:58

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

19 Sep 2020, 17:49

iseahound wrote: (Although your sample looks very good.)
I had never compared the results with an another program.
I did today. Thanks. I saved hBitmap with GDIP [ SavePicture() ]
 
  • Adobe Photoshop 2020
    photoshop.png
    photoshop.png (99.64 KiB) Viewed 300 times
     
  • ToGrayscale
    tograyscale.png
    tograyscale.png (77.11 KiB) Viewed 300 times
     
  • Original / source
    Image
     
blue83
Posts: 125
Joined: 11 Apr 2018, 06:38

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

20 Sep 2020, 00:45

Hi @SKAN ,

Great and useful function.

One question, can we use this script to convert image in black and white using treshold like in python?

And maybe take one picture and create image augumentation to make few images from one image for use in training object detection.

Thanks,
blue
User avatar
SKAN
Posts: 807
Joined: 29 Sep 2013, 16:58

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

20 Sep 2020, 05:14

blue83 wrote: Great and useful function.
 
Thank you :)
 
blue83 wrote: can we use this script to convert image in black and white using treshold like in python?
 
No built-in method in GDI for it. The returned hBitmap has DIB section. We may get a pointer to the bits and do the conversion manually,
which is usually best done with machine code.
 
blue83 wrote: And maybe take one picture and create image augumentation to make few images from one image for use in training object detection.
 
Its above my skillset. I had to Bing to get the faintest idea on what you're talking about. :(


:thumbup: :)
blue83
Posts: 125
Joined: 11 Apr 2018, 06:38

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

20 Sep 2020, 05:27

Haha, thank you anyway :)

Most OCR works better with grayscale image so this is great function.

Thanks,
blue
burque505
Posts: 1372
Joined: 22 Jan 2017, 19:37

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

20 Sep 2020, 15:01

@SKAN, thanks for another great addition. I don't think anyone else has such an arsenal of small but very useful scripts.
By the way, for me on both Win10 and Win7, AHK 1.1.33.02, it works great with 32-bit, but for 64-bit only the first image appears.

32-bit:
grayscale2.PNG
grayscale2.PNG (95.1 KiB) Viewed 227 times
64-bit:
grayscale1.PNG
grayscale1.PNG (83.3 KiB) Viewed 227 times
Regards,
burque505
User avatar
SKAN
Posts: 807
Joined: 29 Sep 2013, 16:58

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

20 Sep 2020, 15:22

burque505 wrote: @SKAN, thanks for another great addition. I don't think anyone else has such an arsenal of small but very useful scripts.
 
Thanks :)
 
burque505 wrote: By the way, for me on both Win10 and Win7, AHK 1.1.33.02, it works great with 32-bit, but for 64-bit only the first image appears.
 
Thanks for the report. Fixed.
gwarble
Posts: 458
Joined: 30 Sep 2013, 15:01

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

20 Sep 2020, 15:38

thanks, very useful and clever solution!
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .
User avatar
SKAN
Posts: 807
Joined: 29 Sep 2013, 16:58

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

21 Sep 2020, 06:03

blue83 wrote: can we use this script to convert image in black and white using treshold like in python?
blue83 also wrote: 
Most OCR works better with grayscale image so this is great function.
 
Oh! OCR.
It seems simple to add threshold parameter to this function.
But I'm not familiar with python. Do you have a link/screenshot to show how threshold affect the original image
blue83
Posts: 125
Joined: 11 Apr 2018, 06:38

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

21 Sep 2020, 07:18

Hi @SKAN ,

Here it is.

https://techtutorialsx.com/2019/04/13/python-opencv-converting-image-to-black-and-white/

Also if there is anything to change image brightness?

Thanks,
blue
User avatar
SKAN
Posts: 807
Joined: 29 Sep 2013, 16:58

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

21 Sep 2020, 08:00

@blue83 Thanks for the link. I will look into it.
iseahound
Posts: 612
Joined: 13 Aug 2016, 21:04
GitHub: iseahound

Re: ToGrayscale() : Converts GDI bitmap to Greyscale

21 Sep 2020, 13:31

You're right about the nearest neighbor. I didn't notice at first, but it doesn't seem to be true greyscale. I can see topological rings of grey in the blurred background of the butterfly picture that aren't present in the photoshop equivalent. You could randomize noise and dither the photo to prevent such occurrences, but I think the converting each channel independently and then forming a weighed average has a better visual perception to greyscale.

My greyscale function only converts a single pixel :(

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Chiefkes, Google [Bot] and 38 guests