java 盲水印实现比其他版本的速度更快 !!!

该盲水印版本速度上更快 ,参照了c的底层实现改编的 java 语法 。 结合先人的经验得以完成。希望能帮助有困惑的朋友


实测代码有效!

下面就是我的代码实现 :

首先是盲水印工具类

导入类

import org.bytedeco.javacpp.Loader;
import org.bytedeco.opencv.opencv_java;
import org.opencv.core.*;

import java.util.ArrayList;
import java.util.List;

import static org.opencv.core.Core.*;
import static org.opencv.core.Core.merge;
import static org.opencv.core.CvType.*;
import static org.opencv.core.CvType.CV_8UC1;
import static org.opencv.imgcodecs.Imgcodecs.imwrite;
import static org.opencv.imgproc.Imgproc.FONT_HERSHEY_COMPLEX;
import static org.opencv.imgproc.Imgproc.putText;

 

public class ImgWatermarkUtil {


    /**
     * <pre>
     *     添加图片文字水印
     * <pre>
     * @param sourceFilePath             图片对象
     * @param watermarkText     水印文字
     */
    public static void addImageWatermarkWithText(String sourceFilePath, String watermarkText, String outputFilePath) {
        List<Mat> planes = new ArrayList<>(3);
        List<Mat> allPlanes = new ArrayList<>(3);
        Mat src = ImgUtils.read(sourceFilePath, CV_8S);
        splitSrc(src, allPlanes);
        for (int i = 0; i < 3; i++) {
            Mat res = new Mat();
            Mat padded = allPlanes.get(i).clone();
            padded.convertTo(padded, CV_32F);
            Mat zeros = Mat.zeros(padded.size(), CV_32F);
            List<Mat> planesa = new ArrayList<>(2);
            planesa.add(0, padded);
            planesa.add(1, zeros);
            merge(planesa, res);
            dft(res, res);
            //加水印
            Scalar s = new Scalar(0, 0, 0);
            Point p = new Point(src.cols() / 8, src.rows() / 8);
            putText(res, watermarkText, p, FONT_HERSHEY_COMPLEX, 1.0, s, 3,
                    8, false);
            flip(res, res, -1);
            putText(res, watermarkText, p, FONT_HERSHEY_COMPLEX, 1.0, s, 3,
                    8, false);
            flip(res, res, -1);
            List<Mat> aplanes = new ArrayList<>(2);
            idft(res, res, Core.DFT_SCALE | Core.DFT_REAL_OUTPUT, 0);
            res.convertTo(res, CvType.CV_8U);
            planes.add(i, res);
        }
        Mat invDFT = new Mat();
        merge(planes, invDFT);
        if (invDFT.rows() != src.rows() || invDFT.cols() != src.cols()) {
            invDFT = new Mat(invDFT, new Rect(0, 0, src.width(), src.height()));
        }
        imwrite(outputFilePath, invDFT);
    }

    /**
     * <pre>
     *     获取图片水印
     * <pre>
     * @param
     */
    public static void getImageWatermarkWithText(String sourceFilePath, String output) {
        Mat src = ImgUtils.read(sourceFilePath, CV_8U);
        src.convertTo(src, CV_32F);
        List<Mat> planes = new ArrayList<>(2);
        Mat com = new Mat();
        planes.add(0, src);
        planes.add(1, Mat.zeros(src.size(), CV_32F));
        merge(planes, com);
        dft(com, com);
        List<Mat> newPlanes = new ArrayList<>(2);
        Mat mag = new Mat();
        split(com, newPlanes);
        magnitude(newPlanes.get(0), newPlanes.get(1), mag);
        add(Mat.ones(mag.size(), CV_32F), mag, mag);
        log(mag, mag);
        mag.convertTo(mag, CV_8UC1);
        normalize(mag, mag, 0, 255, NORM_MINMAX, CV_8UC1);
        imwrite(output, mag);
    }

    private static Mat splitSrc(Mat mat, List<Mat> allPlanes) {
        mat = optimizeImageDim(mat);
        split(mat, allPlanes);
        return mat;
    }

    /**
     * <pre>
     *     为加快傅里叶变换的速度,对要处理的图片尺寸进行优化
     * <pre>
     * @param image
     * @return
     */
    private static Mat optimizeImageDim(Mat image) {
        Mat padded = new Mat();
        int addPixelRows = getOptimalDFTSize(image.rows());
        int addPixelCols = getOptimalDFTSize(image.cols());
        copyMakeBorder(image, padded, 0, addPixelRows - image.rows(), 0, addPixelCols - image.cols(),
                Core.BORDER_CONSTANT, Scalar.all(0));
        return padded;
    }


    public static void main(String[] args) throws Exception {
        //必须要现加载
        Loader.load(opencv_java.class);
        long start = System.currentTimeMillis();
        ImgWatermarkUtil.addImageWatermarkWithText("/Users/XXX/Desktop/测试.jpg", "testtng", "/Users/XXX/Desktop/测试_text_ed.jpeg");
        System.out.println("encode cost : " + (System.currentTimeMillis() - start));
        long start1 = System.currentTimeMillis();
        ImgWatermarkUtil.getImageWatermarkWithText("/Users/XXX/Desktop/测试_text_en.jpeg", "/Users/XXX/Desktop/测试_text_de.jpeg");
        System.out.println("decode cost : " + (System.currentTimeMillis() - start1));
        System.out.println("");
    }

}

 

具体使用方法

加盲水印 

↵↵  

 public void blindWaterMarkEncode(InputStream inputStream, String text, HttpServletResponse response) throws Exception {
        BufferedImage bufferedImage = ImageIO.read(inputStream);
        String sourceFilePath = null;
        String targetFilePath = null;
        try {
            String fileDirectory = "/tmp/images";
            createFileDirectoryIfAbsent(fileDirectory);
            String filePathPrefix = fileDirectory + File.separator + System.currentTimeMillis() + "_";
            sourceFilePath = filePathPrefix + "test.jpg";
            try (BufferedOutputStream outStream = new BufferedOutputStream(new FileOutputStream(sourceFilePath))) {
                ImageIO.write(bufferedImage, "jpg", outStream);
            }
            targetFilePath = filePathPrefix + "blindwatermark_" + "test.jpg";
            //加 盲水印
            long startTime = System.currentTimeMillis();
            ImgWatermarkUtil.addImageWatermarkWithText(sourceFilePath, text, targetFilePath);
            log.info("增加盲水印 耗时 cost :{}", System.currentTimeMillis() - startTime);

            response.setContentType("jpg");
            //把加盲水印后的图片 输出到 HttpServletResponse
            try (InputStream inputStream = new BufferedInputStream(new FileInputStream(targetFilePath))) {
                ImageIO.write(ImageIO.read(inputStream), "jpg", response.getOutputStream());
            }
        } catch (IOException e) {
            throw new Exception("增加盲水印失败");
        } finally {
            //使用后删除临时文件,避免磁盘爆满
            Files.deleteIfExists(Paths.get(sourceFilePath));
            Files.deleteIfExists(Paths.get(targetFilePath));
        }
    }

 

解盲水印

public void blindWaterMarkDecode(MultipartFile multipartFile, HttpServletResponse response) throws Exception {
        int dotIndex = multipartFile.getOriginalFilename().lastIndexOf(".");
        if (dotIndex <= 0 || (dotIndex + 1) == multipartFile.getOriginalFilename().length()) {
            log.info("fileName is illegal! fileName:{} ", multipartFile.getOriginalFilename());
            throw new Exception("图片的文件名非法");
        }
        String fileDirectory = "/tmp/images";
        createFileDirectoryIfAbsent(fileDirectory);
        String filePathPrefix = fileDirectory + File.separator + System.currentTimeMillis() + "_";
        String sourceFilePath = filePathPrefix + "decode_" + multipartFile.getOriginalFilename();
        Files.write(Paths.get(sourceFilePath), multipartFile.getBytes());
        String targetFilePath = filePathPrefix + "watermark_" + multipartFile.getOriginalFilename();
        //获取图片的水印
        long startTime = System.currentTimeMillis();
        ImgWatermarkUtil.getImageWatermarkWithText(sourceFilePath, targetFilePath);
        log.info("解开盲水印 耗时 cost :{}", System.currentTimeMillis() - startTime);
        //设置缓存
        response.setContentType(multipartFile.getContentType());
        try (InputStream inputStream = new BufferedInputStream(new FileInputStream(targetFilePath))) {
            ImageIO.write(ImageIO.read(inputStream), multipartFile.getOriginalFilename().substring(dotIndex + 1), response.getOutputStream());
        }
        //使用后删除临时文件,避免磁盘爆满
        Files.deleteIfExists(Paths.get(sourceFilePath));
        Files.deleteIfExists(Paths.get(targetFilePath));
    }

 

原创不易,多谢关注 !

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在Spring Boot中使用OpenCV实现添加水印和获取水印,可以参考以下步骤: 1. 添加OpenCV依赖 在pom.xml文件中添加OpenCV依赖,例如: ```xml <dependency> <groupId>org.openpnp</groupId> <artifactId>opencv</artifactId> <version>4.5.1-1</version> </dependency> ``` 2. 实现添加水印 通过OpenCV实现添加水印的步骤如下: - 读取原图像和水印图像; - 将水印图像转换为灰度图像; - 将水印图像缩小到原图像的1/4大小; - 将水印图像嵌入到原图像中; - 保存嵌入水印后的图像。 示例代码如下: ```java import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; public class Watermark { public static void addWatermark(String imagePath, String watermarkPath, String outputPath) { // 加载OpenCV库 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 读取原图像和水印图像 Mat image = Imgcodecs.imread(imagePath); Mat watermark = Imgcodecs.imread(watermarkPath, Imgcodecs.IMREAD_GRAYSCALE); // 将水印图像缩小到原图像的1/4大小 Imgproc.resize(watermark, watermark, image.size(), 0.25, 0.25, Imgproc.INTER_AREA); // 将水印图像嵌入到原图像中 Core.addWeighted(image, 1.0, watermark, 0.5, 0, image); // 保存嵌入水印后的图像 Imgcodecs.imwrite(outputPath, image); } } ``` 3. 实现获取水印 通过OpenCV实现获取水印的步骤如下: - 读取带水印的图像; - 将图像转换为灰度图像; - 提取水印信息; - 将提取的水印信息输出。 示例代码如下: ```java import org.opencv.core.Core; import org.opencv.core.Mat; import org.opencv.imgcodecs.Imgcodecs; import org.opencv.imgproc.Imgproc; public class Watermark { public static void extractWatermark(String imagePath) { // 加载OpenCV库 System.loadLibrary(Core.NATIVE_LIBRARY_NAME); // 读取带水印的图像 Mat image = Imgcodecs.imread(imagePath); // 将图像转换为灰度图像 Imgproc.cvtColor(image, image, Imgproc.COLOR_BGR2GRAY); // 提取水印信息 // TODO: 实现提取水印信息的算法 // 输出提取的水印信息 // TODO: 输出提取的水印信息 } } ``` 需要注意的是,提取水印需要使用特定的算法,这里只是示例代码,具体实现需要根据实际情况进行调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值