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 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 113 Scene::~Scene() {} 114 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 132 void Scene::setHour(int hour) { 133 ALOGV("Hour set to: %d", hour); 134 mHour = hour % 24; 135 } 136 137 int Scene::getHour() { return mHour; } 138 139 void Scene::setExposureDuration(float seconds) { mExposureDuration = seconds; } 140 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 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 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