【3D技术宅公社】XR数字艺术论坛  XR技术讨论 XR互动电影 定格动画

 找回密码
 立即注册

QQ登录

只需一步,快速开始

调查问卷
论坛即将给大家带来全新的技术服务,面向三围图形学、游戏、动画的全新服务论坛升级为UTF8版本后,中文用户名和用户密码中有中文的都无法登陆,请发邮件到324007255(at)QQ.com联系手动修改密码

3D技术论坛将以计算机图形学为核心,面向教育 推出国内的三维教育引擎该项目在持续研发当中,感谢大家的关注。

查看: 2397|回复: 0

Android图片素描效果

[复制链接]
发表于 2014-8-11 17:39:46 | 显示全部楼层 |阅读模式

现在很多相机应用都有图片滤镜,实现各种效果,素描是其中一种,我们怎么实现呢?

找到个栗子->使用canvas把照片转换成素描画,作者把原理讲的很清楚了,包括以下几步:


  • 去色,将图片变为灰度图,即黑白图;
  • 反相,得到每个像素的补色,具体效果就像照片的底片;
  • 高斯模糊,把反相后的像素值平均一下;
  • 颜色减淡,将第1步中的像素和第3步得到的像素值进行计算。
作者已经将代码托管到了github,但是是js写的,这里就是把它转换成android用的java而已…
去色[mw_shl_code=java,true]        public static int[] discolor(Bitmap bitmap) {

                int picHeight = bitmap.getHeight();
                int picWidth = bitmap.getWidth();

                int[] pixels = new int[picWidth * picHeight];
                bitmap.getPixels(pixels, 0, picWidth, 0, 0, picWidth, picHeight);

                for (int i = 0; i < picHeight; ++i) {
                        for (int j = 0; j < picWidth; ++j) {
                                int index = i * picWidth + j;
                                int color = pixels[index];
                                int r = (color & 0x00ff0000) >> 16;
                                int g = (color & 0x0000ff00) >> 8;
                                int b = (color & 0x000000ff);
                                int grey = (int) (r * KR + g * KG + b * KB);
                                pixels[index] = grey << 16 | grey << 8 | grey | 0xff000000;
                        }
                }
               
                return pixels;

        }[/mw_shl_code]
反相[mw_shl_code=java,true]public static int[] reverseColor(int[] pixels) {
               
                int length = pixels.length;
                int[] result = new int[length];
                for (int i = 0; i < length; ++i) {
                        int color = pixels;
                       
                        int r = 255 - (color & 0x00ff0000) >> 16;
                        int g = 255 - (color & 0x0000ff00) >> 8;
                        int b = 255 - (color & 0x000000ff);
                        result = r << 16 | g << 8 | b | 0xff000000;
                }
                return result;
               
        }[/mw_shl_code]高斯模糊[mw_shl_code=java,true]        public static void gaussBlur(int[] data, int width, int height, int radius,
                        float sigma) {

                float pa = (float) (1 / (Math.sqrt(2 * Math.PI) * sigma));
                float pb = -1.0f / (2 * sigma * sigma);

                // generate the Gauss Matrix
                float[] gaussMatrix = new float[radius * 2 + 1];
                float gaussSum = 0f;
                for (int i = 0, x = -radius; x <= radius; ++x, ++i) {
                        float g = (float) (pa * Math.exp(pb * x * x));
                        gaussMatrix = g;
                        gaussSum += g;
                }

                for (int i = 0, length = gaussMatrix.length; i < length; ++i) {
                        gaussMatrix /= gaussSum;
                }

                // x direction
                for (int y = 0; y < height; ++y) {
                        for (int x = 0; x < width; ++x) {
                                float r = 0, g = 0, b = 0;
                                gaussSum = 0;
                                for (int j = -radius; j <= radius; ++j) {
                                        int k = x + j;
                                        if (k >= 0 && k < width) {
                                                int index = y * width + k;
                                                int color = data[index];
                                                int cr = (color & 0x00ff0000) >> 16;
                                                int cg = (color & 0x0000ff00) >> 8;
                                                int cb = (color & 0x000000ff);

                                                r += cr * gaussMatrix[j + radius];
                                                g += cg * gaussMatrix[j + radius];
                                                b += cb * gaussMatrix[j + radius];

                                                gaussSum += gaussMatrix[j + radius];
                                        }
                                }

                                int index = y * width + x;
                                int cr = (int) (r / gaussSum);
                                int cg = (int) (g / gaussSum);
                                int cb = (int) (b / gaussSum);
                               
                                data[index] = cr << 16 | cg << 8 | cb | 0xff000000;
                        }
                }

                // y direction
                for (int x = 0; x < width; ++x) {
                        for (int y = 0; y < height; ++y) {
                                float r = 0, g = 0, b = 0;
                                gaussSum = 0;
                                for (int j = -radius; j <= radius; ++j) {
                                        int k = y + j;
                                        if (k >= 0 && k < height) {
                                                int index = k * width + x;
                                                int color = data[index];
                                                int cr = (color & 0x00ff0000) >> 16;
                                                int cg = (color & 0x0000ff00) >> 8;
                                                int cb = (color & 0x000000ff);

                                                r += cr * gaussMatrix[j + radius];
                                                g += cg * gaussMatrix[j + radius];
                                                b += cb * gaussMatrix[j + radius];

                                                gaussSum += gaussMatrix[j + radius];
                                        }
                                }

                                int index = y * width + x;
                                int cr = (int) (r / gaussSum);
                                int cg = (int) (g / gaussSum);
                                int cb = (int) (b / gaussSum);
                                data[index] = cr << 16 | cg << 8 | cb | 0xff000000;
                        }
                }
        }[/mw_shl_code]
颜色减淡[mw_shl_code=java,true]        public static void colorDodge(int[] baseColor, int[] mixColor) {

                for (int i = 0, length = baseColor.length; i < length; ++i) {
                        int bColor = baseColor;
                        int br = (bColor & 0x00ff0000) >> 16;
                        int bg = (bColor & 0x0000ff00) >> 8;
                        int bb = (bColor & 0x000000ff);

                        int mColor = mixColor;
                        int mr = (mColor & 0x00ff0000) >> 16;
                        int mg = (mColor & 0x0000ff00) >> 8;
                        int mb = (mColor & 0x000000ff);

                        int nr = colorDodgeFormular(br, mr);
                        int ng = colorDodgeFormular(bg, mg);
                        int nb = colorDodgeFormular(bb, mb);

                        baseColor = nr << 16 | ng << 8 | nb | 0xff000000;
                }

        }

        private static int colorDodgeFormular(int base, int mix) {
               
                int result = base + (base * mix) / (255 - mix);
                result = result > 255 ? 255 : result;
                return result;
               
        }[/mw_shl_code]
最后将这些过程组合起来就可以得到一个素描画[mw_shl_code=java,true]        public static Bitmap testGaussBlur(Bitmap src, int r, int fai) {

                int width = src.getWidth();
                int height = src.getHeight();

                int[] pixels = Sketch.discolor(src);
                int[] copixels = Sketch.simpleReverseColor(pixels);
                Sketch.simpleGaussBlur(copixels, width, height, r, fai);
                Sketch.simpleColorDodge(pixels, copixels);

                Bitmap bitmap = Bitmap.createBitmap(pixels, width, height,
                                Config.RGB_565);
                return bitmap;

        }[/mw_shl_code]
下面是测试的实际效果图


从左到右依次为原图、灰度图、灰度反相图和最终的素描图。

其实由于灰度图对应到rgb空间后r、g、b的值是相同的,所以去色后面的计算过程可以简化,比如反相[mw_shl_code=java,true]public static int[] simpleReverseColor(int[] pixels) {
                int length = pixels.length;
                int[] result = new int[length];
                for (int i = 0; i < length; ++i) {
                        int color = pixels;
                        int b = 255 - (color & 0x000000ff);
                        result = b << 16 | b << 8 | b | 0xff000000;
                }
                return result;
        }[/mw_shl_code]这样可以加快一些计算速度,不过对于手机来说计算量还是太大,需要时间,高斯运算的时候需要指定采样半径,半径越大,模糊程度越高,计算次数随之也会增加,上面的取样半径都是10个像素,下面一张图是直接将原图高斯模糊的效果



代码看这里->http://download.csdn.net/detail/xu_fu/7068275



您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|3D数字艺术论坛 ( 沪ICP备14023054号 )

GMT+8, 2024-11-27 08:50

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表