I have a script which shows different messages depending on if a particular shade of red or green colours are detected, at set screen coordinates. The green detection is working fine, but the red detection is not working.
The script searches the specified x and y coordinate area which is set as: x1, y1, x2, y2.
Scripts seen below.
The hex colour for the green shade is #32CD32, and for red it SEEMS to be #FF0000 (both determined by hovering over the image using Active Window Spy).
Red text screenshot:
[![Red text to be detected][1]][1]
Green text screenshot:
[![Green text that is already successfully detected][2]][2]
My script is detecting green (#32CD32) perfectly. It will NOT detect the red colour #FF0000. I have tried many different variations of the red colour, and still cannot get the script to recognize it when it is on screen. Does anyone know how I can solve this?
This second script to detect RED does not work (note that the coordinates for both scripts aren't the same- the two colours are in different places on the screen):
^t::
Am I making a mistake with the hex colour of the red text? I know that the method overall works fine for green, so it should be straightforward for red.
This code searches the specified rectangle on the screen for a red pixel:
PixelSearch, Px, Py, 121, 282, 169, 310, 0xFF0000, 3, Fast RGB
AutoHotKey expects colors to be specified using a Blue-Green-Red (BGR) format unless you specify the RGB parameter. See the documentation for PixelSearch
Related
AutoHotkey's PixelSearch allows one to search for a pixel of a certain color in an (X1,Y1)..(X2,Y2) rectangle.
But I want to find any pixel that isn't a certain color, i.e. given a background color, I want to detect when any other color comes up in the foreground.
Is there a way to do this using the built-in PixelSearch, or other built-in functions?
If you have some control over the background color, perhaps you can use PixelSearch's variation parameter.
If your background color is black, search for a white pixel with variation 254. PixelSearch should return any pixel that isn't black.
This code searches for any pixel other than BLACK (untested)
White := 0xFFFFFF
PixelSearch OutputVarX, OutputVarY, X1, Y1, X2, Y2, %White%, 254
If your background is midtone gray (0x7F7F7F), try searching for black and white with variation 127. Again, I haven't tested this. Maybe the variation should be 126 or 63. You might have to engage in some trial and error since the behavior of the variation parameter isn't comprehensively documented.
You can use PixelGetColor to look at an individual pixel. The instruction tells you the color of the pixel at location x, y. An If command determines whether the pixel is 0x9D6346 or not.
Using PixelGetColor in a Loop allows you to test a range of pixels, one at a time by incrementing x, y or both.
And yes the proper order is BGR not RGB. A look at the help file confirmed that. :)
Something is happening to change the color. Perhaps you can look for another way to detect the change on the screen. Is the change of color due to another window or message becoming active? If so there are a number of commands you can use to determine what is appearing on the screen.
The windows spy is good at determining the names of pop up messages. Even if they have the same name as an existing window you can determine which is which by the text included or excluded.
A change of the position of a particular window may be enough to detect the change you are looking for.
Perhaps a bit more detail describing what you are trying to detect will help. It would at least, confirm we are in the same ballpark.
I cannot think of a reliable way to solve this with only built-in functionality. However, you could write it yourself with help of the external GDI+-library.
backgroundColor = 0x644E37
pToken := GDIP_StartUp()
pBitMap := GDIP_BitmapFromScreen()
while(a_index <= a_screenWidth) {
w := a_index
while(a_index <= a_screenHeight) {
h := a_index
ARGB := GDIP_GetPixel(pbitmap, w, h)
RGB := ARGBtoRGB(ARGB)
if(RGB != backgroundColor) {
msgbox, % "found pixel at " w ", " h
}
}
GDIP_DisposeImage(pBitMap)
GDIP_Shutdown(pToken)
return
ARGBtoRGB( ARGB ) {
VarSetCapacity( RGB,6,0 )
DllCall( "msvcrt.dll\sprintf", Str,RGB, Str,"%06X", UInt,ARGB<<8 )
Return "0x" RGB
}
untested
Allegedly, this gdip_bitmapFromScreen() is actually faster than pixelSearch.
source
This pixel search worked for me to find any color other than white:
Search for black (0x000000),
if pixel not found
search for red (0xFF0000),
if pixel not found
search for lime (0x00FF00),
if pixel not found
search for blue (0x0000FF),
if pixel not found, the only color is pure white.
I Set all these to have a variation of 254. A variation of 255 finds everything, including white. I used lime instead of green because the official color called green has a green value of 128, while lime has a green value of 255 (red 0, green 255, blue 0). Seems that just searching for black usually finds NOT white, but sometimes you'll need to work your way down the list. This informs me whether or not there is ANY variation of ANY color other than white, including colors so close to white that I can't see them (when on a white background).
You might have to do a little math and/or experimentation for other colors, but I don't see why this method wouldn't work. I used fast RGB mode and window coordinates. Also I found helpful information here:
https://en.wikipedia.org/wiki/Web_colors
As a relative novice I hate to do this. :)
Right out of PixelSearch in the help file.
PixelSearch, Px, Py, 200, 200, 300, 300, 0x9d6346, 3, Fast
if ErrorLevel
MsgBox, That color was not found in the specified region.
else
MsgBox, A color within 3 shades of variation was found at X%Px% Y%Py%.
Understanding of hexadecimal and how the number applies to the color is necessary.
Color is expressed as a hexadecimal number. In this case 9d6346 and is broken down into three parts. I seem to recall 9d is the value for red, 63 for green, and 46 for blue. Those three numbers can range between Hex 00 to Hex FF (Decimal 0 to 255).
Variation is expressed as a Decimal number is the amount of allowable range in the search color
9D range being 9b to 9f. 63 = 61 to 66, 46 = 44 to 69. Depending on whether the search number is taken in or not my range could be out by 1.
If all else fails Google hexadecimal
Similar possibilities with PixelGetColor followed by a variety of If statements
Be prepared for a very wide variation. Some apps intermingle several distinctly different colors to achieve a desired color.
I've written a program that creates a grid of hexagons, some black, some white. This is done randomly. I then choose randomly a subset of hexagons on the edges of which to place red diamonds. This script is designed to build pretend rock microstructures with grains (hexagons) and pore spaces (diamonds) for materials modeling. I'm using the fill() command to create each shape. The problem is that when I fill in the red diamonds, the edge of the hexagon beneath it is still showing through. I tried to post an image, but since this is my first time posting, it won't let me. I can email though, if anyone wants to see.
So to create the black hexagons:
h= fill(hexXY(i,j,1)+vx,hexXY(i,j,2)+vy,'k');
set(h,'edgecolor','k')
where the hexXY matrix holds x and y coordinates for the center of the hexagon, which added to the vx and vy arrays gives the vertices of each point on the hexagon. I then do the same thing with the diamonds:
h=fill(hexXY(i,j,1)+dvx,hexXY(i,j,2)+dvy,'r');
set(h,'edgecolor','r')
But, as I said, the black edges of the hexagons show through the red. I provided the vertices in order like you would draw them, though I don't think that should matter. I tried uistack and using patch, but neither worked for me. I can't set the hexagon edge color to none, because I have also have white hexagons, and if I set the background color to black I'd get black lines between the white hexagons. I removed have to remove the edge from either black or white hexagons, because where the two touch, the edges give messy pixelation.
Can anyone help me figure out how to get the red diamonds filled in properly?
EDIT: I didn't mention before, that this only occurs while saving the figure.You can't see it in the figure window. I've tried using print() and hgexport(), and changing the renderer, to no avail. Here is a small example with numbers pulled from my code to run:
hold on
v1=[0.3929 0.4107 0.3929 0.3571 0.3393 0.3571];
v2=[0.6907 0.6598 0.6288 0.6288 0.6598 0.6907];
h= fill(v1,v2,'k');
set(h,'edgecolor','k')
v3=[0.3750 0.3929 0.3750 0.3571 0.3750];
v4=[0.6366 0.6288 0.6211 0.6288 0.6366];
h=fill(v3,v4,'r');
set(h,'edgecolor','r')
set(gca,'position',[0 0 1 1],'units','normalized')
set(gcf,'PaperUnits','Inches','PaperPosition',[0 0 5 5]);
hgexport(gcf, 'test', hgexport('factorystyle'), 'Format', 'tiff','Resolution',600);
Here is the image saved with hgexport:
Try making your edges transparent:
set(h,'edgealpha',0)
Something weird is causing the original problem. If the commands are kept simple, everything appears fine:
h1= fill([1,2,3,3,2,1],[2,4,3,2,0,1],'m');
set(h1,'edgecolor','m')
hold on
h2= fill([2,3,2.5],[2,1,pi],'g');
set(h2,'edgecolor','g')
But the background edge moves forward when the foreground triangle is changed.
set(h2,'edgealpha',0) % an example of what can cause the problem to appear.
I don't know what's causing that.
If set(h,'edgealpha',0) does not work (as suggested by #user1739107), you may try set(h,'edgecolor','none').
On OSX R2012b, both solutions work fine.
I am working on replacing certain color in image by User's selected color. I am using OpenCV for color replacement.
Here in short I have described from where I took help and what I got.
How to change a particular color in an image?
I have followed the step or taken basic idea from answer of above link. In correct answer of that link that guy told you only need to change hue for colour replacement.
after that I run into the issue similar like
color replacement in image for iphone application (i.e. It's good code for color replacement for those who are completely beginners)
from that issue I got the idea that I also need to change "Saturation" also.
Now I am running into issues like
"When my source image is too light(i.e. with high brightness) and I am replacing colour with some dark colour then colours looks light in replaced image instead of dark due to that it seems like Replaced colour does not match with colour using that we done replacement"
This happens because I am not considering the brightness in replacement. Here I am stuck what is the formula or idea to change brightness?
Suppose I am replacing the brightness of image with brightness of destination colour then It would look like flat replacemnt and image will lose it's actual shadow or edges.
Edit:
When I am considering the brightness of source(i.e. the pixel to be processed) in replacment then I am facing one issue. let me explain as per scenario of my application.
for example I am changing the colour of car(like whiteAngl explain) after that I am erasing few portion of the newly coloured car. Again I am doing recolour on erased portion but now what happended is colour done after erase and colour before erase doesn't match because both time I am getting different lightness because both time my pixel of to be processed is changed and due to that lightness of colour changed in output. How to overcome this issue
Any help will be appreciated
Without seeing the code you have tried, it's not easy to guess what you have done wrong. To show you with a concrete example how this is done let's change the ugly blue color of this car:
This short python script shows how we can change the color using the HSV color space:
import cv2
orig = cv2.imread("original.jpg")
hsv = cv2.cvtColor(orig, cv2.COLOR_BGR2HSV)
hsv[:,:,0] += 100
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imwrite('changed.jpg', bgr)
and you get:
On wikipedia you see the hue is between 0 to 360 degrees but for the values in OpenCV see the documentation. You see I added 100 to hue of every pixel in the image. I guess you want to change the color of a portion of your image, but probably you get the idea from the above script.
Here is how to get the requested dark red car. First we get the red one:
The dark red one that I tried to keep the metallic feeling in it:
As I said, the equation you use to shift the light of the color depends on the material you want to have for the object. Here I came up with a quick and dirty equation to keep the metallic material of the car. This script produces the above dark red car image from the first light blue car image:
import cv2
orig = cv2.imread("original.jpg")
hls = cv2.cvtColor(orig, cv2.COLOR_BGR2HLS)
hls[:,:,0] += 80 # change color from blue to red, hue
for i in range(1,50): # 50 times reduce lightness
# select indices where lightness is greater than 0 (black) and less than very bright
# 220-i*2 is there to reduce lightness of bright pixel fewer number of times (than 50 times),
# so in the first iteration we don't reduce lightness of pixels which have lightness >= 200, in the second iteration we don't touch pixels with lightness >= 198 and so on
ind = (hls[:,:,1] > 0) & (hls[:,:,1] < (220-i*2))
# from the lightness of the selected pixels we subtract 1, using trick true=1 false=0
# so the selected pixels get darker
hls[:,:,1] -= ind
bgr = cv2.cvtColor(hls, cv2.COLOR_HLS2BGR)
cv2.imwrite('changed.jpg', bgr)
You are right : changing only the hue will not change the brightness at all (or very weakly due to some perceptual effects), and what you want is to change the brightness as well. And as you mentioned, setting the brightness to the target brightness will loose all pixel values (you will only see changes in saturation). So what's next ?
What you can do is to change the pixel's hue plus try to match the average lightness. To do that, just compute the average brightness B of all your pixels to be processed, and then multiply all your brightness values by Bt/B where Bt is the brightness of your target color.
Doing that will both match the hue (due to the first step) and the brightness due to the second step, while preserving the edges (because you only modified the average brightness).
This is a special case of histogram matching, where here, your target histogram has a single value (the target color) so only the mean can be matched in a reasonable way.
And if you're looking for a "credible source" as stated in your bounty request, I am a postdoc at Harvard and will be presenting a paper on color histogram matching at Siggraph this year ;) .
I'm working with this excellent example of converting an image to grayscale: Convert Image to B&W problem CGContext - iPhone Dev
However, for my purposes, I would like to have only pure black and pure white left in the image.
It appears that to do so, I need to pass a black and white color space to the recolor method using a call:
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(/*black and white name*/);
However, I was unable to find the proper iOS color space names. What I found was from Mac, and the "color space names" referenced from the iOS docs does not point anywhere.
How can I properly create a black and white CGColorSpaceRef?
Thank you!
I am not familiar with a black and white only color space but what you can do is calculate the total average RGB value from all the pixels (lets call it totalAvg) and use it as a threshold. Meaning for each pixel if its rgb average is greater than the calculated totalAvg than set it to pure white, otherwise set it to pure black.
I agree it is a bit of more work but thats whay I can think of unless you find the colorspace you are looking for.
You might try creating a gray color space, then creating an indexed color space with two colors (black and white, obviously) and using that.
I've converted a colored photo to black and white, and bolded the edges. Now i need to convert it back to its original color with the bolded edges. Is there any function in matlab which allows me to do so?
Once you remove the colour from an image, there is no possible way to automatically put it back. You're basically reducing a set of 16,777,216 colours to a set of 256 - on average each shade of grey has 65,536 equivalent colours, and without the original image there's no way to guess which it could be.
Now, if you were to take the bolded lines from your black-and-white image and paint them on top of the original coloured image, that might end up producing what you're looking for.
If what you are trying to do is to use some filter over the B/W image and then use that with the original color. I suggest you convert your image to a color space with Lightness channel that suits your needs (for example L*a*b* if you need the ligtness to be uniformly distributed regarding human recognition of differences) and apply your filter only over the Lightness channel.