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 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 111 Scene::~Scene() { 112 } 113 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 125 void Scene::setHour(int hour) { 126 ALOGV("Hour set to: %d", hour); 127 mHour = hour % 24; 128 } 129 130 int Scene::getHour() { 131 return mHour; 132 } 133 134 void Scene::setExposureDuration(float seconds) { 135 mExposureDuration = seconds; 136 } 137 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 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 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