Posts: 236 
	Threads: 26 
	Joined: Mar 2020
	
 Reputation: 
 29
Gimp version: 
 
Operating system(s): Windows (Vista and later)
	  
 
	
	
		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,916 
	Threads: 296 
	Joined: Oct 2016
	
 Reputation: 
 605
Gimp version: 
 
Operating system(s): Linux
	  
 
	
		
		
		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
Gimp version: 
 
Operating system(s): Windows (Vista and later)
	  
 
	
	
		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,916 
	Threads: 296 
	Joined: Oct 2016
	
 Reputation: 
 605
Gimp version: 
 
Operating system(s): Linux
	  
 
	
		
		
		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
Gimp version: 
 
Operating system(s): Windows (Vista and later)
	  
 
	
	
		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,916 
	Threads: 296 
	Joined: Oct 2016
	
 Reputation: 
 605
Gimp version: 
 
Operating system(s): Linux
	  
 
	
	
		 (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
Gimp version: 
 
Operating system(s): Windows (Vista and later)
	  
 
	
	
		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.
	 
	
	
	
		
	 
 
 
	 
 |