1dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford/* 2dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * Copyright (C) 2015 The Android Open Source Project 3dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * 4dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * Licensed under the Apache License, Version 2.0 (the "License"); 5dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * you may not use this file except in compliance with the License. 6dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * You may obtain a copy of the License at 7dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * 8dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * http://www.apache.org/licenses/LICENSE-2.0 9dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * 10dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * Unless required by applicable law or agreed to in writing, software 11dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * distributed under the License is distributed on an "AS IS" BASIS, 12dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * See the License for the specific language governing permissions and 14dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * limitations under the License. 15dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford */ 16dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 17dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordpackage rs.example.android.com.healingbrush; 18dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 19dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.graphics.Bitmap; 20dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.graphics.Canvas; 21dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.graphics.Color; 22dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.graphics.Paint; 23dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.graphics.Path; 24dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.graphics.Rect; 25dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.support.v8.renderscript.Allocation; 26dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.support.v8.renderscript.Element; 27dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.support.v8.renderscript.RenderScript; 28dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.support.v8.renderscript.Script; 29dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.support.v8.renderscript.Type; 30dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport android.util.Log; 31dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 32dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordimport com.example.android.rs.sample.ScriptC_healing; 33dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 34dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hofordpublic class Healing { 35dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford private static final String TAG = "Healing"; 36dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Rect mRoiBounds; // bounding box of the ROI 37dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford float[] mPointsXY; // polygon point in original image coordnates 38dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford int mCutOffsetX; // image coords of the cut (mPointsXY - mPasteOffX + mCutOffsetX) 39dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford int mCutOffsetY; // image coords of the cut (mPointsXY - mPasteOffY + mCutOffsetY) 40dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap mUndoBitmap; 41dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 42dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford public Healing(Rect roiBounds, float[] pointsXY, int cutOffsetX, int cutOffsetY) { 43dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford mRoiBounds = roiBounds; 44dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford mPointsXY = pointsXY; 45dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford mCutOffsetX = cutOffsetX; 46dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford mCutOffsetY = cutOffsetY; 47dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 48dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 49dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford private static Bitmap buildMask(Rect rec, float[] xy) { 50dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap bitmap = Bitmap.createBitmap(rec.width(), rec.height(), Bitmap.Config.ALPHA_8); 51dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 52dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Canvas c = new Canvas(bitmap); 53dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Paint paint = new Paint(); 54dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford paint.setStyle(Paint.Style.FILL); 55dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford paint.setColor(Color.BLACK); 56dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Path path = new Path(); 57dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford for (int i = 0; i < xy.length; i += 2) { 58dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford if (i == 0) { 59dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford path.moveTo(xy[i] - rec.left, xy[i + 1] - rec.top); 60dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } else { 61dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford path.lineTo(xy[i] - rec.left, xy[i + 1] - rec.top); 62dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 63dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 64dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford path.close(); 65dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford c.drawPath(path, paint); 66dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford return bitmap; 67dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 68dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 69dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford /** 70dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * This function only assumes mPointsXY, mPasteOffX, mPasteOffY 71dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * 72dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * @param healing 73dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * @param rs 74dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford * @param image 75dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford */ 76dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford public void heal(ScriptC_healing healing, RenderScript rs, Bitmap image, Bitmap output) { 77dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford long time = System.nanoTime(); 78dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Type.Builder floatImage = new Type.Builder(rs, Element.F32_3(rs)); 79dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford floatImage.setX(mRoiBounds.width()); 80dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford floatImage.setY(mRoiBounds.height()); 81dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 82dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 83dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap maskBitmap = buildMask(mRoiBounds, mPointsXY); 84dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 85dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Allocation dest1 = Allocation.createTyped(rs, floatImage.create()); 86dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Allocation dest2 = Allocation.createTyped(rs, floatImage.create()); 87dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.set_dest1(dest1); 88dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.set_dest2(dest2); 89dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 90dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap destBitmap = createMutableBitmap(image, mRoiBounds.left, mRoiBounds.top, 91dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford mRoiBounds.width(), mRoiBounds.height()); 92dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Allocation dest_uc4 = Allocation.createFromBitmap(rs, destBitmap); 93dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.forEach_convert_to_f(dest_uc4, dest1); 94dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 95dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap src = createMutableBitmap(image, mCutOffsetX, mCutOffsetY, 96dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford mRoiBounds.width(), mRoiBounds.height()); 97dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Allocation src_f3 = Allocation.createTyped(rs, floatImage.create()); 98dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Allocation src_uc4 = Allocation.createFromBitmap(rs, src); 99dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.forEach_convert_to_f(src_uc4, src_f3); 100dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.set_src(src_f3); 101dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 102dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Allocation mask = Allocation.createFromBitmap(rs, maskBitmap); 103dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.set_mask(mask); 104dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 105dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Allocation laplace_f3 = Allocation.createTyped(rs, floatImage.create()); 106dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.set_laplace(laplace_f3); 107dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 108dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Script.LaunchOptions options = new Script.LaunchOptions(); 109dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford options.setX(1, mRoiBounds.width() - 1); 110dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford options.setY(1, mRoiBounds.height() - 1); 111dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.forEach_laplacian(laplace_f3, options); 112dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.forEach_copyMasked(mask, dest1); 113dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford int area = calcMaskArea(mask); 114dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 115dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford int steps = (int) Math.sqrt(area); 116dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 117dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford for (int i = 0; i < steps; i++) { 118dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.forEach_solve1(mask, dest2); 119dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.forEach_solve2(mask, dest1); 120dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 121dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 122dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.forEach_convert_to_uc(dest1, dest_uc4); 123dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford rs.finish(); 124dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 125dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford healing.forEach_alphaMask(dest_uc4, dest_uc4); 126dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford rs.finish(); 127dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 128dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford dest_uc4.copyTo(destBitmap); 129dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford rs.finish(); 130dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford destBitmap.setHasAlpha(true); 131dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford rs.finish(); 132dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford // build the undo 133dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford mUndoBitmap = Bitmap.createBitmap(mRoiBounds.width(), mRoiBounds.height(), 134dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap.Config.ARGB_8888); 135dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Canvas undoCanvas = new Canvas(mUndoBitmap); 136dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Rect undoRect = new Rect(0, 0, mRoiBounds.width(), mRoiBounds.height()); 137dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford undoCanvas.drawBitmap(output, mRoiBounds, undoRect, null); 138dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 139dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Canvas c = new Canvas(output); 140dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford c.drawBitmap(image, 0, 0, null); 141dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford c.drawBitmap(destBitmap, mRoiBounds.left, mRoiBounds.top, null); 142dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Log.v(TAG, " time to smart paste = " + (System.nanoTime() - time) / 1E6f + "ms"); 143dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 144dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 145dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap createMutableBitmap(Bitmap image, int x, int y, int width, int height) { 146dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap ret = Bitmap.createBitmap(image, x, y, width, height); 147dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford return ret.copy(Bitmap.Config.ARGB_8888, true); 148dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 149dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 150dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford private static int calcMaskArea(Allocation mask) { 151dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford int w = mask.getType().getX(); 152dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford int h = mask.getType().getY(); 153dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford byte[] data = new byte[w * h]; 154dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford mask.copyTo(data); 155dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford int count = 0; 156dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford int val = data[0]; 157dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford for (int i = 0; i < data.length; i++) { 158dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford if (data[i] != val) { 159dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford count++; 160dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 161dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 162dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford return count; 163dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 164dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford 165dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford Bitmap getmUndoBitmap() { 166dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford return mUndoBitmap; 167dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford } 168dbf58070bd1a228fc817ea5ddb5c08fe717aecd2hoford} 169