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 17package rs.example.android.com.healingbrush; 18 19import android.graphics.Bitmap; 20import android.graphics.Canvas; 21import android.graphics.Color; 22import android.graphics.Paint; 23import android.graphics.Path; 24import android.graphics.Rect; 25import android.graphics.RectF; 26import android.support.v8.renderscript.Allocation; 27import android.support.v8.renderscript.Element; 28import android.support.v8.renderscript.RenderScript; 29import android.support.v8.renderscript.Script; 30import android.support.v8.renderscript.Type; 31import android.util.Log; 32 33import com.example.android.rs.sample.ScriptC_find_region; 34 35public class FindRegion { 36 private static final String TAG = "FindRegion"; 37 38 Rect mRoiBounds; // bounding box of the ROI 39 int[] mPaste; // contains a copy where to paste 40 float[] mPointsXY; // polygon point in original image coordnates 41 Rect mSearchRange; // range to search in (original image coordinates 42 Bitmap mMaskBitmap; 43 44 int mCutOffsetX; // image coords of the cut (mPointsXY - mPasteOffX + mCutOffsetX) 45 int mCutOffsetY; // image coords of the cut (mPointsXY - mPasteOffY + mCutOffsetY) 46 47 public FindRegion(float[] xy, Bitmap img) { 48 mPointsXY = xy; 49 50 int imgWidth = img.getWidth(); 51 int imgHeight = img.getHeight(); 52 53 mRoiBounds = getBoundingRect(xy); 54 55 if (mRoiBounds.height() <= 2 || 56 mRoiBounds.left < 0 57 || mRoiBounds.top < 0 58 || mRoiBounds.right >= imgWidth 59 || mRoiBounds.bottom >= imgHeight) { 60 throw new RuntimeException("ROI to close to the edge of the image"); 61 } 62 63 mMaskBitmap = buildMask(mRoiBounds, mPointsXY); 64 mPaste = new int[this.mRoiBounds.width() * this.mRoiBounds.height()]; 65 img.getPixels(mPaste, 0, mRoiBounds.width(), 66 mRoiBounds.left, mRoiBounds.top, mRoiBounds.width(), mRoiBounds.height()); 67 68 mSearchRange = calcSearchRange(mRoiBounds, imgWidth, imgHeight); 69 } 70 71 public int getCutOffsetX() { 72 return mCutOffsetX; 73 } 74 75 public int getCutOffsetY() { 76 return mCutOffsetY; 77 } 78 79 public Rect getRoiBounds() { 80 return mRoiBounds; 81 } 82 83 84 public Rect findMatch(ScriptC_find_region findRegion, RenderScript mRs, Bitmap image) { 85 long time = System.nanoTime(); 86 Allocation border_coords; 87 Allocation border_values; 88 89 Type.Builder builderU32_2 = new Type.Builder(mRs, Element.U32_2(mRs)); 90 builderU32_2.setX(mPointsXY.length / 2); 91 border_coords = Allocation.createTyped(mRs, builderU32_2.create()); 92 93 Allocation border_coords_float; 94 border_coords_float = Allocation.createSized(mRs, Element.F32_2(mRs), mPointsXY.length / 2); 95 border_coords_float.copyFrom(mPointsXY); 96 findRegion.forEach_toInt(border_coords_float, border_coords); 97 findRegion.set_border_coords(border_coords); 98 99 findRegion.set_image(Allocation.createFromBitmap(mRs, image)); 100 101 Type.Builder builderF32_3 = new Type.Builder(mRs, Element.F32_3(mRs)); 102 builderF32_3.setX(mPointsXY.length / 2); 103 border_values = Allocation.createTyped(mRs, builderF32_3.create()); 104 findRegion.set_border_values(border_values); 105 findRegion.forEach_extractBorder(border_coords, border_values); 106 107 Type.Builder builderF32 = new Type.Builder(mRs, Element.F32(mRs)); 108 builderF32.setX(mSearchRange.width()); 109 builderF32.setY(mSearchRange.height()); 110 111 Allocation fit = Allocation.createTyped(mRs, builderF32.create()); 112 findRegion.set_borderLength(mPointsXY.length / 2); 113 int noSearch_x = mRoiBounds.left - mSearchRange.left; 114 int noSearch_y = mRoiBounds.top - mSearchRange.top; 115 findRegion.set_imagePosX(noSearch_x); 116 findRegion.set_imagePosY(noSearch_y); 117 Script.LaunchOptions options = new Script.LaunchOptions(); 118 options.setX(0, mSearchRange.width() - mRoiBounds.width()); 119 options.setY(0, mSearchRange.height() - mRoiBounds.height()); 120 findRegion.forEach_bordercorrelation(fit, options); 121 122 123 Log.v(TAG, "noSearch " + noSearch_x + ", " + noSearch_y); 124 Log.v(TAG, "noSearch " + mRoiBounds.width() + ", " + mRoiBounds.height()); 125 126 Allocation fit_max = Allocation.createSized(mRs, Element.I32_2(mRs), 1); 127 128 findRegion.invoke_findMin(fit, fit_max, noSearch_x, noSearch_y, 129 mRoiBounds.width(), mRoiBounds.height()); 130 int[] mina = new int[2]; 131 fit_max.copyTo(mina); 132 133 mCutOffsetX = mina[0] + mSearchRange.left; 134 mCutOffsetY = mina[1] + mSearchRange.top; 135 136 Log.v(TAG, "Time to find replacement= " + (System.nanoTime() - time) / 1E6f + "ms"); 137 138 return mRoiBounds; 139 } 140 141 /** 142 * Computes the bounding box of the polygon 143 * then pads and sizes to multiple of 8 144 * 145 * @param xy points of polygon [x1,y1,x2,y2,...] 146 * @return rectangle 147 */ 148 private static Rect getBoundingRect(float[] xy) { 149 RectF mRect = calcBounds(xy); 150 int mWidth = (((int) (8 + mRect.width())) & ~3); // bounding rectangle that is a power of 8 151 int mHeight = (((int) (8 + mRect.height())) & ~3); 152 int mPasteOffX = (int) mRect.left - 1; 153 int mPasteOffY = (int) mRect.top - 1; 154 return new Rect(mPasteOffX, mPasteOffY, mPasteOffX + mWidth, mPasteOffY + mHeight); 155 } 156 157 private static RectF calcBounds(float[] xy) { 158 float minx = xy[0], miny = xy[1]; 159 float maxx = xy[0], maxy = xy[1]; 160 for (int i = 0; i < xy.length; i += 2) { 161 minx = Math.min(minx, xy[i]); 162 maxx = Math.max(maxx, xy[i]); 163 miny = Math.min(miny, xy[i + 1]); 164 maxy = Math.max(maxy, xy[i + 1]); 165 } 166 RectF rect = new RectF(); 167 rect.set(minx, miny, maxx, maxy); 168 return rect; 169 } 170 171 private static Bitmap buildMask(Rect rec, float[] xy) { 172 Bitmap bitmap = Bitmap.createBitmap(rec.width(), rec.height(), Bitmap.Config.ALPHA_8); 173 174 Canvas c = new Canvas(bitmap); 175 Paint paint = new Paint(); 176 paint.setStyle(Paint.Style.FILL); 177 paint.setColor(Color.BLACK); 178 Path path = new Path(); 179 for (int i = 0; i < xy.length; i += 2) { 180 if (i == 0) { 181 path.moveTo(xy[i] - rec.left, xy[i + 1] - rec.top); 182 } else { 183 path.lineTo(xy[i] - rec.left, xy[i + 1] - rec.top); 184 } 185 } 186 path.close(); 187 c.drawPath(path, paint); 188 return bitmap; 189 } 190 191 private static Rect calcSearchRange(Rect mRoiBounds, int imgWidth, int imgHeight) { 192 int xmin = Math.max(0, (int) (mRoiBounds.left - mRoiBounds.width() * 2)); 193 int ymin = Math.max(0, (int) (mRoiBounds.top - mRoiBounds.height() * 2)); 194 int xmax = (int) (mRoiBounds.right + mRoiBounds.width() * 2); 195 int ymax = (int) (mRoiBounds.bottom + mRoiBounds.height() * 2); 196 xmax = Math.min(imgWidth, xmax); 197 ymax = Math.min(imgHeight, ymax); 198 xmax = Math.max(0, xmax); 199 ymax = Math.max(0, ymax); 200 return new Rect(xmin, ymin, xmax, ymax); 201 } 202} 203