javacv icon indicating copy to clipboard operation
javacv copied to clipboard

After using Javacv, the memory has been in a high occupancy state.Can you tell me how to handle it?

Open 1348079150 opened this issue 2 years ago • 5 comments

Code example: image Even though I proactively released the memory, it is still in a high occupancy state

The memory usage:

image

1348079150 avatar Sep 26 '23 01:09 1348079150

If you have a small code snippet to reproduce the issue, please provide it!

saudet avatar Sep 26 '23 01:09 saudet

public static void addImageWatermarkWithText(String sourcePath, String watermark, String targetPath) throws IOException {
    long timeStart = System.currentTimeMillis();
    Path inputPath = Paths.get(sourcePath);
    Path outPath = Paths.get(targetPath);

    if (!Files.exists(inputPath)) {
        throw new IOException("File not exist");
    }
    Mat imgMat = null;
    Mat watermarkedMat = null;
    Mat cutMat = null;
    try {
        imgMat = imread(inputPath.toAbsolutePath().toString());
        watermarkedMat = addImageWatermarkWithText(imgMat, watermark);
        // 裁剪黑边
        cutMat = new Mat(watermarkedMat, new Rect(0, 0, imgMat.cols(), imgMat.rows()));
        imwrite(outPath.toAbsolutePath().toString(), cutMat);
        logger.info("图片盲水印添加成功,内存已释放,path={},耗时={}ms",targetPath,System.currentTimeMillis() - timeStart);
    } catch (Exception e) {
        throw new IOException("Watermarking Process Error", e);
    }finally {
        // 释放内存,避免老年代积压过多
        if (imgMat != null) {
            imgMat.deallocate();
        }
        if (watermarkedMat != null) {
            watermarkedMat.deallocate();
        }
        if (cutMat != null) {
            cutMat.deallocate();
        }
    }
}

public static String getBase64(Mat image) throws IOException {
    return getBase64(mat2bytes(image));
}

public static String getBase64(byte[] bytes) {
    return "data:image/png;base64," + Base64.getEncoder().encodeToString(bytes);
}

public static byte[] mat2bytes(Mat image) throws IOException {
    BufferedImage bufferedImage = Java2DFrameUtils.toBufferedImage(image);
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ImageIO.write(bufferedImage, "png", baos);
    // 释放内存,避免老年代积压过多
    image.deallocate();
    return baos.toByteArray();
}




public static Mat getImageWatermarkWithText(Mat image) {
    MatVector allPlanes = new MatVector();
    Mat complexImage = getDFT(image, allPlanes);
    return createOptimizedMagnitude(complexImage);
}

public static Mat getDFT(Mat image, MatVector allPlanes) {
    MatVector planes = new MatVector();
    Mat complexImage = new Mat();
    Mat padded = splitSrc(image, allPlanes);
    padded.convertTo(padded, CV_32F);
    planes.push_back(padded);
    planes.push_back(Mat.zeros(padded.size(), CV_32F).asMat());
    merge(planes, complexImage);
    // dft
    dft(complexImage, complexImage);
    // 释放内存,避免老年代积压过多
    padded.deallocate();
    planes.deallocate();
    return complexImage;
}

private static Mat splitSrc(Mat mat, MatVector allPlanes) {
    mat = optimizeImageDim(mat);
    split(mat, allPlanes);
    Mat padded = new Mat();
    if (allPlanes.size() > 1) {
        for (int i = 0; i < allPlanes.size(); i++) {
            if (i == 0) {
                padded = allPlanes.get(i);
                break;
            }
        }
    } else {
        padded = mat;
    }
    return padded;
}
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(),
            BORDER_CONSTANT, Scalar.all(0));
    return padded;
}
private static Mat antitransformImage(Mat complexImage, MatVector allPlanes) {
    Mat invDFT = new Mat();
    idft(complexImage, invDFT, DFT_SCALE | DFT_REAL_OUTPUT, 0);
    Mat restoredImage = new Mat();
    invDFT.convertTo(restoredImage, CV_8U);
    if (allPlanes.size() == 0) {
        allPlanes.push_back(restoredImage);
    } else {
        allPlanes.put(0, restoredImage);
    }
    Mat lastImage = new Mat();
    merge(allPlanes, lastImage);
    // 释放内存,避免老年代积压过多
    complexImage.deallocate();
    restoredImage.deallocate();
    allPlanes.deallocate();
    return lastImage;
}

private static Mat createOptimizedMagnitude(Mat complexImage) {
    MatVector newPlanes = new MatVector();
    Mat mag = new Mat();
    split(complexImage, newPlanes);
    magnitude(newPlanes.get(0), newPlanes.get(1), mag);
    add(Mat.ones(mag.size(), CV_32F).asMat(), mag, mag);
    log(mag, mag);
    shiftDFT(mag);
    mag.convertTo(mag, CV_8UC1);
    normalize(mag, mag, 0, 255, NORM_MINMAX, CV_8UC1, null);
    // 释放内存,避免老年代积压过多
    newPlanes.deallocate();
    complexImage.deallocate();
    return mag;
}

private static void shiftDFT(Mat image) {
    image = image.apply(new Rect(0, 0, image.cols() & -2, image.rows() & -2));
    int cx = image.cols() / 2;
    int cy = image.rows() / 2;

    Mat q0 = new Mat(image, new Rect(0, 0, cx, cy));
    Mat q1 = new Mat(image, new Rect(cx, 0, cx, cy));
    Mat q2 = new Mat(image, new Rect(0, cy, cx, cy));
    Mat q3 = new Mat(image, new Rect(cx, cy, cx, cy));
    Mat tmp = new Mat();
    q0.copyTo(tmp);
    q3.copyTo(q0);
    tmp.copyTo(q3);
    q1.copyTo(tmp);
    q2.copyTo(q1);
    tmp.copyTo(q2);
    // 释放内存,避免老年代积压过多
    q0.deallocate();
    q1.deallocate();
    q2.deallocate();
    q3.deallocate();
    tmp.deallocate();
}

public static String getImageWatermarkWithTextOfBase64(String srcPath) throws IOException {
   return getBase64(getImageWatermarkWithText(srcPath));
}

public static Mat getImageWatermarkWithText(String srcPath) throws IOException {
    long timeStart = System.currentTimeMillis();
    Path path = Paths.get(srcPath);
    if (!Files.exists(path)) {
        throw new IOException("File not exist");
    }
    Mat mat = imread(path.toAbsolutePath().toString());
    Mat imageWatermarkWithText = getImageWatermarkWithText(mat);
    // 释放内存,避免老年代积压过多
    mat.deallocate();
    logger.info("图片盲水印解析成功,内存已释放,path={},耗时={}ms",srcPath,System.currentTimeMillis() - timeStart);
    return imageWatermarkWithText;
}

public static Mat addImageWatermarkWithText(Mat image, String watermarkText) {
    MatVector allPlanes = new MatVector();
    Mat complexImage = getDFT(image, allPlanes);
    Scalar scalar = new Scalar(0x00, 0);
    Point point = new Point(200, 400);
    putText(complexImage, watermarkText, point,FONT_HERSHEY_TRIPLEX, 1.5, scalar, 3, 5, false);
    flip(complexImage, complexImage, -1);
    putText(complexImage, watermarkText, point,FONT_HERSHEY_TRIPLEX, 1.5, scalar, 3, 5, true);
    flip(complexImage, complexImage, -1);

    return antitransformImage(complexImage, allPlanes);
}

1348079150 avatar Sep 26 '23 01:09 1348079150

When I repeatedly call the addImageWatermarkWithText method in a loop, the temporary memory usage continues to rise

<dependency>
		<groupId>org.bytedeco</groupId>
		<artifactId>javacv</artifactId>
		<version>1.5.9</version>
	</dependency>

	<!-- Additional dependencies required to use CUDA and cuDNN -->
	<dependency>
		<groupId>org.bytedeco</groupId>
		<artifactId>opencv-platform</artifactId>
		<version>4.7.0-1.5.9</version>
	</dependency>

1348079150 avatar Sep 26 '23 01:09 1348079150

This is not a small code snippet.

saudet avatar Sep 26 '23 01:09 saudet

You can use this demo to reproduce that problem, hoping to help me solve this memory problem

1348079150 avatar Sep 26 '23 02:09 1348079150