Posts: 236
Threads: 26
Joined: Mar 2020
Reputation:
29
Operating system(s):
- Windows (Vista and later)
Gimp version: Don't know yet
Is there any way to find out, in a Python plugin, if a given point (x,y) is in the selection or not?
Posts: 6,386
Threads: 278
Joined: Oct 2016
Reputation:
566
Operating system(s):
Gimp version: 3.00RC1
01-23-2021, 12:36 PM
(This post was last modified: 01-23-2021, 01:23 PM by Ofnuts.)
From one of my scripts:
Code:
def isSelectedPoint(point,image):
x,y=point.pixelX,point.pixelY
return 0<=x<image.width and 0<=y<image.height and image.selection.get_pixel(x,y)[0] > 0
Instead of testing >0 you may want to try >127.
In my Point class, pixelX and pixelY are pseudo attributes:
Code:
@property
def pixelX(self):
return int(math.floor(self.x))
@property
def pixelY(self):
return int(math.floor(self.y))
Posts: 236
Threads: 26
Joined: Mar 2020
Reputation:
29
Operating system(s):
- Windows (Vista and later)
Gimp version: Don't know yet
Thank you. That also lead me to find it in pdb too:
value = pdb.gimp_selection_value(image, x, y)
In my Gimp it is 127. Is this limit going to change in the future? If so, then the plugin should check the version.
Posts: 6,386
Threads: 278
Joined: Oct 2016
Reputation:
566
Operating system(s):
Gimp version: 3.00RC1
01-23-2021, 04:31 PM
(This post was last modified: 01-23-2021, 04:32 PM by Ofnuts.)
(01-23-2021, 03:02 PM)Ottia Tuota Wrote: Thank you. That also lead me to find it in pdb too:
value = pdb.gimp_selection_value(image, x, y)
In my Gimp it is 127. Is this limit going to change in the future? If so, then the plugin should check the version.
There are places where things are 0-255 integers, and others where they are 0.-1. floats. As parameters some calls accept either.
Posts: 236
Threads: 26
Joined: Mar 2020
Reputation:
29
Operating system(s):
- Windows (Vista and later)
Gimp version: Don't know yet
Testing if a point is in the selection appeared to be slower than desired. Then I wanted to compare the two solutions. I made the following test code:
Code:
def selected1(x,y,image): # Ofnuts
return image.selection.get_pixel(x,y)[0] > 127
def selected2(x,y,image): # pdb
return pdb.gimp_selection_value(image, x, y) > 127
def test(image, N):
x = 500
y = 500
for i in range(N):
test1 = selected1(x,y,image) # Ofnuts
for i in range(N):
test2 = selected2(x,y,image) # pdb
import cProfile
image = gimp.image_list()[0]
command = 'test(image, 100000)'
cProfile.runctx(command, None, locals(), sort='tottime')
I ran it in Gimp's Python console. The results:
Code:
300005 function calls in 62.485 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
100000 39.456 0.000 39.456 0.000 <input>:1(selected2)
100000 16.192 0.000 22.855 0.000 <input>:1(selected1)
100000 6.663 0.000 6.663 0.000 {method 'get_pixel' of 'gimp.Drawable' objects}
1 0.173 0.173 62.485 62.485 <input>:1(test)
2 0.001 0.001 0.001 0.001 {range}
1 0.000 0.000 62.485 62.485 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
So, using a call to pdb (pdb.gimp_selection_value(image, x, y)) takes about 73% more time than your method (image.selection.get_pixel(x,y)[0]). The numbers are 39.456 and 22.855. There must be an explanation?
(Note: I did this on an old and slow machine.)
Posts: 6,386
Threads: 278
Joined: Oct 2016
Reputation:
566
Operating system(s):
Gimp version: 3.00RC1
(01-25-2021, 12:10 PM)Ottia Tuota Wrote: Testing if a point is in the selection appeared to be slower than desired. Then I wanted to compare the two solutions. I made the following test code:
Code:
def selected1(x,y,image): # Ofnuts
return image.selection.get_pixel(x,y)[0] > 127
def selected2(x,y,image): # pdb
return pdb.gimp_selection_value(image, x, y) > 127
def test(image, N):
x = 500
y = 500
for i in range(N):
test1 = selected1(x,y,image) # Ofnuts
for i in range(N):
test2 = selected2(x,y,image) # pdb
import cProfile
image = gimp.image_list()[0]
command = 'test(image, 100000)'
cProfile.runctx(command, None, locals(), sort='tottime')
I ran it in Gimp's Python console. The results:
Code:
300005 function calls in 62.485 seconds
Ordered by: internal time
ncalls tottime percall cumtime percall filename:lineno(function)
100000 39.456 0.000 39.456 0.000 <input>:1(selected2)
100000 16.192 0.000 22.855 0.000 <input>:1(selected1)
100000 6.663 0.000 6.663 0.000 {method 'get_pixel' of 'gimp.Drawable' objects}
1 0.173 0.173 62.485 62.485 <input>:1(test)
2 0.001 0.001 0.001 0.001 {range}
1 0.000 0.000 62.485 62.485 <string>:1(<module>)
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
So, using a call to pdb (pdb.gimp_selection_value(image, x, y)) takes about 73% more time than your method (image.selection.get_pixel(x,y)[0]). The numbers are 39.456 and 22.855. There must be an explanation?
(Note: I did this on an old and slow machine.)
Likely due overhead in the Gimp API and the Python API layer. When you do a get_pixel() a drawable you remove all the code to obtain the drawable via the image.
If you are in a hurry, you can use a pixel_region. A pixel region is a native python vector/list the the pixel channels as bytes. There is some overhead to create one, but then access is near instantaneous. But I wouldn't consider that if you are dealing with paths that are mostly "linear" objects, usually around a thousand), it makes more sense when you are actually dealing with all the pixels ("area objects", often above a million). And then for efficiency you can convert the pixel_region into a numpy array.
Posts: 236
Threads: 26
Joined: Mar 2020
Reputation:
29
Operating system(s):
- Windows (Vista and later)
Gimp version: Don't know yet
Thanks. That makes sense.
I am working with paths, hence I leave learning about pixel regions to some other time. And the code I am working on right now needs much work anyhow to make it faster.
|