Home | History | Annotate | Download | only in healingbrush
      1 /*
      2  * Copyright (C) 2015 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 #pragma version(1)
     18 #pragma rs java_package_name(com.example.android.rs.sample)
     19 #pragma rs_fp_relaxed
     20 rs_allocation tmp;
     21 
     22 static rs_allocation createVectorAllocation(rs_data_type dt, int vecSize,
     23                                             int gDimX, int gDimY, int gDimZ) {
     24   rs_element element;
     25   rs_type type;
     26 
     27   if (vecSize == 1)
     28     element = rsCreateElement(dt);
     29   else
     30     element = rsCreateVectorElement(dt, vecSize);
     31 
     32   if (gDimY == 0) {
     33     type = rsCreateType(element, gDimX);
     34   } else {
     35     type = rsCreateType(element, gDimX, gDimY, gDimZ);
     36   }
     37   tmp = rsCreateAllocation(type);
     38   return tmp;
     39 }
     40 
     41 rs_allocation mImage;
     42 int2 mImgOffset;
     43 int2 mSearchOffset;           // offset to the region we will search
     44 rs_allocation mBorderValues;  // float3
     45 rs_allocation mBorderCoords;  // int2
     46 
     47 int mBorderLength;
     48 int2 __attribute__((kernel)) toInt_ss(int2 in) { return in - mImgOffset; }
     49 
     50 float3 __attribute__((kernel)) extractBorder_ss(uint2 in) {
     51   return convert_float3(rsGetElementAt_uchar4(mImage, in.x, in.y).xyz);
     52 }
     53 
     54 static float4 gCalcBounds(rs_allocation xy) {
     55   int len = rsAllocationGetDimX(xy);
     56   float2 min_xy = rsGetElementAt_float2(xy, 0);
     57   float2 max_xy = min_xy;
     58   for (int i = 1; i < len; i++) {
     59     float2 v = rsGetElementAt_float2(xy, i);
     60     min_xy = min(min_xy, v);
     61     max_xy = max(max_xy, v);
     62   }
     63 
     64   return (float4){min_xy.x, min_xy.y, max_xy.x, max_xy.y};
     65 }
     66 
     67 uint2 __attribute__((kernel)) toInt(float2 in) {
     68   return (uint2){(int)in.x, (int)in.y};
     69 }
     70 
     71 static int4 padRegionRect_ss(float4 rec) {
     72   int width = rec.z - rec.x;
     73   int height = rec.w - rec.y;
     74   int mWidth =
     75       (((int)(8 + width)) & ~3);  // bounding rectangle that is a power of 8 big
     76   int mHeight = (((int)(8 + height)) & ~3);
     77   int4 out = {(int)(rec.x - 1), (int)(rec.y - 1), mWidth + (int)(rec.x - 1),
     78               mHeight + (int)(rec.y - 1)};
     79   return out;
     80 }
     81 
     82 static int4 calcSearchRange_ss(int4 roiBounds, int imgWidth, int imgHeight,
     83                                int pad) {
     84   int2 size = roiBounds.zw - roiBounds.xy;
     85   int2 minr = max((int2){0, 0}, roiBounds.xy - size * (1 + pad));
     86   int2 maxr = min((int2){imgWidth, imgHeight}, roiBounds.zw + size * (1 + pad));
     87   return (int4){minr.x, minr.y, maxr.x, maxr.y};
     88 }
     89 
     90 float __attribute__((kernel)) bordercorrelation_ss(uint32_t x, uint32_t y) {
     91   float sum = 0.f;
     92   int2 delta = {x, y};
     93   delta += mSearchOffset;
     94 
     95   for (int i = 0; i < mBorderLength; i++) {
     96     int2 coord = rsGetElementAt_int2(mBorderCoords, i) + delta;
     97     float3 orig =
     98         convert_float3(rsGetElementAt_uchar4(mImage, coord.x, coord.y).xyz);
     99     float3 candidate = rsGetElementAt_float3(mBorderValues, i).xyz;
    100     sum += distance(orig, candidate);
    101   }
    102   return sum;
    103 }
    104 
    105 static int2 gfindMin_ss(rs_allocation fit, int4 regionInSearch) {
    106   int w = rsAllocationGetDimX(fit);
    107   int h = rsAllocationGetDimY(fit);
    108   float minFit = rsGetElementAt_float(fit, 0, 0);
    109   int2 fit_pos = {0, 0};
    110 
    111   for (int y = 0; y < h; y++) {
    112     for (int x = 0; x < w; x++) {
    113       int2 p = {x, y};
    114       p = (p - regionInSearch.xy) *
    115           (p - regionInSearch.zw);  // positive if outside of exclusion zone
    116       if (!(p.x < 0 && p.y < 0)) {
    117         float v = rsGetElementAt_float(fit, x, y);
    118         if (v < minFit) {
    119           minFit = v;
    120           fit_pos.x = x;
    121           fit_pos.y = y;
    122         }
    123       }
    124     }
    125   }
    126 
    127   return fit_pos;
    128 }
    129 
    130 static int width(int4 rec) { return rec.z - rec.x; }
    131 static int height(int4 rec) { return rec.w - rec.y; }
    132 
    133 /**
    134  *  Entry point to frind region
    135  */
    136 void findRegion(rs_allocation pointsXY, rs_allocation image, int imgWidth,
    137                 int imgHeight, rs_allocation ret) {
    138   rs_allocation fit;
    139 
    140   mImage = image;
    141 
    142   mBorderLength = rsAllocationGetDimX(pointsXY);
    143 
    144   float4 bounds = gCalcBounds(pointsXY);
    145 
    146   int4 roiBounds = padRegionRect_ss(bounds);
    147 
    148   int4 searchRange = calcSearchRange_ss(roiBounds, imgWidth, imgHeight, 2);
    149 
    150   int4 regionInSearch = roiBounds - searchRange.xyxy;
    151 
    152   mSearchOffset = searchRange.xy;
    153   mImgOffset = roiBounds.xy;
    154 
    155   mBorderCoords =
    156       createVectorAllocation(RS_TYPE_SIGNED_32, 2, mBorderLength, 0, 0);
    157 
    158   rsForEach(toInt, pointsXY, mBorderCoords);
    159 
    160   mBorderValues =
    161       createVectorAllocation(RS_TYPE_FLOAT_32, 3, mBorderLength, 0, 0);
    162 
    163   rsForEach(extractBorder_ss, mBorderCoords, mBorderValues);
    164   rsForEach(toInt_ss, mBorderCoords, mBorderCoords);
    165 
    166   int fit_width = width(searchRange) - width(roiBounds);
    167   int fit_height = height(searchRange) - height(roiBounds);
    168 
    169   fit = createVectorAllocation(RS_TYPE_FLOAT_32, 1, fit_width, fit_height, 0);
    170 
    171   int4 noZone = regionInSearch;
    172   noZone.xy -= convert_int2(bounds.zw - bounds.xy);
    173   noZone.zw += convert_int2(bounds.zw - bounds.xy);
    174 
    175   rsForEach(bordercorrelation_ss, fit);
    176 
    177   int2 fit_pos = gfindMin_ss(fit, noZone);
    178 
    179   rsSetElementAt_int2(ret, fit_pos + searchRange.xy, 0);
    180 }
    181