Gimp-Forum.net
Python plugin: point in selection? - Printable Version

+- Gimp-Forum.net (https://www.gimp-forum.net)
+-- Forum: GIMP (https://www.gimp-forum.net/Forum-GIMP)
+--- Forum: Extending the GIMP (https://www.gimp-forum.net/Forum-Extending-the-GIMP)
+---- Forum: Scripting questions (https://www.gimp-forum.net/Forum-Scripting-questions)
+---- Thread: Python plugin: point in selection? (/Thread-Python-plugin-point-in-selection)



Python plugin: point in selection? - Ottia Tuota - 01-23-2021

Is there any way to find out, in a Python plugin, if a given point (x,y) is in the selection or not?


RE: Python plugin: point in selection? - Ofnuts - 01-23-2021

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))



RE: Python plugin: point in selection? - Ottia Tuota - 01-23-2021

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.


RE: Python plugin: point in selection? - Ofnuts - 01-23-2021

(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.


RE: Python plugin: point in selection? - Ottia Tuota - 01-25-2021

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.)


RE: Python plugin: point in selection? - Ofnuts - 01-25-2021

(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.


RE: Python plugin: point in selection? - Ottia Tuota - 01-25-2021

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.