JavaCV與OpenCV的區別和使用中遇到的問題

聖嘆&北京發表於2020-09-16

  寫這篇隨筆的原因是因為我用了JavaCV一段時間後專案情況糟透了,可能大家很熟悉OpenCV,也有一部分人熟悉JavaCV,但是我相信真正把JavaCV用到生產上的不是太多。

我參與圖片處理專案快一個月了,最初抱著很大興趣參與這個專案,漸漸的發現這個領域並不太好走。

  • 官網地址

JavaCV:http://bytedeco.org/,https://github.com/bytedeco/javacv

OpenCV:https://docs.opencv.org

 

  JavaCV據說比OpenCV多封裝了很多庫,但是目前我都沒用到,當時應用JavaCV的理由是不用單獨安裝OpenCV,不用根據環境進行庫的切換,

引入pom檔案後則可以直接幹活。

<dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.5.4</version>
        </dependency>
  • JavaCV的不穩定問題

多次仿射結果不一致,我想用JavaCV做仿射變換,縮小圖片,發現多次結果不一致,但是用OpenCV就沒有這個問題

@Test
    public void warpAffine() {
        Mat src=imread("D:\\img\\0_7p-1.jpg");
        Mat dst = new Mat();
        Point2f point2fSrc = new Point2f(3);

        point2fSrc.position(0).y(0).x(0);//TopLeft
        point2fSrc.position(1).y(0).x(src.cols()-1);//TopRight
        point2fSrc.position(2).y(src.rows()-1).x(0);//Bottom Left


        Point2f point2fDst = new Point2f(3);
        point2fDst.position(0).y(0).x(0);//TopLeft
        point2fDst.position(1).y(0).x(src.cols()/2);//TopRight
        point2fDst.position(2).y(src.rows()/2).x(0);//Bottom Left
 
        Date date=new Date();
        Mat affineTrans2 = opencv_imgproc.getAffineTransform(point2fSrc,point2fDst);
        opencv_imgproc.warpAffine(src, dst, affineTrans2, src.size());
        System.out.println(new Date().getTime()-date.getTime());
        imwrite("D:\\img\\7p-2.jpg", dst);

    }

結果應為等比縮小一倍,但是右邊的圖有變形,而且多次結果會不一致。

再看直接用OpenCV javaAPI的結果

@Test
    public void test(){

        System.load("C:\\Program Files\\opencv\\opencv\\build\\java\\x64\\opencv_java410.dll");

        System.out.println("Welcome to OpenCV " + Core.VERSION);

        Mat src = Imgcodecs.imread("D:/img/0_7p-1.jpg");
        Mat dst = new Mat((src.rows()/2),src.cols()/2,src.type());

        Point p1 = new Point( 0,0 );
        Point p2 = new Point( src.cols() - 1, 0 );
        Point p3 = new Point( 0, src.rows() - 1 );

        Point p4 = new Point( 0, 0);
        Point p5 = new Point( src.cols() /2, 0 );
        Point p6 = new Point( 0, src.rows() /2);

//        Point p4 = new Point( src.cols() /2, 0);
//        Point p5 = new Point( src.cols() /2, src.rows() /2 );
//       Point p6 = new Point( 0, 0);

        MatOfPoint2f ma1 = new MatOfPoint2f(p1,p2,p3);
        MatOfPoint2f ma2 = new MatOfPoint2f(p4,p5,p6);
Date date=new Date();
        // Creating the transformation matrix
        Mat tranformMatrix = Imgproc.getAffineTransform(ma1,ma2);



        // Applying Wrap Affine
        Imgproc.warpAffine(src, dst, tranformMatrix, src.size());
        System.out.println(new Date().getTime()-date.getTime());

        // Writing the image
        Imgcodecs.imwrite("D:/img/bbb.jpg", dst);
    }

bbb.jpg影像處理正確,多次執行程式碼結果一致。

 

  • 效能對比:

同樣的圖片放射縮小,基於JavaCV處理時間為174毫秒,OpenCV javaAPI的處理時間為11毫秒,差別接近17倍;

 

這裡我要說明一下,例子不具備普遍性,其它API我沒有一個一個的測試,希望對大家有幫助。

 

  • JavaCV的另外一個多執行緒併發問題:

我嘗試用20個執行緒壓測系統報了一個JVM錯誤:

#
# A fatal error has been detected by the Java Runtime Environment:
#
#  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffec4062738, pid=21668, tid=8404
#
# JRE version: Java(TM) SE Runtime Environment 18.9 (11.0.8+10) (build 11.0.8+10-LTS)
# Java VM: Java HotSpot(TM) 64-Bit Server VM 18.9 (11.0.8+10-LTS, mixed mode, tiered, compressed oops, g1 gc, windows-amd64)
# Problematic frame:
# C  [opencv_imgproc430.dll+0x1e2738]
#
# Core dump will be written. Default location: E:\img\hs_err_pid21668.mdmp
#
# If you would like to submit a bug report, please visit:
#   https://bugreport.java.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#

檢視mdmp檔案:

轉儲檔案:    hs_err_pid21668.mdmp : E:\img\hs_err_pid21668.mdmp
上次寫入時間:    2020/9/16 10:04:42
程式名稱:    java.exe : C:\Program Files\Java\jdk-11.0.8\bin\java.exe
程式架構:    x64
異常程式碼:    0xC0000005
異常資訊:    該執行緒嘗試讀寫某個虛擬地址,而它對該地址不具有相應的訪問許可權。
堆資訊:    存在

查詢一番資料並沒有找到解決辦法,我並不清楚直接用OpenCV JavaAPI是否有同樣的問題,如果知道如何解決歡迎留言,感激不盡。

雖然找到了一個緩解問題的方法,是設定JVM引數的-Xmx8g -Xms8g -Xmn4g,20個執行緒測試一般不出問題,50個併發有一半的概率死掉。

 

現在我決定用OpenCV重寫專案,但願不會再出現這個問題。

 

相關文章