1 /*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //#define LOG_NDEBUG 0
18 #define LOG_TAG "EmulatedCamera_Scene"
19 #include <log/log.h>
20 #include <stdlib.h>
21 #include <cmath>
22 #include "Scene.h"
23
24 // TODO: This should probably be done host-side in OpenGL for speed and better
25 // quality
26
27 namespace android {
28
29 // Define single-letter shortcuts for scene definition, for directly indexing
30 // mCurrentColors
31 #define G (Scene::GRASS * Scene::NUM_CHANNELS)
32 #define S (Scene::GRASS_SHADOW * Scene::NUM_CHANNELS)
33 #define H (Scene::HILL * Scene::NUM_CHANNELS)
34 #define W (Scene::WALL * Scene::NUM_CHANNELS)
35 #define R (Scene::ROOF * Scene::NUM_CHANNELS)
36 #define D (Scene::DOOR * Scene::NUM_CHANNELS)
37 #define C (Scene::CHIMNEY * Scene::NUM_CHANNELS)
38 #define I (Scene::WINDOW * Scene::NUM_CHANNELS)
39 #define U (Scene::SUN * Scene::NUM_CHANNELS)
40 #define K (Scene::SKY * Scene::NUM_CHANNELS)
41 #define M (Scene::MOON * Scene::NUM_CHANNELS)
42
43 const int Scene::kSceneWidth = 20;
44 const int Scene::kSceneHeight = 20;
45 const int Scene::kMaxWidth = 20;
46 const int Scene::kMaxHeight = 20;
47
48 const uint8_t Scene::kScene[Scene::kSceneWidth * Scene::kSceneHeight] = {
49 // 5 10 15 20
50 K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,
51 K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,
52 K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,
53 K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,
54 K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K, // 5
55 K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,K,
56 K,K,K,K,K,K,K,K,H,H,H,H,H,H,H,H,H,H,H,H,
57 K,K,K,K,K,K,K,K,H,H,H,H,H,H,H,C,C,H,H,H,
58 K,K,K,K,K,K,H,H,H,H,H,H,H,H,H,C,C,H,H,H,
59 H,K,K,K,K,K,H,R,R,R,R,R,R,R,R,R,R,R,R,H, // 10
60 H,K,K,K,K,H,H,R,R,R,R,R,R,R,R,R,R,R,R,H,
61 H,H,H,K,K,H,H,R,R,R,R,R,R,R,R,R,R,R,R,H,
62 H,H,H,K,K,H,H,H,W,W,W,W,W,W,W,W,W,W,H,H,
63 S,S,S,G,G,S,S,S,W,W,W,W,W,W,W,W,W,W,S,S,
64 S,G,G,G,G,S,S,S,W,I,I,W,D,D,W,I,I,W,S,S, // 15
65 G,G,G,G,G,G,S,S,W,I,I,W,D,D,W,I,I,W,S,S,
66 G,G,G,G,G,G,G,G,W,W,W,W,D,D,W,W,W,W,G,G,
67 G,G,G,G,G,G,G,G,W,W,W,W,D,D,W,W,W,W,G,G,
68 G,G,G,G,G,G,G,G,S,S,S,S,S,S,S,S,S,S,G,G,
69 G,G,G,G,G,G,G,G,S,S,S,S,S,S,S,S,S,S,G,G, // 20
70 // 5 10 15 20
71 };
72
73 #undef G
74 #undef S
75 #undef H
76 #undef W
77 #undef R
78 #undef D
79 #undef C
80 #undef I
81 #undef U
82 #undef K
83 #undef M
84
Scene(int sensorWidthPx,int sensorHeightPx,float sensorSensitivity)85 Scene::Scene(
86 int sensorWidthPx,
87 int sensorHeightPx,
88 float sensorSensitivity):
89 mSensorWidth(sensorWidthPx),
90 mSensorHeight(sensorHeightPx),
91 mHour(12),
92 mExposureDuration(0.033f)
93 //mSensorSensitivity(sensorSensitivity)
94 {
95 // Map scene to sensor pixels
96 if (mSensorWidth > mSensorHeight) {
97 mMapDiv = (mSensorWidth / (kSceneWidth + 1) ) + 1;
98 } else {
99 mMapDiv = (mSensorHeight / (kSceneHeight + 1) ) + 1;
100 }
101 mOffsetX = (kSceneWidth * mMapDiv - mSensorWidth) / 2;
102 mOffsetY = (kSceneHeight * mMapDiv - mSensorHeight) / 2;
103
104 // Assume that sensor filters are sRGB primaries to start
105 mFilterR[0] = 3.2406f; mFilterR[1] = -1.5372f; mFilterR[2] = -0.4986f;
106 mFilterGr[0] = -0.9689f; mFilterGr[1] = 1.8758f; mFilterGr[2] = 0.0415f;
107 mFilterGb[0] = -0.9689f; mFilterGb[1] = 1.8758f; mFilterGb[2] = 0.0415f;
108 mFilterB[0] = 0.0557f; mFilterB[1] = -0.2040f; mFilterB[2] = 1.0570f;
109
110
111 }
112
~Scene()113 Scene::~Scene() {
114 }
115
setColorFilterXYZ(float rX,float rY,float rZ,float grX,float grY,float grZ,float gbX,float gbY,float gbZ,float bX,float bY,float bZ)116 void Scene::setColorFilterXYZ(
117 float rX, float rY, float rZ,
118 float grX, float grY, float grZ,
119 float gbX, float gbY, float gbZ,
120 float bX, float bY, float bZ) {
121 mFilterR[0] = rX; mFilterR[1] = rY; mFilterR[2] = rZ;
122 mFilterGr[0] = grX; mFilterGr[1] = grY; mFilterGr[2] = grZ;
123 mFilterGb[0] = gbX; mFilterGb[1] = gbY; mFilterGb[2] = gbZ;
124 mFilterB[0] = bX; mFilterB[1] = bY; mFilterB[2] = bZ;
125 }
126
setHour(int hour)127 void Scene::setHour(int hour) {
128 ALOGV("Hour set to: %d", hour);
129 mHour = hour % 24;
130 }
131
getHour()132 int Scene::getHour() {
133 return mHour;
134 }
135
setExposureDuration(float seconds)136 void Scene::setExposureDuration(float seconds) {
137 mExposureDuration = seconds;
138 }
139
calculateScene(nsecs_t time)140 void Scene::calculateScene(nsecs_t time) {
141 // Calculate time fractions for interpolation
142 int timeIdx = mHour / kTimeStep;
143 int nextTimeIdx = (timeIdx + 1) % (24 / kTimeStep);
144 const nsecs_t kOneHourInNsec = 1e9 * 60 * 60;
145 nsecs_t timeSinceIdx = (mHour - timeIdx * kTimeStep) * kOneHourInNsec + time;
146 float timeFrac = timeSinceIdx / (float)(kOneHourInNsec * kTimeStep);
147
148 // Determine overall sunlight levels
149 float sunLux =
150 kSunlight[timeIdx] * (1 - timeFrac) +
151 kSunlight[nextTimeIdx] * timeFrac;
152 ALOGV("Sun lux: %f", sunLux);
153
154 float sunShadeLux = sunLux * (kDaylightShadeIllum / kDirectSunIllum);
155
156 // Determine sun/shade illumination chromaticity
157 float currentSunXY[2];
158 float currentShadeXY[2];
159
160 const float *prevSunXY, *nextSunXY;
161 const float *prevShadeXY, *nextShadeXY;
162 if (kSunlight[timeIdx] == kSunsetIllum ||
163 kSunlight[timeIdx] == kTwilightIllum) {
164 prevSunXY = kSunsetXY;
165 prevShadeXY = kSunsetXY;
166 } else {
167 prevSunXY = kDirectSunlightXY;
168 prevShadeXY = kDaylightXY;
169 }
170 if (kSunlight[nextTimeIdx] == kSunsetIllum ||
171 kSunlight[nextTimeIdx] == kTwilightIllum) {
172 nextSunXY = kSunsetXY;
173 nextShadeXY = kSunsetXY;
174 } else {
175 nextSunXY = kDirectSunlightXY;
176 nextShadeXY = kDaylightXY;
177 }
178 currentSunXY[0] = prevSunXY[0] * (1 - timeFrac) +
179 nextSunXY[0] * timeFrac;
180 currentSunXY[1] = prevSunXY[1] * (1 - timeFrac) +
181 nextSunXY[1] * timeFrac;
182
183 currentShadeXY[0] = prevShadeXY[0] * (1 - timeFrac) +
184 nextShadeXY[0] * timeFrac;
185 currentShadeXY[1] = prevShadeXY[1] * (1 - timeFrac) +
186 nextShadeXY[1] * timeFrac;
187
188 ALOGV("Sun XY: %f, %f, Shade XY: %f, %f",
189 currentSunXY[0], currentSunXY[1],
190 currentShadeXY[0], currentShadeXY[1]);
191
192 // Converting for xyY to XYZ:
193 // X = Y / y * x
194 // Y = Y
195 // Z = Y / y * (1 - x - y);
196 float sunXYZ[3] = {
197 sunLux / currentSunXY[1] * currentSunXY[0],
198 sunLux,
199 sunLux / currentSunXY[1] *
200 (1 - currentSunXY[0] - currentSunXY[1])
201 };
202 float sunShadeXYZ[3] = {
203 sunShadeLux / currentShadeXY[1] * currentShadeXY[0],
204 sunShadeLux,
205 sunShadeLux / currentShadeXY[1] *
206 (1 - currentShadeXY[0] - currentShadeXY[1])
207 };
208 ALOGV("Sun XYZ: %f, %f, %f",
209 sunXYZ[0], sunXYZ[1], sunXYZ[2]);
210 ALOGV("Sun shade XYZ: %f, %f, %f",
211 sunShadeXYZ[0], sunShadeXYZ[1], sunShadeXYZ[2]);
212
213 // Determine moonlight levels
214 float moonLux =
215 kMoonlight[timeIdx] * (1 - timeFrac) +
216 kMoonlight[nextTimeIdx] * timeFrac;
217 float moonShadeLux = moonLux * (kDaylightShadeIllum / kDirectSunIllum);
218
219 float moonXYZ[3] = {
220 moonLux / kMoonlightXY[1] * kMoonlightXY[0],
221 moonLux,
222 moonLux / kMoonlightXY[1] *
223 (1 - kMoonlightXY[0] - kMoonlightXY[1])
224 };
225 float moonShadeXYZ[3] = {
226 moonShadeLux / kMoonlightXY[1] * kMoonlightXY[0],
227 moonShadeLux,
228 moonShadeLux / kMoonlightXY[1] *
229 (1 - kMoonlightXY[0] - kMoonlightXY[1])
230 };
231
232 // Determine starlight level
233 const float kClearNightXYZ[3] = {
234 kClearNightIllum / kMoonlightXY[1] * kMoonlightXY[0],
235 kClearNightIllum,
236 kClearNightIllum / kMoonlightXY[1] *
237 (1 - kMoonlightXY[0] - kMoonlightXY[1])
238 };
239
240 // Calculate direct and shaded light
241 float directIllumXYZ[3] = {
242 sunXYZ[0] + moonXYZ[0] + kClearNightXYZ[0],
243 sunXYZ[1] + moonXYZ[1] + kClearNightXYZ[1],
244 sunXYZ[2] + moonXYZ[2] + kClearNightXYZ[2],
245 };
246
247 float shadeIllumXYZ[3] = {
248 kClearNightXYZ[0],
249 kClearNightXYZ[1],
250 kClearNightXYZ[2]
251 };
252
253 shadeIllumXYZ[0] += (mHour < kSunOverhead) ? sunXYZ[0] : sunShadeXYZ[0];
254 shadeIllumXYZ[1] += (mHour < kSunOverhead) ? sunXYZ[1] : sunShadeXYZ[1];
255 shadeIllumXYZ[2] += (mHour < kSunOverhead) ? sunXYZ[2] : sunShadeXYZ[2];
256
257 // Moon up period covers 23->0 transition, shift for simplicity
258 int adjHour = (mHour + 12) % 24;
259 int adjMoonOverhead = (kMoonOverhead + 12 ) % 24;
260 shadeIllumXYZ[0] += (adjHour < adjMoonOverhead) ?
261 moonXYZ[0] : moonShadeXYZ[0];
262 shadeIllumXYZ[1] += (adjHour < adjMoonOverhead) ?
263 moonXYZ[1] : moonShadeXYZ[1];
264 shadeIllumXYZ[2] += (adjHour < adjMoonOverhead) ?
265 moonXYZ[2] : moonShadeXYZ[2];
266
267 ALOGV("Direct XYZ: %f, %f, %f",
268 directIllumXYZ[0],directIllumXYZ[1],directIllumXYZ[2]);
269 ALOGV("Shade XYZ: %f, %f, %f",
270 shadeIllumXYZ[0], shadeIllumXYZ[1], shadeIllumXYZ[2]);
271
272 for (int i = 0; i < NUM_MATERIALS; i++) {
273 // Converting for xyY to XYZ:
274 // X = Y / y * x
275 // Y = Y
276 // Z = Y / y * (1 - x - y);
277 float matXYZ[3] = {
278 kMaterials_xyY[i][2] / kMaterials_xyY[i][1] *
279 kMaterials_xyY[i][0],
280 kMaterials_xyY[i][2],
281 kMaterials_xyY[i][2] / kMaterials_xyY[i][1] *
282 (1 - kMaterials_xyY[i][0] - kMaterials_xyY[i][1])
283 };
284
285 if (kMaterialsFlags[i] == 0 || kMaterialsFlags[i] & kSky) {
286 matXYZ[0] *= directIllumXYZ[0];
287 matXYZ[1] *= directIllumXYZ[1];
288 matXYZ[2] *= directIllumXYZ[2];
289 } else if (kMaterialsFlags[i] & kShadowed) {
290 matXYZ[0] *= shadeIllumXYZ[0];
291 matXYZ[1] *= shadeIllumXYZ[1];
292 matXYZ[2] *= shadeIllumXYZ[2];
293 } // else if (kMaterialsFlags[i] * kSelfLit), do nothing
294
295 ALOGV("Mat %d XYZ: %f, %f, %f", i, matXYZ[0], matXYZ[1], matXYZ[2]);
296 //float luxToElectrons = mSensorSensitivity * mExposureDuration /
297 // (kAperture * kAperture);
298 // Hack, fixed value to avoid over exposure and produce more
299 // colors to pass CTS jpeg size check
300 float luxToElectrons = 0.490581;
301 mCurrentColors[i*NUM_CHANNELS + 0] =
302 (mFilterR[0] * matXYZ[0] +
303 mFilterR[1] * matXYZ[1] +
304 mFilterR[2] * matXYZ[2])
305 * luxToElectrons;
306 mCurrentColors[i*NUM_CHANNELS + 1] =
307 (mFilterGr[0] * matXYZ[0] +
308 mFilterGr[1] * matXYZ[1] +
309 mFilterGr[2] * matXYZ[2])
310 * luxToElectrons;
311 mCurrentColors[i*NUM_CHANNELS + 2] =
312 (mFilterGb[0] * matXYZ[0] +
313 mFilterGb[1] * matXYZ[1] +
314 mFilterGb[2] * matXYZ[2])
315 * luxToElectrons;
316 mCurrentColors[i*NUM_CHANNELS + 3] =
317 (mFilterB[0] * matXYZ[0] +
318 mFilterB[1] * matXYZ[1] +
319 mFilterB[2] * matXYZ[2])
320 * luxToElectrons;
321
322 ALOGV("Color %d RGGB: %d, %d, %d, %d", i,
323 mCurrentColors[i*NUM_CHANNELS + 0],
324 mCurrentColors[i*NUM_CHANNELS + 1],
325 mCurrentColors[i*NUM_CHANNELS + 2],
326 mCurrentColors[i*NUM_CHANNELS + 3]);
327 }
328 // Shake viewpoint; horizontal and vertical sinusoids at roughly
329 // human handshake frequencies
330 mHandshakeX =
331 ( kFreq1Magnitude * std::sin(kHorizShakeFreq1 * timeSinceIdx) +
332 kFreq2Magnitude * std::sin(kHorizShakeFreq2 * timeSinceIdx) ) *
333 mMapDiv * kShakeFraction;
334
335 mHandshakeY =
336 ( kFreq1Magnitude * std::sin(kVertShakeFreq1 * timeSinceIdx) +
337 kFreq2Magnitude * std::sin(kVertShakeFreq2 * timeSinceIdx) ) *
338 mMapDiv * kShakeFraction;
339
340 // Set starting pixel
341 setReadoutPixel(0,0);
342 }
343
344 // Handshake model constants.
345 // Frequencies measured in a nanosecond timebase
346 const float Scene::kHorizShakeFreq1 = 2 * M_PI * 1 / 1e9; // 1 Hz
347 const float Scene::kHorizShakeFreq2 = 2 * M_PI * 1 / 1e9; // 1 Hz
348 const float Scene::kVertShakeFreq1 = 2 * M_PI * 1 / 1e9; // 1 Hz
349 const float Scene::kVertShakeFreq2 = 2 * M_PI * 1 / 1e9; // 1 Hz
350 const float Scene::kFreq1Magnitude = 5;
351 const float Scene::kFreq2Magnitude = 1;
352 const float Scene::kShakeFraction = 0.2; // As a fraction of a scene tile
353
354 // RGB->YUV, Jpeg standard
355 const float Scene::kRgb2Yuv[12] = {
356 0.299f, 0.587f, 0.114f, 0.f,
357 -0.16874f, -0.33126f, 0.5f, -128.f,
358 0.5f, -0.41869f, -0.08131f, -128.f,
359 };
360
361 // Aperture of imaging lens
362 const float Scene::kAperture = 2.8;
363
364 // Sun illumination levels through the day
365 const float Scene::kSunlight[24/kTimeStep] =
366 {
367 0, // 00:00
368 0,
369 0,
370 kTwilightIllum, // 06:00
371 kDirectSunIllum,
372 kDirectSunIllum,
373 kDirectSunIllum, // 12:00
374 kDirectSunIllum,
375 kDirectSunIllum,
376 kSunsetIllum, // 18:00
377 kTwilightIllum,
378 0
379 };
380
381 // Moon illumination levels through the day
382 const float Scene::kMoonlight[24/kTimeStep] =
383 {
384 kFullMoonIllum, // 00:00
385 kFullMoonIllum,
386 0,
387 0, // 06:00
388 0,
389 0,
390 0, // 12:00
391 0,
392 0,
393 0, // 18:00
394 0,
395 kFullMoonIllum
396 };
397
398 const int Scene::kSunOverhead = 12;
399 const int Scene::kMoonOverhead = 0;
400
401 // Used for sun illumination levels
402 const float Scene::kDirectSunIllum = 100000;
403 const float Scene::kSunsetIllum = 400;
404 const float Scene::kTwilightIllum = 4;
405 // Used for moon illumination levels
406 const float Scene::kFullMoonIllum = 1;
407 // Other illumination levels
408 const float Scene::kDaylightShadeIllum = 20000;
409 const float Scene::kClearNightIllum = 2e-3;
410 const float Scene::kStarIllum = 2e-6;
411 const float Scene::kLivingRoomIllum = 50;
412
413 const float Scene::kIncandescentXY[2] = { 0.44757f, 0.40745f};
414 const float Scene::kDirectSunlightXY[2] = { 0.34842f, 0.35161f};
415 const float Scene::kDaylightXY[2] = { 0.31271f, 0.32902f};
416 const float Scene::kNoonSkyXY[2] = { 0.346f, 0.359f};
417 const float Scene::kMoonlightXY[2] = { 0.34842f, 0.35161f};
418 const float Scene::kSunsetXY[2] = { 0.527f, 0.413f};
419
420 const uint8_t Scene::kSelfLit = 0x01;
421 const uint8_t Scene::kShadowed = 0x02;
422 const uint8_t Scene::kSky = 0x04;
423
424 // For non-self-lit materials, the Y component is normalized with 1=full
425 // reflectance; for self-lit materials, it's the constant illuminance in lux.
426 const float Scene::kMaterials_xyY[Scene::NUM_MATERIALS][3] = {
427 { 0.3688f, 0.4501f, .1329f }, // GRASS
428 { 0.3688f, 0.4501f, .1329f }, // GRASS_SHADOW
429 { 0.3986f, 0.5002f, .4440f }, // HILL
430 { 0.3262f, 0.5040f, .2297f }, // WALL
431 { 0.4336f, 0.3787f, .1029f }, // ROOF
432 { 0.3316f, 0.2544f, .0639f }, // DOOR
433 { 0.3425f, 0.3577f, .0887f }, // CHIMNEY
434 { kIncandescentXY[0], kIncandescentXY[1], kLivingRoomIllum }, // WINDOW
435 { kDirectSunlightXY[0], kDirectSunlightXY[1], kDirectSunIllum }, // SUN
436 { kNoonSkyXY[0], kNoonSkyXY[1], kDaylightShadeIllum / kDirectSunIllum }, // SKY
437 { kMoonlightXY[0], kMoonlightXY[1], kFullMoonIllum } // MOON
438 };
439
440 const uint8_t Scene::kMaterialsFlags[Scene::NUM_MATERIALS] = {
441 0,
442 kShadowed,
443 kShadowed,
444 kShadowed,
445 kShadowed,
446 kShadowed,
447 kShadowed,
448 kSelfLit,
449 kSelfLit,
450 kSky,
451 kSelfLit,
452 };
453
454 } // namespace android
455