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