基于openCV的图片叠加ImgAdd

很多rpg或gal的cg为了节省空间,使用的都是类似于差分的的图像合成方式,将一组cg分成一张整体和数张微小的不同,在显示对应cg时只需将整体和不同的碎片进行混合,以达到动态的效果。而为了较好的合成效果,碎片的背景通常是绿幕或者透明。

openCV是一个轻量、高效、跨平台的图像处理库。为了模拟cg差分的合成效果,基于openCV写了一个简单的图像混合应用。

在项目中使用openCV
使用OpenCV库,需要在官网(https://opencv.org/)下载项目需要的库,选择对应的开发平台,这里我使用的是windows的4.6版本。
在这里插入图片描述
下载后获得一个exe文件,是一个自动的zip解压。在解压的文件夹进入opencv/build/java/中找到x64或x86,选择开发设备对应内核架构文件夹下的opencv_java460.dll。
在这里插入图片描述

在你的项目中使用openCV,将opencv-460.jar和opencv_java460.dll复制到一个文件夹下,这里我选择直接扔到项目目录,你也可以新建一个lib目录存储这些库。

在这里插入图片描述
打开IDEA,新建一个项目,点击File/Project Structure,选择Project Settings/Libraries,点击加号(+),在弹框中选择java,找到存放opencv库的目录,选择dll文件和jar文件。弹出选择模块(Choose Modules)点击ok。然后应用更改(Apply)并确定(Ok)。
在这里插入图片描述
在这里插入图片描述
写一个测试

package com.demo.coo;

import org.opencv.core.Core;

public class Main {

    static{//启动类中需要加载链接库
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
    }

    public static void main(String[] args) {
	// write your code here
        System.out.println("open cv version->"+Core.VERSION);
    }
}

如果版本能被顺利输出,说明导入成功。
在这里插入图片描述
先写两个方法,用于输出文件和日志。

public static void outDst(Mat dst,String pathName) {
        if(new File(pathName).exists()) {
            throw new RuntimeException("File is exist!");
        }
        Imgcodecs.imwrite(pathName,dst);
    }

    public static final void Dlog(String message){
        System.out.println(message);
    }

图像合并方法的核心代码
根据上文描述,提供了两种图像合成。第一种是绿幕合成,另一种是透明通道合成。

先看第一种

//Add two Images, second of them is clip, merge them into one picture
    public static void ADD_C(String filePath1,String filePath2,String filePath3) {
        Mat srcA = Imgcodecs.imread(filePath1);
        Mat srcB = Imgcodecs.imread(filePath2);

        if(srcA.empty() || srcB.empty()) {
//				  Dlog("File path is empty!");
            if(debug) {
                Dlog("File:"+filePath1+" founded: "+!srcA.empty());
                Dlog("File:"+filePath2+" founded: "+!srcB.empty());
            }
            return;
        }else {
            if(debug) {
                Dlog("Images have been loaded!");
            }
        }

        Mat hsv = new Mat();
        Mat mask = new Mat();

        Imgproc.cvtColor(srcB, hsv, Imgproc.COLOR_BGR2HSV);	//*生成掩膜

        Core.inRange(hsv, new Scalar(35,43,46), new Scalar(77,255,255), mask);	//*绿色覆盖

        Core.bitwise_not(mask, mask);	//反掩

        Mat dst = new Mat();

        Core.bitwise_and(srcB,srcB,dst,mask); //黑底

        List<Mat> _lDstMat = new ArrayList<Mat>();

        Core.split(dst , _lDstMat);

        _lDstMat.add(mask);	//Mask Not

        Mat dstA = new Mat();
        Mat dstB = new Mat();

        Core.merge(_lDstMat, dstB);	//*透明 祛黑

        Imgproc.cvtColor(srcA, dstA, Imgproc.COLOR_BGR2BGRA);	//通道扩容

        Core.copyTo(dstB, dstA, mask);

        outDst(dstA,filePath3);		//*直接覆盖
    }

filePath1 是原图的文件路径
filePath2 是背景为绿幕的碎片的图片路径
filePath3 是输出合成文件的图片路径

写一个测试看看效果。
在这里插入图片描述
在路径下查看,可以发现合成后的图片已被输出。
在这里插入图片描述

然后看第二个图片合成方法。

//用原图的透明通道作为掩膜的图像融合方式,效果更好一些。
    public static void ADD_A(String filePath1,String filePath2,String filePath3) {
        Mat srcA = Imgcodecs.imread(filePath1,Imgcodecs.IMREAD_UNCHANGED);
        Mat srcB = Imgcodecs.imread(filePath2,Imgcodecs.IMREAD_UNCHANGED);	//$1 一定要以IMREAD_UNCHANGED模式读入,否则会忽视透明通道

        Mat cvtB = new Mat();
        Imgproc.cvtColor(srcB, cvtB, Imgproc.COLOR_BGR2BGRA);	//$2 将原图转换为带透明通道模式

        List<Mat> _lB = new ArrayList<Mat>();
        Core.split(cvtB,_lB);	//$3 将转换后的图片按通道分割

        if(_lB.size()!=4 || _lB.get(3).empty()) {
            Dlog("Unable to find alpha channel.");
            return;
        }
        Mat alpha = new Mat();

        List<Mat> _lAlp = new ArrayList<Mat>();

        _lAlp.add(_lB.get(3));	//$4 将透明通道单独提取出 并直接作为掩码

        Core.merge(_lAlp, alpha);

        Mat bin = new Mat();

        Imgproc.threshold(alpha, bin, 0, 255, Imgproc.THRESH_BINARY);

        Core.copyTo(srcB, srcA, bin);

        outDst(srcA,filePath3);
    }

filePath1 是原图的文件路径
filePath2 是背景为透明的碎片的图片路径
filePath3 是输出合成文件的图片路径

写一个测试看看效果。
在这里插入图片描述
在路径下查看,可以发现合成后的图片已被输出。
在这里插入图片描述
git地址:https://github.com/IdleFishEngineer/ImgAdd/tree/master

如果有疑问请在评论区讨论。
写作不易,请给个赞吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值