Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

PixelGetColor monochrome



  • Please log in to reply
14 replies to this topic
read416
  • Members
  • 33 posts
  • Last active: Oct 24 2015 01:13 AM
  • Joined: 24 Jul 2015

It is possible to get the color of the pixel by standard command, PixelGetColor, but in black-and-white monochrome?



Exaskryz
  • Members
  • 3249 posts
  • Last active: Nov 20 2015 05:30 AM
  • Joined: 23 Aug 2012
✓  Best Answer

I would imagine just doing math on your retrieved color to decide it's luminosity. I have no idea if this is the right way to do it, but... here's my proof of concept. My computer is about to die so I apologize I didn't include comments/explain what each thing does. But I break up the RGB values into hex values, add them (SetFormat allows for that I believe, not 100% sure it's required), and then I get stuff... 8% battery life, gotta go.

 

^8::
SetFormat, IntegerFast, H
PixelGetColor, Pisel, 1500, 10
Blue:="0x" SubStr(Pisel,3,2)
Green:="0x" SubStr(Pisel,5,2)
Red:="0x" SubStr(Pisel,7,2)
;MsgBox % Blue " " Green " " Red
Sum:=Blue+Green+Red
Monochrome:=Sum//3
MonochromeRGB:=Monochrome SubStr(Monochrome,3,2) SubStr(Monochrome,3,2)
MsgBox % Pisel "`n" Monochrome "`n" MonochromeRGB "`n" Sum
Gui, New
Gui, Color, %MonochromeRGB%
Gui, Show, w500 h500
return


read416
  • Members
  • 33 posts
  • Last active: Oct 24 2015 01:13 AM
  • Joined: 24 Jul 2015

Thanks! Hope your Computing Machine recovered soon!

 

And if get Monochrome only in some Variable?

 



Exaskryz
  • Members
  • 3249 posts
  • Last active: Nov 20 2015 05:30 AM
  • Joined: 23 Aug 2012

Computer back up.

 

My best advice would be to turn this into a function so you can easily store the value into a variable.

 

I will assume you will want to get a monochrome value such as 0x515151 and not just a hex value of 0x51. If you need just the two digit hex value (0x51), then you would do return Monochrome.

 

^8::
myVariable:=PixelGetMonochrome(1500,10)
; MsgBox %myVariable%
Gui, New
Gui, Color, %myVariable%
Gui, Show, w500 h500
return
 
PixelGetMonochrome(x,y){
SetFormat, IntegerFast, H
PixelGetColor, Pisel, %x%, %y%
Blue:="0x" SubStr(Pisel,3,2)
Green:="0x" SubStr(Pisel,5,2)
Red:="0x" SubStr(Pisel,7,2)
Sum:=Blue+Green+Red
Monochrome:=Sum//3
MonochromeRGB:=Monochrome SubStr(Monochrome,3,2) SubStr(Monochrome,3,2)
return MonochromeRGB
}


kon
  • Members
  • 1652 posts
  • Last active:
  • Joined: 04 Mar 2013
Just some background info:
RGB to monochrome conversion
Converting color to grayscale

kon
  • Members
  • 1652 posts
  • Last active:
  • Joined: 04 Mar 2013

To separate RGB:

Rgb := 0x010203
R := (Rgb >> 16) & 0xFF
G := (Rgb >> 8) & 0xFF
B := Rgb & 0xFF
MsgBox, % R "`n" G "`n" B


Exaskryz
  • Members
  • 3249 posts
  • Last active: Nov 20 2015 05:30 AM
  • Joined: 23 Aug 2012

Thanks for the links kon.  And also for the reminder on bitshifts existing. I need to try my best to remember those. Much better to do than StrSplit(). Aware of any good bitshift tutorials I can try, AHK-strict or not, so I can get comfortable with it?

 

Playing around with it, I think I see where I'm going wrong. I can't read equations right. Wiki isn't trying to produce a six-digit color code, it's trying to get a two-digit gray scale code... duh... Redoing it all! brb

 

Penultimate Edit: Here's two samples from the Wiki link kon provided.

 

Spoiler

 

Spoiler

 

Final Edit: Here's a quick demo of each method and comparing it to the original color with a series of 4 GUIs. I can hardly tell a difference between each result in my testing of the exact same pixels.

 

^-::
samplex:=1500, sampley:=10
Gui, 1:New
Gui, 1:Color, % varX:=PixelGetMonochrome1(samplex,sampley)
Gui, 2:New
Gui, 2:Color, % varY:=PixelGetMonochrome2(samplex,sampley)
Gui, 3:New
Gui, 3:Color, % varZ:=PixelGetMonochrome3(samplex,sampley)
PixelGetColor, original, samplex, sampley, RGB
Gui, 4:New
Gui, 4:Color, % original
Gui, 1:Show, x100 y100 w300 h100, % "One - " varX
Gui, 2:Show, x100 y225 w300 h100, % "Two - " varY
Gui, 3:Show, x100 y350 w300 h100, % "Three - " varZ
Gui, 4:Show, x425 y100 w100 h350, % "Original - " original
return

PixelGetMonochrome1(x,y){
SetFormat, IntegerFast, H
PixelGetColor, Pisel, %x%, %y%
B:=(Pisel >> 16) & 0xFF
G:=(Pisel >> 8) & 0xFF
R:=Pisel & 0xFF
Y:=(B+G+R)//3
return Y << 16 | Y << 8 | Y
}

PixelGetMonochrome2(x,y){
SetFormat, IntegerFast, H
PixelGetColor, Pisel, %x%, %y%
B:=(Pisel >> 16) & 0xFF
G:=(Pisel >> 8) & 0xFF
R:=Pisel & 0xFF
Y:=Round(B*0.114) + Round(G*0.587) + Round(R*0.299)
return Y << 16 | Y << 8 | Y
}

PixelGetMonochrome3(x,y){
SetFormat, IntegerFast, H
PixelGetColor, Pisel, %x%, %y%
B:=(Pisel >> 16) & 0xFF
G:=(Pisel >> 8) & 0xFF
R:=Pisel & 0xFF
Y:=Round(B*0.0722) + Round(G*0.7152) + Round(R*0.2126)
return Y << 16 | Y << 8 | Y
}


kon
  • Members
  • 1652 posts
  • Last active:
  • Joined: 04 Mar 2013

Instead of using substring to re-combine them, you can do the bitwise stuff, but in reverse.

RGB := (R << 16) | (G << 8) | B

 

I'm not aware of any specific tutorial (although I'm sure there are lots), but the examples on the Wikipedia Bitwise operation page seem to be pretty straightforward.



read416
  • Members
  • 33 posts
  • Last active: Oct 24 2015 01:13 AM
  • Joined: 24 Jul 2015

Many thanks!!

 

kon, thank you too!



kon
  • Members
  • 1652 posts
  • Last active:
  • Joined: 04 Mar 2013

You shouldn't need SetFormat, IntegerFast, H now that you aren't manipulating the numbers as strings.



Exaskryz
  • Members
  • 3249 posts
  • Last active: Nov 20 2015 05:30 AM
  • Joined: 23 Aug 2012

Are you sure kon? I just removed it in my test script and now I get colors (Purples and a Gray-green). The color values I get from my GUI titles are:

 

6645093, 6250335, and 5263440

 

Assuming they were parsed as their first 6 digits, it looks kind of like what I'd expect. (Thought, from my mishaps earlier, that could be wrong).



kon
  • Members
  • 1652 posts
  • Last active:
  • Joined: 04 Mar 2013

Ah, yes. I didn't look at the Gui part of your script too closely.

You could move it out of the function though, since the Gui is the only part that needs it now.



Exaskryz
  • Members
  • 3249 posts
  • Last active: Nov 20 2015 05:30 AM
  • Joined: 23 Aug 2012

It would depend on what someone wanted I suppose.

 

If I just call ^h::MsgBox % PixelGetMonochrome1(800,400), then I get a decimal answer. I'd have to remember to call SetFormat, IntegerFast, H if I wanted my output to come as an a hex value, which may well be preferred. In fact, I can't even say that I'm getting an accurate answer for a decimal value in any of my functions if I omit the SetFormat (both from the hotkey and the function). I get from the PixelGetMonochrome1() function 3289650. That doesn't look a think like a color to me, since the max values are 255 in each byte. Either that first one is 328 - so not a color, or 32, which makes the second one either 896 - not a color, or 89, which leaves the last one to be 650.

 

So unless there's some fundamental mistake I've made with my bitshifts or something, I would imagine it is best to keep the SetFormat, IntegerFast, H in the function.
 

 

@read416, before I forget, you're welcome. I hope it helps out.



kon
  • Members
  • 1652 posts
  • Last active:
  • Joined: 04 Mar 2013

3289650 (base 10) = 0x323232 in hex.

 

I think you are correct to assume the user may prefer the return value to be hex. But using SetFormat will change the number format for the whole thread, so if a user copy&pastes your function into a script without noticing that it changes the number format they may get some unexpected results elsewhere in the thread.

 

This will return a hex formatted number without changing the number format of the entire thread:

return Format("0x{:X}", Y << 16 | Y << 8 | Y)



Exaskryz
  • Members
  • 3249 posts
  • Last active: Nov 20 2015 05:30 AM
  • Joined: 23 Aug 2012

Ah, OK. Thanks for the explanation. I was mistaken in my understanding of SetFormat and how it applied to functions; I thought it would be restricted to just the function. Glad to learn one way or the other, thanks.

 

Taking your input, here's a revised script. (I already said I made an ultimate edit in that previous post..)

^-::
samplex:=1500, sampley:=10
Gui, 1:New
Gui, 1:Color, % varX:=PixelGetMonochrome1(samplex,sampley)
Gui, 2:New
Gui, 2:Color, % varY:=PixelGetMonochrome2(samplex,sampley)
Gui, 3:New
Gui, 3:Color, % varZ:=PixelGetMonochrome3(samplex,sampley)
PixelGetColor, original, samplex, sampley, RGB
Gui, 4:New
Gui, 4:Color, % original
Gui, 1:Show, x100 y100 w300 h100, % "One - " varX
Gui, 2:Show, x100 y225 w300 h100, % "Two - " varY
Gui, 3:Show, x100 y350 w300 h100, % "Three - " varZ
Gui, 4:Show, x425 y100 w100 h350, % "Original - " original
; MsgBox % 5+5 ; shows 10 if the thread is using Decimal math, and 0xA if thread is using Hexadecimal. Should always be 10 in this script.
return

^d::MsgBox % PixelGetMonochrome1(1500,10,"d")

PixelGetMonochrome1(x,y,base="h"){
PixelGetColor, Pisel, %x%, %y%
B:=(Pisel >> 16) & 0xFF
G:=(Pisel >> 8) & 0xFF
R:=Pisel & 0xFF
Y:=(B+G+R)//3
return base="h"?Format("0x{:X}",Y << 16 | Y << 8 | Y):(Y << 16 | Y << 8 | Y)
}

PixelGetMonochrome2(x,y,base="h"){
PixelGetColor, Pisel, %x%, %y%
B:=(Pisel >> 16) & 0xFF
G:=(Pisel >> 8) & 0xFF
R:=Pisel & 0xFF
Y:=Round(B*0.114) + Round(G*0.587) + Round(R*0.299)
return base="h"?Format("0x{:X}",Y << 16 | Y << 8 | Y):(Y << 16 | Y << 8 | Y)
}

PixelGetMonochrome3(x,y,base="h"){
PixelGetColor, Pisel, %x%, %y%
B:=(Pisel >> 16) & 0xFF
G:=(Pisel >> 8) & 0xFF
R:=Pisel & 0xFF
Y:=Round(B*0.0722) + Round(G*0.7152) + Round(R*0.2126)
return base="h"?Format("0x{:X}",Y << 16 | Y << 8 | Y):(Y << 16 | Y << 8 | Y)
}