C++程序  |  255行  |  12.6 KB

/*
 * 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