bytedeco/javacv

ContourArea causes program to crash

Open

#2,117 opened on Nov 1, 2023

View on GitHub
 (14 comments) (0 reactions) (0 assignees)Java (1,583 forks)batch import
help wantedquestion

Repository metrics

Stars
 (6,985 stars)
PR merge metrics
 (No merged PRs in 30d)

Description

question

  • How does javaCv manage memory?
  • How do we use these objects correctly?

maven

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

    <dependency>
        <groupId>org.bytedeco</groupId>
        <artifactId>javacpp</artifactId>
        <classifier>macosx-x86_64</classifier>
        <version>1.5.9</version>
    </dependency>
    <dependency>
        <groupId>org.bytedeco</groupId>
        <artifactId>opencv</artifactId>
        <classifier>macosx-x86_64</classifier>
        <version>1.5.9</version>
    </dependency>

code

package com.debug2016.ocr.ofline;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bytedeco.javacpp.indexer.Indexer;
import org.bytedeco.opencv.opencv_core.*;
import org.opencv.core.Core;
import org.opencv.core.CvType;

import java.util.Arrays;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

import static org.bytedeco.opencv.global.opencv_core.*;
import static org.bytedeco.opencv.global.opencv_imgcodecs.imread;
import static org.bytedeco.opencv.global.opencv_imgproc.*;
import static org.bytedeco.opencv.opencv_core.Mat.ones;


public class OriginLightCheck {
private static Logger log = LogManager.getLogger();

public static void main(String[] strings) {
    String imagePath = strings[0];
    Integer count = Integer.valueOf(strings[1]);

    long maxMemory = Runtime.getRuntime().maxMemory();
    long totalMemory = Runtime.getRuntime().totalMemory();
    long freeMemory = Runtime.getRuntime().freeMemory();
    System.out.println("Max Memory: " + maxMemory / 1024 / 1024 + "MB");
    System.out.println("Allocated Memory: " + totalMemory / 1024 / 1024 + "MB");
    System.out.println("Free Memory: " + freeMemory / 1024 / 1024 + "MB");
    log.info("testSdk begin ossKey={}", imagePath);
    Mat test = imread(imagePath);
    if (test == null || test.cols() <= 1) {
        log.warn("testSdk mat downloadMat error");
        return;
    }
    for (int j = 0; j < count; j++) {
        try {
            Mat clone = test.clone();
            ImageCheckResult testSdk = securityCheck(clone, j + "");
            log.info("testSdk-" + Thread.currentThread().getName() + "-" + j + "-" + testSdk);
        } catch (Exception e) {
            log.warn("testSdk mat processing error", e);
        }
    }
}

public static void securityCheck(Mat originMat, String sessionId) {
    log.info("securityCheck {} a originMat={},hash={},reference={}", sessionId, originMat, originMat.hashCode(), originMat.referenceCount());

    Mat hsvMat = new Mat();
    cvtColor(originMat, hsvMat, COLOR_BGR2HSV);

    Scalar lowerBound1 = new Scalar(0, 80, 250, 0);
    Scalar upperBound1 = new Scalar(180, 255, 255, 0); 
    Mat securityMat = new Mat();
    Mat low1 = new Mat(lowerBound1);
    Mat upper1 = new Mat(upperBound1);
    inRange(hsvMat, low1, upper1, securityMat);

    MatExpr securityKernel = ones(5, 5, CV_8UC1);
    Mat securityDilateMat = new Mat();
    dilate(securityMat, securityDilateMat, securityKernel.asMat(), new Point(-1, -1), 3, BORDER_CONSTANT, morphologyDefaultBorderValue());

    MatExpr kernel = ones(3, 3, CV_8UC1);
    Mat securityErodeMat = new Mat();
    erode(securityDilateMat, securityErodeMat, kernel.asMat(), new Point(-1, -1), 4, BORDER_CONSTANT, morphologyDefaultBorderValue());

    MatVector contours = new MatVector();
    Mat hierarchy = new Mat();
    findContours(
            securityErodeMat,
            contours,
            hierarchy,
            RETR_CCOMP,
            CHAIN_APPROX_SIMPLE
    );
    log.info("securityCheck {} contours this={},hash={},reference={}", sessionId, contours, contours.address());
   
    Mat[] mats = contours.get();
    AtomicInteger num = new AtomicInteger(0);
    List<Mat> collect = Arrays.stream(mats).peek(a -> {
        num.getAndIncrement();
        log.info("securityCheck {} newMat count={},Mat={},hash={},reference={},contoursHash={},", sessionId, num.get(), a, a.address(), a.referenceCount());
    }).sorted((o1, o2) -> {
        double area1 = contourArea(o1, false);
        double area2 = contourArea(o2, false);
        return Double.compare(area2, area1);
    }).collect(Collectors.toList());
    
    boolean haveLight = false;
    int loopCount = Math.min(collect.size(), 4);
    for (int i = 0; i < loopCount; ++i) {
        Mat mat = collect.get(i);
        log.info("securityCheck {} preCheck count={},Mat={},hash={},reference={},contoursHash={}", sessionId, i, mat, mat.address(), mat.referenceCount());
    }
    for (int i = 0; i < loopCount; ++i) {
        Mat myMat = collect.get(i);
        try {
            log.info("securityCheck {} start count={},myMat={},hash={},reference={},contoursHash={}", sessionId, i, myMat, myMat.address(), myMat.referenceCount());

            Mat mask = new Mat(originMat.size(), CV_8UC1, Scalar.all(0));
            log.info("securityCheck {} mask count={},myMat={},hash={},reference={},contoursHash={}", sessionId, i, myMat, myMat.address(), myMat.referenceCount());

            drawContours(mask, new MatVector(myMat.clone()), 0, new Scalar(255, 255, 255, 0));
            log.info("securityCheck {} drawContours count={},myMat={},hash={},reference={},contoursHash={}", sessionId, i, myMat, myMat.address(), myMat.referenceCount());

            Mat extractedRegion = new Mat();
            log.info("securityCheck {} extractedRegion count={},myMat={},hash={},reference={},contoursHash={}", sessionId, i, myMat, myMat.address(), myMat.referenceCount());

            hsvMat.copyTo(extractedRegion, mask);
            log.info("securityCheck {} copyTo count={},myMat={},hash={},reference={},contoursHash={}", sessionId, i, myMat, myMat.address(), myMat.referenceCount());

            Map<Scalar, Integer> scalarIntegerMap = checkLightNum(extractedRegion, myMat);
            log.info("securityCheck {} checkLightNum count={},myMat={},hash={},reference={},contoursHash={}", sessionId, i, myMat, myMat.address(), myMat.referenceCount());

            double area = contourArea(myMat, false);
        } catch (Exception e) {
            log.info("securityCheck {} error1 count={},myMat={},hash={},reference={},contoursHash={}", sessionId, i, myMat, myMat.address(), myMat.referenceCount(),e);
        }
        log.info("securityCheck {} end count={},myMat={},hash={},reference={},contoursHash={}", sessionId, i, myMat, myMat.address(), myMat.referenceCount());
    }
    log.info("securityCheck {} end", sessionId);
}

private static Map<Scalar, Integer> checkLightNum(Mat extractedRegion, Mat myMat) {

    log.info("checkLightNum 01 myMat={},hash={},myMatreference={},contoursHash={}", myMat, myMat.address(), myMat.referenceCount());

    List<Scalar> detectedColors = new ArrayList<>();
    Map<Scalar, Integer> colorMap = new HashMap<>();
    Indexer indexer = extractedRegion.createIndexer();
    log.info("checkLightNum 02 myMat={},hash={},myMatreference={},contoursHash={}", myMat, myMat.address(), myMat.referenceCount());


    Boolean isLog = false;
    for (int y = 0; y < extractedRegion.rows(); y++) {
        for (int x = 0; x < extractedRegion.cols(); x++) {
          
            Scalar currentColor = new Scalar(h, s, v, 0);
          if ((myMat.cols()) == 0 && !isLog) {
                isLog = true;
                log.info("checkLightNum findChange myMat={},hash={},myMatreference={},contoursHash={}", myMat, myMat.address(), myMat.referenceCount());
            }
        }
    }
//        detectedColors.forEach(Pointer::deallocate);
//        colorMap.keySet().forEach(Pointer::close);
    log.info("checkLightNum end myMat={},hash={},myMatreference={},contoursHash={}", myMat, myMat.address(), myMat.referenceCount());
    return colorMap;
     }

}

log

  1. securityCheck 256 contours this=org.bytedeco.opencv.opencv_core.Mat[width=1,height=209,depth=-2147483616,channels=2]],address= 0x600002457dc0,reference={}
  2. checkLightNum 02 myMat=org.bytedeco.opencv.opencv_core.Mat[width=1,height=209,depth=-2147483616,channels=2],address=140261930922848,myMatreference=-1,contoursHash={}
  3. [GC (Allocation Failure) 267734K->14246K(595968K), 0.0013573 secs]
  4. Debug: Collecting org.bytedeco.javacpp.Pointer$NativeDeallocator[ownerAddress=0x600002457dc0,deallocatorAddress=0x12647c310]
  5. checkLightNum end myMat=org.bytedeco.opencv.opencv_core.Mat[width=10,height=19576,depth=-2147483640,channels=17],address=140261930922848,myMatreference=-1,contoursHash={}
  6. securityCheck 256 checkLightNum count=1,myMat=org.bytedeco.opencv.opencv_core.Mat[width=10,height=19576,depth=-2147483640,channels=17],address=140261930922848,reference=-1,contoursHash={}

Log conclusion: MatVector(address = 0x600002457dc0), Mat(address=140261930922848). From the above log, it can be seen that before MatVector is deallocated, Mat[width=1,height=209,depth=-2147483616,channels=2], After MatVector deallocate Mat[width=10,height=19576,depth=-2147483640,channels=17]

I am using a Mat object, but changes have occurred inside it, causing my program to crash? Why is it designed like this? How can I avoid this problem?

hs_error_pid.log

`SIGSEGV (0xb) at pc=0x0000000124db5edf, pid=5705, tid=0x0000000000001203 Stack: [0x000000030d836000,0x000000030d936000], sp=0x000000030d9354e0, free space=1021k Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)

  • C [libopencv_core.407.dylib+0x12cedf] cv::Mat::Mat(cv::Mat const&)+0x4f
  • C [libopencv_imgproc.407.dylib+0x278c93] cv::contourArea(cv::_InputArray const&, bool)+0x43
  • C [libjniopencv_imgproc.dylib+0x93571]
  • Java_org_bytedeco_opencv_global_opencv_1imgproc_contourArea__Lorg_bytedeco_opencv_opencv_1core_Mat_2Z+0x81
  • J 1370 org.bytedeco.opencv.global.opencv_imgproc.contourArea(Lorg/bytedeco/opencv/opencv_core/Mat;Z)D (0 bytes) @ 0x00000001101edec4 [0x00000001101ede00+0xc4]`

image

image

Contributor guide