美文网首页
opencv-android滤镜处理

opencv-android滤镜处理

作者: Peakmain | 来源:发表于2019-06-26 12:12 被阅读0次

ColorMatrix滤镜处理

方法很简单,直接新建一个bitmap去操作即可

  public static  Bitmap opencv(Bitmap bitmap){
        Bitmap dst= Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(),bitmap.getConfig());
        Canvas canvas=new Canvas(dst);
        Paint paint=new Paint();
        paint.setAntiAlias(true);
        paint.setDither(true);
        ColorMatrix colorMatrix=new ColorMatrix();
        //饱和 0->灰度图
        colorMatrix.setSaturation(0);
        paint.setColorFilter(new ColorMatrixColorFilter(colorMatrix));
        canvas.drawBitmap(bitmap,0,0,paint);
        return dst;
    }

效果图(第一张是原图,第二张是效果图)


image.png

矩阵乘法运算
参考百科:https://baike.sogou.com/v7527881.htm?fromTitle=%E7%9F%A9%E9%99%A3%E4%B9%98%E6%B3%95

image.png

setSaturation源码分析

    public void setSaturation(float sat) {
        reset();
        float[] m = mArray;

        final float invSat = 1 - sat;
        final float R = 0.213f * invSat;
        final float G = 0.715f * invSat;
        final float B = 0.072f * invSat;

        m[0] = R + sat; m[1] = G;       m[2] = B;
        m[5] = R;       m[6] = G + sat; m[7] = B;
        m[10] = R;      m[11] = G;      m[12] = B + sat;
    }

reset源码中我们可以看注释


image.png
[ 1 0 0 0 0   - red vector
  0 1 0 0 0   - green vector
  0 0 1 0 0   - blue vector
  0 0 0 1 0 ] - alpha vector

我们可以看到这个矩阵实际代表的是原图,回到setSaturation的源码,刚才我们传的值是0,所以我们把相关值,带进去之后会发现,灰图矩阵实际是

ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                0.213f,0.715f,0.072f,0,0,
                0.213f,0.715f,0.072f,0,0,
                0.213f,0.715f,0.072f,0,0,
                0,0,0,1,0,
        });

扩展

  • 底片效果
ColorMatrix colorMatrix = new ColorMatrix(new float[]{
                -1,0,0,0,255,
                0,-1,0,0,255,
                0,0,-1,0,255,
                0,0,0,1,0,
        });

总结:适合做色彩滤镜,但是无法做高斯模糊

Java Bitmap获取像素操作

  public static Bitmap gary(Bitmap bitmap) {
        Bitmap dst = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), bitmap.getConfig());
        //java层像素操作
        int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
        //第二个参数偏移量
        bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
        for (int i = 0; i < pixels.length; i++) {
            int pixel = pixels[I];
            int a = (pixel >> 24) & 0xff;
            int r = (pixel >> 16) & 0xff;
            int g = (pixel >> 8) & 0xff;
            int b = pixel & 0xff;
            // f=.0.213f*r+0.715f*g+0.072f*b;
            //灰度
            //int gery = (int) (0.213f * r + 0.715f * g + 0.072f * b);
            //黑白
            int gery = (a + r + g) / 3 > 125 ? 125 : 0;
            pixels[i] = (a << 24) | (gery << 16) | (gery << 8) | gery;
        }
        dst.setPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());
        return dst;
    }

Native层像素操作

ava_com_peakmain_mall_ndk_MainActivity_gray(JNIEnv *env, jobject instance,
                                             jobject bitmap) {


    AndroidBitmapInfo info;
    int res = AndroidBitmap_getInfo(env, bitmap, &info);

    if (res != 0) {
        return -1;
    }
    void *addrPtr;
    AndroidBitmap_lockPixels(env, bitmap, &addrPtr);
    if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
        for (int i = 0; i < info.width * info.height; ++i) {
            //+i移动指针
            uint32_t *pixel_p = reinterpret_cast<uint32_t *>(addrPtr) + I;
            uint32_t pixel = *pixel_p;

            int a = (pixel >> 24) & 0xff;
            int r = (pixel >> 16) & 0xff;
            int g = (pixel >> 8) & 0xff;
            int b = pixel & 0xff;
            // f = 0.213f * r + 0.715f * g + 0.072f * b
            int gery = (int) (0.213f * r + 0.715f * g + 0.072f * b);
            //重新设置回去
            *pixel_p = (a << 24) | (gery << 16) | (gery << 8) | gery;

        }
    } else if (info.format == ANDROID_BITMAP_FORMAT_RGB_565) {
        for (int i = 0; i < info.width * info.height; ++i) {
            uint16_t *pixel_p = reinterpret_cast<uint16_t *>(addrPtr) + I;
            uint16_t pixel = *pixel_p;
            //5 0001 1111->1f
            //6 0011 1111->3f
            int r = ((pixel >> 11) & 0x1f) << 3;//8->5
            int g = ((pixel >> 5) & 0x3f) << 2;//8->6
            int b = (pixel & 0x1f) << 3;//8->5
            // f = 0.213f * r + 0.715f * g + 0.072f * b
            int gery = (int) (0.213f * r + 0.715f * g + 0.072f * b);
            //重新设置回去
            *pixel_p = ((gery >> 3) << 11) | ((gery >> 2) << 5) | (gery >> 3);
        }
    }
    AndroidBitmap_unlockPixels(env, bitmap);
    return 1;
}

MainActivity层调用

    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inMutable = true;
        //最好的是ARGB8888 32位
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        // RGB_565比ARGB_8888小1 倍
        // ARGB_8888 -> RGB 565 RGB 5位R 6位G 5位B   565是16位
        Bitmap src = BitmapFactory.decodeResource(getResources(), R.mipmap.copy, options);
        gray(src);

        ImageView imageView2 = findViewById(R.id.image_2);
        imageView2.setImageBitmap(src);

    }
    
    public native int gray(Bitmap bitmap);

效果图


image.png

相关文章

网友评论

      本文标题:opencv-android滤镜处理

      本文链接:https://www.haomeiwen.com/subject/hrgbxctx.html