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