Most efficient way of a value within a image that belongs to set of values exist within images?

Here’s my dilemma, I know this can be faster.

I’m looking to find if any value returns 1 if isin(i,your_inputs) is true.

Some code examples:

#@cli rep_sval_in_img: value_0,value_1,...
#@cli : Return the validity of existence of scalar values in image(s)
rep_sval_in_img:
check $#
$! m,M:=min($*),max($*)
repeat w {
	if $M<im#$>||$m>iM#$>
		continue
	fi

	+f[$>] isin(i,$*)
	=.. {iM#-1},$>
	rm.
}

u {crop(#-1)} rm.
#@cli rep_sval_in_img: value_0,value_1,...
#@cli : Return the validity of existence of scalar values in image(s)
rep_sval_in_img:
check $#
$! m,M:=min($*),max($*)
repeat w {
	+rep_mt_f32v_map {whds#$>>>[0,15]},1

	if $M<im#$>||$m>iM#$>
		rm. continue
	fi

	eval. :"
		const img=$>;
		r=J(-1);
		p=(r[0]<<48|r[1]<<24|r[2])-1;
		q=i0<<48|i1<<24|i2;
		while(++p<q,
			c=i[#-2,img];
			c?(break();):(
				isin(i[#img,p],"$*")?(
					i[#-2,img]=1;
					break();
				);
			);
		);
		I;
		"
	rm.
}

u {crop(#-1)} rm.

Second one is faster. If a value exist within image, it’s almost as fast as eq command. But, it is slower if I use multiple eq to find the solution.

Sample output:

C:\Windows\System32>gmic sp cat,dog rep_sval_in_img 2,120 e ${}
[gmic]./ Start G'MIC interpreter (v.3.6.5).
[gmic]./ Input sample image 'cat' (1 image 600x550x1x3).
[gmic]./ Input sample image 'dog' (1 image 1024x685x1x3).
1,1
[gmic]./ Display images [0,1] = 'cat, dog'.
[0] = 'cat':
  size = (600,550,1,3) [3867.2 Kio of float32].
  data = (202,212,212,219,219,219,219,219,219,219,219,219,219,219,219,219,219,219,212,219,212,212,212,212,212,212,212,212,212,202,202,202,202,202,202,202,212,212,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,202,193,193,193,193,193,193,193,188,188,188, ... ,140,128,95,95,79,80,70,81,89,95,117,115,95,70,62,70,70,51,46,45,79,99,117,128,133,128,117,59,16,19,70,80,81,89,99,79,70,79,81,115,128,128,95,59,79,106,117,117,128,128,79,79,95,103,103,95,70,79,128,147,146,117,59,13).
  min = 4, max = 244, mean = 113.418, std = 66.7981, coords_min = (293,0,0,0), coords_max = (144,29,0,0).
[1] = 'dog':
  size = (1024,685,1,3) [8220 Kio of float32].
  data = (67,71,67,71,67,71,71,67,67,71,71,67,71,67,67,71,67,73,67,67,67,67,67,67,67,67,67,67,61,67,61,67,67,67,67,67,67,67,67,67,67,71,67,67,67,67,67,73,67,71,77,73,73,77,81,82,77,82,77,77,82,82,82,82, ... ,106,96,96,90,78,90,90,90,90,106,78,60,77,77,53,60,66,90,96,106,106,96,90,77,77,77,78,90,90,90,78,66,66,77,78,78,78,78,90,77,66,100,77,77,66,60,66,66,68,78,78,78,79,90,90,90,79,79,84,84,84,79,79,79).
  min = 2, max = 254, mean = 119.113, std = 53.8004, coords_min = (409,183,0,0), coords_max = (474,89,0,0).
[gmic]./ End G'MIC interpreter.

Both image returns 1 because at least one pixel is either 2 or 120.

So, is there a better solution here?

The code below seems to do what you want, and stays simple enough (and use parallelization) :

found_value :
  foreach {
    eval. ":begin(found = 0); isin(i,$*)?(found = 1); end(merge(found,|); set('found',found))"
    e "Value found : "$found
  }

Isn’t that kind of solutions you are looking for ?

That works really well. Thanks. It doesn’t have the early termination (stop work on further pixel) using a single value like in my example two if found, but it’ll do.

This is the final code I’ll be using:

#@cli rep_sval_in_img: value_0,value_1,...
#@cli : Return the validity of existence of scalar values in image(s)
rep_sval_in_img:
check $#
$!
repeat w {
	eval[$>] {`whds#$>>0x1000?(_':'):(_'>')`}begin(found=0;);isin(i,$*)?(found=1);end(merge(found,|);set('found',found));
	=. $found,$>
}
u {crop(#-1)} rm.

Actually, I found a better code, only 6 ms slower if it doesn’t found a value. So, 21 ms for not found value vs your 15 ms when either found/not found. And this one is 2 ms when a matching value is found. Given the other attempts I did were slower, I’ll take this one.

#@cli rep_sval_in_img: value_0,value_1,...
#@cli : Return the validity of existence of scalar values in image(s)
rep_sval_in_img:
check $#

$!

repeat w {
	+rep_mt_f32v_map {whds#$>>>[0,14]},1
	eval. :"
		t=J(-1);
		p=t[0]<<48|t[1]<<24|t[2];
		q=i0<<48|i1<<24|i2;
		do(
			v=isin(i[#$>,p],$*);
			if(v||i[#-2,$>],break(););
		,++p<q);
		if(v,i[#-2,$>]=1;);
		I;
		"
	rm.
}

u {crop(#-1)} rm.

I’m afraid that this kind of code won’t work for images that are not integer-valued (even not 8bits-values TBH, as t[0]<<48 will quickly become out-of-range for a double precision storage).

What do you mean? p is current index to be processed, hence the use of i[#$>,p], and q tells it to stop. This allows me to process images between 1 to N threads. The f32 map last value is whds converted to f32 vector.