Home | History | Annotate | Download | only in image
      1 /*
      2  * Copyright (C) 2016 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 #include "ip.rsh"
     18 #pragma rs_fp_relaxed
     19 
     20 int height;
     21 int width;
     22 static int radius;
     23 
     24 rs_allocation InPixel;
     25 rs_allocation ScratchPixel1;
     26 rs_allocation ScratchPixel2;
     27 
     28 const int MAX_RADIUS = 25;
     29 
     30 // Store our coefficients here
     31 static half gaussian[MAX_RADIUS * 2 + 1];
     32 
     33 void setRadius(int rad) {
     34     radius = rad;
     35     // Compute gaussian weights for the blur
     36     // e is the euler's number
     37     half e = 2.718281828459045f;
     38     half pi = 3.1415926535897932f;
     39     // g(x) = ( 1 / sqrt( 2 * pi ) * sigma) * e ^ ( -x^2 / 2 * sigma^2 )
     40     // x is of the form [-radius .. 0 .. radius]
     41     // and sigma varies with radius.
     42     // Based on some experimental radius values and sigma's
     43     // we approximately fit sigma = f(radius) as
     44     // sigma = radius * 0.4  + 0.6
     45     // The larger the radius gets, the more our gaussian blur
     46     // will resemble a box blur since with large sigma
     47     // the gaussian curve begins to lose its shape
     48     half sigma = 0.4f * (half)radius + 0.6f;
     49 
     50     // Now compute the coefficints
     51     // We will store some redundant values to save some math during
     52     // the blur calculations
     53     // precompute some values
     54     half coeff1 = 1.0f / (sqrt( 2.0f * pi ) * sigma);
     55     half coeff2 = - 1.0f / (2.0f * sigma * sigma);
     56 
     57     half normalizeFactor = 0.0f;
     58     half halfR = 0.0f;
     59     for (int r = -radius; r <= radius; r ++) {
     60         halfR = (half)r;
     61         gaussian[r + radius] = coeff1 * pow(e, halfR * halfR * coeff2);
     62         normalizeFactor += gaussian[r + radius];
     63     }
     64 
     65     //Now we need to normalize the weights because all our coefficients need to add up to one
     66     normalizeFactor = 1.0f / normalizeFactor;
     67     for (int r = -radius; r <= radius; r ++) {
     68         halfR = (half)r;
     69         gaussian[r + radius] *= normalizeFactor;
     70     }
     71 }
     72 
     73 half4 RS_KERNEL copyIn(uchar4 in) {
     74     return convert_half4(in);
     75 }
     76 
     77 uchar4 RS_KERNEL vert(uint32_t x, uint32_t y) {
     78     half3 blurredPixel = 0;
     79     int gi = 0;
     80     uchar4 out;
     81     if ((y > radius) && (y < (height - radius))) {
     82         for (int r = -radius; r <= radius; r ++) {
     83             half4 i = rsGetElementAt_half4(ScratchPixel2, x, y + r);
     84             blurredPixel += i.xyz * gaussian[gi++];
     85         }
     86     } else {
     87         for (int r = -radius; r <= radius; r ++) {
     88             int validH = clamp((int)y + r, (int)0, (int)(height - 1));
     89             half4 i = rsGetElementAt_half4(ScratchPixel2, x, validH);
     90             blurredPixel += i.xyz * gaussian[gi++];
     91         }
     92     }
     93 
     94     out.xyz = convert_uchar3(clamp(blurredPixel, (half) 0.f, (half) 255.f));
     95     out.w = 0xff;
     96     return out;
     97 }
     98 
     99 half4 RS_KERNEL horz(uint32_t x, uint32_t y) {
    100     half4 blurredPixel = 0;
    101     int gi = 0;
    102     if ((x > radius) && (x < (width - radius))) {
    103         for (int r = -radius; r <= radius; r ++) {
    104             half4 i = rsGetElementAt_half4(ScratchPixel1, x + r, y);
    105             blurredPixel += i * gaussian[gi++];
    106         }
    107     } else {
    108         for (int r = -radius; r <= radius; r ++) {
    109             // Stepping left and right away from the pixel
    110             int validX = clamp((int)x + r, (int)0, (int)(width - 1));
    111             half4 i = rsGetElementAt_half4(ScratchPixel1, validX, y);
    112             blurredPixel += i * gaussian[gi++];
    113         }
    114     }
    115 
    116     return blurredPixel;
    117 }
    118