Opencv-Java实现简单特效

Opencv-Java实现简单特效

承接上次opencv-java的简单使用,这次分享一些图片处理特效的实现。

这类仿照ps特效教程其实很多,但是大部分都是opencv和python版的,用java版opencv实现的资料较少。以下的很多公式都是在网上可以找到的,而且很多都有c版的实现,这里对照c版进行了一点翻译,还有一点自己的改动。

展示用的图片是缠流子,目前看来速写效果最好,之后看到好的图片直接处理之后就可以交速写作业了(笑)。

这段话可以不看,以下的算法并非本人实现的,因为我选择的大作业形式是系统构建,偏向的是系统,而不是内在算法!三个星期也不能指望我搞出什么大名堂(捷克小哥Photopea的demo都写了3年半),我还有其余7,8门课,必要的时候还要开摆。这里很多算法和实现都是网络上经过大家验证和认可的,但是基本没有什么人用opencv-java实现(至少我冲浪的时候没找到),所以我更多的是做整合、翻译工作。

中点打光
/**
    * 中心打光
    * @param image
    * @param Strength
    * @param value
    */
public static void centerLight(Mat image, int Strength, int value){
    Mat dst = new Mat(image.size(),image.type());
    double[] pixelArr = new double[3];
    // 获取行列
    int rows = image.rows(), cols = image.cols();
    // 光照中心
    int centerX = rows / 2 - value;
    int centerY = cols / 2 + value;
    int radius = Math.min(centerX,centerY);
    // 光照强度
    int strength = Strength;
    for (int i = 0;i<rows;i++){
        for (int j = 0;j<cols;j++){
            pixelArr = image.get(i,j).clone();
            // 计算当前点到中间点的距离
            double distance = Math.pow((centerY-j), 2)+Math.pow((centerX-i),2);
            double r = pixelArr[2], g = pixelArr[1], b = pixelArr[0];

            if(distance<radius*radius){
                double result = (strength*(1.0-Math.sqrt(distance)/radius));
                r = pixelArr[2] +result;
                g = pixelArr[1] +result;
                b = pixelArr[0] +result;
                // 判断边界
                pixelArr[2] = Math.min(255, Math.max(0,r));
                pixelArr[1] = Math.min(255, Math.max(0,g));
                pixelArr[0] = Math.min(255, Math.max(0,b));
                dst.put(i,j,pixelArr);
            }else{
                dst.put(i,j,pixelArr);
            }
        }
    }

    HighGui.imshow("光照中心",dst);
    waitKey();

}
素描效果

模拟ps彩色图片转为素描图片打印的过程。算法的原理流程如下:
1、去色;
2、复制去色图层,并且反色;关于反色可以参考芒果额另一篇文章opencv滤镜-反向滤镜;
3、对反色图像进行高斯模糊;
4、模糊后的图像叠加模式选择颜色减淡效果。
减淡公式:C =MINA+(A×B)/(255−B),255,其中C为混合结果,A为去色后的像素点,B为高斯模糊后的像素点。

/**
    * 素描特效
    * @param image
    */
public static void fastDraw(Mat image){
    Mat dst = new Mat(image.size(),image.type());
    double[] pixelArr = new double[3];

    for (int i=0;i<image.rows();i++){
        for (int j=0;j<image.cols();j++) {
            pixelArr = image.get(i, j).clone();
            double max = Math.max(
                    Math.max(pixelArr[0], pixelArr[1]),
                    pixelArr[2]
            );

            double min = Math.min(
                    Math.min(pixelArr[0], pixelArr[1]),
                    pixelArr[2]
            );

            for (int k = 0; k < 3; k++)
                pixelArr[k] = (max + min) / 2;
            dst.put(i, j, pixelArr);
        }
    }

    //进行反色
    Mat dsting = new Mat(image.size(), image.type());
    double[] pixelArr1 = new double[3];
    for (int i=0;i<dst.rows();i++){
        for (int j=0;j<dst.cols();j++){
            pixelArr = dst.get(i,j).clone();
            pixelArr1 = dsting.get(i,j).clone();
            for (int k=0;k<3;k++){
                pixelArr1[k] = 255 - pixelArr[k];
            }
            dsting.put(i,j,pixelArr1);
        }
    }

    //高斯模糊
    Imgproc.GaussianBlur(dsting,dsting,new Size(7,7),0);

    //模糊后对图像叠加模式选择色彩减淡效果
    // C = Min(A+(A*B)/(255-B),255)

    Mat result = new Mat(image.size(), image.type());
    double[] resultPixel = new double[3];
    for (int i=0;i<dst.rows();i++) {
        for (int j = 0; j < dst.cols(); j++) {
            pixelArr = dst.get(i,j).clone();
            pixelArr1 = dsting.get(i,j).clone();
            resultPixel = result.get(i,j).clone();
            for (int k=0;k<3;k++){
                double a = pixelArr[k], b=pixelArr1[k];
                double c = Math.min(
                        (a+(a*b)/(255-b)),
                        255
                );
                resultPixel[k] = c;

            }
            result.put(i,j,resultPixel);
        }
    }

    HighGui.imshow("素描效果",result);
    waitKey();
}
雕刻效果

用当前像素点的前一个像素点灰度值减去后一个像素点的灰度值,所得结果加上128作为当前像素点的灰度值。
原理的公式为:current(i, j) = current(j+1, j+1) - current(i-1, j-1)
以上的操作可以形成雕刻的原因在于,由于图片中相邻点的颜色值是比较接近的,因此这样的算法处理之后,只有颜色的边沿区域,也就是相邻颜色差异较大的部分的结果才会比较明显,而其他平滑区域则值都接近128左右,也就是灰色,这样就具有了雕刻效果。

public static void stone(Mat image){

    Mat dst = new Mat(image.size(),image.type());
    double[] pixelArr = new double[3];
    for (int i = 1, rlen = image.rows(); i < rlen; i++) {
        for (int j = 1, clen = image.cols(); j < clen; j++) {
            pixelArr = image.get(i,j).clone();
            double[] pixelArrN = image.get(i-1,j-1).clone();
            for (int k = 0;k<3;k++){
                pixelArr[k] = pixelArr[k] - pixelArrN[k]+128;
            }
            dst.put(i,j,pixelArr);
        }
    }
    HighGui.imshow("雕刻效果",dst);
    waitKey();

}
连环画特效
/**
    * 连环画特效
    * @param image
    */
public static void draw(Mat image) {
    Mat dst = new Mat(image.size(), image.type());
    double[] pixelArr = new double[3];

    for (int i = 0, rlen = image.rows(); i < rlen; i++) {
        for (int j = 0, clen = image.cols(); j < clen; j++) {
            pixelArr = image.get(i, j).clone();
            double r = pixelArr[2],g=pixelArr[1],b=pixelArr[0];

            pixelArr[2] = Math.abs(g-b+g+r)*r/256;
            pixelArr[1] = Math.abs(b-g+b+r)*r/256;
            pixelArr[0] = Math.abs(b-g+b+r)*g/256;

            dst.put(i, j, pixelArr);
        }
    }
    HighGui.imshow("连环画",dst);
    waitKey();
}
冰冻效果
/**
    * 冰冻效果
    */
public static void forzee(Mat image){

    Mat dst = new Mat(image.size(),image.type());
    double[] pixelArr = new double[3];

    System.out.println("?");
    for (int i=0,rlen=image.rows();i<rlen;i++){
        for(int j=0,clen=image.cols();j<clen;j++){
            pixelArr = image.get(i, j).clone();
            double r = pixelArr[2],g=pixelArr[1],b=pixelArr[0];
            pixelArr[0] = Math.abs(b - g - r);
            pixelArr[1] = Math.abs(g - r - b);
            pixelArr[2] = Math.abs(r - b - g);

            dst.put(i,j,pixelArr);
        }
    }
    HighGui.imshow("冰冻效果" ,dst);
    waitKey();
}
熔铸效果
/**
    * 熔铸效果
    */
public static void fire(Mat image){
    Mat dst = new Mat(image.size(),image.type());

    double[] pixelArr = new double[3];
    for(int i = 0,rlen=image.rows();i<rlen;i++){
        for (int j=0,clen=image.cols();j<clen;j++){
            pixelArr = image.get(i, j).clone();

            pixelArr[0] = pixelArr[0]*128 / (pixelArr[1]+pixelArr[2]+1);
            pixelArr[1] = pixelArr[1]*128 / (pixelArr[0]+pixelArr[2]+1);
            pixelArr[2] = pixelArr[2]*128 / (pixelArr[0]+pixelArr[1]+1);

            dst.put(i, j, pixelArr);
        }
    }
    HighGui.imshow("熔铸效果",dst);
    waitKey();
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值