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