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
20rs_allocation tmp;
21
22static 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
41rs_allocation mImage;
42int2 mImgOffset;
43int2 mSearchOffset;           // offset to the region we will search
44rs_allocation mBorderValues;  // float3
45rs_allocation mBorderCoords;  // int2
46
47int mBorderLength;
48int2 __attribute__((kernel)) toInt_ss(int2 in) { return in - mImgOffset; }
49
50float3 __attribute__((kernel)) extractBorder_ss(uint2 in) {
51  return convert_float3(rsGetElementAt_uchar4(mImage, in.x, in.y).xyz);
52}
53
54static 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
67uint2 __attribute__((kernel)) toInt(float2 in) {
68  return (uint2){(int)in.x, (int)in.y};
69}
70
71static 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
82static 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
90float __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
105static 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
130static int width(int4 rec) { return rec.z - rec.x; }
131static int height(int4 rec) { return rec.w - rec.y; }
132
133/**
134 *  Entry point to frind region
135 */
136void 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