You are not logged in.

Dear visitor, welcome to krpano.com Forum. If this is your first visit here, please read the Help. It explains in detail how this page works. To use all features of this page, you should consider registering. Please use the registration form, to register here or read more information about the registration process. If you are already registered, please login here.

1

Tuesday, August 24th 2010, 2:15pm

autolevels plugin

I have created a plugin that applies an autolevels effect to the krpano view:
http://fieldofview.com/projects/krpano_autolevels

The effect can be tuned to affect just the luminosity of the view, or the luminosity as well as the color of the view. Please note that the effect is applied to the (jpeg compressed) 8 bit panorama, so if the effect is too pronounced you will start to see artifacts such as banding and color mismatches. There is a number of parameters that will let you tone down the effect to suite your images.

The autolevels effect achieves a similar effect to the Adaptive Dynamic Range concept (ADR) which I previously implemented in SPi-V, but instead of mixing dual exposures, it applies a color transform to the view after it has been drawn by krpano (but just before it is displayed on the screen). This has the advantage of being simpler to author, but has less control and less actual dynamic range than a full ADR implementation.

The plugin requires Flash player 10 or newer. It can be used free of charge and its source code is available under a CC-GNU GPL license.


The autolevels.swf file and its sources are available as part of the krpano_fovplugins package on github.

This post has been edited 2 times, last edit by "ahoeben" (Mar 15th 2011, 4:55pm)


michel

Professional

Posts: 1,153

Location: ANDORRA

Occupation: TV

  • Send private message

2

Tuesday, August 24th 2010, 2:59pm

Adaptive Dynamic Range concept


*attention* C H A P E A U *attention*

That's really great you share such a plugin *thumbsup* ...
Thank you Aldo *thumbup* ...

VN2009

Professional

Posts: 1,334

Location: Duluth MN

  • Send private message

3

Tuesday, August 24th 2010, 3:39pm

wow! absolutley awsome. thanks for sharing!

4

Tuesday, August 24th 2010, 3:39pm

I agree with Michel. It is great to see knowledge and experience shared here.
Thank you for sharing.

Jarred

klausesser

Intermediate

Posts: 289

Location: Düsseldorf

Occupation: Fotograf

  • Send private message

5

Tuesday, August 24th 2010, 10:30pm

Hey Aldo!

Great work!!

best, Klaus
herzlichen Gruß, Klaus

--
“Simplicity is the keynote of all true elegance.”
― Coco Chanel

image360

Intermediate

Posts: 192

Location: Austin, TX and Chicago, IL

Occupation: Photographer

  • Send private message

6

Tuesday, August 24th 2010, 10:56pm

Aldo,

it really is wonderful that you would share this and I'm sure the entire KRPano community greatly appreciates your contributions. And if anyone is not familiar with Also's prior work, you should be if you want to get a better understanding of the 360 world, Aldo is an accomplished pioneer in this world.

Now, I'm trying to understand the purpose of this plugin, that is, what you;re trying to do by building it. Is it to try and simulate the short lag that our vision has when you move from light to dark, that is the small adjustment time before one can see clearly once you've moved from light to dark or vice versa?

Or am I missing the purpose?

Best Regards,

Robert

VN2009

Professional

Posts: 1,334

Location: Duluth MN

  • Send private message

7

Tuesday, August 24th 2010, 10:59pm

with this plugin taking bracketed HDR shots would not be as important i would gather.

image360

Intermediate

Posts: 192

Location: Austin, TX and Chicago, IL

Occupation: Photographer

  • Send private message

8

Tuesday, August 24th 2010, 11:29pm

VN2009,

the plugin is just using the final 8 bit jpg, so I think I can safety say that's not what this is for. Once you've gotten to a single 8 bit file, you have no headroom or dynamic range like you do in RAW. Sure you can lighten a dark area a bit, but you can not darken a blown out area, it will just go grey.

regards,

Robert

9

Tuesday, August 24th 2010, 11:53pm

See the example here:
http://fieldofview.com/projects/krpano_autolevels
Look from the dark hallway into the bright sky, and you should see detail appear. The effect is subtle, and works best if you zoom in a bit. It is all about the effect, not about actually extending the dynamic range. But you'll see that if you have a panorama without blown highlights and without too dark shadows, that there is actually some "room" in the 8 bit image to play with the dynamic range.

Another use of the plugin is for high resolution panoramas with a lot of haze. When zoomed out, the blue haze looks perfectly natural ("atmospheric perspective"), but when you zoom in to the hazy parts of the image near the horizon, the blue tint and lack of contrast will distract from the experience. The autolevels plugin should let you handle this in a nicer way.

michel

Professional

Posts: 1,153

Location: ANDORRA

Occupation: TV

  • Send private message

10

Wednesday, August 25th 2010, 4:11am

Hi,
...there is actually some "room" in the 8 bit image to play with the dynamic range.
*smile* So, come on and play ;-)
To help in playing with the different attributes, I have made a little pluging that uses sliders to tweak the values. As it is based on the "slider-blend-cubes" example from Klaus, you have to retrieve the file "white.jpg". Here is the code:

Source code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<!--
	Just a little plugin that tries to help in setting the values, tweaking
	them using sliders, for the plugin "autolevels.swf" from Aldo Hoeben. !!!
	Hope it can be useful ;)
	
	This plugin is based on the "slider-blend-cubes" example from Klaus.
-->

<krpano version="1.0.8">	
	
	<!-- image -->
	
	<!-- view settings -->

	<plugin name="AutoLevels"
			url="%SWFPATH%/plugin_autolevels/autolevels.swf" 
			enabled="true"
			effect="0" 
			adaptation="0" 
			coloradjust="0" 
			threshold="0"
			attenuation="0"/>
	

	<plugin name="enabled_slider_bg"   url="white.jpg" zorder="1" align="bottom" width="200" height="15" x="0" y="200" handcursor="false" alpha="0.5" />
	<plugin name="enabled_slider_grip" url="white.jpg" zorder="2" align="lefttop" parent="enabled_slider_bg" width="100" height="15" x="0" y="0" blendmode="add" 
			ondown="startdragingslider(enabled,get(name),get(parent));set(onover,'');"
			onup="stopdragingslider();set(onover,'showtext(enabled,FOVTEXT);');"
			onover="showtext(enabled,FOVTEXT);"
			effect="glow(0xFFFFFF,0.7,4,2);glow(0x000000,1,4,2);dropshadow(3,45,0x000000,2,0.6);"
			/>	

	<plugin name="effect_slider_bg"   url="white.jpg" zorder="1" align="bottom" width="200" height="15" x="0" y="175" handcursor="false" alpha="0.5" />
	<plugin name="effect_slider_grip" url="white.jpg" zorder="2" align="lefttop" parent="effect_slider_bg" width="30" height="15" x="0" y="0" blendmode="add" 
			ondown="startdragingslider(effect,get(name),get(parent));set(onover,'');"
			onup="stopdragingslider();set(onover,'showtext(effect,FOVTEXT);');"
			onover="showtext(effect,FOVTEXT);"
			effect="glow(0xFFFFFF,0.7,4,2);glow(0x000000,1,4,2);dropshadow(3,45,0x000000,2,0.6);"
			/>	

	<plugin name="adaptation_slider_bg"   url="white.jpg" zorder="1" align="bottom" width="200" height="15" x="0" y="150" handcursor="false" alpha="0.5" />
	<plugin name="adaptation_slider_grip" url="white.jpg" zorder="2" align="lefttop" parent="adaptation_slider_bg" width="30" height="15" x="0" y="0" blendmode="add" 
			ondown="startdragingslider(adaptation,get(name),get(parent));set(onover,'');"
			onup="stopdragingslider();set(onover,'showtext(adaptation,FOVTEXT);');"
			onover="showtext(adaptation,FOVTEXT);"
			effect="glow(0xFFFFFF,0.7,4,2);glow(0x000000,1,4,2);dropshadow(3,45,0x000000,2,0.6);"
			/>

	<plugin name="coloradjust_slider_bg"   url="white.jpg" zorder="1" align="bottom" width="200" height="15" x="0" y="125" handcursor="false" alpha="0.5" />
	<plugin name="coloradjust_slider_grip" url="white.jpg" zorder="2" align="lefttop" parent="coloradjust_slider_bg" width="30" height="15" x="0" y="0" blendmode="add" 
			ondown="startdragingslider(coloradjust,get(name),get(parent));set(onover,'');"
			onup="stopdragingslider();set(onover,'showtext(coloradjust,FOVTEXT);');"
			onover="showtext(coloradjust,FOVTEXT);"
			effect="glow(0xFFFFFF,0.7,4,2);glow(0x000000,1,4,2);dropshadow(3,45,0x000000,2,0.6);"
			/>

	<plugin name="threshold_slider_bg"   url="white.jpg" zorder="1" align="bottom" width="200" height="15" x="0" y="100" handcursor="false" alpha="0.5" />
	<plugin name="threshold_slider_grip" url="white.jpg" zorder="2" align="lefttop" parent="threshold_slider_bg" width="30" height="15" x="0" y="0" blendmode="add" 
			ondown="startdragingslider(threshold,get(name),get(parent));set(onover,'');"
			onup="stopdragingslider();set(onover,'showtext(threshold,FOVTEXT);');"
			onover="showtext(threshold,FOVTEXT);"
			effect="glow(0xFFFFFF,0.7,4,2);glow(0x000000,1,4,2);dropshadow(3,45,0x000000,2,0.6);"
			/>

	<plugin name="attenuation_slider_bg"   url="white.jpg" zorder="1" align="bottom" width="200" height="15" x="0" y="75" handcursor="false" alpha="0.5" />
	<plugin name="attenuation_slider_grip" url="white.jpg" zorder="2" align="lefttop" parent="attenuation_slider_bg" width="30" height="15" x="0" y="0" blendmode="add" 
			ondown="startdragingslider(attenuation,get(name),get(parent));set(onover,'');"
			onup="stopdragingslider();set(onover,'showtext(attenuation,FOVTEXT);');"
			onover="showtext(attenuation,FOVTEXT);"
			effect="glow(0xFFFFFF,0.7,4,2);glow(0x000000,1,4,2);dropshadow(3,45,0x000000,2,0.6);"
			/>
			
	<plugin name="htmltext" url="%SWFPATH%/plugins/textfield.swf" 
		visible="false"
    	align="bottom"
    	width="300" height="" 
    	x="0" y="300" 
    	html="data:code"
    	borderwidth="10"
    	bordercolor="0xFFFFFF"
    	backgroundcolor="0xFFFFFF"
    	autosize="center"		
		effect="glow(0xFFFFFF,0.7,4,2);glow(0x000000,1,4,2);dropshadow(3,45,0x000000,2,0.6);"
    	/>
	
	<data name="code">
	</data> 

	<style name="buttonstyle"
	   	url="%SWFPATH%/plugins/textfield.swf" keep="true" children="false"
	   	css="p{color:#000000; font-family:Arial; font-weight:bold; font-size:14; margin-left:5; margin-right:5; text-align:center; }"
	   	backgroundcolor="0xFFFFFF" roundedge="5" shadow="1" borderwidth="0" glow="4" glowcolor="0xFFFFFF" visible="false"
	   	onover="tween(alpha,0.7,distance(0.3,0.2));"
	   	onout="tween(alpha,1.0,distance(0.3,0.2));"
	   	onloaded="set(alpha,0);set(textblur,15);set(blur,15); set(visible,true); tween(alpha,1,0.3); tween(textblur,0,0.3); tween(blur,0,0.3);"
	   	width="150" height="22"
	   	/>

	<plugin name="b1" style="buttonstyle"
	    	html="[p]display the code[/p]"
	    	align="bottom" x="0" y="25"
			onclickA="set(plugin[htmltext].visible,true); set(html,[p]hide the code[/p]); set(onclick,onclickB());"
			onclickB="set(plugin[htmltext].visible,false); set(html,[p]display the code[/p]); set(onclick,showcode(); onclickA(););"
	    	onclick="showcode(); onclickA();"
	    	/>


	<textstyle name="FOVTEXT" origin="bottom" edge="bottom" yoffset="230" textalign="center" background="false" border="false" fontsize="25" textcolor="0xFFFFFF" bold="false" effect="glow(0xFFFFFF,0.7,4,2);glow(0x000000,1,4,2);dropshadow(3,45,0x000000,2,0.6);" showtime="2.0" fadetime="1.0" />
	

	<action name="startdragingslider">
		set(plugin[%2].backup_align, get(plugin[%2].align));
		set(plugin[%2].backup_edge,  get(plugin[%2].edge));

		plugin[%2].changeorigin(lefttop,lefttop);

		sub(mouse_x_offset, plugin[%2].x, mouse.x);
		sub(mouse_y_offset, plugin[%2].y, mouse.y);

		set(image_dragging,true);

		dragslider(%1,%2,%3);
	</action>


	<action name="stopdragingslider">
		set(image_dragging, false);
	</action>


	<action name="dragslider">
		if(image_dragging,
			add(xpos, mouse.x, mouse_x_offset);
			sub(xmax, plugin[%3].width, plugin[%2].width);
			if(xpos LT 0, set(xpos,0));
			if(xpos GT xmax, copy(xpos,xmax));
			copy(plugin[%2].x, xpos);

			<!-- val = 0.0 ... 1.0 -->
			div(val, xpos, xmax);
			autolevels_settings(%1);

			delayedcall(0.01, dragslider(%1,%2,%3) );
		  ,
			plugin[%2].changeorigin(get(plugin[%2].backup_align), get(plugin[%2].backup_edge));
		  );
	</action>


	<action name="autolevels_settings">	 
		if( %1 == enabled , if( val LT 0.5 , set(val,true); , set(val,false); );  );
		if( %1 == effect , roundval(val,2); );
		if( %1 == adaptation , if( val LT 0.01 , set(val,0.01); ); roundval(val,2); );
		if( %1 == coloradjust , roundval(val,2); );
		if( %1 == threshold , mul(val,255); roundval(val); );
		if( %1 == attenuation , roundval(val,2); );
		set(plugin[AutoLevels].%1, get(val)); trace(plugin[AutoLevels].%1);
		showvaltext(%1);
		showcode();
	</action>
	
	
	<action name="showvaltext">
		txtadd(msg,%1,' = ',get(val));
		showtext(get(msg),FOVTEXT);
	</action>
	
	
	<action name="showcode">
		txtadd(msg,'&lt;plugin name="AutoLevels" <br/>',
					'url="',get(plugin[AutoLevels].url),'" <br/>',
					'enabled="',get(plugin[AutoLevels].enabled),'" <br/>',
					'effect="',get(plugin[AutoLevels].effect),'" <br/>',
					'adaptation="',get(plugin[AutoLevels].adaptation),'" <br/>',
					'coloradjust="',get(plugin[AutoLevels].coloradjust),'" <br/>',
					'threshold="',get(plugin[AutoLevels].threshold),'" <br/>',
					'attenuation="',get(plugin[AutoLevels].attenuation),'" /&gt;',
					);
		set(data[code].content,get(msg));
		set(plugin[htmltext].html,data:code);
	</action>


</krpano>


It is not a super good looking pluging, but a think it can help to find the right settings...
Hope this can be useful... And thank you again Aldo for this great plugin *thumbup* .

SAlut.

11

Wednesday, August 25th 2010, 11:12am

One word of caution: the plugin basically takes a screenshot of the view whenever the camera changes, and uses that screenshot to do the autolevels calculations. The sliders will be part of the screenshot, so they will be of some influence over the effect. I have shrunk down the ui, added some code so the sliders take their initial values from the xml, and added it to my sample. Thanks!

update: see Klaus' remarks below.

This post has been edited 1 times, last edit by "ahoeben" (Aug 26th 2010, 10:26am)


12

Thursday, August 26th 2010, 10:19am

Hi and welcome!

thank you, a great plugin!

just a short note about the todo note in your in the updateLevels function - the "image.layer" Sprite contains only the pano image, so any <plugin> or <hotspot> elements aren't visible on it when drawing it,

and if you want to draw also the hotspots on it do something like this:

Source code

1
2
this.meterbitmap.draw(this.panosprite,this.scalematrix);
this.meterbitmap.draw(this.krpano.get("hotspot.layer"),this.scalematrix);


best regards,
Klaus

13

Thursday, August 26th 2010, 10:24am

the "image.layer" Sprite contains only the pano image, so any <plugin> or <hotspot> elements aren't visible on it when drawing it

I had not realised that. That's actually quite nice! I'll change the todo text in the next update ;-)

michel

Professional

Posts: 1,153

Location: ANDORRA

Occupation: TV

  • Send private message

14

Thursday, August 26th 2010, 8:06pm

Hi Aldo,
I have shrunk down the ui, added some code so the sliders take their initial values from the xml, and added it to my sample. Thanks!
Yes, that's better *thumbup* ...

Note: I have noticed that when an attribute it is not set inside the xml, some strange results could happen...
ex:
trace('plugin[autolevels].%1 = ',plugin[autolevels].%1)
could return:
plugin[autolevels].adaptation = plugin[autolevels].adaptation
so:
plugin[autolevels].adaptation = NaN

To avoid this I have modified the loadslider() action:

Source code

1
2
3
4
5
6
7
8
9
10
11
	<action name="loadslider">
		set(temp,plugin[autolevels].%1);
		if(plugin[autolevels].%1 == '', set(plugin[autolevels].%1,0); );
		if(temp == 'plugin[autolevels].%1', set(plugin[autolevels].%1,0); );
		set(val, get(plugin[autolevels].%1)); 
		if( %1 == enabled , if( val EQ true , set(val,1); , set(val,0); );  );
		if( %1 == threshold , div(val,255) );
		sub(xmax, plugin[%3].width, plugin[%2].width);
		mul(val, xmax);
		tween(plugin[%2].x, get(val));
	</action>


It seems to work now *smile* ...
You will find the code in the attached zip file....
Hope it is helpful...

SAlut.

edited: the code does not work properly... Sorry... *sad*
michel has attached the following file:

This post has been edited 1 times, last edit by "michel" (Aug 26th 2010, 9:03pm)


michel

Professional

Posts: 1,153

Location: ANDORRA

Occupation: TV

  • Send private message

15

Thursday, August 26th 2010, 9:02pm

The code above does not work properly.... I do not know what it can be .... Sorry.... *sad*

Attached the file I use in trying to get a correct code (it makes some trace() of the variables...)
michel has attached the following file:

michel

Professional

Posts: 1,153

Location: ANDORRA

Occupation: TV

  • Send private message

16

Thursday, August 26th 2010, 11:10pm

Hi,

I think it's working now... *squint*

I think, the problem was the pow(val,3); :

Source code

1
if( %1 == adaptation , pow(val,3); trace('pow(val,3) = ',val); if( val LT 0.001 , set(val,0.001); ); roundval(val,3); );


Comments, enhancements are welcome ;-) ...

SAlut.
michel has attached the following file:

Tuur

Master

Posts: 2,404

Location: Netherlands

Occupation: Virtual Tours / Photography / Musician / Recording engineer

  • Send private message

17

Sunday, August 29th 2010, 3:05pm

HE Aldo,

te gek man!!!

Grtz van Arthur (remember?)

Tuur *thumbsup*

bulp

Intermediate

Posts: 388

Location: Malaysia

  • Send private message

18

Sunday, August 29th 2010, 4:33pm

GREAT.... *thumbsup*

19

Sunday, August 29th 2010, 4:46pm

I think, the problem was the pow(val,3);
The reason I put the pow(val,3) in is because even though the range for "adaptation" is from 0 to 1, only small values give interesting results (ie: 0.001 - 0.2). With the amplification in place, it is easier to tune the adaptation to a low value.

michel

Professional

Posts: 1,153

Location: ANDORRA

Occupation: TV

  • Send private message

20

Monday, August 30th 2010, 9:07pm

Hi Aldo,
The reason I put the pow(val,3) in is because even though the range for "adaptation" is from 0 to 1, only small values give interesting results (ie: 0.001 - 0.2). With the amplification in place, it is easier to tune the adaptation to a low value.
Ok, so I have modified the code on the loadslider() action to makes the sliders reflecting the amplification...

Source code

1
if( %1 == adaptation , pow(val,0.33333333333333333333333333333333) );


It seems that the plugin Autolevels.swf sets default values when no parameters are preset in the xml ... isn't it?...
This has been confusing me a long time *wacko* ... Unless if the preload is set to true for plugin Autolevels.swf, some times they apply, some no *whistling* ...

I think the code works correctly now *squint* ...

SAlut.
michel has attached the following file: