OSDN Git Service

Added sobel filter for edge function.
authorRuben Brunk <rubenbrunk@google.com>
Tue, 11 Dec 2012 02:50:10 +0000 (18:50 -0800)
committerRuben Brunk <rubenbrunk@google.com>
Thu, 13 Dec 2012 00:35:23 +0000 (16:35 -0800)
Change-Id: I4d59a96585f4902cd01d26ff68c777b542041132

jni/Android.mk
jni/filters/edge.c [new file with mode: 0644]
res/values/filtershow_ids.xml
res/values/filtershow_strings.xml
src/com/android/gallery3d/filtershow/FilterShowActivity.java
src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java [new file with mode: 0644]

index 8a2fc9e..6f12b3e 100644 (file)
@@ -29,6 +29,7 @@ LOCAL_SRC_FILES := filters/bw.c \
                    filters/gradient.c \
                    filters/saturated.c \
                    filters/exposure.c \
+                   filters/edge.c \
                    filters/contrast.c \
                    filters/hue.c \
                    filters/shadows.c \
diff --git a/jni/filters/edge.c b/jni/filters/edge.c
new file mode 100644 (file)
index 0000000..9f5d88f
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <math.h>
+#include "filters.h"
+
+void JNIFUNCF(ImageFilterEdge, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat p)
+{
+    char* destination = 0;
+    AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
+
+    // using contrast function:
+    // f(v) = exp(-alpha * v^beta)
+    // use beta ~ 1
+
+    float const alpha = 5.0f;
+    float const beta = p;
+    float const c_min = 100.0f;
+    float const c_max = 500.0f;
+
+    // pixels must be 4 bytes
+    char * dst = destination;
+
+    int j, k;
+    char * ptr = destination;
+    int row_stride = 4 * width;
+
+    // set 2 row buffer (avoids bitmap copy)
+    int buf_len = 2 * row_stride;
+    char buf[buf_len];
+    int buf_row_ring = 0;
+
+    // set initial buffer to black
+    memset(buf, 0, buf_len * sizeof(char));
+    for (j = 3; j < buf_len; j+=4) {
+        *(buf + j) = 255;  // set initial alphas
+    }
+
+    // apply sobel filter
+    for (j = 1; j < height - 1; j++) {
+
+        for (k = 1; k < width - 1; k++){
+            int loc = j * row_stride + k * 4;
+
+            float bestx = 0.0f;
+            int l;
+            for (l = 0; l < 3; l++) {
+                float tmp = 0.0f;
+                tmp += *(ptr + (loc - row_stride + 4 + l));
+                tmp += *(ptr + (loc + 4 + l)) * 2.0f;
+                tmp += *(ptr + (loc + row_stride + 4 + l));
+                tmp -= *(ptr + (loc - row_stride - 4 + l));
+                tmp -= *(ptr + (loc - 4 + l)) * 2.0f;
+                tmp -= *(ptr + (loc + row_stride - 4 + l));
+                if (fabs(tmp) > fabs(bestx)) {
+                    bestx = tmp;
+                }
+            }
+
+            float besty = 0.0f;
+            for (l = 0; l < 3; l++) {
+                float tmp = 0.0f;
+                tmp -= *(ptr + (loc - row_stride - 4 + l));
+                tmp -= *(ptr + (loc - row_stride + l)) * 2.0f;
+                tmp -= *(ptr + (loc - row_stride + 4 + l));
+                tmp += *(ptr + (loc + row_stride - 4 + l));
+                tmp += *(ptr + (loc + row_stride + l)) * 2.0f;
+                tmp += *(ptr + (loc + row_stride + 4 + l));
+                if (fabs(tmp) > fabs(besty)) {
+                    besty = tmp;
+                }
+            }
+
+            // compute gradient magnitude
+            float mag = sqrt(bestx * bestx + besty * besty);
+
+            // clamp
+            mag = MIN(MAX(c_min, mag), c_max);
+
+            // scale to [0, 1]
+            mag = (mag - c_min) / (c_max - c_min);
+
+            float ret = 1.0f - exp (- alpha * pow(mag, beta));
+            ret = 255 * ret;
+
+            int off = k * 4;
+            *(buf + buf_row_ring + off) = ret;
+            *(buf + buf_row_ring + off + 1) = ret;
+            *(buf + buf_row_ring + off + 2) = ret;
+            *(buf + buf_row_ring + off + 3) = *(ptr + loc + 3);
+        }
+
+        buf_row_ring += row_stride;
+        buf_row_ring %= buf_len;
+
+        if (j - 1 >= 0) {
+            memcpy((dst + row_stride * (j - 1)), (buf + buf_row_ring), row_stride * sizeof(char));
+        }
+
+    }
+    buf_row_ring += row_stride;
+    buf_row_ring %= buf_len;
+    int second_last_row = row_stride * (height - 2);
+    memcpy((dst + second_last_row), (buf + buf_row_ring), row_stride * sizeof(char));
+
+    // set last row to black
+    int last_row = row_stride * (height - 1);
+    memset((dst + last_row), 0, row_stride * sizeof(char));
+    for (j = 3; j < row_stride; j+=4) {
+        *(dst + last_row + j) = 255;  // set alphas
+    }
+    AndroidBitmap_unlockPixels(env, bitmap);
+}
index 7f7c98b..4ccbd96 100644 (file)
@@ -31,4 +31,5 @@
     <item type="id" name="sharpenButton" />
     <item type="id" name="curvesButtonRGB" />
     <item type="id" name="negativeButton" />
+    <item type="id" name="edgeButton" />
 </resources>
index e011396..5095e48 100644 (file)
     <string name="negative">Negative</string>
     <!--  Label for having no filters applied to the image [CHAR LIMIT=10] -->
     <string name="none" msgid="3601545724573307541">None</string>
+    <!--  Label for the image edges effect (highlights edges in image) [CHAR LIMIT=10] -->
+    <string name="edge">Edges</string>
 
     <!--  Labels for the curves tool -->
 
index 6275ae6..a3da0c6 100644 (file)
@@ -61,6 +61,7 @@ import com.android.gallery3d.filtershow.filters.ImageFilterBorder;
 import com.android.gallery3d.filtershow.filters.ImageFilterBwFilter;
 import com.android.gallery3d.filtershow.filters.ImageFilterContrast;
 import com.android.gallery3d.filtershow.filters.ImageFilterCurves;
+import com.android.gallery3d.filtershow.filters.ImageFilterEdge;
 import com.android.gallery3d.filtershow.filters.ImageFilterExposure;
 import com.android.gallery3d.filtershow.filters.ImageFilterFx;
 import com.android.gallery3d.filtershow.filters.ImageFilterHue;
@@ -309,7 +310,8 @@ public class FilterShowActivity extends Activity implements OnItemClickListener,
                 new ImageFilterHue(),
                 new ImageFilterSaturated(),
                 new ImageFilterBwFilter(),
-                new ImageFilterNegative()
+                new ImageFilterNegative(),
+                new ImageFilterEdge()
         };
 
         for (int i = 0; i < filters.length; i++) {
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
new file mode 100644 (file)
index 0000000..e2ce0da
--- /dev/null
@@ -0,0 +1,40 @@
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+
+import com.android.gallery3d.R;
+
+public class ImageFilterEdge extends ImageFilter {
+
+    public ImageFilterEdge() {
+        mName = "Edge";
+        mPreviewParameter = 0;
+    }
+
+    native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float p);
+
+    @Override
+    public int getButtonId() {
+        return R.id.edgeButton;
+    }
+
+    @Override
+    public int getTextId() {
+        return R.string.edge;
+    }
+
+    @Override
+    public boolean isNil() {
+        return false;
+    }
+
+    @Override
+    public Bitmap apply(Bitmap bitmap, float scaleFactor, boolean highQuality) {
+        int w = bitmap.getWidth();
+        int h = bitmap.getHeight();
+        float p = mParameter + 101;
+        p = (float) p / 100;
+        nativeApplyFilter(bitmap, w, h, p);
+        return bitmap;
+    }
+}