1. 程式人生 > >java Bufferdimage與opencv Mat在記憶體中的轉化

java Bufferdimage與opencv Mat在記憶體中的轉化

開發十年,就只剩下這套架構體系了! >>>   

以前寫Java人臉識別爬蟲的時候遇到的問題,最早的時候是用tempfile的形式去解決每一個爬蟲執行緒爬取圖片到本地,儲存為tempfile,然後opencv再讀取出來做處理和識別,但是這樣涉及磁碟io,爬蟲效能異常緩慢,所以後面思考了一段時間琢磨出來再記憶體裡面對影象進行轉化,本質上,影象資料對Java來說都是bytes[]串,所以我的轉化過程的思路,就是把byte串取出來,重新組裝。

opencv Mat轉BufferImage

    public static BufferedImage toBufferedImage(Mat matrix) {
        int type = BufferedImage.TYPE_BYTE_GRAY;
        if (matrix.channels() > 1) {
            type = BufferedImage.TYPE_3BYTE_BGR;
        }
        int bufferSize = matrix.channels() * matrix.cols() * matrix.rows();
        byte[] buffer = new byte[bufferSize];
        matrix.get(0, 0, buffer); // get all pixel from martix
        BufferedImage image = new BufferedImage(matrix.cols(), matrix.rows(), type);
        final byte[] targetPixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        System.arraycopy(buffer, 0, targetPixels, 0, buffer.length);
        return image;
    }

BufferImage轉為opencv Mat

    public static Mat bufferToMartix(BufferedImage image) {
        Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
        byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
        if (mat != null) {
            try {
                mat.put(0, 0, data);
            } catch (Exception e) {
                return null;
            }
        }
        return mat;
    }

byte陣列轉opencv Mat

    public static Mat bufferToMartix(byte[] image) throws IOException {
        BufferedImage bImage = ImageIO.read(new ByteArrayInputStream(image));
        byte[] bytes = ((DataBufferByte) bImage.getRaster().getDataBuffer()).getData();
        Mat data = new Mat(bImage.getHeight(), bImage.getWidth(), CvType.CV_8UC3);
        data.put(0, 0, bytes);
        return data;
    }

有意思的是,當我讓一個BufferedImage巢狀為

//這裡假設b_image裡面包含有影象資料
BufferedImage b_image=b_image=new BufferedImage();
Mat matrix=toBufferedImage(bufferToMartix(b_image))

的時候,JVM概率死掉報出Core Error,於是我分離了這兩個函式避免巢狀使用,沒有去深究這個問題,猜測這可能與JVM的GC(垃圾回收)有關係,而且就算不出現JVM致命錯誤,這樣出來的影象也是有問題的,會缺失很多資料,然後變成一堆噪聲和一片白,直觀感覺就是toBufferedImage呼叫結束後圖像資料記憶體就被釋放掉了,當bufferToMartix從後面執行的時候取了同樣大小的記憶體區塊當做影象,隨機產生了JVM致命記憶體衝突,或者不衝突但是資料混亂的問題,因為不是專業Java這個