/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <android/bitmap.h> #include <jni.h> #include <cmath> #include <cstdlib> #include <cstring> #include "utils.h" #include "_jni.h" using android::apps::photoeditor::utils::clamp; using android::apps::photoeditor::utils::LockBitmaps; using android::apps::photoeditor::utils::pixel32_t; using android::apps::photoeditor::utils::UnlockBitmaps; namespace { // Array of approximated CDF of normal distribution. // 1024 Entries in total. The array is approximated by sigmoid function and // the exact command in "octave" is: // x = [2/1029:1/1029:1025/1029]; // y = (-1/11.5*log(1./x-0.9999)+0.5)*766*0.9+766*0.05; const int kCDFEntries = 1024; const uint32_t normal_cdf[] = { 9, 33, 50, 64, 75, 84, 92, 99, 106, 112, 117, 122, 126, 130, 134, 138, 142, 145, 148, 150, 154, 157, 159, 162, 164, 166, 169, 170, 173, 175, 177, 179, 180, 182, 184, 186, 188, 189, 190, 192, 194, 195, 197, 198, 199, 200, 202, 203, 205, 206, 207, 208, 209, 210, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, 234, 235, 236, 236, 237, 238, 239, 239, 240, 240, 242, 242, 243, 244, 245, 245, 246, 247, 247, 248, 249, 249, 250, 250, 251, 252, 253, 253, 254, 255, 255, 256, 256, 257, 258, 258, 259, 259, 259, 260, 261, 262, 262, 263, 263, 264, 264, 265, 265, 266, 267, 267, 268, 268, 269, 269, 269, 270, 270, 271, 272, 272, 273, 273, 274, 274, 275, 275, 276, 276, 277, 277, 277, 278, 278, 279, 279, 279, 280, 280, 281, 282, 282, 282, 283, 283, 284, 284, 285, 285, 285, 286, 286, 287, 287, 288, 288, 288, 289, 289, 289, 290, 290, 290, 291, 292, 292, 292, 293, 293, 294, 294, 294, 295, 295, 296, 296, 296, 297, 297, 297, 298, 298, 298, 299, 299, 299, 299, 300, 300, 301, 301, 302, 302, 302, 303, 303, 304, 304, 304, 305, 305, 305, 306, 306, 306, 307, 307, 307, 308, 308, 308, 309, 309, 309, 309, 310, 310, 310, 310, 311, 312, 312, 312, 313, 313, 313, 314, 314, 314, 315, 315, 315, 315, 316, 316, 316, 317, 317, 317, 318, 318, 318, 319, 319, 319, 319, 319, 320, 320, 320, 321, 321, 322, 322, 322, 323, 323, 323, 323, 324, 324, 324, 325, 325, 325, 325, 326, 326, 326, 327, 327, 327, 327, 328, 328, 328, 329, 329, 329, 329, 329, 330, 330, 330, 330, 331, 331, 332, 332, 332, 333, 333, 333, 333, 334, 334, 334, 334, 335, 335, 335, 336, 336, 336, 336, 337, 337, 337, 337, 338, 338, 338, 339, 339, 339, 339, 339, 339, 340, 340, 340, 340, 341, 341, 342, 342, 342, 342, 343, 343, 343, 344, 344, 344, 344, 345, 345, 345, 345, 346, 346, 346, 346, 347, 347, 347, 347, 348, 348, 348, 348, 349, 349, 349, 349, 349, 349, 350, 350, 350, 350, 351, 351, 352, 352, 352, 352, 353, 353, 353, 353, 354, 354, 354, 354, 355, 355, 355, 355, 356, 356, 356, 356, 357, 357, 357, 357, 358, 358, 358, 358, 359, 359, 359, 359, 359, 359, 359, 360, 360, 360, 360, 361, 361, 362, 362, 362, 362, 363, 363, 363, 363, 364, 364, 364, 364, 365, 365, 365, 365, 366, 366, 366, 366, 366, 367, 367, 367, 367, 368, 368, 368, 368, 369, 369, 369, 369, 369, 369, 370, 370, 370, 370, 370, 371, 371, 372, 372, 372, 372, 373, 373, 373, 373, 374, 374, 374, 374, 374, 375, 375, 375, 375, 376, 376, 376, 376, 377, 377, 377, 377, 378, 378, 378, 378, 378, 379, 379, 379, 379, 379, 379, 380, 380, 380, 380, 381, 381, 381, 382, 382, 382, 382, 383, 383, 383, 383, 384, 384, 384, 384, 385, 385, 385, 385, 385, 386, 386, 386, 386, 387, 387, 387, 387, 388, 388, 388, 388, 388, 389, 389, 389, 389, 389, 389, 390, 390, 390, 390, 391, 391, 392, 392, 392, 392, 392, 393, 393, 393, 393, 394, 394, 394, 394, 395, 395, 395, 395, 396, 396, 396, 396, 396, 397, 397, 397, 397, 398, 398, 398, 398, 399, 399, 399, 399, 399, 399, 400, 400, 400, 400, 400, 401, 401, 402, 402, 402, 402, 403, 403, 403, 403, 404, 404, 404, 404, 405, 405, 405, 405, 406, 406, 406, 406, 406, 407, 407, 407, 407, 408, 408, 408, 408, 409, 409, 409, 409, 409, 409, 410, 410, 410, 410, 411, 411, 412, 412, 412, 412, 413, 413, 413, 413, 414, 414, 414, 414, 415, 415, 415, 415, 416, 416, 416, 416, 417, 417, 417, 417, 418, 418, 418, 418, 419, 419, 419, 419, 419, 419, 420, 420, 420, 420, 421, 421, 422, 422, 422, 422, 423, 423, 423, 423, 424, 424, 424, 425, 425, 425, 425, 426, 426, 426, 426, 427, 427, 427, 427, 428, 428, 428, 429, 429, 429, 429, 429, 429, 430, 430, 430, 430, 431, 431, 432, 432, 432, 433, 433, 433, 433, 434, 434, 434, 435, 435, 435, 435, 436, 436, 436, 436, 437, 437, 437, 438, 438, 438, 438, 439, 439, 439, 439, 439, 440, 440, 440, 441, 441, 442, 442, 442, 443, 443, 443, 443, 444, 444, 444, 445, 445, 445, 446, 446, 446, 446, 447, 447, 447, 448, 448, 448, 449, 449, 449, 449, 449, 450, 450, 450, 451, 451, 452, 452, 452, 453, 453, 453, 454, 454, 454, 455, 455, 455, 456, 456, 456, 457, 457, 457, 458, 458, 458, 459, 459, 459, 459, 460, 460, 460, 461, 461, 462, 462, 462, 463, 463, 463, 464, 464, 465, 465, 465, 466, 466, 466, 467, 467, 467, 468, 468, 469, 469, 469, 469, 470, 470, 470, 471, 472, 472, 472, 473, 473, 474, 474, 474, 475, 475, 476, 476, 476, 477, 477, 478, 478, 478, 479, 479, 479, 480, 480, 480, 481, 482, 482, 483, 483, 484, 484, 484, 485, 485, 486, 486, 487, 487, 488, 488, 488, 489, 489, 489, 490, 490, 491, 492, 492, 493, 493, 494, 494, 495, 495, 496, 496, 497, 497, 498, 498, 499, 499, 499, 500, 501, 502, 502, 503, 503, 504, 504, 505, 505, 506, 507, 507, 508, 508, 509, 509, 510, 510, 511, 512, 513, 513, 514, 515, 515, 516, 517, 517, 518, 519, 519, 519, 520, 521, 522, 523, 524, 524, 525, 526, 526, 527, 528, 529, 529, 530, 531, 532, 533, 534, 535, 535, 536, 537, 538, 539, 539, 540, 542, 543, 544, 545, 546, 547, 548, 549, 549, 550, 552, 553, 554, 555, 556, 558, 559, 559, 561, 562, 564, 565, 566, 568, 569, 570, 572, 574, 575, 577, 578, 579, 582, 583, 585, 587, 589, 590, 593, 595, 597, 599, 602, 604, 607, 609, 612, 615, 618, 620, 624, 628, 631, 635, 639, 644, 649, 654, 659, 666, 673, 680, 690, 700, 714}; extern "C" JNIEXPORT void JNICALL Java_com_android_photoeditor_filters_ImageUtils_nativeHEQ( JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { pHEQType f = (pHEQType)JNIFunc[JNI_HEQ].func_ptr; return f(env, obj, src_bitmap, dst_bitmap, scale); } extern "C" void HEQ( JNIEnv *env, jobject obj, jobject src_bitmap, jobject dst_bitmap, jfloat scale) { AndroidBitmapInfo src_info; AndroidBitmapInfo dst_info; void* src_pixels; void* dst_pixels; int ret = LockBitmaps( env, src_bitmap, dst_bitmap, &src_info, &dst_info, &src_pixels, &dst_pixels); if (ret < 0) { LOGE("LockBitmaps in HEQ failed, error=%d", ret); return; } const int kEnergyLevels = 766; // 255 * 3 + 1 // The energy has the range of [0, kEnergyLevels] int accumulated_histogram[kEnergyLevels]; memset(accumulated_histogram, 0, sizeof(accumulated_histogram)); // Store all the energy in the dst_pixels pixel32_t* dst = reinterpret_cast<pixel32_t*>(dst_pixels); pixel32_t const* src = reinterpret_cast<pixel32_t const*>(src_pixels); pixel32_t const* src_end = reinterpret_cast<pixel32_t const*>( reinterpret_cast<char const*>(src) + src_info.stride * src_info.height); while (src < src_end) { dst->rgba32 = src->rgba8[0] + src->rgba8[1] + src->rgba8[2]; ++src; ++dst; } // Build up the accumulated histogram table by ignoring borders (1/20 = 5% width). float border_thickness_ratio = 0.05; int y_border_thickness = dst_info.height * border_thickness_ratio; pixel32_t* dst_line = reinterpret_cast<pixel32_t*>( reinterpret_cast<char*>(dst_pixels) + dst_info.stride * y_border_thickness); pixel32_t* dst_line_end = reinterpret_cast<pixel32_t*>( reinterpret_cast<char*>(dst_pixels) + dst_info.stride * (dst_info.height - y_border_thickness)); int x_border_thickness = dst_info.width * border_thickness_ratio; int x_border_end = dst_info.width - x_border_thickness; while (dst_line < dst_line_end) { pixel32_t* dp = dst_line + x_border_thickness; pixel32_t* dp_end = dst_line + x_border_end; while (dp < dp_end) { ++accumulated_histogram[dp->rgba32]; ++dp; } dst_line = reinterpret_cast<pixel32_t*>( reinterpret_cast<char*>(dst_line) + dst_info.stride); } for (int i = 1; i < kEnergyLevels; i++) { accumulated_histogram[i] += accumulated_histogram[i - 1]; } uint32_t const* src_line = reinterpret_cast<uint32_t const*>(src_pixels); dst_line = reinterpret_cast<pixel32_t*>(dst_pixels); dst_line_end = reinterpret_cast<pixel32_t*>(reinterpret_cast<char*>(dst_line) + dst_info.height * dst_info.stride); // The whole process is done by apply the HEQ result with a mask. // The mask is a curve segmented by the energy_middle which could be tuned // based on each bitmap. For the lower part, the mask tries to make the change // significant for greater energy. For the smaller part, the mask does the // contrary. The two curve should be continuous on the energy_middle so the // final result is more natural. In this implementation, what I defined is two // curve based on the energy 'e', for the smaller part, e^2 is used. For the // greater part, e^1.5 is used. That is, for pixel with energy 'e', the mask // is obtained by: // if e > energy_middle // (e - energy_middle)^1.5 / (765 - energy_middle)^1.5 // else // (e - energy_middle)^2 / (energy_middle)^2 const int kShiftBits = 10; const int kShiftValue = (1 << kShiftBits); const int scale_shifted = scale * kShiftValue; const int normalization_scale_shifted = (1.0 - scale) * kShiftValue; const int energy_middle = 382; // 765 / 2 = 382.5 const int normalization_low = 7481; // (765 - 382.5)^1.5 const int normalization_high = 146307; // 382.5^2 int total_pixels = accumulated_histogram[kEnergyLevels - 1]; while (dst_line < dst_line_end) { pixel32_t const* sp = reinterpret_cast<pixel32_t const*>(src_line); pixel32_t* dp = dst_line; pixel32_t* dp_end = dp + dst_info.width; while (dp < dp_end) { if (!dp->rgba32) { // the energy is 0, no changes will be made. dp->rgba32 = sp->rgba32; } else { uint32_t energy = dp->rgba32; int mask_normalization; int mask_value = energy - energy_middle; if (mask_value > 0) { mask_value = mask_value * sqrt(mask_value); mask_normalization = normalization_low; } else { mask_value *= mask_value; mask_normalization = normalization_high; } mask_value = ((mask_value * scale_shifted) + (mask_normalization * (normalization_scale_shifted))) >> kShiftBits; // The final picture is masked by the original energy. // Assumption: Lower energy can result in low-confidence information and // higher energy indicates good confidence. // Therefore, pixels with low and high confidence should not be changed // greatly. uint32_t dst_energy = normal_cdf[ kCDFEntries * accumulated_histogram[energy] / total_pixels]; dst_energy = (energy * mask_value + dst_energy * (mask_normalization - mask_value)) / mask_normalization; // Ensure there is no RGB value will be greater than 255. uint32_t max_energy = energy * 255 / MAX3(sp->rgba8[0], sp->rgba8[1], sp->rgba8[2]); if (dst_energy > max_energy) { dst_energy = max_energy; } dst_energy = (dst_energy << kShiftBits) / energy; uint32_t dst_red = (sp->rgba8[0] * dst_energy) >> kShiftBits; uint32_t dst_green = (sp->rgba8[1] * dst_energy) >> kShiftBits; uint32_t dst_blue = (sp->rgba8[2] * dst_energy) >> kShiftBits; dp->rgba32 = (sp->rgba8[3] << 24) | (dst_blue << 16) | (dst_green << 8) | dst_red; } dp++; sp++; } src_line = reinterpret_cast<uint32_t const*>( reinterpret_cast<char const*>(src_line) + src_info.stride); dst_line = reinterpret_cast<pixel32_t*>( reinterpret_cast<char*>(dst_line) + dst_info.stride); } UnlockBitmaps(env, src_bitmap, dst_bitmap); } } // namespace