POV-Ray : Newsgroups : povray.general : macro to find average colors of image_map Server Time
25 Apr 2024 10:17:20 EDT (-0400)
  macro to find average colors of image_map (Message 1 to 4 of 4)  
From: Kenneth
Subject: macro to find average colors of image_map
Date: 2 Aug 2017 22:05:01
Message: <web.5982834b9cc5ef1a883fb31c0@news.povray.org>
While working on my 'city buildings' scene, I had a need to find the average of
all the colors in a digital photo image. So I wrote this macro, which uses
eval_pigment.

(A note: This code doesn't actually check *every* pixel in the image. Instead,
it checks lots of random positions. My own theory is that such a 'statistical'
approach produces a result that is just about as good as checking each and every
pixel-- and it's faster.)

-----------
#macro AVG_COLOR(MY_PIG) // NOTE: evaluated pigment is within the image_map's
// 1X1 POV-Ray default area.
#local CC = seed(32);
#local LIM_C = 0;
#local SP = 1;
#local SUM=<.5,.5,.5>;
#while(SP <= 100) // 100 random points in the image are evaluated
#local LIM_C = LIM_C + 1;
#local TEMP_EVAL = eval_pigment(MY_PIG, <rand(CC),rand(CC),0>);
#if(
    (TEMP_EVAL.x < .1
    & TEMP_EVAL.y < .1
    & TEMP_EVAL.z < .1
    )
    |
    (TEMP_EVAL.x > .9
    & TEMP_EVAL.y > .9
    & TEMP_EVAL.z > .9
    )
    )
#local SP = SP - 1; // to IGNORE the found value, and set the main counter back
by 1
#else
#local SUM = SUM + TEMP_EVAL;
#end
#local SP = SP + 1;
#if(LIM_C > 5000)
#local SP = 100000; // A safety limiter, to purposely end the while loop
// if the main counter SP loops more than 5000 times total.
#else
#end
#end
srgb 1.0*vnormalize(<SUM.x,SUM.y,SUM.z>) // the actual VALUE of the macro.
//#debug concat("\n","Total while-loop iterations = ",str(LIM_C,1,0),"\n")
#end
-----------

An example of how to use the macro:

#declare P =
pigment{
image_map{jpeg "my_photo_image.jpg" gamma 2.2 interpolate 2}
}

pigment{AVG_COLOR(P)}

-------------------
SOME NOTES:

Interpolate 2 may not be needed in the image_map. I think interpolation is
solely a rendering-specific operation, in which case eval_pigment ignores it.

The #if(TEMP_EVAL...) section is optional-- to restrict the search for colors to
be within two threshold values. Very dark colors (or very bright ones) don't
have much *color* in them anyway-- being close to pure black or pure white
(i.e., greyish)--   and don't add much to the final color IMO, except to either
darken it with muddiness, or make it lighter and more pastel. (A debatable
point, I admit.) This keeps those found colors out of the average. To use EVERY
pixel color, just make the thresholds all 0.0's and 1.0's, respectively.

It's currently set up to evaluate 100 random locations in the image (SP.) You
can change that higher or lower. (The #if(TEMP_EVAL...) section actually
increases this number-- so that 100 *useful* colors are eventually found.)

LIM_C is a 'safety' counter, to end the while loop in the extreme case of not
finding ANY usuable colors in the image_map; I included it only because of the
#if(TEMP_EVAL...) thresholds, which naturally increase the number of #while-loop
iterations. Excluding some evaluated colors makes the #while loop work harder!

The use of vnormalize is an easy way of 'compressing' the (large!) final SUM
value, into the range from 0.0 to 1.0. (Interestingly, the final components of
SUM are somewhere between .4 and .6-- a natural result of the 'average' of all
the image colors.)

You could probably stick *any* three values into the initial SUM, as it will
ultimately be 'swamped' by the additional 100 colors that are found. I used
<.5,.5,.5>  *just in case* the total search for colors (SUM) ended up as
<0,0,0> -- which would probably never happen anyway, except when trying to
evaluate a perfectly BLACK image! But I didn't want vnormalize to be given
<0,0,0> as a final input, which is 'undefined' behavior. So it's not a good idea
to use <0,0,0> as the initial SUM.

Thinking of other uses of this macro: It could probably be re-written to be a
color-histogram tool. Or a color-pallette generator, to find *numerous* general
colors from an image_map background for applying to a scene's objects, to better
'harmonize' all the colors.  (I'm thinking about Old Master paintings, and how
well a painting's colors harmonize with each other.)

SOME EVAL_PIGMENT DETAILS...
In the macro, the output can be either RGB or SRGB; you can choose. But it made
me think about the subtleties of eval_pigment's behavior, AND of what the
image_map's gamma should be set to, in the code.

AFAIK, eval_pigment operates on LINEAR colors (i.e., 3.7xx's RGB color space),
not gamma-bent colors that are usually found in a typical digital photo; those
are generally gamma 2.2 or srgb. So my thinking was that eval-pigment would not
return the colors *as I see them* in the digital photo, but rather a gamma 1.0
version of the colors-- which I didn't want. So I changed the macro's output to
srgb.

(By the way, in the image_map's pigment block, adding either gamma 2.2 or srgb
after the image_map causes no change--none that I can see, anyway. So the
default gamma there must be 2.2 or so, which matches most photo images.  Or,
perhaps POV-ray automatically chooses the proper gamma value, from the image
itself?)

Comments (or corrections!) welcome!


Post a reply to this message

From: Sven Littkowski
Subject: Re: macro to find average colors of image_map
Date: 2 Aug 2017 22:19:01
Message: <59828815@news.povray.org>
On 02.08.2017 22:01, Kenneth wrote:
> While working on my 'city buildings' scene, I had a need to find the aver
age of
> all the colors in a digital photo image. So I wrote this macro, which use
s
> eval_pigment.
> 
> (A note: This code doesn't actually check *every* pixel in the image. Ins
tead,
> it checks lots of random positions. My own theory is that such a 'statist
ical'
> approach produces a result that is just about as good as checking each an
d every
> pixel-- and it's faster.)
> 
> -----------
> #macro AVG_COLOR(MY_PIG) // NOTE: evaluated pigment is within the image_m
ap's
> // 1X1 POV-Ray default area.
> #local CC = seed(32);
> #local LIM_C = 0;
> #local SP = 1;
> #local SUM=<.5,.5,.5>;
> #while(SP <= 100) // 100 random points in the image are evaluated
> #local LIM_C = LIM_C + 1;
> #local TEMP_EVAL = eval_pigment(MY_PIG, <rand(CC),rand(CC),0>);
> #if(
>     (TEMP_EVAL.x < .1
>     & TEMP_EVAL.y < .1
>     & TEMP_EVAL.z < .1
>     )
>     |
>     (TEMP_EVAL.x > .9
>     & TEMP_EVAL.y > .9
>     & TEMP_EVAL.z > .9
>     )
>     )
> #local SP = SP - 1; // to IGNORE the found value, and set the main coun
ter back
> by 1
> #else
> #local SUM = SUM + TEMP_EVAL;
> #end
> #local SP = SP + 1;
> #if(LIM_C > 5000)
> #local SP = 100000; // A safety limiter, to purposely end the while loo
p
> // if the main counter SP loops more than 5000 times total.
> #else
> #end
> #end
> srgb 1.0*vnormalize(<SUM.x,SUM.y,SUM.z>) // the actual VALUE of the macro
.
> //#debug concat("\n","Total while-loop iterations = ",str(LIM_C,1,0),"\
n")
> #end
> -----------
> 
> An example of how to use the macro:
> 
> #declare P =
> pigment{
> image_map{jpeg "my_photo_image.jpg" gamma 2.2 interpolate 2}
> }
> 
> pigment{AVG_COLOR(P)}
> 
> -------------------
> SOME NOTES:
> 
> Interpolate 2 may not be needed in the image_map. I think interpolation i
s
> solely a rendering-specific operation, in which case eval_pigment ignores
 it.
> 
> The #if(TEMP_EVAL...) section is optional-- to restrict the search for co
lors to
> be within two threshold values. Very dark colors (or very bright ones) do
n't
> have much *color* in them anyway-- being close to pure black or pure whit
e
> (i.e., greyish)--   and don't add much to the final color IMO, except to 
either
> darken it with muddiness, or make it lighter and more pastel. (A debatabl
e
> point, I admit.) This keeps those found colors out of the average. To use
 EVERY
> pixel color, just make the thresholds all 0.0's and 1.0's, respectively.
> 
> It's currently set up to evaluate 100 random locations in the image (SP.)
 You
> can change that higher or lower. (The #if(TEMP_EVAL...) section actually
> increases this number-- so that 100 *useful* colors are eventually found.
)
> 
> LIM_C is a 'safety' counter, to end the while loop in the extreme case of
 not
> finding ANY usuable colors in the image_map; I included it only because o
f the
> #if(TEMP_EVAL...) thresholds, which naturally increase the number of #whi
le-loop
> iterations. Excluding some evaluated colors makes the #while loop work ha
rder!
> 
> The use of vnormalize is an easy way of 'compressing' the (large!) final 
SUM
> value, into the range from 0.0 to 1.0. (Interestingly, the final componen
ts of
> SUM are somewhere between .4 and .6-- a natural result of the 'average' o
f all
> the image colors.)
> 
> You could probably stick *any* three values into the initial SUM, as it w
ill
> ultimately be 'swamped' by the additional 100 colors that are found. I us
ed
> <.5,.5,.5>  *just in case* the total search for colors (SUM) ended up as
> <0,0,0> -- which would probably never happen anyway, except when trying t
o
> evaluate a perfectly BLACK image! But I didn't want vnormalize to be give
n
> <0,0,0> as a final input, which is 'undefined' behavior. So it's not a go
od idea
> to use <0,0,0> as the initial SUM.
> 
> Thinking of other uses of this macro: It could probably be re-written to 
be a
> color-histogram tool. Or a color-pallette generator, to find *numerous* g
eneral
> colors from an image_map background for applying to a scene's objects, to
 better
> 'harmonize' all the colors.  (I'm thinking about Old Master paintings, an
d how
> well a painting's colors harmonize with each other.)
> 
> SOME EVAL_PIGMENT DETAILS...
> In the macro, the output can be either RGB or SRGB; you can choose. But i
t made
> me think about the subtleties of eval_pigment's behavior, AND of what the

> image_map's gamma should be set to, in the code.
> 
> AFAIK, eval_pigment operates on LINEAR colors (i.e., 3.7xx's RGB color sp
ace),
> not gamma-bent colors that are usually found in a typical digital photo; 
those
> are generally gamma 2.2 or srgb. So my thinking was that eval-pigment wou
ld not
> return the colors *as I see them* in the digital photo, but rather a gamm
a 1.0
> version of the colors-- which I didn't want. So I changed the macro's out
put to
> srgb.
> 
> (By the way, in the image_map's pigment block, adding either gamma 2.2 or
 srgb
> after the image_map causes no change--none that I can see, anyway. So the

> default gamma there must be 2.2 or so, which matches most photo images.  
Or,
> perhaps POV-ray automatically chooses the proper gamma value, from the im
age
> itself?)
> 
> Comments (or corrections!) welcome!
> 
> 
> 
> 
Sounds excellent!

- Being a macro, it means that the user can set the amount of random points
?

- You could also offer different methods to capture colors inside an
image: on method is your random method, and another method would be to
sample each 2nd pixel - the user can decide about the method (where he
also can decide about which other pixel to sample: each 2nd, each 3rd,
etc.).

Just suggesting.

---
Diese E-Mail wurde von AVG auf Viren geprüft.
http://www.avg.com


Post a reply to this message

From: Kenneth
Subject: Re: macro to find average colors of image_map
Date: 2 Aug 2017 22:35:00
Message: <web.59828b92e30e73f2883fb31c0@news.povray.org>
Sven Littkowski <I### [at] SvenLittkowskiname> wrote:

> Sounds excellent!
>
> - Being a macro, it means that the user can set the amount of random points
> ?

Yes, within the macro itself (the #while-loop counter.) I guess I could have
included that as a variable or argument in the #macro's name instead. That would
probably be a good addition.


Post a reply to this message

From: Sven Littkowski
Subject: Re: macro to find average colors of image_map
Date: 6 Aug 2017 04:13:33
Message: <5986cfad@news.povray.org>
On 02.08.2017 22:33, Kenneth wrote:
> Yes, within the macro itself (the #while-loop counter.) I guess I could h
ave
> included that as a variable or argument in the #macro's name instead. Tha
t would
> probably be a good addition.

Looking forward! :-)

---
Diese E-Mail wurde von AVG auf Viren geprüft.
http://www.avg.com


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.